Summary: Customize authentication to meet your application requirements
OverviewThere are three actors in the authentication life cycle:
When a client needs to contact a server for the first time, it uses a CredentialsProvider to create a UserDetails which encapsulates the credentials required for authentication, and send it to the server. The server then uses its SecurityManager to authenticate the UserDetails and to obtain its privileges. The server then generates a unique authentication token which is used to cache the user's credentials and privileges, and return it to the client. From this point whenever the client sends a request to that server it binds the authentication token to the request, so the server doesn't need to re-authenticate it. Custom CredentialsThe credentials which a client passes to the server for authentication are encapsulated in an interface called UserDetails. GigaSpaces XAP provides a built-in UserDetails implementation called User which supports username-password authentication patterns. It is recommended to extend the User class instead of directly implementing the UserDetails interface, and override the super class if needed. For example, in our demo we only need to add a String payload, hence the following class will suffice: public class CustomUserDetails extends com.gigaspaces.security.directory.User { private String customPayload; public CustomUserDetails(String username, String password, String customPayload) { super(username, password); this.customPayload = customPayload; } public String getCustomPayload() { return customPayload; } } Note that since User is Serializable, the customPayload field is automatically serialized along with the default credentials.
The Client sideA secured proxy is usually configured with a username-password pair, which are implicitly translated to a default UserDetails implementation as discussed above. When custom credentials are required, the proxy can be configured with a CredentialsProvider implementation, which is used to obtain a UserDetails instance whenever the client connects to a new server. The custom credentials provider usually stores the required credentials internally and uses them to create a new UserDetails when needed. For example: public class CustomCredentialsProvider extends CredentialsProvider { private String username; private String password; private String serverAddress; public CustomCredentialsProvider() {} public CustomCredentialsProvider(String username, String password, String serverAddress) { initialize(username, password, serverAddress); } @Override public void initialize(Properties properties) { super.initialize(properties); initialize(properties.getProperty(USERNAME_PROPERTY), properties.getProperty(PASSWORD_PROPERTY), properties.getProperty("custom-security.server-address")); } private void initialize(String username, String password, String serverAddress) { this.username = username; this.password = password; this.serverAddress = serverAddress; } @Override public UserDetails getUserDetails() { // A real-life implementation would use some external service to generate the custom payload. // Since this is a demo we mock this by generating the payload locally: String payload = serverAddress + "#" + username; return new CustomUserDetails(username, password, payload); } }
UsageCustom CredentialsProvider can be provided in several ways, as follows:
Namespace
<!-- Creating the custom credentials provider --> <bean id="myCredentialsProvider" class="com.demo.CustomCredentialsProvider"> <constructor-arg><value>user1</value></constructor-arg> <constructor-arg><value>123456</value></constructor-arg> <constructor-arg><value>myServer</value></constructor-arg> </bean> <!-- Creating an embedded secured Space --> <os-core:space id="embeddedSpace" url="/./mySpace"> <os-core:security credentials-provider="myCredentialsProvider" /> </os-core:space> <!-- Looking up a secured Space --> <os-core:space id="space" url="jini://*/*/mySpace"> <os-core:security credentials-provider="myCredentialsProvider" /> </os-core:space> Plain XML <!-- Creating the custom credentials provider --> <bean id="myCredentialsProvider" class="com.demo.CustomCredentialsProvider"> <constructor-arg><value>user1</value></constructor-arg> <constructor-arg><value>123456</value></constructor-arg> <constructor-arg><value>myServer</value></constructor-arg> </bean> <!-- Creating an embedded secured Space --> <bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean"> <property name="url"><value>"/./mySpace"</value></property> <property name="credentialsProvider"><ref local="myCredentialsProvider"/></property> </bean> <!-- Looking up a secured Space --> <bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean"> <property name="url"><value>"jini://*/*/mySpace"</value></property> <property name="credentialsProvider"><ref local="myCredentialsProvider"/></property> </bean> Code CredentialsProvider myCredentialsProvider = new CustomCredentialsProvider("user1", "123456", "myServer"); // Looking up a remote space UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("jini://*/*/mySpace").credentialsProvider(myCredentialsProvider); GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).gigaSpace(); // Constructing an Admin instance Admin admin = new AdminFactory().credentialsProvider(myCredentialsProvider).createAdmin(); // Space Deployment admin.getGridServiceManagers().deploy(new SpaceDeployment("mySpace").userDetails(myCredentialsProvider.getUserDetails())); // Processing Unit Deployment admin.getGridServiceManagers().deploy(new ProcessingUnitDeployment("myPu").userDetails(myCredentialsProvider.getUserDetails())); The Server SideWhen a secured server receives a request from the client for the first time, it needs to authenticate the UserDetails instance bundled with the request. This is done by invoking the authenticate(UserDetails) method of the SecurityManager component in the server, which is in charge of both authenticating the user and obtaining its privileges set. The default SecurityManager provided in GigaSpaces XAP is called FileSecurityManager, which (as its name implies) authenticates the UserDetails against a file which stores all the users credentials and privileges. public class CustomSecurityManager implements com.gigaspaces.security.SecurityManager { private String serverAddress; public CustomSecurityManager() {} public CustomSecurityManager(String serverAddress) { initialize(serverAddress); } @Override public void init(Properties properties) throws com.gigaspaces.security.SecurityException { initialize(properties.getProperty("custom-security.server-address")); } private void initialize(String serverAddress) { this.serverAddress = serverAddress; } @Override public void close() { } @Override public Authentication authenticate(UserDetails userDetails) throws AuthenticationException { if (!(userDetails instanceof CustomUserDetails)) throw new AuthenticationException("Invalid credentials class: " + userDetails.getClass()); if (!isValid((CustomUserDetails) userDetails)) throw new AuthenticationException("Invalid credentials for user '" + userDetails.getUsername() + "'"); Authority[] authorities = getUserAuthorities(userDetails.getUsername()); return new Authentication(new User(userDetails.getUsername(), userDetails.getPassword(), authorities)); } private boolean isValid(CustomUserDetails credentials) { // A real-life implementation would use some external service to authenticate the credentials. // Since this is a demo we mock it by generating the payload locally and comparing it to the client's payload: String expectedPayload = serverAddress + "#" + credentials.getUsername(); return expectedPayload.equals(credentials.getCustomPayload()); } private Authority[] getUserAuthorities(String username) { // A real implementation would receive the client's privileges from a security repository. // Since this is a demo we mock it by returning a fixed set of privileges: return new Authority[] { new GridAuthority(GridAuthority.GridPrivilege.MANAGE_GRID), new GridAuthority(GridAuthority.GridPrivilege.MANAGE_PU), new GridAuthority(GridAuthority.GridPrivilege.PROVISION_PU), new MonitorAuthority(MonitorAuthority.MonitorPrivilege.MONITOR_JVM), new MonitorAuthority(MonitorAuthority.MonitorPrivilege.MONITOR_PU), new SystemAuthority(SystemPrivilege.MANAGE_ROLES), new SystemAuthority(SystemPrivilege.MANAGE_USERS), new SpaceAuthority(SpaceAuthority.SpacePrivilege.WRITE), new SpaceAuthority(SpaceAuthority.SpacePrivilege.READ), new SpaceAuthority(SpaceAuthority.SpacePrivilege.TAKE)}; } @Override public DirectoryManager createDirectoryManager(UserDetails userDetails) throws AuthenticationException, AccessDeniedException { throw new DirectoryAccessDeniedException("Creating a directory manager is not supported in this example."); } } Authentication resultThe authenticate method not only validates the credentials are authentic - it also returns the Authority (XAP name for privilege) set granted to the user. The authenticate method returns an Authentication instance, which is created using a UserDetails instance which stores the user's authorities. You can choose between using the built-in User class to encapsulate the original credentials with the granted authorities (as shown in the demo implementation), or adjusting your custom user details implementation to store the authorities.
Security repositories and administrators often prefer not to map users directly to privileges, but rather to create roles (e.g. Admins, Managers, Employees), map a role to a set of privileges (e.g. Write, Read) and then map users to roles (this simplifies management of large sets of users). However, XAP expects a flat array of Authority. To bridge this gap you can either traverse the roles hierarchy and flatten it, or use the PopulatedRoleAuthority class, which implicitly flattens the hierarchy for authorization but maintains it for administration. Custom DirectoryManagerThe createDirectoryManager method can be used to implement a custom users-roles directory management component. However, this is not part of the authentication process, but rather an administrative task, hence our demo throws an exception. If you want to learn more, see Custom User-Role Management. UsageCustom SecurityManager can be provided in several ways, as follows:
Namespace
<!-- Configuring a secured space using custom properties --> <os-core:space id="space" url="/./space"> <os-core:security secured="true"/> <os-core:properties> <props> <prop key="com.gs.security.security-manager.class">com.demo.CustomSecurityManager</prop> <prop key="custom-security.server-address">myServer</prop> </props> </os-core:properties> </os-core:space> Code // Creating a secured space using custom properties: UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("/./mySpace") .secured(true) .addProperty("com.gs.security.security-manager.class", CustomSecurityManager.class.getName()) .addProperty("custom-security.server-address", "myServer"); GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).create(); // Creating a secured space using an injected security manager instance: CustomSecurityManager securityManager = new CustomSecurityManager(); Properties securityProperties = new Properties(); securityProperties.put(CustomSecurityManager.SECURITY_MANAGER_CLASS_PROPERTY_KEY, securityManager); UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("/./mySpace") .secured(true) .addProperties(securityProperties); GigaSpace gigaSpace = new GigaSpaceConfigurer(urlSpaceConfigurer).create(); Properties The SecurityManager can be configured using custom properties supplied as part of the security properties file (see Security Configurations for information about configuring security properties). com.gs.security.security-manager.class = com.demo.CustomSecurityManager custom-security.server-address = myServer CLI and Custom CredentialsUse the -user-details-provider and -user-details-properties arguments to use a custom credentials provider with the CLI.
Run the gs script, and then use the login command: gs(.sh/bat) gs> login -user-details-provider com.demo.CustomCredentialsProvider -user-details-properties -user-details-properties username=user1;password=123456;custom-security.server-address=myServer gs> ... UI and Custom CredentialsThe "Custom Login" option can be accessed using the drop-down menu of the "Security" menu. The "Custom Login" dialog allows to input the class name of the CredentialsProvider implementation and the required properties.
gs-ui(.sh/.bat) -user-details-provider com.demo.CustomCredentialsProvider |
![]() |
GigaSpaces.com - Legal Notice - 3rd Party Licenses - Site Map - API Docs - Forum - Downloads - Blog - White Papers - Contact Tech Writing - Gen. by Atlassian Confluence |