8.7. Data Security for Remote Client Server Mode

8.7.1. About Security Realms

A security realm is a series of mappings between users and passwords, and users and roles. Security realms are a mechanism for adding authentication and authorization to your EJB and Web applications. Red Hat JBoss Data Grid Server provides two security realms by default:
  • ManagementRealm stores authentication information for the Management API, which provides the functionality for the Management CLI and web-based Management Console. It provides an authentication system for managing JBoss Data Grid Server itself. You could also use the ManagementRealm if your application needed to authenticate with the same business rules you use for the Management API.
  • ApplicationRealm stores user, password, and role information for Web Applications and EJBs.
Each realm is stored in two files on the filesystem:
  • REALM-users.properties stores usernames and hashed passwords.
  • REALM-roles.properties stores user-to-role mappings.
  • mgmt-groups.properties stores user-to-role mapping file for ManagementRealm.
The properties files are stored in the domain/configuration/ and standalone/configuration/ directories. The files are written simultaneously by the add-user.sh or add-user.bat command. When you run the command, the first decision you make is which realm to add your new user to.

8.7.2. Add a New Security Realm

  1. Run the Management CLI.

    Start the cli.sh or cli.bat command and connect to the server.
  2. Create the new security realm itself.

    Run the following command to create a new security realm named MyDomainRealm on a domain controller or a standalone server.
    /host=master/core-service=management/security-realm=MyDomainRealm:add()
  3. Create the references to the properties file which will store information about the new role.

    Run the following command to create a pointer a file named myfile.properties, which will contain the properties pertaining to the new role.

    Note

    The newly-created properties file is not managed by the included add-user.sh and add-user.bat scripts. It must be managed externally.
    /host=master/core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties)
Result

Your new security realm is created. When you add users and roles to this new realm, the information will be stored in a separate file from the default security realms. You can manage this new file using your own applications or procedures.

8.7.3. Add a User to a Security Realm

  1. Run the add-user.sh or add-user.bat command.

    Open a terminal and change directories to the JDG_HOME/bin/ directory. If you run Red Hat Enterprise Linux or another UNIX-like operating system, run add-user.sh. If you run Microsoft Windows Server, run add-user.bat.
  2. Choose whether to add a Management User or Application User.

    For this procedure, type b to add an Application User.
  3. Choose the realm the user will be added to.

    By default, the only available realm is ApplicationRealm. If you have added a custom realm, you can type its name instead.
  4. Type the username, password, and roles, when prompted.

    Type the desired username, password, and optional roles when prompted. Verify your choice by typing yes, or type no to cancel the changes. The changes are written to each of the properties files for the security realm.

8.7.4. Configuring Security Realms Declaratively

In Remote Client-Server mode, a Hot Rod endpoint must specify a security realm.
The security realm declares an authentication and an authorization section.

Example 8.12. Configuring Security Realms Declaratively

<security-realms>
            <security-realm name="ManagementRealm">
                <authentication>
                    <local default-user="$local" skip-group-loading="true"/>
                    <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>
                <authorization map-groups-to-roles="false">
                    <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
            </security-realm>
            <security-realm name="ApplicationRealm">
                <authentication>
                    <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
                    <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>
                <authorization>
                    <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
            </security-realm>
        </security-realms>
The server-identities parameter can also be used to specify certificates.

8.7.5. Loading Roles from LDAP for Authorization (Remote Client-Server Mode)

An LDAP directory contains entries for user accounts and groups, cross referenced by attributes. Depending on the LDAP server configuration, a user entity may map the groups the user belongs to through memberOf attributes; a group entity may map which users belong to it through uniqueMember attributes; or both mappings may be maintained by the LDAP server.
Users generally authenticate against the server using a simple user name. When searching for group membership information, depending on the directory server in use, searches could be performed using this simple name or using the distinguished name of the user's entry in the directory.
The authentication step of a user connecting to the server always happens first. Once the user is successfully authenticated the server loads the user's groups. The authentication step and the authorization step each require a connection to the LDAP server. The realm optimizes this process by reusing the authentication connection for the group loading step. As will be shown within the configuration steps below it is possible to define rules within the authorization section to convert a user's simple user name to their distinguished name. The result of a "user name to distinguished name mapping" search during authentication is cached and reused during the authorization query when the force attribute is set to "false". When force is true, the search is performed again during authorization (while loading groups). This is typically done when different servers perform authentication and authorization.
<authorization>
    <ldap connection="...">
    	<!-- OPTIONAL -->
       <username-to-dn force="true"> 
           <!-- Only one of the following. -->
           <username-is-dn />
           <username-filter base-dn="..." recursive="..." user-dn-attribute="..." attribute="..." />
           <advanced-filter base-dn="..." recursive="..." user-dn-attribute="..." filter="..." />
        </username-to-dn>
        
       <group-search group-name="..." iterative="..." group-dn-attribute="..." group-name-attribute="..." >
           <!-- One of the following -->
           <group-to-principal base-dn="..." recursive="..." search-by="...">
               <membership-filter principal-attribute="..." />
           </group-to-principal>
           <principal-to-group group-attribute="..." />
       </group-search>
    </ldap>
</authorization>

Important

These examples specify some attributes with their default values. This is done for demonstration. Attributes that specify their default values are removed from the configuration when it is persisted by the server. The exception is the force attribute. It is required, even when set to the default value of false.

username-to-dn

The username-to-dn element specifies how to map the user name to the distinguished name of their entry in the LDAP directory. This element is only required when both of the following are true:
  • The authentication and authorization steps are against different LDAP servers.
  • The group search uses the distinguished name.
1:1 username-to-dn

This specifies that the user name entered by the remote user is the user's distinguished name.
<username-to-dn force="false">
   <username-is-dn />
</username-to-dn>

This defines a 1:1 mapping and there is no additional configuration.
username-filter

The next option is very similar to the simple option described above for the authentication step. A specified attribute is searched for a match against the supplied user name.
<username-to-dn force="true">
    <username-filter base-dn="dc=people,dc=harold,dc=example,dc=com" recursive="false" attribute="sn" user-dn-attribute="dn" />
</username-to-dn>

The attributes that can be set here are:
  • base-dn: The distinguished name of the context to begin the search.
  • recursive: Whether the search will extend to sub contexts. Defaults to false.
  • attribute: The attribute of the users entry to try and match against the supplied user name. Defaults to uid.
  • user-dn-attribute: The attribute to read to obtain the users distinguished name. Defaults to dn.
advanced-filter

The final option is to specify an advanced filter, as in the authentication section this is an opportunity to use a custom filter to locate the users distinguished name.
<username-to-dn force="true">
    <advanced-filter base-dn="dc=people,dc=harold,dc=example,dc=com" recursive="false" filter="sAMAccountName={0}" user-dn-attribute="dn" />
</username-to-dn>

For the attributes that match those in the username-filter example, the meaning and default values are the same. There is one new attribute:
  • filter: Custom filter used to search for a user's entry where the user name will be substituted in the {0} place holder.

Important

The XML must remain valid after the filter is defined so if any special characters are used such as & ensure the proper form is used. For example &amp; for the & character.

The Group Search

There are two different styles that can be used when searching for group membership information. The first style is where the user's entry contains an attribute that references the groups the user is a member of. The second style is where the group contains an attribute referencing the users entry.

When there is a choice of which style to use Red Hat recommends that the configuration for a user's entry referencing the group is used. This is because with this method group information can be loaded by reading attributes of known distinguished names without having to perform any searches. The other approach requires extensive searches to identify the groups that reference the user.

Before describing the configuration here are some LDIF examples to illustrate this.

Example 8.13. Principal to Group - LDIF example.

This example illustrates where we have a user TestUserOne who is a member of GroupOne, GroupOne is in turn a member of GroupFive. The group membership is shown by the use of a memberOf attribute which is set to the distinguished name of the group of which the user (or group) is a member.

It is not shown here but a user could potentially have multiple memberOf attributes set, one for each group of which the user is directly a member.
dn: uid=TestUserOne,ou=users,dc=principal-to-group,dc=example,dc=org
objectClass: extensibleObject
objectClass: top
objectClass: groupMember
objectClass: inetOrgPerson
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
cn: Test User One
sn: Test User One
uid: TestUserOne
distinguishedName: uid=TestUserOne,ou=users,dc=principal-to-group,dc=example,dc=org
memberOf: uid=GroupOne,ou=groups,dc=principal-to-group,dc=example,dc=org
memberOf: uid=Slashy/Group,ou=groups,dc=principal-to-group,dc=example,dc=org
userPassword:: e1NTSEF9WFpURzhLVjc4WVZBQUJNbEI3Ym96UVAva0RTNlFNWUpLOTdTMUE9PQ==

dn: uid=GroupOne,ou=groups,dc=principal-to-group,dc=example,dc=org
objectClass: extensibleObject
objectClass: top
objectClass: groupMember
objectClass: group
objectClass: uidObject
uid: GroupOne
distinguishedName: uid=GroupOne,ou=groups,dc=principal-to-group,dc=example,dc=org
memberOf: uid=GroupFive,ou=subgroups,ou=groups,dc=principal-to-group,dc=example,dc=org

dn: uid=GroupFive,ou=subgroups,ou=groups,dc=principal-to-group,dc=example,dc=org
objectClass: extensibleObject
objectClass: top
objectClass: groupMember
objectClass: group
objectClass: uidObject
uid: GroupFive
distinguishedName: uid=GroupFive,ou=subgroups,ou=groups,dc=principal-to-group,dc=example,dc=org

Example 8.14. Group to Principal - LDIF Example

This example shows the same user TestUserOne who is a member of GroupOne which is in turn a member of GroupFive - however in this case it is an attribute uniqueMember from the group to the user being used for the cross reference.

Again the attribute used for the group membership cross reference can be repeated, if you look at GroupFive there is also a reference to another user TestUserFive which is not shown here.
dn: uid=TestUserOne,ou=users,dc=group-to-principal,dc=example,dc=org
objectClass: top
objectClass: inetOrgPerson
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
cn: Test User One
sn: Test User One
uid: TestUserOne
userPassword:: e1NTSEF9SjR0OTRDR1ltaHc1VVZQOEJvbXhUYjl1dkFVd1lQTmRLSEdzaWc9PQ==

dn: uid=GroupOne,ou=groups,dc=group-to-principal,dc=example,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: Group One
uid: GroupOne
uniqueMember: uid=TestUserOne,ou=users,dc=group-to-principal,dc=example,dc=org

dn: uid=GroupFive,ou=subgroups,ou=groups,dc=group-to-principal,dc=example,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: Group Five
uid: GroupFive
uniqueMember: uid=TestUserFive,ou=users,dc=group-to-principal,dc=example,dc=org
uniqueMember: uid=GroupOne,ou=groups,dc=group-to-principal,dc=example,dc=org

General Group Searching

Before looking at the examples for the two approaches shown above we first need to define the attributes common to both of these.
<group-search group-name="..." iterative="..." group-dn-attribute="..." group-name-attribute="..." >
    ...
</group-search>
  • group-name: This attribute is used to specify the form that should be used for the group name returned as the list of groups of which the user is a member. This can either be the simple form of the group name or the group's distinguished name. If the distinguished name is required this attribute can be set to DISTINGUISHED_NAME. Defaults to SIMPLE.
  • iterative: This attribute is used to indicate if, after identifying the groups a user is a member of, we should also iteratively search based on the groups to identify which groups the groups are a member of. If iterative searching is enabled we keep going until either we reach a group that is not a member if any other groups or a cycle is detected. Defaults to false.

Cyclic group membership is not a problem. A record of each search is kept to prevent groups that have already been searched from being searched again.

Important

For iterative searching to work the group entries need to look the same as user entries. The same approach used to identify the groups a user is a member of is then used to identify the groups of which the group is a member. This would not be possible if for group to group membership the name of the attribute used for the cross reference changes or if the direction of the reference changes.
  • group-dn-attribute: On an entry for a group which attribute is its distinguished name. Defaults to dn.
  • group-name-attribute: On an entry for a group which attribute is its simple name. Defaults to uid.

Example 8.15. Principal to Group Example Configuration

Based on the example LDIF from above here is an example configuration iteratively loading a user's groups where the attribute used to cross reference is the memberOf attribute on the user.
<authorization>
    <ldap connection="LocalLdap">
        <username-to-dn>
            <username-filter base-dn="ou=users,dc=principal-to-group,dc=example,dc=org" recursive="false" attribute="uid" user-dn-attribute="dn" />
        </username-to-dn>
        <group-search group-name="SIMPLE" iterative="true" group-dn-attribute="dn" group-name-attribute="uid">
            <principal-to-group group-attribute="memberOf" />
        </group-search>
    </ldap>
</authorization>

The most important aspect of this configuration is that the principal-to-group element has been added with a single attribute.
  • group-attribute: The name of the attribute on the user entry that matches the distinguished name of the group the user is a member of. Defaults to memberOf.

Example 8.16. Group to Principal Example Configuration

This example shows an iterative search for the group to principal LDIF example shown above.
<authorization>
      <ldap connection="LocalLdap">
          <username-to-dn>
              <username-filter base-dn="ou=users,dc=group-to-principal,dc=example,dc=org" recursive="false" attribute="uid" user-dn-attribute="dn" />
          </username-to-dn>
          <group-search group-name="SIMPLE" iterative="true" group-dn-attribute="dn" group-name-attribute="uid">
              <group-to-principal base-dn="ou=groups,dc=group-to-principal,dc=example,dc=org" recursive="true" search-by="DISTINGUISHED_NAME">
                  <membership-filter principal-attribute="uniqueMember" />
              </group-to-principal>
          </group-search>
      </ldap>
  </authorization>

Here an element group-to-principal is added. This element is used to define how searches for groups that reference the user entry will be performed. The following attributes are set:
  • base-dn: The distinguished name of the context to use to begin the search.
  • recursive: Whether sub-contexts also be searched. Defaults to false.
  • search-by: The form of the role name used in searches. Valid values are SIMPLE and DISTINGUISHED_NAME. Defaults to DISTINGUISHED_NAME.

Within the group-to-principal element there is a membership-filter element to define the cross reference.
  • principal-attribute: The name of the attribute on the group entry that references the user entry. Defaults to member.

8.7.6. Hot Rod Interface Security

8.7.6.1. Publish Hot Rod Endpoints as a Public Interface

Red Hat JBoss Data Grid's Hot Rod server operates as a management interface as a default. To extend its operations to a public interface, alter the value of the interface parameter in the socket-binding element from management to public as follows:
<socket-binding name="hotrod" interface="public" port="11222" />

8.7.6.2. Encryption of communication between Hot Rod Server and Hot Rod client

Hot Rod can be encrypted using TLS/SSL, and has the option to require certificate-based client authentication.
Use the following procedure to secure the Hot Rod connector using SSL.

Procedure 8.3. Secure Hot Rod Using SSL/TLS

  1. Generate a Keystore

    Create a Java Keystore using the keytool application distributed with the JDK and add your certificate to it. The certificate can be either self signed, or obtained from a trusted CA depending on your security policy.
  2. Place the Keystore in the Configuration Directory

    Put the keystore in the ~/JDG_HOME/standalone/configuration directory with the standalone-hotrod-ssl.xml file from the ~/JDG_HOME/docs/examples/configs directory.
  3. Declare an SSL Server Identity

    Declare an SSL server identity within a security realm in the management section of the configuration file. The SSL server identity must specify the path to a keystore and its secret key.
    <server-identities>
      <ssl protocol="...">
        <keystore path="..." relative-to="..." keystore-password="${VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::ENCRYPTED_VALUE}" />
      </ssl>
      <secret value="..." />
    </server-identities>
  4. Add the Security Element

    Add the security element to the Hot Rod connector as follows:
    <hotrod-connector socket-binding="hotrod" cache-container="local">
        <encryption ssl="true" security-realm="ApplicationRealm" require-ssl-client-auth="false" />
    </hotrod-connector>
    1. Server Authentication of Certificate

      If you require the server to perform authentication of the client certificate, create a truststore that contains the valid client certificates and set the require-ssl-client-auth attribute to true.
  5. Start the Server

    Start the server using the following:
    bin/standalone.sh -c standalone-hotrod-ssl.xml
    This will start a server with a Hot Rod endpoint on port 11222. This endpoint will only accept SSL connections.
Securing Hot Rod using SSL can also be configured programmatically.

Example 8.17. Secure Hot Rod Using SSL/TLS

package org.infinispan.client.hotrod.configuration;
		
import java.util.Arrays;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

public class SslConfiguration {
	private final boolean enabled;
	private final String keyStoreFileName;
	private final char[] VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::keyStorePassword;
	private final SSLContext sslContext;
	private final String trustStoreFileName;
	private final char[] VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::trustStorePassword;
	
	SslConfiguration(boolean enabled, String keyStoreFileName, char[] keyStorePassword, SSLContext sslContext, String trustStoreFileName, char[] trustStorePassword) {
		this.enabled = enabled;
		this.keyStoreFileName = keyStoreFileName;
		this.keyStorePassword = VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::keyStorePassword;
		this.sslContext = sslContext;
		this.trustStoreFileName = trustStoreFileName;
		this.trustStorePassword = VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::trustStorePassword;
	}
	
	public boolean enabled() {
		return enabled;
	}
	
	public String keyStoreFileName() {
		return keyStoreFileName;
	}
	
	public char[] keyStorePassword() {
		return keyStorePassword;
	}
	
	public SSLContext sslContext() {
		return sslContext;
	}
	
	public String trustStoreFileName() {
		return trustStoreFileName;
	}
	
	public char[] trustStorePassword() {
		return trustStorePassword;
	}
	
	@Override
	public String toString() {
		return "SslConfiguration [enabled=" + enabled + ", keyStoreFileName="
			+ keyStoreFileName + ", sslContext=" + sslContext + ", trustStoreFileName=" + trustStoreFileName + "]";
	}
}

Important

To prevent plain text passwords from appearing in configurations or source codes, plain text passwords should be changed to Vault passwords. For more information about how to set up Vault passwords, see the Red Hat Enterprise Application Platform Security Guide.

8.7.6.3. Securing Hot Rod to LDAP Server using SSL

When connecting to an LDAP server with SSL enabled it may be necessary to specify a trust store or key store containing the appropriate certificates.
Section 8.7.6.2, “Encryption of communication between Hot Rod Server and Hot Rod client” describes how to set up SSL for Hot Rod client-server communication. This can be used, for example, for secure Hot Rod client authentication with PLAIN username/password. When the username/password is checked against credentials in LDAP, a secure connection from the Hot Rod server to the LDAP server is also required. To enable connection from the Hot Rod server to LDAP via SSL, a security realm must be defined as follows:

Example 8.18. Hot Rod Client Authentication to LDAP Server

<management>  
        <security-realms>  
            <security-realm name="LdapSSLRealm">  
                <authentication>  
                    <truststore  path="ldap.truststore" relative-to="jboss.server.config.dir" keystore-password=${VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::ENCRYPTED_VALUE} />  
                </authentication>  
            </security-realm>  
        </security-realms>  
        <outbound-connections>  
            <ldap name="LocalLdap" url="ldaps://localhost:10389" search-dn="uid=wildfly,dc=simple,dc=wildfly,dc=org" search-credential="secret" security-realm="LdapSSLRealm" />  
        </outbound-connections>  
    </management>

Example 8.19. Hot Rod Client Authentication to LDAP Server

public class HotRodPlainAuthLdapOverSslIT extends HotRodSaslAuthTestBase {
	private static final String KEYSTORE_NAME = "keystore_client.jks";
	private static final String KEYSTORE_PASSWORD = "VAULT::VAULT_BLOCK::ATTRIBUTE_NAME::ENCRYPTED_VALUE";
	
	private static ApacheDsLdap ldap;
	
	@InfinispanResource("hotrodAuthLdapOverSsl")
	private RemoteInfinispanServer server;
	
	@BeforeClass
	public static void kerberosSetup() throws Exception {
		ldap = new ApacheDSLdapSSL("localhost", ITestUtils.SERVER_CONFIG_DIR + File.separator + KEYSTORE_NAME, KEYSTORE_PASSWORD);
		ldap.start();
	}
	
	@AfterClass
	public static void ldapTearDown() throws Exception {
		ldap.stop();
	}
	
	@Override
	public String getTestedMech() {
		return "PLAIN";
	}

	@Override
	public RemoteInfinispanServer getRemoteServer() {
		return server;
	}
	
	@Override
	public void initAsAdmin() {
		initializeOverSsl(ADMIN_LOGIN, ADMIN_PASSWD);
	}
	
	@Override
	public void initAsReader() {
		initializeOverSsl(READER_LOGIN, READER_PASSWD);
	}
	
	@Override
	public void initAsWriter() {
		initializeOverSsl(WRITER_LOGIN, WRITER_PASSWD);
	}
	
	@Override
	public void initAsSupervisor() {
		initializeOverSsl(SUPERVISOR_LOGIN, SUPERVISOR_PASSWD);
	}
}

Important

To prevent plain text passwords from appearing in configurations or source codes, plain text passwords should be changed to Vault passwords. For more information about how to set up Vault passwords, see the Red Hat Enterprise Application Platform Security Guide.

8.7.7. User Authentication over Hot Rod Using SASL

User authentication over Hot Rod can be implemented using the following Simple Authentication and Security Layer (SASL) mechanisms:
  • PLAIN is the least secure mechanism because credentials are transported in plain text format. However, it is also the simplest mechanism to implement. This mechanism can be used in conjunction with encryption (SSL) for additional security.
  • DIGEST-MD5 is a mechanism than hashes the credentials before transporting them. As a result, it is more secure than the PLAIN mechanism.
  • GSSAPI is a mechanism that uses Kerberos tickets. As a result, it requires a correctly configured Kerberos Domain Controller (for example, Microsoft Active Directory).
  • EXTERNAL is a mechanism that obtains the required credentials from the underlying transport (for example, from a X.509 client certificate) and therefore requires client certificate encryption to work correctly.

8.7.7.1. Configure Hot Rod Authentication (GSSAPI/Kerberos)

Use the following steps to set up Hot Rod Authentication using the SASL GSSAPI/Kerberos mechanism:

Procedure 8.4. Configure SASL GSSAPI/Kerberos Authentication

  1. Server-side Configuration

    The following steps must be configured on the server-side:
    1. Define a Kerberos security login module using the security domain subsystem:
      <system-properties>
          <property name="java.security.krb5.conf" value="/tmp/infinispan/krb5.conf"/>
          <property name="java.security.krb5.debug" value="true"/>
          <property name="jboss.security.disable.secdomain.option" value="true"/>
      </system-properties>
      
      <security-domain name="infinispan-server" cache-type="default">
          <authentication>
              <login-module code="Kerberos" flag="required">
                  <module-option name="debug" value="true"/>
                  <module-option name="storeKey" value="true"/>
                  <module-option name="refreshKrb5Config" value="true"/>
                  <module-option name="useKeyTab" value="true"/>
                  <module-option name="doNotPrompt" value="true"/>
                  <module-option name="keyTab" value="/tmp/infinispan/infinispan.keytab"/>
                  <module-option name="principal" value="HOTROD/localhost@INFINISPAN.ORG"/>
              </login-module>
          </authentication>
      </security-domain>
    2. Configure a Hot Rod connector as follows:
      <hotrod-connector socket-binding="hotrod" 
      		  cache-container="default">
      	<authentication security-realm="ApplicationRealm">
      		<sasl server-name="node0" 
      		      mechanisms="{mechanism_name}" 
      		      qop="{qop_name}" 
      		      strength="{value}">
      			<policy>
      				<no-anonymous value="true" />
      			</policy>
      			<property name="com.sun.security.sasl.digest.utf8">true</property>
      		</sasl>
        </authentication>
      </hotrod-connector>
      • The server-name attribute specifies the name that the server declares to incoming clients. The client configuration must also contain the same server name value.
      • The server-context-name attribute specifies the name of the login context used to retrieve a server subject for certain SASL mechanisms (for example, GSSAPI).
      • The mechanisms attribute specifies the authentication mechanism in use. See Section 8.7.7, “User Authentication over Hot Rod Using SASL” for a list of supported mechanisms.
      • The qop attribute specifies the SASL quality of protection value for the configuration. Supported values for this attribute are auth (authentication), auth-int (authentication and integrity, meaning that messages are verified against checksums to detect tampering), and auth-conf (authentication, integrity, and confidentiality, meaning that messages are also encrypted). Multiple values can be specified, for example, auth-int auth-conf. The ordering implies preference, so the first value which matches both the client and server's preference is chosen.
      • The strength attribute specifies the SASL cipher strength. Valid values are low, medium, and high.
      • The no-anonymous element within the policy element specifies whether mechanisms that accept anonymous login are permitted. Set this value to false to permit and true to deny.
  2. Client-side Configuration

    The following steps must be configured on the client-side:
    1. Define a login module in a login configuration file (gss.conf) on the client side:
      GssExample {
          com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
      };
    2. Set up the following system properties:
      java.security.auth.login.config=gss.conf
      java.security.krb5.conf=/etc/krb5.conf

      Note

      The krb5.conf file is dependent on the environment and must point to the Kerberos Key Distribution Center.
    3. Configure the Hot Rod Client:
      public class MyCallbackHandler implements CallbackHandler {
         final private String username;
         final private char[] password;
         final private String realm;
      
         public MyCallbackHandler() { }
      
         public MyCallbackHandler (String username, String realm, char[] password) {
            this.username = username;
            this.password = password;
            this.realm = realm;
         }
      
         @Override
         public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            for (Callback callback : callbacks) {
               if (callback instanceof NameCallback) {
                  NameCallback nameCallback = (NameCallback) callback;
                  nameCallback.setName(username);
               } else if (callback instanceof PasswordCallback) {
                  PasswordCallback passwordCallback = (PasswordCallback) callback;
                  passwordCallback.setPassword(password);
               } else if (callback instanceof AuthorizeCallback) {
                  AuthorizeCallback authorizeCallback = (AuthorizeCallback) callback;
                  authorizeCallback.setAuthorized(authorizeCallback.getAuthenticationID().equals(
                        authorizeCallback.getAuthorizationID()));
               } else if (callback instanceof RealmCallback) {
                  RealmCallback realmCallback = (RealmCallback) callback;
                  realmCallback.setText(realm);
               } else {
                  throw new UnsupportedCallbackException(callback);
               }
            }
         }}
      LoginContext lc = new LoginContext("GssExample", new MyCallbackHandler("krb_user", "krb_password".toCharArra()));lc.login();Subject clientSubject = lc.getSubject();
      
      ConfigurationBuilder clientBuilder = new ConfigurationBuilder();clientBuilder
          .addServer()
              .host("127.0.0.1")
              .port(11222)
          .socketTimeout(1200000)
          .security()
              .authentication()
                  .enable()
                  .serverName("infinispan-server")
                  .saslMechanism("GSSAPI")
                  .clientSubject(clientSubject)
                  .callbackHandler(new MyCallbackHandler());remoteCacheManager = new RemoteCacheManager(clientBuilder.build());RemoteCache<String, String> cache = remoteCacheManager.getCache("secured");

8.7.7.2. Configure Hot Rod Authentication (MD5)

Use the following steps to set up Hot Rod Authentication using the SASL using the MD5 mechanism:

Procedure 8.5. Configure Hot Rod Authentication (MD5)

  1. Set up the Hot Rod Connector configuration by adding the sasl element to the authentication element (for details on the authentication element, see Section 8.7.4, “Configuring Security Realms Declaratively”) as follows:
    <hotrod-connector socket-binding="hotrod" 
                                cache-container="default">
        <authentication security-realm="ApplicationRealm">
            <sasl server-name="myhotrodserver" 
                     mechanisms="DIGEST-MD5" 
                     qop="auth" />
        </authentication>
    </hotrod-connector>
    • The server-name attribute specifies the name that the server declares to incoming clients. The client configuration must also contain the same server name value.
    • The mechanisms attribute specifies the authentication mechanism in use. See Section 8.7.7, “User Authentication over Hot Rod Using SASL” for a list of supported mechanisms.
    • The qop attribute specifies the SASL quality of production value for the configuration. Supported values for this attribute are auth, auth-int, and auth-conf.
  2. Connect the client to the configured Hot Rod connector as follows:
    public class MyCallbackHandler implements CallbackHandler {
       final private String username;
       final private char[] password;
       final private String realm;
    
       public MyCallbackHandler (String username, String realm, char[] password) {
          this.username = username;
          this.password = password;
          this.realm = realm;
       }
    
       @Override
       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
          for (Callback callback : callbacks) {
             if (callback instanceof NameCallback) {
                NameCallback nameCallback = (NameCallback) callback;
                nameCallback.setName(username);
             } else if (callback instanceof PasswordCallback) {
                PasswordCallback passwordCallback = (PasswordCallback) callback;
                passwordCallback.setPassword(password);
             } else if (callback instanceof AuthorizeCallback) {
                AuthorizeCallback authorizeCallback = (AuthorizeCallback) callback;
                authorizeCallback.setAuthorized(authorizeCallback.getAuthenticationID().equals(
                      authorizeCallback.getAuthorizationID()));
             } else if (callback instanceof RealmCallback) {
                RealmCallback realmCallback = (RealmCallback) callback;
                realmCallback.setText(realm);
             } else {
                throw new UnsupportedCallbackException(callback);
             }
          }
       }}
    ConfigurationBuilder clientBuilder = new ConfigurationBuilder();clientBuilder
        .addServer()
            .host("127.0.0.1")
            .port(11222)
        .socketTimeout(1200000)
        .security()
            .authentication()
                .enable()
                .serverName("myhotrodserver")
                .saslMechanism("DIGEST-MD5")
                .callbackHandler(new MyCallbackHandler("myuser", "ApplicationRealm", "qwer1234!".toCharArray()));remoteCacheManager = new RemoteCacheManager(clientBuilder.build());RemoteCache<String, String> cache = remoteCacheManager.getCache("secured");

8.7.7.3. Configure Hot Rod Using LDAP/Active Directory

Use the following to configure authentication over Hot Rod using LDAP or Microsoft Active Directory:
<security-realms>
	<security-realm name="ApplicationRealm">
		<authentication>
			<ldap connection="ldap_connection" 
			      recursive="true" 
			      base-dn="cn=users,dc=infinispan,dc=org">
				<username-filter attribute="cn" />
			</ldap>
		</authentication>
	</security-realm>
</security-realms>
<outbound-connections>
	<ldap name="ldap_connection" 
	      url="ldap://my_ldap_server" 
	      search-dn="CN=test,CN=Users,DC=infinispan,DC=org" 
	      search-credential="Test_password"/>
</outbound-connections>
The following are some details about the elements and parameters used in this configuration:
  • The security-realm element's name parameter specifies the security realm to reference to use when establishing the connection.
  • The authentication element contains the authentication details.
  • The ldap element specifies how LDAP searches are used to authenticate a user. First, a connection to LDAP is established and a search is conducted using the supplied user name to identify the distinguished name of the user. A subsequent connection to the server is established using the password supplied by the user. If the second connection succeeds, the authentication is a success.
    • The connection parameter specifies the name of the connection to use to connect to LDAP.
    • The (optional) recursive parameter specifies whether the filter is executed recursively. The default value for this parameter is false.
    • The base-dn parameter specifies the distinguished name of the context to use to begin the search from.
    • The (optional) user-dn parameter specifies which attribute to read for the user's distinguished name after the user is located. The default value for this parameter is dn.
  • The outbound-connections element specifies the name of the connection used to connect to the LDAP. directory.
  • The ldap element specifies the properties of the outgoing LDAP connection.
    • The name parameter specifies the unique name used to reference this connection.
    • The url parameter specifies the URL used to establish the LDAP connection.
    • The search-dn parameter specifies the distinguished name of the user to authenticate and to perform the searches.
    • The search-credential parameter specifies the password required to connect to LDAP as the search-dn.
    • The (optional) initial-context-factory parameter allows the overriding of the initial context factory. the default value of this parameter is com.sun.jndi.ldap.LdapCtxFactory.

8.7.7.4. Configure Hot Rod Authentication (X.509)

The X.509 certificate can be installed at the node, and be made available to other nodes for authentication purposes for inbound and outbound SSL connections. This is enabled using the <server-identities/> element of a security realm definition, which defines how a server appears to external applications. This element can be used to configure a password to be used when establishing a remote connection, as well as the loading of an X.509 key.
The following example shows how to install an X.509 certificate on the node.
<security-realm name="ApplicationRealm">
  <server-identities>
    <ssl protocol="...">
      <keystore path="..." relative-to="..." keystore-password="..." alias="..." key-password="..." />
    </ssl>
  </server-identities>

  [... authentication/authorization ...]

 </security-realms>
In the provided example, the SSL element contains the <keystore/> element, which is used to define how to load the key from the file-based keystore. The following parameters ave available for this element.

Table 8.4. <server-identities/> Options

Parameter Mandatory/Optional Description
path Mandatory This is the path to the keystore, this can be an absolute path or relative to the next attribute.
relative-to Optional The name of a service representing a path the keystore is relative to.
keystore-password Mandatory The password required to open the keystore.
alias Optional The alias of the entry to use from the keystore - for a keystore with multiple entries in practice the first usable entry is used but this should not be relied on and the alias should be set to guarantee which entry is used.
key-password Optional The password to load the key entry, if omitted the keystore-password will be used instead.

Note

If the following error occurs, specify a key-password as well as an alias to ensure only one key is loaded.
UnrecoverableKeyException: Cannot recover key