Home
WebSphere eXtreme Scale Security
Scenario: Securing the data grid in eXtreme Scale
WebSphere eXtreme Scale data grids store information that is sensitive and must be protected.
- Install the product. Install both the server runtime and the clients. For clients, we can use both Java and .NET clients.
- If we are upgrading from a previous release, you must have all of your container and catalog servers at the same release level.
For a secure deployment, use several layers of protection for optimal security. The first element of protection is the use of firewalls to segment the network. The standard tiered model for web applications is comprised of web clients, a presentation tier of HTTP servers, an application tier comprised of application servers, a data tier, and a storage tier.
eXtreme Scale data grid servers are deployed as part of the data tier. Standard practice is to put the presentation layer servers in a demilitarized zone (DMZ) protected by one firewall, and to put the application, data, and storage tiers in network segments protected by additional firewalls. Do not deploy eXtreme Scale servers in a DMZ. eXtreme Scale servers must be protected as all elements of the data tier are, according to standard industry practice.
However, for optimal protection against security threats, use an in-depth defense mechanism, where a number of additional measures protect eXtreme Scale operation and the data that is stored in the data grid. These additional measures not only help in defending against external threats, but also prevent unauthorized data access by employees and contractors who might have access to network segments in which the eXtreme Scale servers reside.
Use the following end-to-end steps to configure security in WebSphere eXtreme Scale, whether you have stand-alone servers, the Liberty profile, the OSGi framework, or WebSphere Application Server installed in your environment:
Data grid authentication
Use the secure token manager plug-in to enable server-to-server authentication, which requires you to implement the SecureTokenManager interface.
The generateToken(Object) method takes an object protect, and then generates a token that cannot be understood by others. The verifyTokens(byte[]) method does the reverse process: it converts the token back to the original object.
A simple SecureTokenManager implementation uses a simple encoding algorithm, such as a XOR algorithm, to encode the object in serialized form and then use corresponding decoding algorithm to decode the token. This implementation is not secure and is easy to break.
WebSphere eXtreme Scale default implementation
WebSphere eXtreme Scale provides an immediately available implementation for this interface. This default implementation uses a key pair to sign and verify the signature, and uses a secret key to encrypt the content. Every server has a JCKES type keystore to store the key pair, a private key and public key, and a secret key. The keystore has to be the JCKES type to store secret keys. These keys are used to encrypt and sign or verify the secret string on the sending end. Also, the token is associated with an expiration time. On the receiving end, the data is verified, decrypted, and compared to the receiver secret string. SSL communication protocols are not required between a pair of servers for authentication because the private keys and public keys serve the same purpose. However, if server communication is not encrypted, the data can be stolen by looking at the communication. Because the token expires soon, the replay attack threat is minimized. This possibility is significantly decreased if all servers are deployed behind a firewall.
The disadvantage of this approach is that the WebSphere eXtreme Scale administrators have to generate keys and transport them to all servers, which can cause security breach during transportation.
Data grid security
Data grid security ensures that a joining server has the right credentials, so a malicious server cannot join the data grid. Data grid security uses a shared secret string mechanism.
All WebSphere eXtreme Scale servers, including catalog servers, agree on a shared secret string. When a server joins the data grid, it is challenged to present the secret string. If the secret string of the joining server matches the string in the president server or catalog server, the joining server is accepted. If the string does not match, the join request is rejected.
Sending a clear text secret is not secure. The WebSphere eXtreme Scale security infrastructure provides a secure token manager plug-in to allow the server to secure this secret before sending. You must decide how to implement the secure operation. WebSphere eXtreme Scale provides an out-of-the-box implementation, in which the secure operation is implemented to encrypt and sign the secret.
The secret string is set in the server.properties file. See Server properties file for more information about the authenticationSecret property.
SecureTokenManager plug-in
A secure token manager plug-in is represented by the com.ibm.websphere.objectgrid.security.plugins.SecureTokenManager interface.
The generateToken(Object) method takes an object, and then generates a token that cannot be understood by others. The verifyTokens(byte[]) method does the reverse process: the method converts the token back to the original object.
A simple SecureTokenManager implementation uses a simple encoding algorithm, such as an exclusive or (XOR) algorithm, to encode the object in serialized form and then use the corresponding decoding algorithm to decode the token. This implementation is not secure.
WebSphere eXtreme Scale provides an immediately available implementation for this interface.
The default implementation uses a key pair to sign and verify the signature, and uses a secret key to encrypt the content. Every server has a JCKES type keystore to store the key pair, a private key and public key, and a secret key. The keystore has to be the JCKES type to store secret keys.
These keys are used to encrypt and sign or verify the secret string on the sending end. Also, the token is associated with an expiration time. On the receiving end, the data is verified, decrypted, and compared to the receiver secret string. SSL communication protocols are not required between a pair of servers for authentication because the private keys and public keys serve the same purpose. However, if server communication is not encrypted, the data can be stolen by looking at the communication. Because the token expires soon, the replay attack threat is minimized. This possibility is significantly decreased if all servers are deployed behind a firewall.
The disadvantage of this approach is that the WebSphere eXtreme Scale administrators have to generate keys and transport them to all servers, which can cause security breach during transportation.
Sample scripts to create default secure token manager properties
As noted in the previous section, we can create a keystore that contains a key pair to sign and verify the signature and a secret key to encrypt the content.
For example, we can use the JDK 6 keytool command to create the keys as follows:
keytool -genkeypair -alias keypair1 -keystore key1.jck -storetype JCEKS -keyalg rsa -dname "CN=sample.ibm.com, OU=WebSphere eXtreme Scale" -storepass key111 -keypass keypair1 -validity 10000
keytool -genseckey -alias seckey1 -keystore key1.jck -storetype JCEKS -keyalg DES -storepass key111 -keypass seckey1 -validity 1000These two commands create a key pair "keypair1" and a secret key "seckey1". We can then configure the following in the server property file:
secureTokenKeyStore=key1.jck secureTokenKeyStorePassword=key111 secureTokenKeyStoreType=JCEKS secureTokenKeyPairAlias=keypair1 secureTokenKeyPairPassword=keypair1 secureTokenSecretKeyAlias=seckey1 secureTokenSecretKeyPassword=seckey1 secureTokenCipherAlgorithm=DES secureTokenSignAlgorithm=RSA
Configuration
See Server properties for more information about the properties that you use to configure the secure token manager.
Authenticating and authorizing clients
We can enable security and credential authentication to authenticate clients. In addition, we can authorize administrative clients to access the data grid.
Authenticating application clients
Application client authentication consists of enabling client-server security and credential authentication, and configuring an authenticator and a system credential generator.
- Enable client-server security
Enable security on both the client and server to successfully authenticate with the ObjectGrid.
- Enable client security.
WebSphere eXtreme Scale provides a client property sample file, the sampleClient.properties file, in the was_root/optionalLibraries/ObjectGrid/properties directory for a WebSphere Application Server installation, or the /ObjectGrid/properties directory in a mixed-server installation. We can modify this template file with appropriate values. Set the securityEnabled property in the objectgridClient.properties file to true. The securityEnabled property indicates if security is enabled. When a client connects to a server, the value on the client and server side must be set both true or both false. If the connected server security is enabled, the property value must be set to true on the client side for the client to connect to the server.
The com.ibm.websphere.objectgrid.security.config.ClientSecurityConfiguration interface represents the security.ogclient.props file. Use the com.ibm.websphere.objectgrid.security.config.ClientSecurityConfigurationFactory public API to create an instance of this interface with default values, or we can create an instance by passing the ObjectGrid client security property file. The security.ogclient.props file contains other properties. See the ClientSecurityConfiguration API Documentation and ClientSecurityConfigurationFactory API Documentation for more details.
- Enable server security.
To enable the security on the server side, we can set the securityEnabled property in the security.xml file to true. Use a security descriptor XML file to specify the data grid security configuration to isolate the grid-wide security configuration from the non-security configuration.
- Enable credential authentication.
After the eXtreme Scale client retrieves the Credential object using the CredentialGenerator object, the Credential object is sent along with the client request to the eXtreme Scale server. The server authenticates the Credential object before processing the request. If the Credential object is authenticated successfully, a Subject object is returned to represent this Credential object. This Subject object is then used for authorizing the request.
Set the credentialAuthentication property on the client and server properties files to enable the credential authentication.
The following table provides which authentication mechanism to use under different settings.
Client credential authentication Server credential authentication Result No Never Disabled No Supported Disabled No Required Error case Supported Never Disabled Supported Supported Enabled Supported Required Enabled Required Never Error case Required Supported Enabled Required Required Enabled
- Configure an authenticator.
The eXtreme Scale server uses the Authenticator plug-in to authenticate the Credential object. An implementation of the Authenticator interface gets the Credential object and then authenticates it to a user registry, for example, a Lightweight Directory Access Protocol (LDAP) server, and so on. eXtreme Scale does not provide a registry configuration. Connecting to a user registry and authenticating to it must be implemented in this plug-in.
For example, one Authenticator implementation extracts the user ID and password from the credential, uses them to connect and validate to an LDAP server, and creates a Subject object as a result of the authentication. The implementation can use Java Authentication and Authorization Service (JAAS) login modules. A Subject object is returned as a result of authentication.
We can configure the authenticator in the security descriptor XML file, as shown in the following example:
<?xml version="1.0" encoding="UTF-8"?> <securityConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ibm.com/ws/objectgrid/config/security ../objectGridSecurity.xsd" xmlns="http://ibm.com/ws/objectgrid/config/security"> <security securityEnabled="true" loginSessionExpirationTime="300"> <authenticator className ="com.ibm.websphere.objectgrid.security.plugins.builtins.KeyStoreLoginAuthenticator"> </authenticator> </security> </securityConfig>Use the -clusterSecurityFile option when starting a secure server to set the security XML file. See the Java SE security tutorial - Step 2 for samples on how to start a secure server.
- Configure a system credential generator.
The system credential generator is used to represent a factory for the system credential. A system credential is similar to an administrator credential. We can configure the SystemCredentialGenerator element in the catalog security XML file, as shown in the following example:
<systemCredentialGenerator className ="com.ibm.websphere.objectgrid.security.plugins. builtins.UserPasswordCredentialGenerator"> <property name="properties" type="java.lang.String" value="manager manager1" description="username password" /> </systemCredentialGenerator>For demonstration purposes, the user name and password are stored in clear text. Do not store the user name and password in clear text in a production environment.WebSphere eXtreme Scale provides a default system credential generator, which uses the server credentials. If you do not explicitly specify the system credential generator, this default system credential generator is used.
Authorizing application clients
Application client authorization consists of ObjectGrid permission classes, authorization mechanisms, a permission checking period, and access by creator only authorization.
For WXS, authorization is based on the Subject object and permissions. The product supports two kinds of authorization mechanisms: Java Authentication and Authorization Service (JAAS) and custom authorization.
There are four different types of permission classes as follows.
- The MapPermission class represents permissions to access the data in ObjectGrid maps.
- The ObjectGridPermission class represents permissions to access ObjectGrid.
- The ServerMapPermission class represents permissions to access ObjectGrid maps on the server side from a client.
- The AgentPermission class represents permissions to start an agent on the server side.
- Set the permission checking period.
eXtreme Scale supports caching the map permission checking results for performance reasons. Without this mechanism, when a method that is in the list of methods that for your particular permission class is called, the runtime calls the configured authorization mechanism to authorize access. With this permission checking period set, the authorization mechanism is called periodically based on the permission checking period.
The permission authorization information is based on the Subject object. When a client tries to access the methods, the eXtreme Scale runtime looks up the cache based on the Subject object. If the object cannot be found in the cache, the runtime checks the permissions granted for this Subject object, and then stores the permissions in a cache.
The permission checking period must be defined before the ObjectGrid is initialized. The permission checking period can be configured in two ways:
Use the ObjectGrid XML file to define an ObjectGrid and set the permission check period.
In the following example, the permission check period is set to 45 seconds:
<objectGrids> <objectGrid name="secureClusterObjectGrid" securityEnabled="true" authorizationMechanism="AUTHORIZATION_MECHANISM_JAAS" permissionCheckPeriod="45"> <bean id="bean id="TransactionCallback" className="com.ibm.websphere.samples.objectgrid.HeapTransactionCallback" /> ... </objectGrids>To create an ObjectGrid with APIs, call the following method to set the permission checking period. This method can be called only before the ObjectGrid instance is initialized. This method applies only to the local eXtreme Scale programming model when you instantiate the ObjectGrid instance directly.
/** * This method takes a single parameter indicating how often you * want to check the permission used to allow a client access. If the * parameter is 0 then every single get/put/update/remove/evict call * asks the authorization mechanism, either JAAS authorization or custom * authorization, to check if the current subject has permission. This might be * prohibitively expensive from a performance point of view depending on * the authorization implementation, but if you need to have ever call check the * authorization mechanism, then set the parameter to 0. * Alternatively, if the parameter is > 0 then it indicates the number * of seconds to cache a set of permissions before returning to * the authorization mechanism to refresh them. This value provides much * better performance, but if the back-end * permissions are changed during this time then the ObjectGrid can * allow or prevent access even though the back-end security * provider was modified. * * @param period the permission check period in seconds. */ void setPermissionCheckPeriod(int period);
- Configure access-by-creator-only authorization.
Access by creator only authorization ensures that only the user (represented by the Principal objects associated with it) who inserts the entry into the ObjectGrid map can access (read, update, invalidate and remove) that entry.
The existing ObjectGrid map authorization model is based on the access type but not data entries. In other words, a user has a particular type of access, such as read, write, insert, delete, or invalidate, to either all the data in the map or none of the data. However, eXtreme Scale does not authorize users for individual data entry. This feature offers a new way to authorize users to data entries.
In a scenario where different users access different sets of data, this model can be useful. When the user loads data from the persistent store into the ObjectGrid maps, the access can be authorized by the persistent store. In this case, there is no need to do another authorization in the ObjectGrid map layer. You need only ensure that the person who loads the data into the map can access it by enabling the access by creator only feature.
- Creator only mode attribute values:
disabled
- The access by creator only feature is disabled.
complement
- The access by creator only feature is enabled to complement the map authorization. In other words, both map authorization and access by creator only feature takes effect. Therefore, we can further limit the operations to the data. For example, the creator cannot invalidate the data.
supersede
- The access by creator only feature is enabled to supersede the map authorization. In other words, the access by creator only feature supersedes the map authorization; no map authorization occurs.
- Configure the access-by-creator-only mode with an XML file.
Use the ObjectGrid XML file to define an ObjectGrid and set the access by creator only mode to either
disabled,
complement, or supersede, as shown in the following example:
<objectGrids> <objectGrid name="secureClusterObjectGrid" securityEnabled="true" accessByCreatorOnlyMode="supersede" <bean id="TransactionCallback" classname="com.ibm.websphere.samples.objectgrid.HeapTransactionCallback" /> ... </objectGrids>- Configure the access-by-creator-only mode programmatically.
To create an ObjectGrid programmatically, we can call the following method to set the access by creator only mode. Calling this method applies only to the local eXtreme Scale programming model when you directly instantiate the ObjectGrid instance:
/** * Set the "access by creator only" mode. * Enabling "access by creator only" mode ensures that only the user (represented * by the Principals associated with it), who inserts the record into the map, * can access (read, update, invalidate, and remove) the record. * The "access by creator only" mode can be disabled, or can complement the * ObjectGrid authorization model, or it can supersede the ObjectGrid * authorization model. The default value is disabled: * {@link SecurityConstants#ACCESS_BY_CREATOR_ONLY_DISABLED}. * @see SecurityConstants#ACCESS_BY_CREATOR_ONLY_DISABLED * @see SecurityConstants#ACCESS_BY_CREATOR_ONLY_COMPLEMENT * @see SecurityConstants#ACCESS_BY_CREATOR_ONLY_SUPERSEDE * * @param accessByCreatorOnlyMode the access by creator mode. * * @since WAS XD 6.1 FIX3 */ void setAccessByCreatorOnlyMode(int accessByCreatorOnlyMode);To further illustrate, consider a scenario in which an ObjectGrid map account is in a banking grid, and Manager1 and Employee1 are the two users. The eXtreme Scale authorization policy grants all access permissions to Manager1, but only read access permission to Employee1. The JAAS policy for the ObjectGrid map authorization is shown the following example:
grant codebase "http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction" Principal com.acme.PrincipalImpl "Manager1" { permission com.ibm.websphere.objectgrid.security.MapPermission "banking.account", "all"}; grant codebase "http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction" Principal com.acme.PrincipalImpl "Employee1" { permission com.ibm.websphere.objectgrid.security.MapPermission "banking.account", "read, insert"};Remember: Consider how the access by creator only feature affects authorization:
- disabled If the access by creator only feature is disabled, the map authorization is no different. The user "Manager1" can access all the data in the "account" map. The user "Employee1" can read and insert all the data in the map but cannot update, invalidate, remove any data in the map.
- complement If the access by creator only feature is enabled with "complement" option, both the map authorization and access by creator only authorization will take effect. The user "Manager1" can access the data in the "account" map, but only if the user alone loaded them into the map. The user "Employee1" can read the data in the "account" map, but only if that user alone loaded them into the map. (However, this user cannot update, invalidate, or remove any data in the map.)
- supersede If the access by creator only feature is enabled with "supersede" option, the map authorization will not be enforced. The access by creator only authorization will be the only authorization policy. The user "Manager1" has the same privilege as in the "complement" mode: this user can access the data in the "account" map only if the same user loaded the data into the map. However, the user "Employee1" now has full access to the data in the "account" map if this user loaded them into the map. In other words, the authorization policy defined in the Java Authentication and Authorization Service (JAAS) policy will then not be enforced.
Authorizing administrative clients
Through administrative security, we can authorize users to access the data grid. Certain conditions are required, depending on the WXS installation environment and the users to have access.
When users are authorized to access a WXS data grid, those users might also be authorized to perform management operations using the xscmd command or the stopOgServer command. Most data grid deployers restrict administrative access to only a subset of the users who can access grid data.
- Configure authorization for xscmd operations and the stopOgServer command.
If you use the following command to access the data grid, you might also be authorized to perform administrative actions, such as running the listAllJMXAddresses command:
./xscmd.sh -user <user> -password <password> <other_parameters>If the user can run the previous command, then any xscmd operation or the stopOgServer command might also be performed by the same user.When eXtreme Scale components run with WebSphere Application Server, use the WebSphere Application Server administrative console to activate the security manager. To restrict application access to local resources, click Security > Global Security, and select the check boxes, Enable administrative security and Use Java 2 Security, to restrict application access to local resources.
Access to the management operations is controlled by the WebSphere Application Server security manager and is granted only to the users who belong to the WebSphere Administrator role. Run the xscmd command and the stopOgServer command from the WebSphere Application Server directory.
- Configure administrative authorization in stand-alone installations.
When eXtreme Scale components run in a stand-alone environment, more steps are required to implement administrative security. Run the catalog servers and container servers using the Java security manager, which requires a policy file.
The policy file resembles the following example:
Remember: The policy file also typically contains MapPermission entries, as documented in Java SE security tutorial - Step 5 .
grant codeBase "file:${objectgrid.home}/lib/*" { permission java.security.AllPermission;}; grant principal javax.security.auth.x500.X500Principal "CN=manager,O=acme,OU=OGSample" { permission javax.management.MBeanPermission "*", "getAttribute,setAttribute,invoke,queryNames";};If the client is a Java Spring application, the following AgentPermission entry is needed in policy file, to allow the CN=manager account to access the data grid from the Spring client.grant codebase "http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction" principal javax.security.auth.x500.X500Principal "CN=manager,O=acme,OU=OGSample" { permission com.ibm.websphere.objectgrid.security.AgentPermission "*", "com.ibm.ws.objectgrid.spring.PutAgent";};If you configuring authorization security in a Multi-Master Replication (MMR) environment, then all catalog and container servers must run with the following policy in the og_auth.config file:grant { permission java.net.SocketPermission "localhost", "resolve"; permission java.lang.RuntimePermission "accessDeclaredMembers";};In this example, only the manager principal is authorized for administrative operations with the xscmd command or the stopOgServer command. We can add other lines as necessary to give more principals MBean permissions. A different type of principal is needed if you use LDAP authentication.
Enter the following command:
startOgServer.sh <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=$OBJECTGRID_HOME
startXsServer.sh <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=$OBJECTGRID_HOME
startOgServer.bat <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=%OBJCTGRID_HOME%startXsServer.bat <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=%OBJCTGRID_HOME%
Enable LDAP authentication in eXtreme scale catalog and container servers
Enable the WXS servers and catalog servers for Lightweight Directory Access Protocol (LDAP) authentication with a Java Authentication and Authorization Service (JAAS) policy file used for authorization.
In this task, you use LDAP as an authentication mechanism that provides access to the data grid, according to the permissions that you set in the JAAS authorization policy configuration file.
- Create a wxs_ldap.config file; for example:
LDAPLogin { com.ibm.websphere.objectgrid.security.plugins.builtins.SimpleLDAPLoginModule required providerURL=.ldap://yourldapserver.yourcompany.com:389/. factoryClass=.com.sun.jndi.ldap.LdapCtxFactory. };
- Create a wxs_ldap.auth.config file. Replace the principal with the user that logs in to the data grid. Also replace YourGridName with the name of the data grid. Repeat this step as necessary for additional users and data grids. See the following example:
grant codebase .http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction. principal javax.security.auth.x500.X500Principal .CN=manager,O=acme,OU=sample. { permission com.ibm.websphere.objectgrid.security.MapPermission .*.*., .all.; permission com.ibm.websphere.objectgrid.security.ObjectGridPermission .*.*., .all.;};Alternatively, we can grant permission to all data grids; for example:grant codebase .http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction. principal javax.security.auth.x500.X500Principal .CN=manager,O=acme,OU=sample. { permission com.ibm.websphere.objectgrid.security.MapPermission .*., .all.; permission com.ibm.websphere.objectgrid.security.ObjectGridPermission .*., .all.;};
- Create a server-side security.xml file; for example:
<?xml version=.1.0. encoding=.UTF-8.?> <securityConfig xmlns:xsi=.http://www.w3.org/2001/XMLSchema-instance. xsi:schemaLocation=.http://ibm.com/ws/objectgrid/config/security ../objectGridSecurity.xsd. xmlns=.http://ibm.com/ws/objectgrid/config/security.> <security securityEnabled=.true. loginSessionExpirationTime=.300. > <authenticator className =.com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthenticator.> </authenticator> </security> </securityConfig>
- Edit your objectGridServer.properties file with the following properties. If you do not have an objectGridServer.properties file, we can use the sampleServer.properties file that is in the wxs_home/properties directory to create your properties file.
securityEnabled=true credentialAuthentication=Required
- Start the catalog servers.
Deprecated: The startOgServer and stopOgServer commands start servers that use the ORB transport mechanism. The ORB is deprecated, but we can continue using these scripts if you were using the ORB in a previous release. The IBM eXtremeIO (XIO) transport mechanism replaces the ORB. Use the startXsServer and stopXsServer scripts to start and stop servers that use the XIO transport.
-Dobjectgrid.cluster.security.url=file:///security/security.xml -Dobjectgrid.server.props="/security/objectGridServer.properties" -Djava.security.policy="/security/wxs_ldap_auth.config"
- Start your container servers.
Dobjectgrid.server.props="/security/objectGridServer.properties" -Djava.security.policy="/security/wxs_ldap_auth.config"
- Edit your client-side objectGridClient.properties file. If WebSphere Application Server is the client, then the file that you update is was_profile_dir/properties.
securityEnabled=true credentialAuthentication=Supported
- Configure your client to pass the required LDAP login credentials. Load a client properties file. This file can contain the user ID and password. If the properties file does not include the user ID and password, add them to the configuration in the client program.
In the following example, a client properties file is loaded using a program parameter. Then, the user ID and password are added to the configuration.
String userid = .CN=manager,O=acme,OU=sample.; String pw=.password.; //Creates a ClientSecurityConfiguration object using the specified file ClientSecurityConfiguration clientSC = ClientSecurityConfigurationFactory .getClientSecurityConfiguration(args[0]); //Creates a CredentialGenerator using the user and password. CredentialGenerator credGen = new UserPasswordCredentialGenerator(userid,password); clientSC.setCredentialGenerator(credGen); // Create an ObjectGrid by connecting to the catalog server ClientClusterContext ccContext = ogManager.connect(.cataloghostname:2809., clientSC, null); ObjectGrid og = ogManager.getObjectGrid(ccContext, .YourGridName.);.
Enable keystore authentication in eXtreme Scale container and catalog servers
Enable the WXS servers and catalog servers for keystore authentication with a Java Authentication and Authorization Service (JAAS) policy file used for authorization.
In this task, you use a keystore file as an authentication mechanism that provides access to the data grid, according to the permissions that you set in the JAAS authorization policy configuration file.
- Create a keystore with login aliases
- Create a wxs_keystore.config file. Replace the principal with the user that logs in to the data grid. Also, replace YourGridName with the name of the data grid. Repeat this step as necessary for more users and data grids. See the following example:
KeyStoreLogin { com.ibm.websphere.objectgrid.security.plugins.builtins.KeyStoreLoginModule required keyStoreFile="/security/sampleKS.jks";}
- Create a server-side security.xml file; for example:
<?xml version=.1.0. encoding=.UTF-8.?> <securityConfig xmlns:xsi=.http://www.w3.org/2001/XMLSchema-instance. xsi:schemaLocation=.http://ibm.com/ws/objectgrid/config/security ../objectGridSecurity.xsd. xmlns=.http://ibm.com/ws/objectgrid/config/security.> <security securityEnabled=.true. loginSessionExpirationTime=.300. > <authenticator className="com.ibm.websphere.objectgrid.security.plugins.builtins.KeyStoreLoginAuthenticator> </authenticator> </security> </securityConfig>
- Edit your objectGridServer.properties file with the following properties. If you do not have an objectGridServer.properties file, we can use the sampleServer.properties file that is in the wxs_home/properties directory to create your properties file.
securityEnabled=true credentialAuthentication=Required
- Start the catalog servers.
Deprecated: The startOgServer and stopOgServer commands start servers that use the ORB transport mechanism. The ORB is deprecated, but we can continue using these scripts if you were using the ORB in a previous release. The IBM eXtremeIO (XIO) transport mechanism replaces the ORB. Use the startXsServer and stopXsServer scripts to start and stop servers that use the XIO transport.
startOgServer.sh catalogServer -clusterSecurityFile /security/security.xml -serverProps /security/objectGridServer.properties -jvmArgs -Djava.security.auth.login.config=./security/wxs_keystore.config. -Djava.security.policy=./security/wxs_ldap_auth.config.startXsServer.sh catalogServer -clusterSecurityFile /security/security.xml -serverProps /security/objectGridServer.properties -jvmArgs -Djava.security.auth.login.config=./security/wxs_keystore.config. -Djava.security.policy=./security/wxs_ldap_auth.config.
- Start your container servers.
startOgServer.sh c0 -objectgridFile /xml/objectgrid.xml -deploymentPolicyFile /xml/deployment.xml -catalogServiceEndPoints cataloghostname:2809 -serverProps /security/objectGridServer.properties -jvmArgs -Djava.security.auth.login.config=./security/wxs_keystore.config. -Djava.security.policy=./security/wxs_ldap_auth.config.startXsServer.sh c0 -objectgridFile /xml/objectgrid.xml -deploymentPolicyFile /xml/deployment.xml -catalogServiceEndPoints cataloghostname:2809 -serverProps /security/objectGridServer.properties -jvmArgs -Djava.security.auth.login.config=./security/wxs_keystore.config. -Djava.security.policy=./security/wxs_ldap_auth.config.
- Edit your client-side objectGridClient.properties file. If WebSphere Application Server is the client, then the file that you update is was_profile_dir/properties.
securityEnabled=true credentialAuthentication=Supported transportType=TCP/IP singleSignOnEnabled=false
- Modify your client application to pass the required keystore login credentials.
String userid = .CN=manager,O=acme,OU=sample.; String pw=.password.; // Creates a ClientSecurityConfiguration object using the specified file ClientSecurityConfiguration clientSC = ClientSecurityConfigurationFactory .getClientSecurityConfiguration(args[0]); // Creates a CredentialGenerator using the passed-in user and password. CredentialGenerator credGen = new UserPasswordCredentialGenerator(userid,password); clientSC.setCredentialGenerator(credGen); // Create an ObjectGrid by connecting to the catalog server ClientClusterContext ccContext = ogManager.connect(.cataloghostname:2809., clientSC, null); ObjectGrid og = ogManager.getObjectGrid(ccContext, .YourGridName.);.
Configure secure transport types
Transport layer security (TLS) provides secure communication between the client and server. The communication mechanism used depends on the value of the transportType parameter specified in the client and server configuration files.
When SSL is used, the SSL configuration parameters must be provided on both the client and server side. In a Java SE environment, the SSL configuration is configured in the client or server property files. If the client or server is in WebSphere Application Server, then we can use the existing WebSphere Application Server CSIV2 transport settings for your container servers and clients. See Security integration with WebSphere Application Server for more information.
Table 1. Transport protocol to use under client transport and server transport settings. If the transportType settings are different between the client and server, the resulting protocol can vary or result in an error.
Client transportType property Server transportType property Resulting protocol TCP/IP TCP/IP TCP/IP TCP/IP SSL-supported TCP/IP TCP/IP SSL-required Error SSL-supported TCP/IP TCP/IP SSL-supported SSL-supported SSL (if SSL fails, then TCP/IP) SSL-supported SSL-required SSL SSL-required TCP/IP Error SSL-required SSL-supported SSL SSL-required SSL-required SSL
Transport layer security and secure sockets layer
WebSphere eXtreme Scale supports both TCP/IP and Transport Layer Security/Secure Sockets Layer (TLS/SSL) for secure communication between clients and servers.
Enable TLS/SSL in both directions
TLS/SSL is sometimes enabled in one direction. For example, the server public certificate is imported in the client truststore, but not the client public certificate is not imported to the server truststore. However, WebSphere eXtreme Scale extensively uses data grid agents. A characteristic of a data grid agent is when the server sends responds back to the client, it creates a new connection. The eXtreme Scale server then acts as a client. Therefore, you must import the client public certificate into the server truststore.
Enable transport security for Oracle JDK
WebSphere eXtreme Scale requires IBM Java Secure Sockets Extension (IBMJSSE) or the IBM Java Secure Sockets Extension 2 (IBMJSSE2). The IBMJSSE and IBMJSSE2 providers contain a reference implementation supporting SSL and Transport Layer Security (TLS) protocols and an application programming interface (API) framework.
The Oracle JDK does not ship the IBM JSSE and IBM JSSE2 providers, therefore transport security cannot be enabled with an Oracle JDK. In order to make this work, an Oracle JDK shipped with WebSphere Application Server is required. The WebSphere Application Server shipped Oracle JDK contains the IBM JSSE and IBM JSSE2 providers.
See Configuring a custom Object Request Broker for information about using a non-IBM JDK for WebSphere eXtreme Scale. If
-Djava.endorsed.dirs is configured, it points to both the objectgridRoot/lib/endorsed and the JRE/lib/endorsed directories. The directory objectgridRoot/lib/endorsed is required so the IBM ORB is used, and the directory JRE/lib/endorsed is required to load the IBM JSSE and IBM JSSE2 providers.
Use the Java SE security tutorial - Step 4 to configure your required SSL properties, to create keystores and truststores, and to start secure servers in WebSphere eXtreme Scale.
Configure SSL parameters for clients or servers
How you configure SSL parameters varies between clients and servers.
TLS/SSL is sometimes enabled in one direction. For example, the server public certificate is imported in the client truststore, but the client public certificate is not imported to the server truststore. However, WebSphere eXtreme Scale extensively uses data grid agents. A characteristic of a data grid agent is when the server sends responds back to the client, it creates a connection. The eXtreme Scale server then acts as a client. Therefore, you must import the client public certificate into the server truststore.
- Configure client SSL parameters.
Use one of the following options to configure SSL parameters on the client:
- Create a com.ibm.websphere.objectgrid.security.config.SSLConfiguration object using the com.ibm.websphere.objectgrid.security.config.ClientSecurityConfigurationFactory factory class.
- Configure the parameters in the client.properties file. We can then either set the property file as a JVM client property or we can use the WebSphere eXtreme Scale APIs. Pass the properties file into the ClientSecurityConfigurationFactory.getClientSecurityConfiguration(String) method for the client and use the returned object as a parameter to the ObjectGridManager.connect(String, ClientSecurityConfiguration, URL) method.
- Configure server SSL parameters.
SSL parameters are configured for servers using the server.properties file. To start a container or catalog server with a specific property file, use the -serverProps parameter on the startOgServer or startXsServer script.
JMX security
We can secure managed beans (MBean) invocations in a distributed environment.
In the distributed deployment topology, MBeans are directly hosted in the catalog servers and container servers. In general, JMX security in a distributed topology follows the JMX security specification as specified in the JMX Specification. It consists of the following three parts:
- Authentication: The remote client needs to be authenticated in the connector server.
- Access control: MBean access control limits who can access the MBean information and who can perform the MBean operations.
- Secure transport: The transport between the JMX client and server can be secured with TLS/SSL.
Authentication
JMX provides methods for the connector servers to authenticate the remote clients. For the RMI connector, authentication is completed by supplying an object that implements the JMXAuthenticator interface when the connector server is created. So eXtreme Scale implements this JMXAuthenticator interface to use the ObjectGrid Authenticator plug-in to authenticate the remote clients. See Java SE security tutorial - Step 2 for details on how eXtreme Scale authenticates a client.
The JMX client follows the JMX APIs to provide credentials to connect to the connector server. The JMX framework passes the credential to the connector server, and then calls the JMXAuthenticator implementation for authentication. As described previously, the JMXAuthenticator implementation then delegates the authentication to the ObjectGrid Authenticator implementation.
Review the following example that describes how to connect to a connector server with a credential:
javax.management.remote.JMXServiceURL jmxUrl = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:1099/objectgrid/MBeanServer"); environment.put(JMXConnector.CREDENTIALS, new UserPasswordCredential("admin", "xxxxxx")); // Create the JMXCconnectorServer JMXConnector cntor = JMXConnectorFactory.newJMXConnector(jmxUrl, null); // Connect and invoke an operation on the remote MBeanServer cntor.connect(environment);In the preceding example, a UserPasswordCredential object is provided with the user ID set to admin and the password set to xxxxx. This UserPasswordCredential object is set in the environment map, which is used in the JMXConnector.connect(Map) method. This UserPasswordCredential object is then passed to the server by the JMX framework, and finally passed to the ObjectGrid authentication framework for authentication.
The client programming model strictly follows the JMX specification.
Access control
A JMX MBean server might have access to sensitive information and might be able to perform sensitive operations. JMX provides necessary access control that identifies which clients can access that information and who can perform those operations. The access control is built on the standard Java security model by defining permissions that control access to the MBean server and its operations.
For JMX operation access control or authorization, eXtreme Scale relies on the JAAS support provided by the JMX implementation. At any point in the execution of a program, there is a current set of permissions that a thread of execution holds. When such a thread calls a JMX specification operation, these permissions are known as the held permissions. When a JMX operation is performed, a security check is done to check whether the needed permission is implied by the held permission.
The MBean policy definition follows the Java policy format. For example, the following policy grants all signers and all code bases with the right to retrieve the server JMX address for the PlacementServiceMBean. However, the signers and code bases are restricted to the com.ibm.websphere.objectgrid domain.
grant { permission javax.management.MBeanPermission "com.ibm.websphere.objectgrid.management.PlacementServiceMBean#retrieveServerJMXAddress [com.ibm.websphere.objectgrid:*,type=PlacementService]", "invoke";}Use the following policy example to complete authorization based on remote client identity. The policy grants the same MBean permission as shown in the preceding example, except only to users with X500Principal name as:
CN=Administrator,OU=software,O=IBM,L=Rochester,ST=MN,C=US.
grant principal javax.security.auth.x500.X500Principal "CN=Administrator,OU=software,O=IBM, L=Rochester,ST=MN,C=US" {permission javax.management.MBeanPermission "com.ibm.websphere.objectgrid.management.PlacementServiceMBean#retrieveServerJMXAddress [com.ibm.websphere.objectgrid:*,type=PlacementService]", "invoke";}Java policies are checked only if the security manager is turned on. Start catalog servers and container servers with the -Djava.security.manager JVM argument to enforce the MBean operation access control.
Secure transport
The transport between the JMX client and server can be secured with TLS/SSL. If the transportType of catalog server or container server is set to SSL_Required or SSL_Supported, then use SSL to connect to the JMX server.
To use SSL, you need to configure the truststore, truststore type, and truststore password on the MBean client with -D system properties:
- -Djavax.net.ssl.trustStore=TRUST_STORE_LOCATION
- -Djavax.net.ssl.trustStorePassword=TRUST_STORE_PASSWORD
- -Djavax.net.ssl.trustStoreType=TRUST_STORE_TYPE
If you use com.ibm.websphere.ssl.protocol.SSLSocketFactory as your SSL socket factory in your java_home /jre/lib/security/java.security file, then use the following properties:
- -Dcom.ibm.ssl.trustStore=TRUST_STORE_LOCATION
- -Dcom.ibm.ssl.trustStorePassword=TRUST_STORE_PASSWORD
- -Dcom.ibm.ssl.trustStoreType=TRUST_STORE_TYPE
To obtain this information when Transport Layer Security/Secure Sockets Layer (TLS/SSL) is enabled in stand-alone configurations, start the catalog and container servers with the JMX service port set. Use one of the following methods to set the JMX service port:
- Use the -JMXServicePort option on the startOgServer or startXsServer script.
- If we are using an embedded server, call the setJMXServicePort method in the ServerProperties interface to set the JMX service port.
The default value for the JMX service port on catalog servers is
1099. You must use a different port number for each JVM in the configuration. To use JMX/RMI, explicitly specify the-JMXServicePort option and port number, even to use the default port value.
Setting the JMX service port is required when we want to display container server information from the catalog server. For example, the port is required when we are using the xscmd -c showMapSizes command.
Set the JMX connector port to avoid ephemeral port creation. Use one of the following methods to set the JMX connector port.
- Use the -JMXConnectorPort option on the startOgServer or startXsServer script.
- If we are using an embedded server, call the setJMVConnectorPort method in the ServerProperties interface.
Security integration with external providers
To protect your data, the product can integrate with several security providers.
WebSphere eXtreme Scale can integrate with an external security implementation. This external implementation must provide authentication and authorization services for WebSphere eXtreme Scale. WebSphere eXtreme Scale has plug-in points to integrate with a security implementation.WebSphere eXtreme Scale has been successfully integrated with the following components:
- Lightweight Directory Access Protocol (LDAP)
- Kerberos
- ObjectGrid security
- Tivoli Access Manager
- Java Authentication and Authorization Service (JAAS)
eXtreme Scale uses the security provider for the following tasks:
- Authenticating clients to servers.
- Authorizing clients to access certain eXtreme Scale artifacts or to specify what can be done with WXS artifacts.
eXtreme Scale has the following types of authorizations:
If we had security already enabled for the back end, remember that these security settings are no longer sufficient to protect your data. Security settings from your database or other datastore does not in any way transfer to the cache. Separately protect the data that is now cached using the eXtreme Scale security mechanism, including authentication, authorization, and transport level security.
- Map authorization
- Clients or groups can be authorized to perform insert, read, update, evict or delete operations on maps.
- ObjectGrid authorization
- Clients or groups can be authorized to perform object or entity queries on objectGrids.
- DataGrid agent authorization
- Clients or groups can be authorized to allow DataGrid agents to be deployed to an ObjectGrid.
- Server-side map authorization
- Clients or groups can be authorized to replicate a server map to client side or create a dynamic index to the server map.
- Administration authorization
- Clients or groups can be authorized to perform administration tasks.
Use a Development Kit or Runtime Environment at Version 1.6 and later to support SSL Transport security with WebSphere eXtreme Scale Version 7.1.1 and later.
10. Securing the REST data service
Secure multiple aspects of the REST data service. Access to the eXtreme Scale REST data service can be secured through authentication and authorization. Access can also be controlled by service-scoped configuration rules, known as access rules. Transport security is the third consideration.
Access to the eXtreme Scale REST data service can be secured through authentication and authorization. Authentication and authorization is accomplished by integrating with WXS security.
Access can also be controlled by service-scoped configuration rules, known as access rules Two types of access rules exist, service operation rights which control the CRUD operations that are allowed by the service and entity access rights which control the CRUD operations that are allowed for a particular entity type.
Transport security is provided by the hosting container configuration for connections between the web client and the REST service. And transport security is provided by eXtreme Scale client configuration (for REST service to WXS data grid connections).
- Control authentication and authorization.
Access to the eXtreme Scale REST data service can be secured through authentication and authorization. Authentication and authorization are accomplished by integrating with WXS security.
The eXtreme Scale REST data service uses eXtreme Scale security, for authentication and authorization, to control which users can access the service and the operations a user is allowed to perform through the service. The eXtreme Scale REST data service uses either a configured global credential, with user and password, or a credential derived from an HTTP BASIC challenge that is sent with each transaction to the eXtreme Scale data grid where authentication and authorization is performed.
- Configure eXtreme Scale client authentication and authorization on the grid See Security integration with external providers for details about how to configure eXtreme Scale client authentication and authorization.
- Configure the eXtreme Scale client, which is used by the REST service, for security.
The eXtreme Scale REST data service invokes the eXtreme Scale client library when communicating with the eXtreme Scale grid. Therefore, the eXtreme Scale client must be configured for eXtreme Scale security.
eXtreme Scale client authentication is enabled via properties in objectgrid client properties file. At a minimum, the following attributes must be enabled when using client security with the REST service:
securityEnabled=true credentialAuthentication=Supported [-or-] Required credentialGeneratorProps=user:pass [-or-] {xor encoded user:pass}Remember: The user and password specified in the credentialGeneratorProps property must map to an ID in the authentication registry and have sufficient ObjectGrid policy rights to connect to and create ObjectGrids.
A sample objectgrid client policy file is located in restservice_home /security/security.ogclient.properties. See also Client properties file .
- Configure the eXtreme Scale REST data service for security.
The eXtreme Scale REST data service configuration properties file needs to contain the following entries to integrate with WXS security:
ogClientPropertyFile=file_nameThe ogClientPropertyFile is the location of the propery file that contains ObjectGrid client properties mentioned in the preceding step. The REST service uses this file to initialize the eXtreme Scale client to talk to the grid when security is enabled.
loginType=basic [-or-] noneThe loginType property configures the REST service for the login type. If a value of
none is specified, the .global. user id and password defined by the credentialGeneratorProps will be sent to the grid for each transaction. If a value of
basic is specified, the REST service will present an HTTP BASIC challenge to the client asking for credentials that it will send in each transaction when communicating with the grid.
- Apply access rules.
Access can also be controlled by service scoped configuration rules, known as access rules Two types of access rules exist, service operation rights which control the CRUD operations that are allowed by the service and entity access rights which control the CRUD operations that are allowed for a particular entity type.
The eXtreme Scale REST data service optionally allows access rules that can be configured to restrict access to the service and entities in the service. These access rules are specified in the REST service access rights property file. The name of this file is specified in the REST data service properties file by the wxsRestAccessRightsFile property. This file is a typical Java property file with key and value pairs. Two types of access rules exist, service operation rights which control the CRUD operations that are allowed by the service and entity access rights which control the CRUD operations that are allowed for a particular entity type.
- Configure service operation rights.
Service Operations rights specify access rights that apply to all the ObjectGrids exposed via the REST service or to all entities of an individual ObjectGrid as specified.
Use the following syntax.
serviceOperationRights=service_operation_right serviceOperationRights.grid_name -OR- *=service_operation_rightwhere
- serviceOperationRights can be one of the following [NONE, READSINGLE, READMULTIPLE, ALLREAD, ALL]
- serviceOperationRights.grid_name -OR- * implies that the access right applies to all the ObjectGrids, else name of a specific ObjectGrid can be provided.
For example:
serviceOperationsRights=ALL serviceOperationsRights.*=NONE serviceOperationsRights.EMPLOYEEGRID=READSINGLEThe first example specifies that all service operations are allowed for all the ObjectGrids exposed by this REST Service. The second example is similar to the first example as it also applies to all the ObjectGrids exposed by the REST service, however it specifies the access right as NONE, which means none of the service operations are allowed on the ObjectGrids. The last example specifies how to control the service operations for a specific grid, here only Reads which results in a single record are allowed for all entities of the EMPLOYEEGRID.
The default assumed by the REST service is
serviceOperationsRights=ALL which means that all operations are allowed for all the ObjectGrids exposed by this service. This is different from the Microsoft implementation, for which the default is
NONE, so no operations are allowed on the REST Service.
The service operations rights are evaluated in the order they are specified in this file, so the last specified right will override the rights preceding it.
- Configure entity access rights.
Entity set rights specify access rights that apply to specific ObjectGrid entities exposed via the REST service. These rights provide a way to impose tighter and more finer-grained access control on individual ObjectGrid entities than compared to Service Operation rights.
Use the following syntax.
entitySetRights.grid_name.entity_name=entity_set_rightwhere
- entity_set_right can be one of the following rights.
Table 1. Entity access rights. Supported values. Access right Description NONE Denies all rights to access data READSINGLE Allows to read single data items READMULTIPLE Allows reading sets of data ALLREAD Allows reading single or multiple sets of data WRITEAPPEND Allows creating new data items in data sets WRITEREPLACE Allows replacing data WRITEDELETE Allows deleting data items from data sets WRITEMERGE Allows merging data ALLWRITE Allows to write (i.e. create, replace, merge or delete) data ALL Allows creating, reading, updating, and deleting data - entity_name is the name of a specific ObjectGrid within the REST service.
- grid_name is the name of a specific entity within the specified ObjectGrid.
If both service operation rights and entity set rights are specified for a respective ObjectGrid and its entities, then the more restrictive of those rights will be enforced, as illustrated in the following examples. Note also that the entity set rights are evaluated in the order they are specified in the file. The last specified right will override the rights preceding it.
Example 1: If serviceOperationsRights.NorthwindGrid=READSINGLE and entitySetRights.NorthwindGrid.Customer=ALL are specified. READSINGLE will be enforced for the Customer entity.
Example 2: If serviceOperationsRights.NorthwindGrid=ALLREAD is specified and entitySetRights.NorthwindGrid.Customer=ALLWRITE is specified then only Reads will be allowed for all entities of NorthwindGrid. However for Customer its entity set rights will prevent any Reads (since it specified ALLWRITE) and hence effectively the Customer entity will have access right as NONE.
- Secure transports.
Transport security is provided by the hosting container configuration for connections between the web client and REST service. Transport security is provided by the eXtreme Scale client configuration for connections between the REST service and the eXtreme Scale grid.
- Secure the connection from the client and REST service. Transport security for this connection is provided by the hosting container environment, not in eXtreme Scale.
- Secure the connection from the REST service and the eXtreme Scale grid. Transport security for this connection is configured in eXtreme Scale. See Transport layer security and secure sockets layer .
11. Security integration with WebSphere Application Server
When WebSphere eXtreme Scale is deployed in a WebSphere Application Server environment, we can simplify the authentication flow and transport layer security configuration from WebSphere Application Server.
Simplified authentication flow
When eXtreme Scale clients and servers are running in WebSphere Application Server and in the same security domain, we can use the WebSphere Application Server security infrastructure to propagate the client authentication credentials to the eXtreme Scale server. For example, if a servlet acts as a WXS client to connect to a WXS server in the same security domain, and the servlet is already authenticated, it is possible to propagate the authentication token from the client (servlet) to the server, and then use the WebSphere Application Server security infrastructure to convert the authentication token back to the client credentials.
Figure 1. Authentication flow for servers within the same security domain
In the previous diagram, the application servers are in the same security domain. One application server hosts the web application, which is also a WXS client. The other application server hosts the container server. The dmgr or node agent JVM hosts the catalog service. Use this type of configuration in development environments. However, for production environments run the catalog servers in separate processes, and if possible, run catalog servers on a different system from where the container servers are running. The arrows in the diagram indicate how the authentication process flows:
- An enterprise application user uses a Web browser to log in to the first application server with a user name and password.
- The first application server sends the client user name and password to the WebSphere Application Server security infrastructure to authenticate with the user registry. For example, this user registry might be an LDAP server. As a result, the security information is stored in the application server thread.
- The JavaServer Pages (JSP) file acts as a WXS client to retrieve the security information from the server thread. The JSP file calls the WebSphere Application Server security infrastructure to get the security tokens that represent the enterprise application user.
- The eXtreme Scale client, or JSP file, sends the security tokens with the request to the container server and catalog service that is hosted in the other JVMs. The catalog server and container server use the WebSphere Application Server security tokens as a WXS client credential.
- The catalog and container servers send the security tokens to the WebSphere Application Server security infrastructure to convert the security tokens into user security information. This user security information is represented by a Subject object, which contains the principals, public credentials, and private credentials. This conversion can occur because the application servers that are hosting the eXtreme Scale client, catalog server, and container server are sharing the same WebSphere Application Server Lightweight Third-Party Authentication (LTPA) tokens.
Authentication integration
Distributed security integration with WebSphere Application Server:
For the distributed model, use the following classes:
- com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator
- com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenAuthenticator
- com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredential
On the server side, use the WSTokenAuthentication authenticator to authenticate the WSTokenCredential object.
Local security integration with WebSphere Application Server:
For the local ObjectGrid model, use the following classes:
- com.ibm.websphere.objectgrid.security.plugins.builtins.WSSubjectSourceImpl
- com.ibm.websphere.objectgrid.security.plugins.builtins.WSSubjectValidationImpl
We can configure the WSSubjectSourceImpl class as the SubjectSource plug-in, and the WSSubjectValidationImpl class as the SubjectValidation plug-in.
Transport layer security support in WebSphere Application Server
When a WXS client, container server, or catalog server is running in a WebSphere Application Server process, eXtreme Scale transport security is managed by the WebSphere Application Server CSIV2 transport settings. For the eXtreme Scale client or container server, you should not use eXtreme Scale client or server properties to configure the SSL settings. All the SSL settings should be specified in the WebSphere Application Server configuration.
However, the catalog server is a little different. The catalog server has its own proprietary transport paths which cannot be managed by the WebSphere Application Server CSIV2 transport settings. Therefore, the SSL properties still need to be configured in the server properties file for the catalog server. See Tutorial: Integrate WebSphere eXtreme Scale security with WebSphere Application Server for more information.
- Configuring client security on a catalog service domain
By configuring client security on a catalog service domain, we can define default client authentication configuration properties. These properties are used when a client properties file is not located in the JVM that is hosting the client or when the client does not programmatically specify security properties. If a client properties file exists, the properties that you specify in the console override the values in the file. We can override these properties by specifying a splicer.properties file with the com.ibm.websphere.xs.sessionFilterProps custom property or by splicing the application EAR file.
Configure client security on a catalog service domain
By configuring client security on a catalog service domain, we can define default client authentication configuration properties. These properties are used when a client properties file is not located in the JVM that is hosting the client or when the client does not programmatically specify security properties. If a client properties file exists, the properties that you specify in the console override the values in the file. We can override these properties by specifying a splicer.properties file with the com.ibm.websphere.xs.sessionFilterProps custom property or by splicing the application EAR file.
- You must know the CredentialGenerator implementation that we are using to authenticate clients with the remote data grid. Use one of the implementations that are provided by WebSphere eXtreme Scale: UserPasswordCredentialGenerator or WSTokenCredentialGenerator.
We can also use a custom implementation of the CredentialGenerator interface. The custom implementation must be in the class path of the runtime client and the server. If we are configuring an HTTP session scenario with WebSphere Application Server, you must put the implementation in the class path of the dmgr and the class path of the application server in which the client is running.
- You must have a catalog service domain defined. See Creating catalog service domains in WebSphere Application Server for more information.
Configure client security on the catalog service domain when you have enabled credential authentication on the server side, by configuring one of the following scenarios:
- The server-side security policy has the credentialAuthentication property set to Required.
- The server-side security policy has the credentialAuthentication property set to Supported AND an authorizationMechanism has been specified in the ObjectGrid XML file.
In these scenarios, a credential must be passed from the client. The credential that is passed from the client is retrieved from the getCredential method on a class that implements the CredentialGenerator interface. In an HTTP session configuration scenario, the run time must know the CredentialGenerator implementation to use to generate a credential that is passed to a remote data grid. If you do not specify the CredentialGenerator implementation class to use, the remote data grid would reject requests from the client because the client cannot be authenticated.
Define client security properties. In the WebSphere Application Server administrative console, click System administration > WebSphere eXtreme Scale > Catalog service domains > catalog_service_domain_name > Client security properties. Specify client security properties on the page and save your changes. See Client security properties for a list of the properties we can set.
Results
The client security properties that you configured on the catalog service domain are used as default values. The values you specify override any properties that are defined in the client.properties files.
What to do next
Configure the applications to use WebSphere eXtreme Scale for session management. See Automatically splicing applications for HTTP session management in WebSphere Application Server for more information.
12. Configure data grid security and SSL for .NET
We can configure .NET and Java to communicate over SSL and to use the UserPassword authentication logic.
You must have the key.jks and trust.jks files for your environment.
- Enable and configure security in your servers. If security is not already configured on your servers... to configure security with the external authenticator sample.
- Obtain the sample security files. Download the sample files in the security_extauth.zip file from on the WebSphere eXtreme Scale wiki .
- xsjaas3.config : Defines the Java Authentication and Authorization Service (JAAS) configuration.
- sampleKS3.jks Contains the keystore of JAAS user and password values.
- security3.xml Defines the authenticator to use for security.
- Edit the xsjaas3.config file and fix the path to the sampleKS3.jks file.
- To generate your own private keystore instead of using the sample sampleKS3.jks file, use the keytool utility to generate the private key.
keytool -genkey -alias myalias -keysize 2048 -keystore key.jks -keyalg rsa -dname "CN=www.mydomain.com" -storepass password -keypass password -validity 3650- Edit the sampleServer.properties to enable security. The sampleServer.properties file is in the wxs_install_root \properties directory. Uncomment and edit the following property values:
securityEnabled=true secureTokenManagerType=none alias=ogsample contextProvider=IBMJSSE2 protocol=SSL keyStoreType=JKS keyStore=../../../../xio.test/etc/test/security/key.jks keyStorePassword=ogpass trustStoreType=JKS trustStore=../../../../xio.test/etc/test/security/trust.jks trustStorePassword=ogpass- Start the catalog and container servers.
startXsServer.bat cs0 -catalogServiceEndPoints cs0:localhost:6600:6601 -listenerPort 2809 -objectgridFile gettingstarted\xml\objectgrid.xml -deploymentPolicyFile gettingstarted\xml\deployment.xml -serverProps ..\properties\sampleServer.properties -clusterSecurityFile security3.xml -jvmArgs -Djava.security.auth.login.config="xsjaas3.config"startXsServer.bat c0 -catalogServiceEndPoints localhost:2809 -objectgridFile gettingstarted\xml\objectgrid.xml -deploymentPolicyFile gettingstarted\xml\deployment.xml -serverProps ..\properties\sampleServer.properties -clusterSecurityFile security3.xml -jvmArgs -Djava.security.auth.login.config="xsjaas3.config"
- Configure security for the .NET client.
- Optional: Using the keytool utility, extract the public certificate from the key.jks file that you configured for the server.
keytool -export -alias myalias -keystore key.jks -file public.cer -storepass passwordImport this public key into the Windows Certificate store with the Certificate Management Tool, certmgr.msc, to import the key into the .Trusted Root Certification Authority. or .Trusted People. certificate folder. (The keyStore property in the client.properties file can point to this file)- Edit the Client.Net.properties file to include the following property values:
securityEnabled=true credentialAuthentication=supported authenticationRetryCount=3 credentialGeneratorAssembly=IBM.WebSphere.Caching.CredentialGenerator,Version=8.6.0.0, Culture=neutral,PublicKeyToken=b439a24ee43b0816 credentialGeneratorProps=manager manager1 transportType=ssl-required publicKeyFile=<name>.cerThe value of the credentialGeneratorProps property,manager manager1 is used as the user name and password values that are supplied to the server in the Credential object.
The publicKeyFile property is set as a relative path to the .NET run time. If the publicKeyFile property is not set, the Windows certificate store is searched for the public.cer file. If the publicKeyFile property is set, then the specified file is used for the SSL public certificate file. If the specified file cannot be found, the .NET client attempts to find a matching public.cer file in the certificate store.
- Copy the net_client_home \IBM.WebSphere.Caching.CredentialGenerator.dll to the net_client_home \sample\SimpleClient\bin\<ConfigurationName> directory
- Build the sample with the ConfigurationName project context. Run the sample against your server.
13. Enable data grid authorization
WebSphere eXtreme Scale provides several security endpoints to integrate custom mechanisms. In the local programming model, the main security function is authorization, and has no authentication support. Authenticate independently from the already existing WebSphere Application Server authentication. However, we can use the provided plug-ins to obtain and validate Subject objects.
We can enable local security with the ObjectGrid XML descriptor file or programmatically.
- Enable local security with the ObjectGrid XML descriptor XML file.
The secure-objectgrid-definition.xml file used in the ObjectGridSample enterprise application sample is shown in the following example. Set the securityEnabled attribute to true to enable security.
<objectGrids> <objectGrid name="secureClusterObjectGrid" securityEnabled="true" authorizationMechanism="AUTHORIZATION_MECHANISM_JAAS"> ... </objectGrids>
- Enable local security programmatically.
To create an ObjectGrid using the ObjectGrid.setSecurityEnabled method, call the following method on the ObjectGrid interface:
/** * Enable the ObjectGrid security */ void setSecurityEnabled();
What to do next
Start the container and catalog servers with security enabled.
14. Starting and stopping secure servers
Security is enabled by specifying security-specific configurations when you start and stop servers.
Starting secure servers in a stand-alone environment
To start secure stand-alone servers, you pass the proper configuration files by specifying parameters on the startOgServer or startXsServer command.
Deprecated: The startOgServer and stopOgServer commands start servers that use the ORB transport mechanism. The ORB is deprecated, but we can continue using these scripts if you were using the ORB in a previous release. The IBM eXtremeIO (XIO) transport mechanism replaces the ORB. Use the startXsServer and stopXsServer scripts to start and stop servers that use the XIO transport.
- Start secure container servers.
Starting a secure container server requires the following security configuration file:
- Server property file: The server property file configures the security properties specific to the server. Refer to the Server properties file for more details.
Specify the location of this configuration file by providing the following argument to the startOgServer or startXsServer script:
- -serverProps
- Location of the server property file, which contains the server-specific security properties. The file name specified for this property is in plain file path format, such as ../security/server.properties.
Enter the following lines when we run the startOgServer command or startXsServer command:
startOgServer.sh <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=$OBJECTGRID_HOME
startXsServer.sh <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=$OBJECTGRID_HOME
startOgServer.bat <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=%OBJECTGRID_HOME%startXsServer.bat <arguments> -jvmargs -Djava.security.auth.login.config=jaas.config -Djava.security.manager -Djava.security.policy="auth.policy" -Dobjectgrid.home=%OBJECTGRID_HOME%
- Start secure catalog servers.
To start a secure catalog service, you must have the following configuration files:
- Security descriptor XML file: The security descriptor XML file describes the security properties common to all servers, including catalog servers and container servers. One property example is the authenticator configuration which represents the user registry and authentication mechanism.
- Server property file: The server property file configures the security properties that are specific to the server.
Specify the location of these configuration files by providing the following arguments to the startOgServer or startXsServer script:
- -clusterSecurityFile and -clusterSecurityUrl
- These arguments specify the location of the Security descriptor XML file. Use the -clusterSecurityFile parameter to specify a local file, or the -clusterSecurityUrl parameter to specify the URL of the objectGridSecurity.xml file.
- -serverProps
- Location of the server property file, which contains the server-specific security properties. The file name specified for this property is in plain file path format, such as c:/tmp/og/catalogserver.props.
Next topic: Start and stopping secure servers in the Liberty profile
Starting secure servers in WebSphere Application Server
To start secure servers in WebSphere Application Server, specify the security configuration files in the generic Java virtual machine (JVM) arguments.
- Associate WebSphere eXtreme Scale catalog servers with WebSphere application servers using the administrative console. In the administrative console, click System Administration > WebSphere eXtreme Scale > Catalog Service Domains.
- Associate WebSphere eXtreme Scale container servers with particular WebSphere application servers by deploying an enterprise archive (EAR) file that contains the required XML descriptors for the data grid.
- Specify JVM arguments that point to configuration files to make the catalog and container servers secure. In addition, specify securityEnabled="true" in the objectgrid xml file for each data grid. After you specify the JVM arguments and enable security in the data grids, we can start the servers or clusters that act as eXtreme Scale catalog servers or container servers.
- Start catalog and containers servers with the WebSphere Application Server administrative console, or use the WebSphere Application Server command line.
Stopping secure servers
Stopping secure catalog servers or container servers requires one security configuration file.
- Stop a secure catalog server or container server in stand-alone deployments. In stand-alone environments, stop WebSphere eXtreme Scale catalog and container servers using the teardown function of the xscmd command, or using the stopXsServer or stopOgServer commands.
Restrict access to these operations to authorized administrators only. When authentication or SSL is used, the stopXsServer and stopOgServer commands require that a client properties file be passed as a parameter.
- Use the WebSphere Application Server administrative console to stop eXtreme Scale server that run with WebSphere Application Server. WebSphere Application Server administrative security should be configured to restrict access for starting and stopping servers to authorized administrators.
15. Configure WebSphere eXtreme Scale to use FIPS 140-2
Federal Information Processing Standard (FIPS) 140-2 specifies required levels of encryption for Transport Layer Security/Secure Sockets Layer (TLS/SSL). This standard ensures high protection of data as it is sent over the wire.
- You must be using an IBM Runtime Environment.
- Configure transport layer security and secure sockets layer in both directions. Your catalog server truststore file must contain the self-signed certificates for the container servers. The container servers must contain the self-signed certificates for the catalog server.
Use the following steps to configure the catalog servers and container servers in the WXS stand-alone installation to use FIPS.
If we are using WebSphere eXtreme Scale integrated with WebSphere Application Server, the catalog servers and container servers inherit the security properties from the application server. When a catalog server runs in WebSphere Application Server, some of the communication is controlled by the server.properties file. Update the server.properties file to contain the same properties that are required for stand-alone catalog servers.
- Edit the java.security file. The location of the java.security depends on your JVM configuration:
- If we are using the default JVM that ships with the product, the file is in the /path/to/java/jre/lib/security directory.
- If we are using a different JVM, edit the file in the java_home /jre/lib/security directory.
The file must contain the following text:
security.provider.1=com.ibm.crypto.fips.provider.IBMJCEFIPS security.provider.2=com.ibm.jsse2.IBMJSSEProvider2 security.provider.3=com.ibm.crypto.provider.IBMJCE security.provider.4=com.ibm.security.jgss.IBMJGSSProvider security.provider.5=com.ibm.security.cert.IBMCertPath security.provider.6=com.ibm.security.sasl.IBMSASL security.provider.7=com.ibm.xml.crypto.IBMXMLCryptoProvider security.provider.8=com.ibm.xml.enc.IBMXMLEncProvider security.provider.9=org.apache.harmony.security.provider.PolicyProvider security.provider.10=com.ibm.security.jgss.mech.spnego.IBMSPNEGO
- Edit the server properties files for the catalog server and container servers.
These files must contain the following properties and values:
contextProvider=IBMJSSE2 transportType=SSL-Required
- Configure key pairs that use the RSA key generation algorithm in the key ring for the catalog server and container servers. The minimum key length is 1024 bits.
- Restart the catalog and container servers.
When you start the catalog servers, specify JVM arguments. The arguments you use depend on which version of Java SE we are using.
- For Java 5 and Java 6 up to SR 9, specify the -Dcom.ibm.jsse2.JSSEFIPS=true argument when you start the server.
- For Java 6 SR 10 and later, or Java 7, specify the -Dcom.ibm.jsse2.usefipsprovider=true argument when you start the server.
16. Configure security profiles for the xscmd utility
By creating a security profile, we can use saved security parameters to use the xscmd utility with secure environments.
Use the -ssp profile_name or --saveSecProfile profile_name parameter with the rest of your xscmd command. to save a security profile. The profile can contain settings for user names and passwords, credential generators, keystores, truststores, and transport types. The ProfileManagement command group in the xscmd utility contains commands for managing your security profiles.
- Save a security profile.
To save a security profile, use the -ssp profile_name or --saveSecProfile profile_name parameter with the rest of your command. Adding this parameter to your command saves the following parameters:
-al,--alias <alias> -arc,--authRetryCount <integer> -ca,--credAuth <support> -cgc,--credGenClass <className> -cgp,--credGenProps <property> -cxpv,--contextProvider <provider> -ks,--keyStore <Security profiles are saved in the $HOME \.xscmd\profiles\security\<profile_name>.properties directory.filePath> -ksp,--keyStorePassword <password> -kst,--keyStoreType <type> -prot,--protocol <protocol> -pwd,--password <password> -ts,--trustStore <filePath> -tsp,--trustStorePassword <password> -tst,--trustStoreType <type> -tt,--transportType <type> -user,--username <username>
Do not include the .properties file name extension on the profile_name parameter. This extension is automatically added to the file name.
- Use a saved security profile.
To use a saved security profile, add the -sp profile_name or --securityProfile profile_name parameter to the command we are running. Command example:
xscmd -c listHosts -cep myhost.mycompany.com -sp myprofile
- List the commands in the ProfileManagement command group.
Run the following command: xscmd -lc ProfileManagement.
- List the existing security profiles.
Run the following command: xscmd -c listProfiles -v.
- Display the settings that are saved in a security profile.
Run the following command: xscmd -c showProfile -pn profile_name.
- Remove an existing security profile.
Run the following command: xscmd -c RemoveProfile -pn profile_name.
17. Securing J2C client connections
Use the Java 2 Connector (J2C) architecture to secure connections between WebSphere eXtreme Scale clients and the applications.
Applications reference the connection factory, which establishes the connection to the remote data grid. Each connection factory hosts a single eXtreme Scale client connection that is reused for all application components.
Since the eXtreme Scale client connection might include a near cache, it is important that applications do not share a connection. A connection factory must exist for a single application instance to avoid problems sharing objects between applications.
We can set the credential generator with the API or in the client properties file. In the client properties file, the securityEnabled and credentialGenerator properties are used.
In the following example, some lines of code are continued on the next line for publication purposes.
securityEnabled=true credentialGeneratorClass=com.ibm.websphere.objectgrid.security.plugins.builtins. UserPasswordCredentialGenerator credentialGeneratorProps=operator XXXXXXThe credential generator and credential in the client properties file are used for the eXtreme Scale connect operation and the default J2C credentials. Therefore, the credentials specified with the API are used at J2C connect time for the J2C connection. However, if no credentials are specified at J2C connect time, then the credential generator in the client properties file is used.
- Set up secure access where the J2C connection represents the eXtreme Scale client. Use the ClientPropertiesResource connection factory property or the ClientPropertiesURL connection factory property to configure client authentication.
If we are using WebSphere eXtreme Scale with WebSphere Application Server, then specify the client properties on the catalog service domain configuration. When the connection factory references the domain, it automatically uses this configuration.
- Configure the client security properties to use the connection factory that references the appropriate credential generator object for eXtreme Scale. These properties are also compatible with WXS server security. For example, use the WSTokenCredentialGenerator credential generator for WebSphere credentials when eXtreme Scale is installed with WebSphere Application Server. Alternatively, use the UserPasswordCredentialGenerator credential generator when we run the eXtreme Scale in a stand-alone environment.
In the following example, credentials are passed programmatically using the API call instead of using the configuration in the client properties:
XSConnectionSpec spec = new XSConnectionSpec(); spec.setCredentialGenerator(new UserPasswordCredentialGenerator("operator", "xxxxxx")); Connection conn = connectionFactory.getConnection(spec);
- (Optional) Disable the near cache, if required.
All J2C connections from a single connection factory share a single near cache. Grid entry permissions and map permissions are validated on the server, but not on the near cache . When an application uses multiple credentials to create J2C connections, and the configuration uses specific permissions for grid entries and maps for those credentials, then disable the near cache . Disable the near cache using the connection factory property, ObjectGridResource or ObjectGridURL.
- (Optional) Set security policy settings, if required.
If the J2EE application contains the embedded eXtreme Scale resource adapter archive (RAR) file configuration, you might be required to set additional security policy settings in the security policy file for the application. For example, these policies are required:
permission com.ibm.websphere.security.WebSphereRuntimePermission "accessRuntimeClasses"; permission java.lang.RuntimePermission "accessDeclaredMembers"; permission javax.management.MBeanTrustPermission "register"; permission java.lang.RuntimePermission "getClassLoader";Additionally, any property or resource files used by connection factories require file or other permissions, such as permission java.io.FilePermission "filePath";. For WebSphere Application Server, the policy file is META-INF/was.policy, and it is located in the J2EE EAR file.
Results
The client security properties that you configured on the catalog service domain are used as default values. The values that you specify override any properties that are defined in the client.properties files.
What to do next
Use eXtreme Scale data access APIs to develop client components to use transactions.
18. Programming for security
Use programming interfaces to handle various aspects of security in a WXS environment.
Security API
WebSphere eXtreme Scale adopts an open security architecture. It provides a basic security framework for authentication, authorization, and transport security, and requires users to implement plug-ins to complete the security infrastructure.
The following image shows the basic flow of client authentication and authorization for a WXS server.
Figure 1. Flow of client authentication and authorization
The authentication flow and authorization flow are as follows.
Authentication flow
- The authentication flow starts with a WXS client getting a credential. This is done by the com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator plug-in.
- A CredentialGenerator object knows how to generate a valid client credential, for example, a user ID and password pair, Kerberos ticket, and so on. This generated credential is sent back to the client.
- After the client retrieves the Credential object using the CredentialGenerator object, this Credential object is sent along with the eXtreme Scale request to the eXtreme Scale server.
- The eXtreme Scale server authenticates the Credential object before processing the eXtreme Scale request. Then the server uses the Authenticator plug-in to authenticate the Credential object.
- The Authenticator plug-in represents an interface to the user registry, for example, a Lightweight Directory Access Protocol (LDAP) server or an operating system user registry. The Authenticator consults the user registry and makes authentication decisions.
- If the authentication is successful, a Subject object is returned to represent this client.
Authorization flow
WebSphere eXtreme Scale adopts a permission-based authorization mechanism, and has different permission categories represented by different permission classes. For example, a com.ibm.websphere.objectgrid.security.MapPermission object represents permissions to read, write, insert, invalidate, and remove the data entries in an ObjectMap. Because WebSphere eXtreme Scale supports Java Authentication and Authorization Service (JAAS) authorization out-of-box, we can use JAAS to handle authorization by providing authorization policies.
Also, eXtreme Scale supports custom authorizations. Custom authorizations are plugged in by the plug-in com.ibm.websphere.objectgrid.security.plugins.ObjectGridAuthorization. The flow of the customer authorization is as follows.
- The server runtime sends the Subject object and the required permission to the authorization plug-in.
- The authorization plug-in consults the Authorization service and makes an authorization decision. If permission is granted for this Subject object, a value of true is returned, otherwise falseis returned.
- This authorization decision, true or false, is returned to the server runtime.
Security implementation
The topics in this section discuss how to program a secure WebSphere eXtreme Scale deployment and how to program the plug-in implementations. The section is organized based on the various security features. In each subtopic, you will learn about relevant plug-ins and how to implement the plug-ins. In the authentication section, you will see how to connect to a secure WebSphere eXtreme Scale deployment environment.
Client Authentication: The client authentication topic describes how a WXS client gets a credential and how a server authenticates the client. It will also discuss how a WXS client connects to a secure WebSphere eXtreme Scale server.
Authorization: The authorization topic explains how to use the ObjectGridAuthorization to do customer authorization besides JAAS authorization.
Grid Authentication: The data grid authentication topic discusses how we can use SecureTokenManager to securely transport server secrets.
JMX programming: When the WebSphere eXtreme Scale server is secured, the JMX client might need to send a JMX credential to the server.
Client authentication programming
For authentication, WebSphere eXtreme Scale provides a runtime to send the credential from the client to the server side, and then calls the authenticator plug-in to authenticate the users.
WebSphere eXtreme Scale requires you to implement the following plug-ins to complete the authentication.
- Credential: A Credential represents a client credential, such as a user ID and password pair.
- CredentialGenerator: A CredentialGenerator represents a credential factory to generate the credential.
- Authenticator: An Authenticator authenticates the client credential and retrieves client information.
Credential and CredentialGenerator plug-ins
When a WXS client connects to a server that requires authentication, the client is required to provide a client credential. A client credential is represented by a com.ibm.websphere.objectgrid.security.plugins.Credential interface. A client credential can be a user name and password pair, a Kerberos ticket, a client certificate, or data in any format that the client and server agree upon. This interface explicitly defines the equals(Object) and hashCode methods. These two methods are important because the authenticated Subject objects are cached using the Credential object as the key on the server side. WebSphere eXtreme Scale also provides a plug-in to generate a credential. This plug-in is represented by the com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator interface and is useful when the credential can expire. In this case, the getCredential method is called to renew a credential.
The Credential interface explicitly defines the equals(Object) and hashCode methods. These two methods are important because the authenticated Subject objects are cached using the Credential object as the key on the server side.
You may also use the provided plug-in to generate a credential. This plug-in is represented by the com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator interface, and is useful when the credential can expire. In this case, the getCredential method is called to renew a credential. See CredentialGenerator interface for more details.
There are three provided default implementations for the Credential interfaces:
- The com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredential implementation, which contains a user ID and password pair.
- The com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredential implementation, which contains WebSphere Application Server-specific authentication and authorization tokens. These tokens can be used to propagate the security attributes across the application servers in the same security domain.
WebSphere eXtreme Scale also provides a plug-in to generate a credential. This plug-in is represented by the com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator interface.WebSphere eXtreme Scale provides two default built-in implementations:
- The com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator constructor takes a user ID and a password. When the getCredential method is called, it returns a UserPasswordCredential object that contains the user ID and password.
- The com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator represents a credential (security token) generator when running in WebSphere Application Server. When the getCredential method is called, the Subject that is associated with the current thread is retrieved. Then the security information in this Subject object is converted into a WSTokenCredential object. We can specify whether to retrieve a runAs subject or a caller subject from the thread using the constant WSTokenCredentialGenerator.RUN_AS_SUBJECT or WSTokenCredentialGenerator.CALLER_SUBJECT.
UserPasswordCredential and UserPasswordCredentialGenerator
For testing purposes, WebSphere eXtreme Scale provides the following plug-in implementations:
com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredential com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator
The user password credential stores a user ID and password. The user password credential generator then contains this user ID and password.
The following example code shows how to implement these two plug-ins.
UserPasswordCredential.java // This sample program is provided AS IS and may be used, executed, copied and modified // without royalty payment by customer // (a) for its own instruction and study, // (b) to develop applications designed to run with an IBM WebSphere product, // either for customer's own internal use or for redistribution by customer, as part of such an // application, in customer's own products. // Licensed Materials - Property of IBM // 5724-J34 © COPYRIGHT International Business Machines Corp. 2007 package com.ibm.websphere.objectgrid.security.plugins.builtins; import com.ibm.websphere.objectgrid.security.plugins.Credential; /** * This class represents a credential containing a user ID and password. * * @ibm-api * @since WAS XD 6.0.1 * * @see Credential * @see UserPasswordCredentialGenerator#getCredential() */ public class UserPasswordCredential implements Credential { private static final long serialVersionUID = 1409044825541007228L; private String ivUserName; private String ivPassword; /** * Creates a UserPasswordCredential with the specified user name and * password. * * @param userName the user name for this credential * @param password the password for this credential * * @throws IllegalArgumentException if userName or password is <code>null</code> */ public UserPasswordCredential(String userName, String password) { super(); if (userName == null || password == null) { throw new IllegalArgumentException("User name and password cannot be null."); } this.ivUserName = userName; this.ivPassword = password; } /** * Gets the user name for this credential. * * @return the user name argument that was passed to the constructor * or the <code>setUserName(String)</code> * method of this class * * @see #setUserName(String) */ public String getUserName() { return ivUserName; } /** * Sets the user name for this credential. * * @param userName the user name to set. * * @throws IllegalArgumentException if userName is <code>null</code> */ public void setUserName(String userName) { if (userName == null) { throw new IllegalArgumentException("User name cannot be null."); } this.ivUserName = userName; } /** * Gets the password for this credential. * * @return the password argument that was passed to the constructor * or the <code>setPassword(String)</code> * method of this class * * @see #setPassword(String) */ public String getPassword() { return ivPassword; } /** * Sets the password for this credential. * * @param password the password to set. * * @throws IllegalArgumentException if password is <code>null</code> */ public void setPassword(String password) { if (password == null) { throw new IllegalArgumentException("Password cannot be null."); } this.ivPassword = password; } /** * Checks two UserPasswordCredential objects for equality. * <p> * Two UserPasswordCredential objects are equal if and only if their user names * and passwords are equal. * * @param o the object we are testing for equality with this object. * * @return <code>true</code> if both UserPasswordCredential objects are equivalent. * * @see Credential#equals(Object) */ public boolean equals(Object o) { if (this == o) { return true; } if (o instanceof UserPasswordCredential) { UserPasswordCredential other = (UserPasswordCredential) o; return other.ivPassword.equals(ivPassword) && other.ivUserName.equals(ivUserName); } return false; } /** * Returns the hashcode of the UserPasswordCredential object. * * @return the hash code of this object * * @see Credential#hashCode() */ public int hashCode() { return ivUserName.hashCode() + ivPassword.hashCode(); }}UserPasswordCredentialGenerator.java // This sample program is provided AS IS and may be used, executed, copied and modified // without royalty payment by customer // (a) for its own instruction and study, // (b) to develop applications designed to run with an IBM WebSphere product, // either for customer's own internal use or for redistribution by customer, as part of such an // application, in customer's own products. // Licensed Materials - Property of IBM // 5724-J34 © COPYRIGHT International Business Machines Corp. 2007 package com.ibm.websphere.objectgrid.security.plugins.builtins; import java.util.StringTokenizer; import com.ibm.websphere.objectgrid.security.plugins.Credential; import com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator; /** * This credential generator creates <code>UserPasswordCredential</code> objects. * <p> * UserPasswordCredentialGenerator has a one to one relationship with * UserPasswordCredential because it can only create a UserPasswordCredential * representing one identity. * * @since WAS XD 6.0.1 * @ibm-api * * @see CredentialGenerator * @see UserPasswordCredential */ public class UserPasswordCredentialGenerator implements CredentialGenerator { private String ivUser; private String ivPwd; /** * Creates a UserPasswordCredentialGenerator with no user name or password. * * @see #setProperties(String) */ public UserPasswordCredentialGenerator() { super(); } /** * Creates a UserPasswordCredentialGenerator with a specified user name and * password * * @param user the user name * @param pwd the password */ public UserPasswordCredentialGenerator(String user, String pwd) { ivUser = user; ivPwd = pwd; } /** * Creates a new <code>UserPasswordCredential</code> object using this * object's user name and password. * * @return a new <code>UserPasswordCredential</code> instance * * @see CredentialGenerator#getCredential() * @see UserPasswordCredential */ public Credential getCredential() { return new UserPasswordCredential(ivUser, ivPwd); } /** * Gets the password for this credential generator. * * @return the password argument that was passed to the constructor */ public String getPassword() { return ivPwd; } /** * Gets the user name for this credential. * * @return the user argument that was passed to the constructor * of this class */ public String getUserName() { return ivUser; } /** * Sets additional properties namely a user name and password. * * @param properties a properties string with a user name and * a password separated by a blank. * * @throws IllegalArgumentException if the format is not valid */ public void setProperties(String properties) { StringTokenizer token = new StringTokenizer(properties, " "); if (token.countTokens() != 2) { throw new IllegalArgumentException( "The properties should have a user name and password and separated by a blank."); } ivUser = token.nextToken(); ivPwd = token.nextToken(); } /** * Checks two UserPasswordCredentialGenerator objects for equality. * <p> * Two UserPasswordCredentialGenerator objects are equal if and only if * their user names and passwords are equal. * * @param obj the object we are testing for equality with this object. * * @return <code>true</code> if both UserPasswordCredentialGenerator objects * are equivalent. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj instanceof UserPasswordCredentialGenerator) { UserPasswordCredentialGenerator other = (UserPasswordCredentialGenerator) obj; boolean bothUserNull = false; boolean bothPwdNull = false; if (ivUser == null) { if (other.ivUser == null) { bothUserNull = true; } else { return false; } } if (ivPwd == null) { if (other.ivPwd == null) { bothPwdNull = true; } else { return false; } } return (bothUserNull || ivUser.equals(other.ivUser)) && (bothPwdNull || ivPwd.equals(other.ivPwd)); } return false; } /** * Returns the hashcode of the UserPasswordCredentialGenerator object. * * @return the hash code of this object */ public int hashCode() { return ivUser.hashCode() + ivPwd.hashCode(); }}The UserPasswordCredential class contains two attributes: user name and password. The UserPasswordCredentialGenerator serves as a factory that contains the UserPasswordCredential objects.
WSTokenCredential and WSTokenCredentialGenerator
When the WebSphere eXtreme Scale clients and servers are all deployed in WebSphere Application Server, the client application can use these two built-in implementations when the following conditions are satisfied:
- WebSphere Application Server global security is turned on.
- All WebSphere eXtreme Scale clients and servers are running in WebSphere Application Server Java virtual machines.
- The application servers are in the same security domain.
- The client is already authenticated in WebSphere Application Server.
In this situation, the client can use the com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator class to generate a credential. The server uses the WSAuthenticator implementation class to authenticate the credential.
This scenario takes advantage of the fact that the eXtreme Scale client has already been authenticated. Because the application servers that have the servers are in the same security domain as the application servers that house the clients, the security tokens can be propagated from the client to the server so that the same user registry does not need to be authenticated again. Do not assume that a CredentialGenerator always generates the same credential. For an expirable and refreshable credential, the CredentialGenerator should be able to generate the latest valid credential to make sure the authentication succeeds. One example is using the Kerberos ticket as a Credential object. When the Kerberos ticket refreshes, the CredentialGenerator should retrieve the refreshed ticket when CredentialGenerator.getCredential is called.
Authenticator plug-in
After the eXtreme Scale client retrieves the Credential object using the CredentialGenerator object, this client Credential object is sent along with the client request to the eXtreme Scale server. The server authenticates the Credential object before processing the request. If the Credential object is authenticated successfully, a Subject object is returned to represent this client.
This Subject object is then cached, and it expires after its lifetime reaches the session timeout value. The login session timeout value can be set using the loginSessionExpirationTime property in the cluster XML file. For example, setting loginSessionExpirationTime="300" makes the Subject object expire in 300 seconds.
This Subject object is then used for authorizing the request, which is shown later. An eXtreme Scale server uses the Authenticator plug-in to authenticate the Credential object. See Authenticator for more details.
The Authenticator plug-in is where the eXtreme Scale runtime authenticates the Credential object from the client user registry, for example, a Lightweight Directory Access Protocol (LDAP) server.
WebSphere eXtreme Scale does not provide an immediately available user registry configuration. The configuration and management of user registry is left outside of WXS for simplicity and flexibility. This plug-in implements connecting and authenticating to the user registry. For example, an Authenticator implementation extracts the user ID and password from the credential, uses them to connect and validate to an LDAP server, and creates a Subject object as a result of the authentication. The implementation might use JAAS login modules. A Subject object is returned as a result of authentication.
Notice that this method creates two exceptions: InvalidCredentialException and ExpiredCredentialException. The InvalidCredentialException exception indicates that the credential is not valid. The ExpiredCredentialException exception indicates that the credential expired. If one of these two exceptions result from the authenticate method, the exceptions are sent back to the client. However, the client runtime handles these two exceptions differently:
- If the error is an InvalidCredentialException exception, the client run time displays this exception. Your application must handle the exception. We can correct the CredentialGenerator, for example, and then try the operation again.
- If the error is an ExpiredCredentialException exception, and the retry count is not 0, the client run time calls the CredentialGenerator.getCredential method again, and sends the new Credential object to the server. If the new credential authentication succeeds, the server processes the request. If the new credential authentication fails, the exception is sent back to the client. If the number of authentication retry attempts reaches the supported value and the client still gets an ExpiredCredentialException exception, the ExpiredCredentialException exception results. Your application must handle the error.
The Authenticator interface provides great flexibility. We can implement the Authenticator interface in your own specific way. For example, we can implement this interface to support two different user registries.
WebSphere eXtreme Scale provides sample authenticator plug-in implementations. Except for the WebSphere Application Server authenticator plug-in, the other implementations are only samples for testing purposes.
KeyStoreLoginAuthenticator
This example uses a WXS built-in implementation: KeyStoreLoginAuthenticator, which is for testing and sample purposes (a keystore is a simple user registry and should not be used for a production environment). Again, the class is displayed to further demonstrate how to implement an authenticator.
In the following example, some lines of code are continued on the next line for publication purposes.
KeyStoreLoginAuthenticator.java // This sample program is provided AS IS and may be used, executed, copied and modified // without royalty payment by customer // (a) for its own instruction and study, // (b) to develop applications designed to run with an IBM WebSphere product, // either for customer's own internal use or for redistribution by customer, as part of such an // application, in customer's own products. // Licensed Materials - Property of IBM // 5724-J34 © COPYRIGHT International Business Machines Corp. 2007 package com.ibm.websphere.objectgrid.security.plugins.builtins; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import com.ibm.websphere.objectgrid.security.plugins.Authenticator; import com.ibm.websphere.objectgrid.security.plugins.Credential; import com.ibm.websphere.objectgrid.security.plugins.ExpiredCredentialException; import com.ibm.websphere.objectgrid.security.plugins.InvalidCredentialException; import com.ibm.ws.objectgrid.Constants; import com.ibm.ws.objectgrid.ObjectGridManagerImpl; import com.ibm.ws.objectgrid.security.auth.callback.UserPasswordCallbackHandlerImpl; /** * This class is an implementation of the <code>Authenticator</code> interface * when a user name and password are used as a credential. * <p> * When user ID and password authentication is used, the credential passed to the * <code>authenticate(Credential)</code> method is a UserPasswordCredential object. * <p> * This implementation will use a <code>KeyStoreLoginModule</code> to authenticate * the user into the keystore using the JAAS login module "KeyStoreLogin". The key * store can be configured as an option to the <code>KeyStoreLoginModule</code> * class. Please see the <code>KeyStoreLoginModule</code> class for more details * about how to set up the JAAS login configuration file. * <p> * This class is only for sample and quick testing purpose. Users should * write your own Authenticator implementation which can fit better into * the environment. * * @ibm-api * @since WAS XD 6.0.1 * * @see Authenticator * @see KeyStoreLoginModule * @see UserPasswordCredential */ public class KeyStoreLoginAuthenticator implements Authenticator { /** * Creates a new KeyStoreLoginAuthenticator. */ public KeyStoreLoginAuthenticator() { super(); } /** * Authenticates a <code>UserPasswordCredential</code>. * <p> * Uses the user name and password from the specified UserPasswordCredential * to login to the KeyStoreLoginModule named "KeyStoreLogin". * * @throws InvalidCredentialException if credential isn't a * UserPasswordCredential or some error occurs during processing * of the supplied UserPasswordCredential * * @throws ExpiredCredentialException if credential is expired. This exception * is not used by this implementation * * @see Authenticator#authenticate(Credential) * @see KeyStoreLoginModule */ public Subject authenticate(Credential credential) throws InvalidCredentialException, ExpiredCredentialException { if (credential == null) { throw new InvalidCredentialException("Supplied credential is null"); } if (! (credential instanceof UserPasswordCredential) ) { throw new InvalidCredentialException("Supplied credential is not a UserPasswordCredential"); } UserPasswordCredential cred = (UserPasswordCredential) credential; LoginContext lc = null; try { lc = new LoginContext("KeyStoreLogin", new UserPasswordCallbackHandlerImpl(cred.getUserName(), cred.getPassword().toCharArray())); lc.login(); Subject subject = lc.getSubject(); return subject; } catch (LoginException le) { throw new InvalidCredentialException(le); } catch (IllegalArgumentException ile) { throw new InvalidCredentialException(ile); } }}
In the following example, some lines of code are continued on the next line for publication purposes.
KeyStoreLoginModule.java // This sample program is provided AS IS and may be used, executed, copied and modified // without royalty payment by customer // (a) for its own instruction and study, // (b) to develop applications designed to run with an IBM WebSphere product, // either for customer's own internal use or for redistribution by customer, as part of such an // application, in customer's own products. // Licensed Materials - Property of IBM // 5724-J34 © COPYRIGHT International Business Machines Corp. 2007 package com.ibm.websphere.objectgrid.security.plugins.builtins; import java.io.File; import java.io.FileInputStream; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500PrivateCredential; import com.ibm.websphere.objectgrid.ObjectGridRuntimeException; import com.ibm.ws.objectgrid.Constants; import com.ibm.ws.objectgrid.ObjectGridManagerImpl; import com.ibm.ws.objectgrid.util.ObjectGridUtil; /** * A KeyStoreLoginModule is keystore authentication login module based on * JAAS authentication. * <p> * A login configuration should provide an option "<code>keyStoreFile</code>" to * indicate where the keystore file is located. If the <code>keyStoreFile</code> * value contains a system property in the form, <code>${system.property}</code>, * it will be expanded to the value of the system property. * <p> * If an option "<code>keyStoreFile</code>" is not provided, the default keystore * file name is <code>"${java.home}${/}.keystore"</code>. * <p> * Here is a Login module configuration example: * <pre><code> * KeyStoreLogin { * com.ibm.websphere.objectgrid.security.plugins.builtins.KeystoreLoginModule required * keyStoreFile="${user.dir}${/}security${/}.keystore"; * }; * </code></pre> * * @ibm-api * @since WAS XD 6.0.1 * * @see LoginModule */ public class KeyStoreLoginModule implements LoginModule { private static final String CLASS_NAME = KeyStoreLoginModule.class.getName(); /** * keystore file property name */ public static final String KEY_STORE_FILE_PROPERTY_NAME = "keyStoreFile"; /** * keystore type. Only JKS is supported */ public static final String KEYSTORE_TYPE = "JKS"; /** * The default keystore file name */ public static final String DEFAULT_KEY_STORE_FILE = "${java.home}${/}.keystore"; private CallbackHandler handler; private Subject subject; private boolean debug = false; private Set principals = new HashSet(); private Set publicCreds = new HashSet(); private Set privateCreds = new HashSet(); protected KeyStore keyStore; /** * Creates a new KeyStoreLoginModule. */ public KeyStoreLoginModule() { } /** * Initializes the login module. * * @see LoginModule#initialize(Subject, CallbackHandler, Map, Map) */ public void initialize(Subject sub, CallbackHandler callbackHandler, Map mapSharedState, Map mapOptions) { // initialize any configured options debug = "true".equalsIgnoreCase((String) mapOptions.get("debug")); if (sub == null) throw new IllegalArgumentException("Subject is not specified"); if (callbackHandler == null) throw new IllegalArgumentException( "CallbackHander is not specified"); // Get the keystore path String sKeyStorePath = (String) mapOptions .get(KEY_STORE_FILE_PROPERTY_NAME); // If there is no keystore path, the default one is the .keystore // file in the java home directory if (sKeyStorePath == null) { sKeyStorePath = DEFAULT_KEY_STORE_FILE; } // Replace the system enviroment variable sKeyStorePath = ObjectGridUtil.replaceVar(sKeyStorePath); File fileKeyStore = new File(sKeyStorePath); try { KeyStore store = KeyStore.getInstance("JKS"); store.load(new FileInputStream(fileKeyStore), null); // Save the keystore keyStore = store; if (debug) { System.out.println("[KeyStoreLoginModule] initialize: Successfully loaded keystore"); } } catch (Exception e) { ObjectGridRuntimeException re = new ObjectGridRuntimeException( "Failed to load keystore: " + fileKeyStore.getAbsolutePath()); re.initCause(e); if (debug) { System.out.println("[KeyStoreLoginModule] initialize: keystore loading failed with exception " + e.getMessage()); } } this.subject = sub; this.handler = callbackHandler; } /** * Authenticates a user based on the keystore file. * * @see LoginModule#login() */ public boolean login() throws LoginException { if (debug) { System.out.println("[KeyStoreLoginModule] login: entry"); } String name = null; char pwd[] = null; if (keyStore == null || subject == null || handler == null) { throw new LoginException("Module initialization failed"); } NameCallback nameCallback = new NameCallback("Username:"); PasswordCallback pwdCallback = new PasswordCallback("Password:", false); try { handler.handle(new Callback[] { nameCallback, pwdCallback }); } catch (Exception e) { throw new LoginException("Callback failed: " + e); } name = nameCallback.getName(); char[] tempPwd = pwdCallback.getPassword(); if (tempPwd == null) { // treat a NULL password as an empty password tempPwd = new char[0]; } pwd = new char[tempPwd.length]; System.arraycopy(tempPwd, 0, pwd, 0, tempPwd.length); pwdCallback.clearPassword(); if (debug) { System.out.println("[KeyStoreLoginModule] login: " + "user entered user name: " + name); } // Validate the user name and password try { validate(name, pwd); } catch (SecurityException se) { principals.clear(); publicCreds.clear(); privateCreds.clear(); LoginException le = new LoginException( "Exception encountered during login"); le.initCause(se); throw le; } if (debug) { System.out.println("[KeyStoreLoginModule] login: exit"); } return true; } /** * Indicates the user is accepted. * <p> * This method is called only if the user is authenticated by all modules in * the login configuration file. The principal objects will be added to the * stored subject. * * @return false if for some reason the principals cannot be added; true * otherwise * * @exception LoginException * LoginException is thrown if the subject is readonly or if * any unrecoverable exceptions is encountered. * * @see LoginModule#commit() */ public boolean commit() throws LoginException { if (debug) { System.out.println("[KeyStoreLoginModule] commit: entry"); } if (principals.isEmpty()) { throw new IllegalStateException("Commit is called out of sequence"); } if (subject.isReadOnly()) { throw new LoginException("Subject is Readonly"); } subject.getPrincipals().addAll(principals); subject.getPublicCredentials().addAll(publicCreds); subject.getPrivateCredentials().addAll(privateCreds); principals.clear(); publicCreds.clear(); privateCreds.clear(); if (debug) { System.out.println("[KeyStoreLoginModule] commit: exit"); } return true; } /** * Indicates the user is not accepted * * @see LoginModule#abort() */ public boolean abort() throws LoginException { boolean b = logout(); return b; } /** * Logs the user out. Clear all the maps. * * @see LoginModule#logout() */ public boolean logout() throws LoginException { // Clear the instance variables principals.clear(); publicCreds.clear(); privateCreds.clear(); // clear maps in the subject if (!subject.isReadOnly()) { if (subject.getPrincipals() != null) { subject.getPrincipals().clear(); } if (subject.getPublicCredentials() != null) { subject.getPublicCredentials().clear(); } if (subject.getPrivateCredentials() != null) { subject.getPrivateCredentials().clear(); } } return true; } /** * Validates the user name and password based on the keystore. * * @param userName user name * @param password password * @throws SecurityException if any exceptions encountered */ private void validate(String userName, char password[]) throws SecurityException { PrivateKey privateKey = null; // Get the private key from the keystore try { privateKey = (PrivateKey) keyStore.getKey(userName, password); } catch (NoSuchAlgorithmException nsae) { SecurityException se = new SecurityException(); se.initCause(nsae); throw se; } catch (KeyStoreException kse) { SecurityException se = new SecurityException(); se.initCause(kse); throw se; } catch (UnrecoverableKeyException uke) { SecurityException se = new SecurityException(); se.initCause(uke); throw se; } if (privateKey == null) { throw new SecurityException("Invalid name: " + userName); } // Check the certificats Certificate certs[] = null; try { certs = keyStore.getCertificateChain(userName); } catch (KeyStoreException kse) { SecurityException se = new SecurityException(); se.initCause(kse); throw se; } if (debug) { System.out.println(" Print out the certificates:"); for (int i = 0; i < certs.length; i++) { System.out.println(" certificate " + i); System.out.println(" " + certs[i]); } } if (certs != null && certs.length > 0) { // If the first certificate is an X509Certificate if (certs[0] instanceof X509Certificate) { try { // Get the first certificate which represents the user X509Certificate certX509 = (X509Certificate) certs[0]; // Create a principal X500Principal principal = new X500Principal(certX509 .getIssuerDN() .getName()); principals.add(principal); if (debug) { System.out.println(" Principal added: " + principal); } // Create the certification path object and add it to the // public credential set CertificateFactory factory = CertificateFactory .getInstance("X.509"); java.security.cert.CertPath certPath = factory .generateCertPath(Arrays.asList(certs)); publicCreds.add(certPath); // Add the private credential to the private credential set privateCreds.add(new X500PrivateCredential(certX509, privateKey, userName)); } catch (CertificateException ce) { SecurityException se = new SecurityException(); se.initCause(ce); throw se; } } else { // The first certificate is not an X509Certificate // We just add the certificate to the public credential set // and the private key to the private credential set. publicCreds.add(certs[0]); privateCreds.add(privateKey); } } }}Using the LDAP authenticator plug-in
You are provided with the com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthenticator default implementation to handle the user name and password authentication to an LDAP server. This implementation uses the LDAPLogin login module to log the user into a Lightweight Directory Access Protocol (LDAP) server.The following snippet demonstrates how the authenticate method is implemented:
In the following example, some lines of code are continued on the next line for publication purposes.
/** * @see com.ibm.ws.objectgrid.security.plugins.Authenticator# * authenticate(LDAPLogin) */ public Subject authenticate(Credential credential) throws InvalidCredentialException, ExpiredCredentialException { UserPasswordCredential cred = (UserPasswordCredential) credential; LoginContext lc = null; try { lc = new LoginContext("LDAPLogin", new UserPasswordCallbackHandlerImpl(cred.getUserName(), cred.getPassword().toCharArray())); lc.login(); Subject subject = lc.getSubject(); return subject; } catch (LoginException le) { throw new InvalidCredentialException(le); } catch (IllegalArgumentException ile) { throw new InvalidCredentialException(ile); }}Also, eXtreme Scale ships a login module com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPLoginModule for this purpose. You must provide the following two options in the JAAS login configuration file.
- providerURL: The LDAP server provider URL
- factoryClass: The LDAP context factory implementation class
The LDAPLoginModule module calls the com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPAuthentcationHelper.authenticate method. The following code snippet shows how we can implement the authenticate method of the LDAPAuthenticationHelper.
/** * Authenticate the user to the LDAP directory. * @param user the user ID, e.g., uid=xxxxxx,c=us,ou=bluepages,o=ibm.com * @param pwd the password * * @throws NamingException */ public String[] authenticate(String user, String pwd) throws NamingException { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, factoryClass); env.put(Context.PROVIDER_URL, providerURL); env.put(Context.SECURITY_PRINCIPAL, user); env.put(Context.SECURITY_CREDENTIALS, pwd); env.put(Context.SECURITY_AUTHENTICATION, "simple"); InitialContext initialContext = new InitialContext(env); // Look up for the user DirContext dirCtx = (DirContext) initialContext.lookup(user); String uid = null; int iComma = user.indexOf(","); int iEqual = user.indexOf("="); if (iComma > 0 && iComma > 0) { uid = user.substring(iEqual + 1, iComma); } else { uid = user; } Attributes attributes = dirCtx.getAttributes(""); // Check the UID String thisUID = (String) (attributes.get(UID).get()); String thisDept = (String) (attributes.get(HR_DEPT).get()); if (thisUID.equals(uid)) { return new String[] { thisUID, thisDept }; } else { return null; }}If authentication succeeds, the ID and password are considered valid. Then the login module gets the ID information and department information from this authenticate method. The login module creates two principals: SimpleUserPrincipal and SimpleDeptPrincipal. Use the authenticated subject for group authorization (in this case, the department is a group) and individual authorization.
The following example shows a login module configuration that is used to log in to the LDAP server:
LDAPLogin { com.ibm.websphere.objectgrid.security.plugins.builtins.LDAPLoginModule required providerURL="ldap://directory.acme.com:389/" factoryClass="com.sun.jndi.ldap.LdapCtxFactory";};In the previous configuration, the LDAP server points to the ldap://directory.acme.com:389/server. Change this setting to your LDAP server. This login module uses the provided ID and password to connect to the LDAP server. This implementation is for testing purposes only.
Using the WebSphere Application Server authenticator plug-in
Also, eXtreme Scale provides the com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenAuthenticator built-in implementation to use the WebSphere Application Server security infrastructure. This built-in implementation can be used when the following conditions are true.
- WebSphere Application Server global security is turned on.
- All eXtreme Scale clients and servers are launched in WebSphere Application Server JVMs.
- These application servers are in the same security domain.
- The eXtreme Scale client is already authenticated in WebSphere Application Server.
The client can use the com.ibm.websphere.objectgrid.security.plugins.builtins.WSTokenCredentialGenerator class to generate a credential. The server uses this Authenticator implementation class to authenticate the credential. If the token is authenticated successfully, a Subject object returns.
This scenario takes advantage of the fact that the client has already been authenticated. Because the application servers that have the servers are in the same security domain as the application servers that house the clients, the security tokens can be propagated from the client to the server so that the same user registry does not need to be authenticated again.
Using the Tivoli Access Manager authenticator plug-in
Tivoli Access Manager is used widely as a security server. We can also implement Authenticator using the Tivoli Access Manager's provided login modules.
To authenticate a user for Tivoli Access Manager, apply the com.tivoli.mts.PDLoginModule login module, which requires that the calling application provide the following information:
- A principal name, specified as either a short name or an X.500 name (DN)
- A password
The login module authenticates the principal and returns the Tivoli Access Manager credential. The login module expects the calling application to provide the following information:
- The user name, through a javax.security.auth.callback.NameCallback object.
- The password, through a javax.security.auth.callback.PasswordCallback object.
When the Tivoli Access Manager credential is successfully retrieved, the JAAS LoginModule creates a Subject and a PDPrincipal. No built-in for Tivoli Access Manager authentication is provided, because it is just with the PDLoginModule module. See the IBM Tivoli Access Manager Authorization Java Classes Developer Reference for more details.
Connecting to WebSphere eXtreme Scale securely
To connect a WXS client to a server securely, we can use any connect method in the ObjectGridManager interface which takes a ClientSecurityConfiguration object. The following is a brief example.
public ClientClusterContext connect(String catalogServerEndpoints, ClientSecurityConfiguration securityProps, URL overRideObjectGridXml) throws ConnectException;This method takes a parameter of the ClientSecurityConfiguration type, which is an interface representing a client security configuration. Use com.ibm.websphere.objectgrid.security.config.ClientSecurityConfigurationFactory public API to create an instance with default values, or we can create an instance by passing the WebSphere eXtreme Scale client property file. This file contains the following properties that are related to authentication. The value marked with a plus sign (+) is the default.
- securityEnabled (true, false+): This property indicates if security is enabled. When a client connects to a server, the securityEnabled value on the client and server side must be both true or both false. For example, if the connected server security is enabled, the client has to set this property to true to connect to the server.
- authenticationRetryCount (an integer value, 0+): This property determines how many retries are attempted for login when a credential is expired. If the value is 0, no retries are attempted. The authentication retry only applies to the case when the credential is expired. If the credential is not valid, there is no retry. Your application is responsible for trying the operation again.
After you create a com.ibm.websphere.objectgrid.security.config.ClientSecurityConfiguration object, set the credentialGenerator object on the client using the following method:
/** * Set the {@link CredentialGenerator} object for this client. * @param generator the CredentialGenerator object associated with this client */ void setCredentialGenerator(CredentialGenerator generator);We can set the CredentialGenerator object in the WebSphere eXtreme Scale client property file too, as follows.
- credentialGeneratorClass: The class implementation name for the CredentialGenerator object. It must have a default constructor.
- credentialGeneratorProps: The properties for the CredentialGenerator class. If the value is not null, it is set to the constructed CredentialGenerator object using the setProperties(String) method.
Here is a sample to instantiate a ClientSecurityConfiguration and then use it to connect to the server.
/** * Get a secure ClientClusterContext * @return a secure ClientClusterContext object */ protected ClientClusterContext connect() throws ConnectException { ClientSecurityConfiguration csConfig = ClientSecurityConfigurationFactory .getClientSecurityConfiguration("/properties/security.ogclient.props"); UserPasswordCredentialGenerator gen= new UserPasswordCredentialGenerator("manager", "manager1"); csConfig.setCredentialGenerator(gen); return objectGridManager.connect(csConfig, null);}When the connect is called, the WebSphere eXtreme Scale client calls the CredentialGenerator.getCredential method to get the client credential. This credential is sent along with the connect request to the server for authentication.
Use a different CredentialGenerator instance per session
In some cases, a WXS client represents just one client identity, but in others, it might represent multiple identities. Here is one scenario for the latter case: An WebSphere eXtreme Scale client is created and shared in a Web server. All servlets in this Web server use this one WebSphere eXtreme Scale client. Because every servlet represents a different Web client, use different credentials when sending requests to WebSphere eXtreme Scale servers.
WebSphere eXtreme Scale provides for changing the credential on the session level. Every session can uses a different CredentialGenerator object. Therefore, the previous scenarios can be implemented by letting the servlet get a session with a different CredentialGenerator object. The following example illustrates the ObjectGrid.getSession(CredentialGenerator) method in the ObjectGridManager interface.
In the following example, some lines of code are continued on the next line for publication purposes.
/** * Get a session using a <code>CredentialGenerator</code>. * <p> * This method can only be called by the ObjectGrid client in an ObjectGrid * client server environment. If ObjectGrid is used in a local model, that is, * within the same JVM with no client or server existing, <code>getSession(Subject)</code> * or the <code>SubjectSource</code> plugin should be used to secure the ObjectGrid. * * <p>If the <code>initialize()</code> method has not been invoked prior to * the first <code>getSession</code> invocation, an implicit initialization * will occur. This ensures that all of the configuration is complete * before any runtime usage is required.</p> * * @param credGen A <code>CredentialGenerator</code> for generating a credential * for the session returned. * * @return An instance of <code>Session</code> * * @throws ObjectGridException if an error occurs during processing * @throws TransactionCallbackException if the <code>TransactionCallback</code> * throws an exception * @throws IllegalStateException if this method is called after the * <code>destroy()</code> method is called. * * @see #destroy() * @see #initialize() * @see CredentialGenerator * @see Session * @since WAS XD 6.0.1 */ Session getSession(CredentialGenerator credGen) throws ObjectGridException, TransactionCallbackException;The following is an example:
ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager(); CredentialGenerator credGenManager = new UserPasswordCredentialGenerator("manager", "xxxxxx"); CredentialGenerator credGenEmployee = new UserPasswordCredentialGenerator("employee", "xxxxxx"); ObjectGrid og = ogManager.getObjectGrid(ctx, "accounting"); // Get a session with CredentialGenerator; Session session = og.getSession(credGenManager ); // Get the employee map ObjectMap om = session.getMap("employee"); // start a transaction. session.begin(); Object rec1 = map.get("xxxxxx"); session.commit(); // Get another session with a different CredentialGenerator; session = og.getSession(credGenEmployee ); // Get the employee map om = session.getMap("employee"); // start a transaction. session.begin(); Object rec2 = map.get("xxxxx"); session.commit();If you use the ObjectGird.getSession method to get a Session object, the session uses the CredentialGenerator object set on the ClientConfigurationSecurity object. The ObjectGrid.getSession(CredentialGenerator) method overrides the CredentialGenerator set in the ClientSecurityConfiguration object.
If we can reuse the Session object, a performance gain results. However, calling the ObjectGrid.getSession(CredentialGenerator) method is not very expensive. The major overhead is the increased object garbage collection time. Make sure that you release the references after we are done with the Session objects. Generally, if your Session object can share the identity, try to reuse the Session object. If not, use the ObjectGrid.getSession(CredentialGenerator) method.
Client authorization programming
WebSphere eXtreme Scale supports Java Authentication and Authorization Service (JAAS) authorization that is ready to use and also supports custom authorization using the ObjectGridAuthorization interface.
The ObjectGridAuthorization plug-in is used to authorize ObjectGrid, ObjectMap, and JavaMap accesses to the Principals represented by a Subject object in a custom way. A typical implementation of this plug-in is to retrieve the Principals from the Subject object, and then check whether the specified permissions are granted to the Principals.
A permission passed to the checkPermission(Subject, Permission) method can be one of the following permissions:
- MapPermission
- ObjectGridPermission
- ServerMapPermission
- AgentPermission
Refer to ObjectGridAuthorization API documentation for more details.
MapPermission
The com.ibm.websphere.objectgrid.security.MapPermission public class represents permissions to the ObjectGrid resources, specifically the methods of ObjectMap or JavaMap interfaces. WebSphere eXtreme Scale defines the following permission strings to access the methods of ObjectMap and JavaMap:
- read: Permission to read the data from the map. The integer constant is defined as MapPermission.READ.
- write: Permission to update the data in the map. The integer constant is defined as MapPermission.WRITE.
- insert: Permission to insert the data into the map. The integer constant is defined as MapPermission.INSERT.
- remove: Permission to remove the data from the map. The integer constant is defined as MapPermission.REMOVE.
- invalidate: Permission to invalidate the data from the map. The integer constant is defined as MapPermission.INVALIDATE.
- all: All above permissions: read, write, insert, remote, and invalidate. The integer constant is defined as MapPermission.ALL.
Refer to MapPermission API documentation for more details.
We can construct a MapPermission object by passing the fully qualified ObjectGrid map name (in format [ObjectGrid_name].[ObjectMap_name]) and the permission string or integer value. A permission string can be a comma-delimited string of the previous permission strings such as read, insert, or it can be all. A permission integer value can be any previously mentioned permission integer constants or a mathematical value of several integer permission constants, such as MapPermission.READ|MapPermission.WRITE.
The authorization occurs when an ObjectMap or JavaMap method is called. The run time checks different permissions for different methods. If the required permissions are not granted to the client, an AccessControlException results.
Table 1. List of methods and the required MapPermission Permission ObjectMap/JavaMap read Boolean containsKey(Object) Boolean equals(Object) Object get(Object) Object get(Object, Serializable) List getAll(List) List getAll(List keyList, Serializable) List getAllForUpdate(List) List getAllForUpdate(List, Serializable) Object getForUpdate(Object) Object getForUpdate(Object, Serializable) public Object getNextKey(long) write Object put(Object key, Object value) void put(Object, Object, Serializable) void putAll(Map) void putAll(Map, Serializable) void update(Object, Object) void update(Object, Object, Serializable) insert public void insert (Object, Object) void insert(Object, Object, Serializable) remove Object remove (Object) void removeAll(Collection) void clear() invalidate public void invalidate (Object, Boolean) void invalidateAll(Collection, Boolean) void invalidateUsingKeyword(Serializable) int setTimeToLive(int) Authorization is based solely on which method is used, rather than what the method really does. For example, a put method can insert or update a record based on whether the record exists. However, the insert or update cases are not distinguished.
Note: The setPutMode(PutMode.UPSERT) method is added to change the default behavior of the ObjectMap and JavaMap put() and putAll() methods to behave like ObjectMap.upsert() and upsertAll() methods.
The PutMode.UPSERT method replaces the setPutMode(PutMode.INSERTUPDATE) method. Use the PutMode.UPSERT method to tell the BackingMap and loader that an entry in the data grid needs to place the key and value into the grid. The BackingMap and loader does either an insert or an update to place the value into the grid and loader. If we run the upsert API within the applications, then the loader gets an UPSERT LogElement type, which allows loaders to do database merge or upsert calls instead of using insert or update.
An operation type can be achieved by combinations of other types. For example, an update can be achieved by a remove and then an insert. Consider these combinations when designing your authorization policies.
ObjectGridPermission
A com.ibm.websphere.objectgrid.security.ObjectGridPermission represents permissions to the ObjectGrid:
- Query: permission to create an object query or entity query. The integer constant is defined as ObjectGridPermission.QUERY.
- Dynamic map: permission to create a dynamic map based on the map template. The integer constant is defined as ObjectGridPermission.DYNAMIC_MAP.
Refer to ObjectGridPermission API documentation for more details.
The following table summarizes the methods and the required ObjectGridPermission:
Table 2. List of methods and the required ObjectGridPermission Permission action Methods query
com.ibm.websphere.objectgrid.Session.createObjectQuery(String) query
com.ibm.websphere.objectgrid.em.EntityManager.createQuery(String) dynamicmap
com.ibm.websphere.objectgrid.Session.getMap(String)
ServerMapPermission
An ServerMapPermission represents permissions to an ObjectMap hosted in a server. The name of the permission is the full name of the ObjectGrid map name. It has the following actions:
- replicate: permission to replicate a server map to near cache
- dynamicIndex: permission for a client to create or remove a dynamic index on a server
Refer to ServerMapPermission API documentation for more details. The detailed methods, which require different ServerMapPermission, are listed in the following table:
Table 3. Permissions to a server-hosted ObjectMap Permission action Methods replicate
com.ibm.websphere.objectgrid.ClientReplicableMap.enableClientReplication(Mode, int[], ReplicationMapListener) dynamicIndex
com.ibm.websphere.objectgrid.BackingMap.createDynamicIndex(String, Boolean, String, DynamicIndexCallback) dynamicIndex
com.ibm.websphere.objectgrid.BackingMap.removeDynamicIndex(String)
AgentPermission
An AgentPermission represents permissions to the datagrid agents. The name of the permission is the full name of the ObjectGrid map, and the action is a comma-delimited string of agent implementation class names or package names.
Refer to AgentPermission API documentation for more information.
The following methods in the class com.ibm.websphere.objectgrid.datagrid.AgentManager require AgentPermission.
com.ibm.websphere.objectgrid.datagrid.AgentManager#callMapAgent(MapGridAgent, Collection)com.ibm.websphere.objectgrid.datagrid.AgentManager#callMapAgent(MapGridAgent)com.ibm.websphere.objectgrid.datagrid.AgentManager#callReduceAgent(ReduceGridAgent, Collection)com.ibm.websphere.objectgrid.datagrid.AgentManager#callReduceAgent(ReduceGridAgent, Collection)
Authorization mechanisms
WebSphere eXtreme Scale supports two kinds of authorization mechanisms: Java Authentication and Authorization Service (JAAS) authorization and custom authorization. These mechanisms apply to all authorizations. JAAS authorization augments the Java security policies with user-centric access controls. Permissions can be granted based not just on what code is running, but also on who is running it. JAAS authorization is part of the SDK Version 5 and later.
Additionally, WebSphere eXtreme Scale also supports custom authorization with the following plug-in:
- ObjectGridAuthorization: custom way to authorize access to all artifacts.
We can implement your own authorization mechanism if you do not want to use JAAS authorization. By using a custom authorization mechanism, we can use the policy database, policy server, or Tivoli Access Manager to manage the authorizations.
We can configure the authorization mechanism in two ways:
- XML configuration
Use the ObjectGrid XML file to define an ObjectGrid and set the authorization mechanism to either AUTHORIZATION_MECHANISM_JAAS or AUTHORIZATION_MECHANISM_CUSTOM. Here is the secure-objectgrid-definition.xml file used in the enterprise application ObjectGridSample:
<objectGrids> <objectGrid name="secureClusterObjectGrid" securityEnabled="true" authorizationMechanism="AUTHORIZATION_MECHANISM_JAAS"> <bean id="TransactionCallback" classname="com.ibm.websphere.samples.objectgrid.HeapTransactionCallback" /> ... </objectGrids>- Programmatic configuration
To create an ObjectGrid using method ObjectGrid.setAuthorizationMechanism(int), we can call the following method to set the authorization mechanism. Calling this method applies only to the local WebSphere eXtreme Scale programming model when you directly instantiate the ObjectGrid instance:
/** * Set the authorization Mechanism. The default is * com.ibm.websphere.objectgrid.security.SecurityConstants. * AUTHORIZATION_MECHANISM_JAAS. * @param authMechanism the map authorization mechanism */ void setAuthorizationMechanism(int authMechanism);
JAAS authorization
A javax.security.auth.Subject object represents an authenticated user. A Subject consists of a set of principals, and each Principal represents an identity for that user. For example, a Subject can have a name principal, for example, Joe Smith, and a group principal, for example, manager.
Using the JAAS authorization policy, permissions can be granted to specific Principals. WebSphere eXtreme Scale associates the Subject with the current access control context. For each call to the ObjectMap or Javamap method, the Java runtime automatically determines if the policy grants the required permission only to a specific Principal and if so, the operation is allowed only if the Subject associated with the access control context contains the designated Principal.
You must be familiar with the policy syntax of the policy file. For detailed description of JAAS authorization, refer to the JAAS Reference Guide.
WebSphere eXtreme Scale has a special code base used for checking the JAAS authorization to the ObjectMap and JavaMap method calls. This special code base is http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction. Use this code base when granting ObjectMap or JavaMap permissions to principals. This special code was created because the JAR file for eXtreme Scale is granted with all permissions.
The template of the policy to grant the MapPermission permission is:
grant codeBase "http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction" <Principal field(s)>{ permission com.ibm.websphere.objectgrid.security.MapPermission "[ObjectGrid_name].[ObjectMap_name]", "action"; .... permission com.ibm.websphere.objectgrid.security.MapPermission "[ObjectGrid_name].[ObjectMap_name]", "action"; };A Principal field looks like the following example:principal Principal_class "principal_name"In this policy, only insert and read permissions are granted to these four maps to a certain principal. The other policy file, fullAccessAuth.policy, grants all permissions to these maps to a principal. Before running the application, change the principal_name and principal class to appropriate values. The value of the principal_name depends on the user registry. For example, if local OS is used as user registry, the machine name is MACH1, the user ID is user1, and the principal_name is
MACH1/user1.
The JAAS authorization policy can be put directly into the Java policy file, or it can be put in a separate JAAS authorization file and then set in either of two ways:
- Use the following JVM argument:
-Djava.security.policy=file:[JAAS_AUTH_POLICY_FILE]- Use the following property in the java.security file:
-Dauth.policy.url.x=file:[JAAS_AUTH_POLICY_FILE]
Custom ObjectGrid authorization
ObjectGridAuthorization plug-in is used to authorize ObjectGrid, ObjectMap, and JavaMap accesses to the Principals represented by a Subject object in a custom way. A typical implementation of this plug-in is to retrieve the Principals from the Subject object, and then check whether or not the specified permissions are granted to the Principals.
A permission passed to the checkPermission(Subject, Permission) method could be one of the following:
- MapPermission
- ObjectGridPermission
- AgentPermission
- ServerMapPermission
Refer to ObjectGridAuthorization API documentation for more details.
The ObjectGridAuthorization plug-in can be configured in the following ways:
- XML configuration
Use the ObjectGrid XML file to define an ObjectAuthorization plug-in. Here is an example:
<objectGrids> <objectGrid name="secureClusterObjectGrid" securityEnabled="true" authorizationMechanism="AUTHORIZATION_MECHANISM_CUSTOM"> ... <bean id="ObjectGridAuthorization" className="com.acme.ObjectGridAuthorizationImpl" /> </objectGrids>- Programmatic configuration
To create an ObjectGrid using the API method ObjectGrid.setObjectGridAuthorization(ObjectGridAuthorization), we can call the following method to set the authorization plug-in. This method only applies to the local eXtreme Scale programming model when you directly instantiate the ObjectGrid instance.
In the following example, some lines of code are continued on the next line for publication purposes.
/** * Sets the <code>ObjectGridAuthorization</code> for this ObjectGrid instance. * <p> * Passing <code>null</code> to this method removes a previously set * <code>ObjectGridAuthorization</code> object from an earlier invocation of this method * and indicates that this <code>ObjectGrid</code> is not associated with a * <code>ObjectGridAuthorization</code> object. * <p> * This method should only be used when ObjectGrid security is enabled. If * the ObjectGrid security is disabled, the provided <code>ObjectGridAuthorization</code> object * will not be used. * <p> * A <code>ObjectGridAuthorization</code> plug-in can be used to authorize * access to the ObjectGrid and maps. Please refer to <code>ObjectGridAuthorization</code> for more details. * * <p> * As of XD 6.1, the <code>setMapAuthorization</code> is deprecated and * <code>setObjectGridAuthorization</code> is recommended for use. However, * if both <code>MapAuthorization</code> plug-in and <code>ObjectGridAuthorization</code> plug-in * are used, ObjectGrid will use the provided <code>MapAuthorization</code> to authorize map accesses, * even though it is deprecated. * <p> * Note, to avoid an <code>IllegalStateException</code>, this method must be * called prior to the <code>initialize()</code> method. Also, keep in mind * that the <code>getSession</code> methods implicitly call the * <code>initialize()</code> method if it has yet to be called by the * application. * * @param ogAuthorization the <code>ObjectGridAuthorization</code> plug-in * * @throws IllegalStateException if this method is called after the * <code>initialize()</code> method is called. * * @see #initialize() * @see ObjectGridAuthorization * @since WAS XD 6.1 */ void setObjectGridAuthorization(ObjectGridAuthorization ogAuthorization);
Implementing ObjectGridAuthorization
The Boolean checkPermission(Subject subject, Permission permission) method of the ObjectGridAuthorization interface is called by theWebSphere eXtreme Scale run time to check whether the passed-in subject object has the passed-in permission. The implementation of the ObjectGridAuthorization interface returns true if the object has the permission, and false if not.
A typical implementation of this plug-in is to retrieve the principals from the Subject object and check whether the specified permissions are granted to the principals by consulting specific policies. These policies are defined by users. For example, the policies can be defined in a database, a plain file, or a Tivoli Access Manager policy server.
For example, we can use Tivoli Access Manager policy server to manage the authorization policy and use its API to authorize the access. For how to use Tivoli Access Manager Authorization APIs, refer to the IBM Tivoli Access Manager Authorization Java Classes Developer Reference for more details.
This sample implementation has the following assumptions:
- Check authorization for MapPermission only. For other permissions, always return true.
- The Subject object contains a com.tivoli.mts.PDPrincipal principal.
- The Tivoli Access Manager policy server has defined the following permissions for the ObjectMap or JavaMap name object. The object that is defined in the policy server must have the same name as the ObjectMap or JavaMap name in the format of [ObjectGrid_name].[ObjectMap_name]. The permission is the first character of the permission strings that are defined in the MapPermission permission. For example, the permission "r" that is defined in the policy server represents the read permission to the ObjectMap map.
The following code snippet demonstrates how to implement the checkPermission method:
/** * @see com.ibm.websphere.objectgrid.security.plugins. * MapAuthorization#checkPermission * (javax.security.auth.Subject, com.ibm.websphere.objectgrid.security. * MapPermission) */ public boolean checkPermission(final Subject subject, Permission p) { // For non-MapPermission, we always authorize. if (!(p instanceof MapPermission)){ return true; } MapPermission permission = (MapPermission) p; String[] str = permission.getParsedNames(); StringBuffer pdPermissionStr = new StringBuffer(5); for (int i=0; i<str.length; i++) { pdPermissionStr.append(str[i].substring(0,1)); } PDPermission pdPerm = new PDPermission(permission.getName(), pdPermissionStr.toString()); Set principals = subject.getPrincipals(); Iterator iter= principals.iterator(); while(iter.hasNext()) { try { PDPrincipal principal = (PDPrincipal) iter.next(); if (principal.implies(pdPerm)) { return true; } } catch (ClassCastException cce) { // Handle exception } } return false;}
Local security programming
WebSphere eXtreme Scale provides several security endpoints to allow you to integrate custom mechanisms. In the local programming model, the main security function is authorization, and has no authentication support . Authenticate outside of WebSphere Application Server. However, there are provided plug-ins to obtain and validate Subject objects.
Authentication
In the local programming model, eXtreme Scale does not provide any authentication mechanism, but relies on the environment, either application servers or applications, for authentication. When eXtreme Scale is used in WebSphere Application Server or WebSphere Extended Deployment, applications can use the WebSphere Application Server security authentication mechanism. When eXtreme Scale is running in a Java 2 Platform, Standard Edition (J2SE) environment, the application has to manage authentications with Java Authentication and Authorization Service (JAAS) authentication or other authentication mechanisms. JAAS reference guide . The contract between an application and an ObjectGrid instance is the javax.security.auth.Subject object. After the client is authenticated by the application server or the application, the application can retrieve the authenticated javax.security.auth.Subject object and use this Subject object to get a session from the ObjectGrid instance by calling the ObjectGrid.getSession(Subject) method. This Subject object is used to authorize accesses to the map data. This contract is called a subject passing mechanism. The following example illustrates the ObjectGrid.getSession(Subject) API.
/** * This API allows the cache to use a specific subject rather than the one * configured on the ObjectGrid to get a session. * @param subject * @return An instance of Session * @throws ObjectGridException * @throws TransactionCallbackException * @throws InvalidSubjectException the subject passed in is not valid based * on the SubjectValidation mechanism. */ public Session getSession(Subject subject) throws ObjectGridException, TransactionCallbackException, InvalidSubjectException;The ObjectGrid.getSession() method in the ObjectGrid interface can also be used to get a Session object:
/** * This method returns a Session object that can be used by a single thread at a time. * We cannot share this Session object between threads without placing a * critical section around it. While the core framework allows the object to move * between threads, the TransactionCallback and Loader might prevent this usage, * especially in J2EE environments. When security is enabled, this method uses the * SubjectSource to get a Subject object. * * If the initialize method has not been invoked prior to the first * getSession invocation, then an implicit initialization occurs. This * initialization ensures that all of the configuration is complete before * any runtime usage is required. * * @see #initialize() * @return An instance of Session * @throws ObjectGridException * @throws TransactionCallbackException * @throws IllegalStateException if this method is called after the * destroy() method is called. */ public Session getSession() throws ObjectGridException, TransactionCallbackException;As the API documentation specifies, when security is enabled, this method uses the SubjectSource plug-in to get a Subject object. The SubjectSource plug-in is one of the security plug-ins defined in eXtreme Scale to support propagating Subject objects. See Security-related plug-ins for more information. The getSession(Subject) method can be called on the local ObjectGrid instance only. If you call the getSession(Subject) method on a client side in a distributed eXtreme Scale configuration, an IllegalStateException results.
Security plug-ins
WebSphere eXtreme Scale provides two security plug-ins that are related to the subject passing mechanism: the SubjectSource and SubjectValidation plug-ins.
SubjectSource plug-in
The SubjectSource plug-in, represented by the com.ibm.websphere.objectgrid.security.plugins.SubjectSource interface, is a plug-in used to get a Subject object from a WXS running environment. This environment can be an application using the ObjectGrid or an application server that hosts the application. Consider the SubjectSource plug-in an alternative to the subject passing mechanism. Using the subject passing mechanism, the application retrieves the Subject object and uses it to get the ObjectGrid session object. With the SubjectSource plug-in, the eXtreme Scale runtime retrieves the Subject object and uses it to get the session object. The subject passing mechanism gives the control of Subject objects to applications, while the SubjectSource plug-in mechanism frees applications from retrieving the Subject object. Use the SubjectSource plug-in to get a Subject object that represents a WXS client used for authorization. When the ObjectGrid.getSession method is called, the Subject getSubject throws an ObjectGridSecurityException if security is enabled. WebSphere eXtreme Scale provides a default implementation of this plug-in: com.ibm.websphere.objectgrid.security.plugins.builtins.WSSubjectSourceImpl. This implementation can be used to retrieve a caller subject or a RunAs subject from the thread when an application is running in WebSphere Application Server. We can configure this class in your ObjectGrid descriptor XML file as the SubjectSource implementation class when using eXtreme Scale in WebSphere Application Server. The following code snippet shows the main flow of the WSSubjectSourceImpl.getSubject method.
Subject s = null; try { if (finalType == RUN_AS_SUBJECT) { // get the RunAs subject s = com.ibm.websphere.security.auth.WSSubject.getRunAsSubject(); } else if (finalType == CALLER_SUBJECT) { // get the callersubject s = com.ibm.websphere.security.auth.WSSubject.getCallerSubject(); }} catch (WSSecurityException wse) { throw new ObjectGridSecurityException(wse);} return s;For other details, refer to the API documentation for the SubjectSource plug-in and the WSSubjectSourceImpl implementation.SubjectValidation plug-in
The SubjectValidation plug-in, which is represented by the com.ibm.websphere.objectgrid.security.plugins.SubjectValidation interface, is another security plug-in. The SubjectValidation plug-in can be used to validate that a javax.security.auth.Subject, either passed to the ObjectGrid or retrieved by the SubjectSource plug-in, is a valid Subject that has not been tampered with.
The SubjectValidation.validateSubject(Subject) method in the SubjectValidation interface takes a Subject object and returns a Subject object. Whether a Subject object is considered valid and which Subject object is returned are all up to your implementations. If the Subject object is not valid, an InvalidSubjectException results.
Use this plug-in if you do not trust the Subject object that is passed to this method. This case is rare considering that you trust the application developers who develop the code to retrieve the Subject object.
An implementation of this plug-in needs support from the Subject object creator because only the creator knows if the Subject object has been tampered with. However, some subject creator might not know if the Subject has been tampered with. In this case, this plug-in is not useful.
WebSphere eXtreme Scale provides a default implementation of SubjectValidation: com.ibm.websphere.objectgrid.security.plugins.builtins.WSSubjectValidationImpl. Use this implementation to validate the WebSphere Application Server-authenticated subject. We can configure this class as the SubjectValidation implementation class when using eXtreme Scale in WebSphere Application Server. The WSSubjectValidationImpl implementation considers a Subject object valid only if the credential token that is associated with this Subject has not been tampered with. We can change other parts of the Subject object. The WSSubjectValidationImpl implementation asks WebSphere Application Server for the original Subject corresponding to the credential token and returns the original Subject object as the validated Subject object. Therefore, the changes made to the Subject contents other than the credential token have no effects. The following code snippet shows the basic flow of the WSSubjectValidationImpl.validateSubject(Subject).
// Create a LoginContext with scheme WSLogin and // pass a Callback handler. LoginContext lc = new LoginContext("WSLogin", new WSCredTokenCallbackHandlerImpl(subject)); // When this method is called, the callback handler methods // will be called to log the user in. lc.login(); // Get the subject from the LoginContext return lc.getSubject();In the previous code snippet, a credential token callback handler object, WSCredTokenCallbackHandlerImpl, is created with the Subject object to validate. Then a LoginContext object is created with the login scheme WSLogin. When the lc.login method is called, WebSphere Application Server security retrieves the credential token from the Subject object and then returns the correspondent Subject as the validated Subject object.For other details, refer to the Java APIs of SubjectValidation and WSSubjectValidationImpl implementation.
Plug-in configuration
We can configure the SubjectValidation plug-in and SubjectSource plug-in in two ways:
- XML ConfigurationUse the ObjectGrid XML file to define an ObjectGrid and set these two plug-ins. Here is an example, in which the WSSubjectSourceImpl class is configured as the SubjectSource plug-in and the WSSubjectValidation class is configured as the SubjectValidation plug-in.
In the following example, some lines of code are continued on the next line for publication purposes.
<objectGrids> <objectGrid name="secureClusterObjectGrid" securityEnabled="true" authorizationMechanism="AUTHORIZATION_MECHANISM_JAAS"> <bean id="SubjectSource" className="com.ibm.websphere.objectgrid.security.plugins.builtins. WSSubjectSourceImpl" /> <bean id="SubjectValidation" className="com.ibm.websphere.objectgrid.security.plugins.builtins. WSSubjectValidationImpl" /> <bean id="TransactionCallback" className="com.ibm.websphere.samples.objectgrid. HeapTransactionCallback" /> ... </objectGrids>- Programming To create an ObjectGrid through APIs, we can call the following methods to set the SubjectSource or SubjectValidation plug-ins.
** * Set the SubjectValidation plug-in for this ObjectGrid instance. A * SubjectValidation plug-in can be used to validate the Subject object * passed in as a valid Subject. Refer to {@link SubjectValidation} * for more details. * @param subjectValidation the SubjectValidation plug-in */ void setSubjectValidation(SubjectValidation subjectValidation); /** * Set the SubjectSource plug-in. A SubjectSource plug-in can be used * to get a Subject object from the environment to represent the * ObjectGrid client. * * @param source the SubjectSource plug-in */ void setSubjectSource(SubjectSource source);
Write your own JAAS authentication code
We can write you own Java Authentication and Authorization Service (JAAS) authentication code to handle the authentication. You need to write your own login modules and then configure the login modules for your authentication module.
The login module receives information about a user and authenticates the user. This information can be anything that can identify the user. For example, the information can be a user ID and password, client certificate, and so on. After receiving the information, the login module verifies that the information represents a valid subject and then creates a Subject object. Currently, several implementations of login modules are available to the public.
After a login module is written, configure this login module for the run time to use. Configure a JAAS login module. This login module contains the login module and its authentication scheme. For example:
FileLogin { com.acme.auth.FileLoginModule required};The authentication scheme is FileLogin and the login module is com.acme.auth.FileLoginModule. The required token indicates that the FileLoginModule module must validate this login or the entire scheme fails.
Setting the JAAS login module configuration file can be done in one of the following ways:
- Set the JAAS login module configuration file in the login.config.url property in the java.security file, for example:
login.config.url.1=file:${java.home}/lib/security/file.login- Set the JAAS login module configuration file from the command line using the -Djava.security.auth.login.config JVM arguments , for example, -Djava.security.auth.login.config ==$JAVA_HOME/lib/security/file.login
If your code is running in WebSphere Application Server, configure the JAAS login in the administrative console and store this login configuration in the application server configuration. See Login configuration for Java Authentication and Authorization Service for details.
Programming .NET client authentication
To send credentials from the .NET client to the server side, you must implement the ICredentialGenerator and ICredential interfaces. These interfaces generate a credential object that is passed to the data grid and interpreted on the server side. On the server side, the corresponding plug-in interprets the credential object.
To complete authentication, your .NET application must implement the following interfaces:
- ICredential: A Credential represents a client credential, such as a user ID and password pair.
- ICredentialGenerator: A CredentialGenerator represents a credential factory to generate the credential.
When a .NET client application connects to a server that requires authentication, the client is required to provide a client credential. A client credential is represented by the ICredential interface. A client credential can be a user name and password pair, a Kerberos ticket, a client certificate, or data in any format that the client and server agree upon. This interface explicitly defines the equals(Object) and hashCode methods. These two methods are important because the authenticated Subject objects are cached using the Credential object as the key on the server side. We can also generate a credential with the ICredentialGenerator interface. This interface is useful when the credential can expire. A new credential is generated whenever the Credential property is obtained.
We can also use the provided CredentialGenerator plugin to create a credential that is based on the credentialGeneratorProps= setting in the Client.Net.Properties file. The additional settings that define the credential plug-in are credentialGeneratorAssembly and credentialGeneratorClass.
Implement the ICredentialGenerator and ICredential interfaces in your .NET client application.
Remember: If the you implement this client credential plug-in, then also implement a corresponding server credential plug-in that can interpret and receive the authentication credentials from the .NET client. Use the following examples to develop the application:
- Example: Implementing a user password credential for .NET applications
- Example: Implementing a user credential generator for .NET applications
- Example: Implementing a user password credential for .NET applications
Use this example to write your own implementation of the ICredential interface. The user password credential stores a user ID and password.- Example: Implementing a user credential generator for .NET applications
Use this example to write your own implementation of the ICredentialGenerator interface. The interface takes a user ID and a password. The UserPasswordCredential object contains the user ID and password, which is obtained from the read-only Credential property.
18.6.1. Example: Implementing a user password credential for .NET applications
Use this example to write your own implementation of the ICredential interface. The user password credential stores a user ID and password.
UserPasswordCredential.cs
// Module : UserPasswordCrediential.cs using System; using IBM.WebSphere.Caching.Security; namespace com.ibm.websphere.objectgrid.security.plugins.builtins { public class UserPasswordCredential : ICredential { private String ivUserName; private String ivPassword; /// <summary> ///Creates a UserPasswordCredential with the specified user name and /// password. /// /// ArgumentException if userName or password is null /// </summary> /// <param name="userName">the user name for this credential</param> /// <param name="password">the password for this credential</param> public UserPasswordCredential(String userName, String password) { if (userName == null || password == null) { throw new ArgumentException("User name and password cannot be null."); } this.ivUserName = userName; this.ivPassword = password; } /// <summary>Gets the user name for this credential.</summary> /// <returns>the user name argument that was passed to the constructor ///or the setUserName(String) method of this class </returns> public String GetUserName() { return ivUserName; } /// <summary>Sets the user name for this credential. ///ArgumentException if userName is null /// </summary> /// <param name="userName">userName the user name to set.</param> public void SetUserName(String userName) { if (userName == null) { throw new ArgumentException("User name cannot be null."); } this.ivUserName = userName; } /// <summary>Gets the password for this credential. /// </summary> /// <returns>the password argument that was passed to the constructor or the setPassword(String) method of this class</returns> public String GetPassword() { return ivPassword; } /// <summary>Sets the password for this credential. ///ArgumentException if password is null /// </summary> /// <param name="password">the password to set.</param> public void SetPassword(String password) { if (password == null) { throw new ArgumentException("Password cannot be null."); } this.ivPassword = password; } /// <summary>Checks two UserPasswordCredential objects for equality. ///<p> /// Two UserPasswordCredential objects are equal if and only if their user names /// and passwords are equal. /// </summary> /// <param name="o">the object we are testing for equality with this object.</param> /// <returns>true if both UserPasswordCredential objects are equivalent.</returns> public bool Equals(ICredential credential) { if (this == credential) { return true; } if (credential is UserPasswordCredential) { UserPasswordCredential other = (UserPasswordCredential)credential; return other.ivPassword.Equals(ivPassword) && other.ivUserName.Equals(ivUserName); } return false; } /// <summary>Returns the hashcode of the UserPasswordCredential object. /// </summary> /// <returns>return the hash code of this object</returns> public override int GetHashCode() { int ret = ivUserName.GetHashCode() + ivPassword.GetHashCode(); return ret; } /// <summary>this.Object as a string /// </summary> /// <returns>return the string presentation of the UserPasswordCredential object.</returns> public override String ToString() { return typeof(UserPasswordCredential).FullName + "[" + ivUserName + ",xxxxxx]"; } }}Programming .NET client authentication
ICredentialGenerator interface
18.6.2. Example: Implementing a user credential generator for .NET applications
Use this example to write your own implementation of the ICredentialGenerator interface. The interface takes a user ID and a password. The UserPasswordCredential object contains the user ID and password, which is obtained from the read-only Credential property.
UserPasswordCredentialGenerator.cs
// Module : UserPasswordCredientialGenerator.cs // // Source File Description: Reference Documentation // using System; using System.Security.Authentication; using IBM.WebSphere.Caching.Security; using com.ibm.websphere.objectgrid.security.plugins.builtins; namespace IBM.WebSphere.Caching.Security { public class UserPasswordCredentialGenerator : ICredentialGenerator { private String ivUser; private String ivPwd; public ICredential Credential { get { return _getCredential(); } } public string Properties { set {_setProperties(value);} } public UserPasswordCredentialGenerator() { ivUser = null; ivPwd = null; } public UserPasswordCredentialGenerator(String user=null, String pwd=null) { ivUser = user; ivPwd = pwd; } /// <summary>Creates a new UserPasswordCredential object using this object's user name and password. /// </summary> /// <returns>new UserPasswordCredential instance</returns> private ICredential _getCredential() { try { ICredential MyCredential = new UserPasswordCredential(ivUser, ivPwd) as ICredential; return (ICredential) MyCredential; } catch (Exception e) { AuthenticationException CannotGenerateCredentialException = new AuthenticationException(e.ToString()); throw CannotGenerateCredentialException; } } /// <summary>Gets the password for this credential generator. /// </summary> /// <returns>the password argument that was passed to the constructor</returns> public String getPassword() { return ivPwd; } /// <summary>Gets the user name for this credential. /// </summary> /// <returns>the user argument that was passed to the constructor of this class</returns> public String getUserName() { return ivUser; } /// <summary>Sets additional properties namely a user name and password. ///Throws ArgumentException if the format is not valid /// </summary> /// <param name="properties">properties a properties string with a user name and a password separated by a blank.</param> private void _setProperties(string properties) { String token = properties; char[] Seperator = { ' ' }; String[] StringProperty = properties.Split(Seperator); if (StringProperty.Length != 2) { throw new ArgumentException( "The properties should have a user name and password and separated by a space."); } ivUser = StringProperty[0]; ivPwd = StringProperty[1]; } /// <summary>Checks two UserPasswordCredentialGenerator objects for equality. ///<p> ///Two UserPasswordCredentialGenerator objects are equal if and only if ///their user names and passwords are equal. /// </summary> /// <param name="obj">the object we are testing for equality with this object.</param> /// <returns><code>true</code> if both UserPasswordCredentialGenerator objects are equivalent</returns> public override bool Equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj is UserPasswordCredentialGenerator) { UserPasswordCredentialGenerator other = (UserPasswordCredentialGenerator)obj; Boolean bothUserNull = false; Boolean bothPwdNull = false; if (ivUser == null) { if (other.ivUser == null) { bothUserNull = true; } else { return false; } } if (ivPwd == null) { if (other.ivPwd == null) { bothPwdNull = true; } else { return false; } } return (bothUserNull || ivUser.Equals(other.ivUser)) && (bothPwdNull || ivPwd.Equals(other.ivPwd)); } return false; } /// <summary>Returns the hashcode of the UserPasswordCredentialGenerator object. /// </summary> /// <returns>the hash code of this object</returns> public override int GetHashCode() { return ivUser.GetHashCode() + ivPwd.GetHashCode(); } }}