Chapter 25. Red Hat JBoss Data Grid Security: Authorization and Authentication

25.1. Red Hat JBoss Data Grid Security: Authorization and Authentication

Red Hat JBoss Data Grid is able to perform authorization on CacheManagers and Caches. JBoss Data Grid authorization is built on standard security features available in a JDK, such as JAAS and the SecurityManager.

If an application attempts to interact with a secured CacheManager and Cache, it must provide an identity which JBoss Data Grid’s security layer can validate against a set of required roles and permissions. Once validated, the client is issued a token for subsequent operations. Where access is denied, an exception indicating a security violation is thrown.

When a cache has been configured for with authorization, retrieving it returns an instance of SecureCache. SecureCache is a simple wrapper around a cache, which checks whether the "current user" has the permissions required to perform an operation. The "current user" is a Subject associated with the AccessControlContext.

JBoss Data Grid maps Principals names to roles, which in turn, represent one or more permissions. The following diagram represents these relationships:

Figure 25.1. Roles and Permissions Mapping

Roles and Permissions Security Mapping

25.2. Permissions

Access to a CacheManager or a Cache is controlled using a set of required permissions. Permissions control the type of action that is performed on the CacheManager or Cache, rather than the type of data being manipulated. Some of these permissions can apply to specifically name entities, such as a named cache. Different types of permissions are available depending on the entity.

Table 25.1. CacheManager Permissions

PermissionFunctionDescription

CONFIGURATION

defineConfiguration

Whether a new cache configuration can be defined.

LISTEN

addListener

Whether listeners can be registered against a cache manager.

LIFECYCLE

stop, start

Whether the cache manager can be stopped or started respectively.

ALL

 

A convenience permission which includes all of the above.

Table 25.2. Cache Permissions

PermissionFunctionDescription

READ

get, contains

Whether entries can be retrieved from the cache.

WRITE

put, putIfAbsent, replace, remove, evict

Whether data can be written/replaced/removed/evicted from the cache.

EXEC

distexec, mapreduce

Whether code execution can be run against the cache.

LISTEN

addListener

Whether listeners can be registered against a cache.

BULK_READ

keySet, values, entrySet,query

Whether bulk retrieve operations can be executed.

BULK_WRITE

clear, putAll

Whether bulk write operations can be executed.

LIFECYCLE

start, stop

Whether a cache can be started / stopped.

ADMIN

getVersion, addInterceptor*, removeInterceptor, getInterceptorChain, getEvictionManager, getComponentRegistry, getDistributionManager, getAuthorizationManager, evict, getRpcManager, getCacheConfiguration, getCacheManager, getInvocationContextContainer, setAvailability, getDataContainer, getStats, getXAResource

Whether access to the underlying components/internal structures is allowed.

ALL

 

A convenience permission which includes all of the above.

ALL_READ

 

Combines READ and BULK_READ.

ALL_WRITE

 

Combines WRITE and BULK_WRITE.

Note

Some permissions may need to be combined with others in order to be useful. For example, EXEC with READ or with WRITE.

25.3. Role Mapping

In order to convert the Principals in a Subject into a set of roles used for authorization, a PrincipalRoleMapper must be specified in the global configuration. Red Hat JBoss Data Grid ships with three mappers, and also allows you to provide a custom mapper.

Table 25.3. Mappers

Mapper NameJavaXMLDescription

IdentityRoleMapper

org.infinispan.security.impl.IdentityRoleMapper

<identity-role-mapper />

Uses the Principal name as the role name.

CommonNameRoleMapper

org.infinispan.security.impl.CommonRoleMapper

<common-name-role-mapper />

If the Principal name is a Distinguished Name (DN), this mapper extracts the Common Name (CN) and uses it as a role name. For example the DN cn=managers,ou=people,dc=example,dc=com will be mapped to the role managers.

ClusterRoleMapper

org.infinispan.security.impl.ClusterRoleMapper

<cluster-role-mapper />

Uses the ClusterRegistry to store principal to role mappings. This allows the use of the CLI’s GRANT and DENY commands to add/remove roles to a Principal.

Custom Role Mapper

 

<custom-role-mapper class="a.b.c" />

Supply the fully-qualified class name of an implementation of org.infinispan.security.impl.PrincipalRoleMapper

25.4. Configuring Authentication and Role Mapping using Login Modules

When using the authentication login-module for querying roles from LDAP, you must implement your own mapping of Principals to Roles, as custom classes are in use. The following example demonstrates how to map a principal obtained from a login-module to a role. It maps user principal name to a role, performing a similar action to the IdentityRoleMapper:

Mapping a Principal

public class SimplePrincipalGroupRoleMapper implements PrincipalRoleMapper {
   @Override
   public Set<String> principalToRoles(Principal principal) {
      if (principal instanceof SimpleGroup) {
         Enumeration<Principal> members = ((SimpleGroup) principal).members();
         if (members.hasMoreElements()) {
            Set<String> roles = new HashSet<String>();
            while (members.hasMoreElements()) {
               Principal innerPrincipal = members.nextElement();
               if (innerPrincipal instanceof SimplePrincipal) {
                  SimplePrincipal sp = (SimplePrincipal) innerPrincipal;
                  roles.add(sp.getName());
               }
            }
            return roles;
         }
      }
      return null;
   }
}

Important

For information on configuring an LDAP server, or specifying users and roles in an LDAP server, refer to the Red Hat Directory Server Administration Guide .

25.5. Configuring Red Hat JBoss Data Grid for Authorization

Authorization is configured at two levels: the cache container (CacheManager), and at the single cache.

Each cache container determines:

  • whether to use authorization.
  • a class which will map principals to a set of roles.
  • a set of named roles and the permissions they represent.

You can choose to use only a subset of the roles defined at the container level.

Roles

Roles may be applied on a cache-per-cache basis, using the roles defined at the cache-container level, as follows:

Important

Any cache that is intended to require authentication must have a listing of roles defined; otherwise authentication is not enforced as the no-anonymous policy is defined by the cache’s authorization.

Programmatic CacheManager Authorization (Library Mode)

The following example shows how to set up the same authorization parameters for Library mode using programmatic configuration:

CacheManager Authorization Programmatic Configuration

GlobalConfigurationBuilder global = new GlobalConfigurationBuilder();
  global
     .security()
        .authorization()
           .principalRoleMapper(new IdentityRoleMapper())
           .role("admin")
              .permission(CachePermission.ALL)
           .role("supervisor")
              .permission(CachePermission.EXEC)
              .permission(CachePermission.READ)
              .permission(CachePermission.WRITE)
           .role("reader")
              .permission(CachePermission.READ);
  ConfigurationBuilder config = new ConfigurationBuilder();
  config
     .security()
        .enable()
        .authorization()
           .role("admin")
           .role("supervisor")
           .role("reader");

Important

The REST protocol is not supported for use with authorization, and any attempts to access a cache with authorization enabled will result in a SecurityException.

25.6. Data Security for Library Mode

25.6.1. Subject and Principal Classes

To authorize access to resources, applications must first authenticate the request’s source. The JAAS framework defines the term subject to represent a request’s source. The Subject class is the central class in JAAS. A Subject represents information for a single entity, such as a person or service. It encompasses the entity’s principals, public credentials, and private credentials. The JAAS APIs use the existing Java 2 java.security.Principal interface to represent a principal, which is a typed name.

During the authentication process, a subject is populated with associated identities, or principals. A subject may have many principals. For example, a person may have a name principal (John Doe), a social security number principal (123-45-6789), and a user name principal (johnd), all of which help distinguish the subject from other subjects. To retrieve the principals associated with a subject, two methods are available:

public Set getPrincipals() {...}
public Set getPrincipals(Class c) {...}

getPrincipals() returns all principals contained in the subject. getPrincipals(Class c) returns only those principals that are instances of class c or one of its subclasses. An empty set is returned if the subject has no matching principals.

Note

The java.security.acl.Group interface is a sub-interface of java.security.Principal, so an instance in the principals set may represent a logical grouping of other principals or groups of principals.

25.6.2. Obtaining a Subject

In order to use a secured cache in Library mode, you must obtain a javax.security.auth.Subject. The Subject represents information for a single cache entity, such as a person or a service.

Red Hat JBoss Data Grid allows a JAAS Subject to be obtained either by using your container’s features, or by using a third-party library.

In JBoss containers, this can be done using the following:

Subject subject = SecurityContextAssociation.getSubject();

The Subject must be populated with a set of Principals, which represent the user and groups it belongs to in your security domain, for example, an LDAP or Active Directory.

The Java EE API allows retrieval of a container-set Principal through the following methods:

  • Servlets: ServletRequest.getUserPrincipal()
  • EJBs: EJBContext.getCallerPrincipal()
  • MessageDrivenBeans: MessageDrivenContext.getCallerPrincipal()

The mapper is then used to identify the principals associated with the Subject and convert them into roles that correspond to those you have defined at the container level.

A Principal is only one of the components of a Subject, which is retrieved from the java.security.AccessControlContext. Either the container sets the Subject on the AccessControlContext, or the user must map the Principal to an appropriate Subject before wrapping the call to the JBoss Data Grid API using a Security.doAs() method.

Once a Subject has been obtained, the cache can be interacted with in the context of a PrivilegedAction.

Obtaining a Subject

import org.infinispan.security.Security;

Security.doAs(subject, new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
    cache.put("key", "value");
}
});

The Security.doAs() method is in place of the typical Subject.doAs() method. Unless the AccessControlContext must be modified for reasons specific to your application’s security model, using Security.doAs() provides a performance advantage.

To obtain the current Subject, use Security.getSubject();, which will retrieve the Subject from either the JBoss Data Grid context, or from the AccessControlContext.

25.6.3. Subject Authentication

Subject Authentication requires a JAAS login. The login process consists of the following points:

  1. An application instantiates a LoginContext and passes in the name of the login configuration and a CallbackHandler to populate the Callback objects, as required by the configuration LoginModules.
  2. The LoginContext consults a Configuration to load all the LoginModules included in the named login configuration. If no such named configuration exists the other configuration is used as a default.
  3. The application invokes the LoginContext.login method.
  4. The login method invokes all the loaded LoginModules. As each LoginModule attempts to authenticate the subject, it invokes the handle method on the associated CallbackHandler to obtain the information required for the authentication process. The required information is passed to the handle method in the form of an array of Callback objects. Upon success, the LoginModules associate relevant principals and credentials with the subject.
  5. The LoginContext returns the authentication status to the application. Success is represented by a return from the login method. Failure is represented through a LoginException being thrown by the login method.
  6. If authentication succeeds, the application retrieves the authenticated subject using the LoginContext.getSubject method.
  7. After the scope of the subject authentication is complete, all principals and related information associated with the subject by the login method can be removed by invoking the LoginContext.logout method.

The LoginContext class provides the basic methods for authenticating subjects and offers a way to develop an application that is independent of the underlying authentication technology. The LoginContext consults a Configuration to determine the authentication services configured for a particular application. LoginModule classes represent the authentication services. Therefore, you can plug different login modules into an application without changing the application itself. The following code shows the steps required by an application to authenticate a subject.

CallbackHandler handler = new MyHandler();
LoginContext lc = new LoginContext("some-config", handler);

try {
    lc.login();
    Subject subject = lc.getSubject();
} catch(LoginException e) {
    System.out.println("authentication failed");
    e.printStackTrace();
}

// Perform work as authenticated Subject
// ...

// Scope of work complete, logout to remove authentication info
try {
    lc.logout();
} catch(LoginException e) {
    System.out.println("logout failed");
    e.printStackTrace();
}

// A sample MyHandler class
class MyHandler
    implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws
        IOException, UnsupportedCallbackException
    {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                NameCallback nc = (NameCallback)callbacks[i];
                nc.setName(username);
            } else if (callbacks[i] instanceof PasswordCallback) {
                PasswordCallback pc = (PasswordCallback)callbacks[i];
                pc.setPassword(password);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                                                       "Unrecognized Callback");
            }
        }
    }
}

Developers integrate with an authentication technology by creating an implementation of the LoginModule interface. This allows an administrator to plug different authentication technologies into an application. You can chain together multiple LoginModules to allow for more than one authentication technology to participate in the authentication process. For example, one LoginModule may perform user name/password-based authentication, while another may interface to hardware devices such as smart card readers or biometric authenticators.

The life cycle of a LoginModule is driven by the LoginContext object against which the client creates and issues the login method. The process consists of two phases. The steps of the process are as follows:

  • The LoginContext creates each configured LoginModule using its public no-arg constructor.
  • Each LoginModule is initialized with a call to its initialize method. The Subject argument is guaranteed to be non-null. The signature of the initialize method is: public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
  • The login method is called to start the authentication process. For example, a method implementation might prompt the user for a user name and password and then verify the information against data stored in a naming service such as NIS or LDAP. Alternative implementations might interface to smart cards and biometric devices, or simply extract user information from the underlying operating system. The validation of user identity by each LoginModule is considered phase 1 of JAAS authentication. The signature of the login method is boolean login() throws LoginException . A LoginException indicates failure. A return value of true indicates that the method succeeded, whereas a return value of false indicates that the login module should be ignored.
  • If the LoginContext's overall authentication succeeds, commit is invoked on each LoginModule. If phase 1 succeeds for a LoginModule, then the commit method continues with phase 2 and associates the relevant principals, public credentials, and/or private credentials with the subject. If phase 1 fails for a LoginModule, then commit removes any previously stored authentication state, such as user names or passwords. The signature of the commit method is: boolean commit() throws LoginException . Failure to complete the commit phase is indicated by throwing a LoginException. A return of true indicates that the method succeeded, whereas a return of false indicates that the login module should be ignored.
  • If the LoginContext's overall authentication fails, then the abort method is invoked on each LoginModule. The abort method removes or destroys any authentication state created by the login or initialize methods. The signature of the abort method is boolean abort() throws LoginException . Failure to complete the abort phase is indicated by throwing a LoginException. A return of true indicates that the method succeeded, whereas a return of false indicates that the login module should be ignored.
  • To remove the authentication state after a successful login, the application invokes logout on the LoginContext. This in turn results in a logout method invocation on each LoginModule. The logout method removes the principals and credentials originally associated with the subject during the commit operation. Credentials should be destroyed upon removal. The signature of the logout method is: boolean logout() throws LoginException . Failure to complete the logout process is indicated by throwing a LoginException. A return of true indicates that the method succeeded, whereas a return of false indicates that the login module should be ignored.

When a LoginModule must communicate with the user to obtain authentication information, it uses a CallbackHandler object. Applications implement the interface and pass it to the LoginContext, which send the authentication information directly to the underlying login modules.

Login modules use the CallbackHandler both to gather input from users, such as a password or smart card PIN, and to supply information to users, such as status information. By allowing the application to specify the CallbackHandler, underlying LoginModules remain independent from the different ways applications interact with users. For example, a CallbackHandler's implementation for a GUI application might display a window to solicit user input. On the other hand, a CallbackHandler implementation for a non-GUI environment, such as an application server, might simply obtain credential information by using an application server API. The interface has one method to implement:

void handle(Callback[] callbacks)
    throws java.io.IOException,
           UnsupportedCallbackException;

The Callback interface is the last authentication class we will look at. This is a tagging interface for which several default implementations are provided, including the NameCallback and PasswordCallback used in an earlier example. A LoginModule uses a Callback to request information required by the authentication mechanism. LoginModules pass an array of Callbacks directly to the CallbackHandler.handle method during the authentication’s login phase. If a CallbackHandler does not understand how to use a Callback object passed into the handle method, it throws an UnsupportedCallbackException to abort the login call.

25.7. Securing Interfaces

25.7.1. Securing Interfaces

While the Hot Rod interface may be secured programmatically, both the memcached and REST interfaces must be secured declaratively. Instructions for securing these interfaces are located in the JBoss Data Grid Administration and Configuration Guide .

25.7.2. Hot Rod Interface Security

25.7.2.1. 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.

Secure Hot Rod Using SSL/TLS

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.impl.ConfigurationProperties;

[...]

public class SslConfiguration {

    public static final String ISPN_IP = "127.0.0.1";
    public static final String SERVER_NAME = "node0";
    public static final String SASL_MECH = "EXTERNAL";

    private static final String KEYSTORE_PATH = "./keystore_client.jks";
    private static final String KEYSTORE_PASSWORD = "secret";
    private static final String TRUSTSTORE_PATH = "./truststore_client.jks";
    private static final String TRUSTSTORE_PASSWORD = "secret";

    SslConfiguration(boolean enabled,
                     String keyStoreFileName,
                     char[] keyStorePassword,
                     SSLContext sslContext,
                     String trustStoreFileName,
                     char[] trustStorePassword) {
        ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.addServer()
            .host(ISPN_IP)
            .port(ConfigurationProperties.DEFAULT_HOTROD_PORT);
        //setup auth
        builder.security()
            .authentication()
            .serverName(SERVER_NAME)
            .saslMechanism(SASL_MECH)
            .enable()
            .callbackHandler(new VoidCallbackHandler());
        //setup encrypt
        builder.security()
            .ssl()
            .enable()
            .keyStoreFileName(KEYSTORE_PATH)
            .keyStorePassword(KEYSTORE_PASSWORD.toCharArray())
            .trustStoreFileName(TRUSTSTORE_PATH)
            .trustStorePassword(TRUSTSTORE_PASSWORD.toCharArray());

        RemoteCacheManager cacheManager = new RemoteCacheManager(builder.build());
        RemoteCache<Object, Object> cache = cacheManager.getCache(RemoteCacheManager.DEFAULT_CACHE_NAME);
    }

    private static class VoidCallbackHandler implements CallbackHandler {
        @Override
        public void handle(Callback[] clbcks) throws IOException, UnsupportedCallbackException {
        }
    }
}

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 Password Vault section of the JBoss Enterprise Application Platform security documentation. .

25.7.2.2. 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.

PLAIN authentication over SSL may be used for Hot Rod client authentication against an LDAP server. The Hot Rod client sends plain text credentials to the JBoss Data Grid server over SSL, and the server subsequently verifies the provided credentials against the specified LDAP server. In addition, a secure connection must be configured between the JBoss Data Grid server and the LDAP server. Refer to the JBoss Data Grid Administration and Configuration Guide for additional information on configuring the server to communicate to an LDAP backend. The example below demonstrates configuring PLAIN authentication over SSL on the Hot Rod client side:

Hot Rod Client Authentication to LDAP Server

import static org.infinispan.demo.util.CacheOps.dumpCache;
import static org.infinispan.demo.util.CacheOps.onCache;
import static org.infinispan.demo.util.CacheOps.putTestKV;
import static org.infinispan.demo.util.CmdArgs.LOGIN_KEY;
import static org.infinispan.demo.util.CmdArgs.PASS_KEY;
import static org.infinispan.demo.util.CmdArgs.getCredentials;

import java.util.Map;

import javax.net.ssl.SSLContext;

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.impl.ConfigurationProperties;
import org.infinispan.commons.util.SslContextFactory;
import org.infinispan.demo.util.SaslUtils.SimpleLoginHandler;

public class HotRodPlainAuthOverSSL {

    public static final String ISPN_IP = "127.0.0.1";
    public static final String SERVER_NAME = "node0";
    public static final String SASL_MECH = "PLAIN";
    private static final String SECURITY_REALM = "ApplicationRealm";

    private static final String TRUSTSTORE_PATH = "./truststore_client.jks";
    private static final String TRUSTSTORE_PASSWORD = "secret";

    public static void main(String[] args) {
        Map<String, String> userArgs = null;
        try {
            userArgs = getCredentials(args);
        } catch (IllegalArgumentException e) {
            System.err.println(e.getMessage());
            System.err.println(
                    "Invalid credentials format, plase provide credentials (and optionally cache name) with --cache=<cache> --user=<user> --password=<password>");
            System.exit(1);
        }

        ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.addServer().host(ISPN_IP).port(ConfigurationProperties.DEFAULT_HOTROD_PORT);

        //set up PLAIN auth
        builder.security().authentication().serverName(SERVER_NAME).saslMechanism(SASL_MECH).enable().callbackHandler(
                new SimpleLoginHandler(userArgs.get(LOGIN_KEY), userArgs.get(PASS_KEY), SECURITY_REALM));

        //set up SSL
        SSLContext cont = SslContextFactory.getContext(null, null, TRUSTSTORE_PATH, TRUSTSTORE_PASSWORD.toCharArray());
        builder.security().ssl().sslContext(cont).enable();

        RemoteCacheManager cacheManager = new RemoteCacheManager(builder.build());
        RemoteCache<Object, Object> cache = cacheManager.getCache(RemoteCacheManager.DEFAULT_CACHE_NAME);

        onCache(cache, putTestKV.andThen(dumpCache));

        cacheManager.stop();
        System.exit(0);
    }

}

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 .

25.7.2.3. User Authentication over Hot Rod Using SASL

25.7.2.3.1. 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.
25.7.2.3.2. Configure Hot Rod Authentication (GSSAPI/Kerberos)

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

Configure SASL GSSAPI/Kerberos Authentication - Client-side Configuration

  1. Ensure that the Server-Side configuration has been completed. As this is configured declaratively this configuration is found in the JBoss Data Grid Administration and Configuration Guide .
  2. Define a login module in a login configuration file (gss.conf ) on the client side:

    [source],options="nowrap"

GssExample {
    com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
};
  1. 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.

  2. Implement the CallbackHandler:

    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);
                }
            }
        }
    }
  3. Configure the Hot Rod Client, as seen in the below snippet:

    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");
25.7.2.3.3. Configure Hot Rod Authentication (MD5)

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

  1. Ensure that the server has been configured for MD5 Authentication. Instructions for performing this configuration on the server are found in JBoss Data Grid’s Administration and Configuration Guide .
  2. Implement the CallbackHandler:

    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);
             }
          }
       }
    }
  3. Connect the client to the configured Hot Rod connector as seen below:

    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");
25.7.2.3.4. Configure Hot Rod C++ Authentication (GSSAPI/Kerberos)

Use the following steps to set up Hot Rod C++ client authentication using the SASL GSSAPI/Kerberos mechanism:

Configure SASL GSSAPI/Kerberos Authentication - Client-side Configuration

  1. Ensure that the Server-Side configuration has been completed. As this is configured declaratively this configuration is found in the JBoss Data Grid Administration and Configuration Guide .

Below is a complete example of using Kerberos with the Hot Rod C++ client:

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <sasl/saslplug.h>
#include <krb5.h>
#include <err.h>
#include <stdlib.h>

using namespace infinispan::hotrod;

int kinit();
void kdestroy();

 /* Hotrod SASL is based on Cyrus Sasl libraries.
  * Check cyrus docs for more info on how to setup callbacks
  * https://www.cyrusimap.org/sasl/
  */
static int simple(void*  context , int id, const char **result, unsigned *len) {
    *result = *(char**)context;
    if (len)
        *len = strlen(*result);
    return SASL_OK;
}

static int getsecret(void* /* conn */, void*  context, int id, sasl_secret_t **psecret) {
    char *secret_data=*(char**)context;
    size_t len = strlen(secret_data);
    static sasl_secret_t *x;
    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
    x->len = len;
    strcpy((char *) x->data, secret_data);
    *psecret = x;
    return SASL_OK;
}

char *pusername;
char *psecret;

static std::vector<sasl_callback_t> callbackHandler {
        { SASL_CB_USER, (sasl_callback_ft) &simple, &pusername },
        {SASL_CB_PASS, (sasl_callback_ft) &getsecret, &psecret },
        {SASL_CB_LIST_END, NULL, NULL } };

int kinit();
void kdestroy();

int main(int argc, char** argv) {
    int result = 0;
    {
        kinit();
        ConfigurationBuilder builder;
        char username[]="supervisor@INFINISPAN.ORG";
        char secret_data[]="lessStrongPassword";
        pusername=username;
        psecret=secret_data;
        builder.addServer().host(argc > 1 ? argv[1] : "127.0.0.1").port(argc > 2 ? atoi(argv[2]) : 11222);
        builder.protocolVersion(Configuration::PROTOCOL_VERSION_24);
        builder.security().authentication().saslMechanism("GSSAPI").serverFQDN(
                "node0").callbackHandler(callbackHandler).enable();
        builder.balancingStrategyProducer(nullptr);
        RemoteCacheManager cacheManager(builder.build(), false);
        BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
        BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
        RemoteCache<std::string, std::string> cache = cacheManager.getCache<std::string, std::string>(km,
                &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy, std::string("authCache"));
        cacheManager.start();
        try {
            cache.put("key", "value");
            std::shared_ptr<std::string> ret(cache.get("key"));
            result = 0;
        } catch (Exception& ex) {
            std::cerr << "FAIL: 'supervisor' should read and write" << std::endl;
            result = -1;
        }
        cacheManager.stop();
        std::cout << "PASS: 'GSSAPI' sasl authorization" << std::endl;
        kdestroy();
    }
    return result;
}

krb5_context context;
krb5_creds creds;
krb5_principal client_princ = NULL;

int kinit() {
    // Delegate Kerberos setup to the system
    setenv("KRB5CCNAME", "krb5cc_hotrod", 1);
    setenv("KRB5_CONFIG", "krb5.conf", 1);
    std::system("echo lessStrongPassword | kinit -c krb5cc_hotrod supervisor@INFINISPAN.ORG");
}
void kdestroy() {
    std::system("kdestroy");
}
25.7.2.3.5. Configure Hot Rod C++ Authentication (MD5)

Use the following steps to set up Hot Rod C++ client authentication using the SASL MD5 mechanism:

Configure SASL MD5 Authentication - Client-side Configuration

  1. Ensure that the Server-Side configuration has been completed. As this is configured declaratively this configuration is found in the JBoss Data Grid Administration and Configuration Guide .

Below is a complete example of using SASL MD5 with the Hot Rod C++ client:

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <sasl/saslplug.h>
#include <krb5.h>


using namespace infinispan::hotrod;

 /* Hotrod SASL is based on Cyrus Sasl libraries.
  * Check cyrus docs for more info on how to setup callbacks
  * https://www.cyrusimap.org/sasl/
  */
static int simple(void*  context , int id, const char **result, unsigned *len) {
    *result = *(char**)context;
    if (len)
        *len = strlen(*result);
    return SASL_OK;
}

static int getsecret(void* /* conn */, void*  context, int id, sasl_secret_t **psecret) {
    char *secret_data=*(char**)context;
    size_t len = strlen(secret_data);
    static sasl_secret_t *x;
    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
    x->len = len;
    strcpy((char *) x->data, secret_data);
    *psecret = x;
    return SASL_OK;
}

char *pusername;
char *psecret;

static std::vector<sasl_callback_t> callbackHandler {
        { SASL_CB_AUTHNAME, (sasl_callback_ft) &simple, &pusername },
        {SASL_CB_PASS, (sasl_callback_ft) &getsecret, &psecret },
        {SASL_CB_LIST_END, NULL, NULL } };

/* This sample authenticates the client with
 * user=reader
 * password=password
 * credential, which is an account that can only do WRITE
 * on the server.
 */
int main(int argc, char** argv) {
    int result = 0;
    {
        ConfigurationBuilder builder;
        char username[]="reader";
        char secret_data[]="password";
        pusername=username;
        psecret=secret_data;
        builder.addServer().host("127.0.0.1").port(11222);
        builder.protocolVersion(Configuration::PROTOCOL_VERSION_24);
        builder.security().authentication().saslMechanism("DIGEST-MD5").serverFQDN("node0").callbackHandler(callbackHandler).enable();
        RemoteCacheManager cacheManager(builder.build(), false);
        BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
        BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
        auto cache = cacheManager.getCache<std::string, std::string>(km, &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy, std::string("authCache"));
        cacheManager.start();
        std::shared_ptr<std::string> ret(cache.get("key"));
        try {
            cache.put("key", "value");
            std::cerr << "FAIL: 'reader' should not write" << std::endl;
            return -1;
        } catch (Exception& ex) {

        }
        std::cout << "PASS: 'DIGEST-MD5' sasl authorization" << std::endl;
        cacheManager.stop();
    }
    return result;
}
25.7.2.3.6. Configure Hot Rod C++ Authentication (PLAIN)

Use the following steps to set up Hot Rod C++ client authentication using the SASL PLAIN mechanism:

Configure SASL PLAIN Authentication - Client-side Configuration

  1. Ensure that the Server-Side configuration has been completed. As this is configured declaratively this configuration is found in the JBoss Data Grid Administration and Configuration Guide .

Below is a complete example of using SASL PLAIN with the Hot Rod C++ client:

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <sasl/saslplug.h>
#include <krb5.h>

using namespace infinispan::hotrod;

 /* Hotrod SASL is based on Cyrus Sasl libraries.
  * Check cyrus docs for more info on how to setup callbacks
  * https://www.cyrusimap.org/sasl/
  */
static int simple(void*  context , int id, const char **result, unsigned *len) {
    *result = *(char**)context;
    if (len)
        *len = strlen(*result);
    return SASL_OK;
}

static int getsecret(void* /* conn */, void*  context, int id, sasl_secret_t **psecret) {
    char *secret_data=*(char**)context;
    size_t len = strlen(secret_data);
    static sasl_secret_t *x;
    x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
    x->len = len;
    strcpy((char *) x->data, secret_data);
    *psecret = x;
    return SASL_OK;
}

char *pusername;
char *psecret;

static std::vector<sasl_callback_t> callbackHandler {
        { SASL_CB_AUTHNAME, (sasl_callback_ft) &simple, &pusername },
        {SASL_CB_PASS, (sasl_callback_ft) &getsecret, &psecret },
        {SASL_CB_LIST_END, NULL, NULL } };

/* This sample authenticates the client with
 * user=writer
 * password=somePassword
 * credential, which is an account that can only do WRITE
 * on the server.
 */
int main(int argc, char** argv) {
    int result = 0;
    {
        ConfigurationBuilder builder;
        char username[]="writer";
        char secret_data[]="somePassword";
        pusername=username;
        psecret=secret_data;
        builder.addServer().host("127.0.0.1").port(11222);
        builder.protocolVersion(Configuration::PROTOCOL_VERSION_24);
        builder.security().authentication().saslMechanism("PLAIN").serverFQDN("node0").callbackHandler(callbackHandler).enable();
        RemoteCacheManager cacheManager(builder.build(), false);
        BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
        BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
        auto cache = cacheManager.getCache<std::string, std::string>(km, &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy, std::string("authCache"));
        cacheManager.start();
        cache.put("key", "value");
        try {
            std::shared_ptr<std::string> ret(cache.get("key"));
            std::cerr << "FAIL: 'writer' should not read" << std::endl;
            return -1;
        } catch (Exception& ex) {

        }
        std::cout << "PASS: 'PLAIN' sasl authorization" << std::endl;
        cacheManager.stop();
    }
    return result;
}
25.7.2.3.7. Configure Hot Rod C# Authentication (EXTERNAL)

Use the following steps to set up Hot Rod C# client authentication using the SASL EXTERNAL mechanism:

Configure SASL EXTERNAL Authentication - Client-side Configuration

  1. Ensure that the Server-Side configuration has been completed. As this is configured declaratively this configuration is found in the JBoss Data Grid Administration and Configuration Guide .

Below is a complete example of using SASL EXTERNAL with the Hot Rod C# client:

using Infinispan.HotRod;
using Infinispan.HotRod.Config;
using System;
using System.Text;

namespace Authentication
{
    class Program
    {

        static void Main(string[] args)
        {
            ConfigurationBuilder conf = new ConfigurationBuilder();
            conf.AddServer()
                    .Host("127.0.0.1")
                    .Port(11222)
                    .ConnectionTimeout(90000)
                    .SocketTimeout(900);
// Enable EXTERNAL mechanism for SASL
            conf.Security().Authentication()
                                .Enable()
                                .SaslMechanism("EXTERNAL")
                                .ServerFQDN("node0");
// Enable SSL (EXTERNAL is based on the client certificate)
            conf.Ssl().Enable()
                .ServerCAFile("infinispan-ca.pem")
                .ClientCertificateFile("keystore_client.p12");
// end of SASL configuration
// The subject specified in the truststore_client.p12 cert will be used to identify the client
            IMarshaller marshaller = new JBasicMarshaller();
            conf.Marshaller(marshaller);
            Configuration c = conf.Build();
            RemoteCacheManager remoteManager = new RemoteCacheManager(c, true);
            IRemoteCache<string, string> authCache = remoteManager.GetCache<string, string>("authCache");
            authCache.Put("K1", "V1");
            authCache.Get("K1");
            authCache.Clear();

        }
    }
}
25.7.2.3.8. Configure Hot Rod C# Authentication (MD5)

Use the following steps to set up Hot Rod C# client authentication using the SASL MD5 mechanism:

Configure SASL MD5 Authentication - Client-side Configuration

  1. Ensure that the Server-Side configuration has been completed. As this is configured declaratively this configuration is found in the JBoss Data Grid Administration and Configuration Guide .

Below is a complete example of using SASL MD5 with the Hot Rod C# client:

using Infinispan.HotRod;
using Infinispan.HotRod.Config;
using System;
using System.Text;

namespace Authentication
{
    class Program
    {
        static void Main(string[] args)
        {
            ConfigurationBuilder conf = new ConfigurationBuilder();
            conf.AddServer()
                    .Host("127.0.0.1")
                    .Port(11222)
                    .ConnectionTimeout(90000)
                    .SocketTimeout(900);
// Enable authentication use PLAIN as mechanism  (DIGEST-MD5 can be used the same way)
// and setup user password and realm
            conf.Security().Authentication()
                           .Enable()
                           .SaslMechanism("DIGEST-MD5")
                           .ServerFQDN("node0")
                           .SetupCallback("writer", "somePassword", "ApplicationRealm");
// end of SASL configuration
            IMarshaller marshaller = new JBasicMarshaller();
            conf.Marshaller(marshaller);
            Configuration c = conf.Build();
            RemoteCacheManager remoteManager = new RemoteCacheManager(c, true);
            IRemoteCache<string, string> authCache = remoteManager.GetCache<string, string>("authCache");
            authCache.Put("K1", "V1");
            authCache.Get("K1");
            authCache.Clear();
        }
    }
}

25.7.3. Hot Rod C++ Client Encryption

By default all communication with the remote server is unencrypted; however, TLS encryption may be enabled by defining the server’s key via the serverCAFile method on the SslConfigurationBuilder. Additionally, the client’s certificate may be defined with the clientCertificateFile, allowing for client authentication.

The following example demonstrates defining a server key with an optional client certificate:

Hot Rod C++ TLS Example

#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
#include "infinispan/hotrod/Version.h"

#include "infinispan/hotrod/JBasicMarshaller.h"
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <typeinfo>

using namespace infinispan::hotrod;

int main(int argc, char** argv) {
    std::cout << "TLS Test" << std::endl;
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " server_ca_file [client_ca_file]" << std::endl;
        return 1;
    }
    {
      ConfigurationBuilder builder;
      builder.addServer().host("127.0.0.1").port(11222).protocolVersion(Configuration::PROTOCOL_VERSION_24);
      // Enable the TLS layer and install the server public key
      // this ensure that the server is authenticated
      builder.ssl().enable().serverCAFile(argv[1]);
      if (argc > 2) {
          // Send a client certificate for authentication (optional)
          // without this the socket will only be encrypted
          std::cout << "Using supplied client certificate for authentication against the server" << std::endl;
          builder.ssl().clientCertificateFile(argv[2]);
      }
      // That's all. Now do business as usual
      RemoteCacheManager cacheManager(builder.build(), false);
      BasicMarshaller<std::string> *km = new BasicMarshaller<std::string>();
      BasicMarshaller<std::string> *vm = new BasicMarshaller<std::string>();
      RemoteCache<std::string, std::string> cache = cacheManager.getCache<std::string, std::string>(km,
          &Marshaller<std::string>::destroy, vm, &Marshaller<std::string>::destroy );
      cacheManager.start();
      cache.clear();
      std::string k1("key13");
      std::string v1("boron");

      cache.put(k1, v1);
      std::unique_ptr<std::string> rv(cache.get(k1));
      if (rv->compare(v1)) {
          std::cerr << "get/put fail for " << k1 << " got " << *rv << " expected " << v1 << std::endl;
          return 1;
      }
      cacheManager.stop();
    }
    return 0;
}

The client may also indicate which hostname it is attempting to connect to at the start of the TLS/SNI handshaking process by providing a value to the sniHostName function. For instance, the following could be used:

[...]
    builder.ssl().enable().serverCAFile(argv[1]).sniHostName("sni");
[...]

25.7.4. Hot Rod C# Client Encryption

By default all communication with the remote server is unencrypted; however, TLS encryption may be enabled by defining the server’s key via the ServerCAFile method on the SslConfigurationBuilder. Additionally, the client’s certificate may be defined with the ClientCertificateFile, allowing for client authentication.

The following example demonstrates defining a server key with an optional client certificate:

Hot Rod C# TLS Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Infinispan.HotRod;
using Infinispan.HotRod.Config;

namespace TLS
{
    /// <summary>
    /// This sample code shows how to perform operations over TLS using the C# client
    /// </summary>

    class TLS
    {
        static void Main(string[] args)
        {
            // Cache manager setup
            RemoteCacheManager remoteManager;
            ConfigurationBuilder conf = new ConfigurationBuilder();
            conf.AddServer().Host("127.0.0.1").Port(11222).ConnectionTimeout(90000).SocketTimeout(900);
            SslConfigurationBuilder sslConfB = conf.Ssl();
            // Retrieve the server public certificate, needed to do server authentication. Mandatory
            if (!System.IO.File.Exists("resources/infinispan-ca.pem"))
            {
                Console.WriteLine("File not found: resources/infinispan-ca.pem.");
                Environment.Exit(-1);
            }
            sslConfB.Enable().ServerCAFile("resources/infinispan-ca.pem");
            // Retrieve the client public certificate, needed if the server requires client authentication. Optional
            if (!System.IO.File.Exists("resources/keystore_client.p12"))
            {
                Console.WriteLine("File not found: resources/keystore_client.p12.");
                Environment.Exit(-1);
            }
            sslConfB.ClientCertificateFile("resources/keystore_client.p12");

            // Usual business now
            conf.Marshaller(new JBasicMarshaller());
            remoteManager = new RemoteCacheManager(conf.Build(), true);
            IRemoteCache<string, string> testCache = remoteManager.GetCache<string, string>();
            testCache.Clear();
            string k1 = "key13";
            string v1 = "boron";
            testCache.Put(k1, v1);
        }
    }
}

The client may also indicate which hostname it is attempting to connect to at the start of the TLS/SNI handshaking process by providing a value to SniHostName. For instance, the following call could be included immediately after defining the ServerCAFile:

[...]
sslConfB.ServerCAFile("resources/infinispan-ca.pem").SniHostName("sni");
[...]

25.7.5. Hot Rod Node.js Encryption

The Node.js client supports encryption via SSL/TLS with optional TLS/SNI support. To configure this on the client it is necessary to create a Java KeyStore (JKS) using the keytool application included in the JDK. The created keystore must contain the keys and certificates necessary for the JBoss Data Grid server to authorize connections, and the JBoss Data Grid server must be configured for encryption. For details on configuring the server for encryption, refer to the JBoss Data Grid Administration and Configuration Guide.

Important

The Node.js client implementation of TLS/SSL does not allow self-signed certificates. It is recommended to either configure a local Certificate Authority to sign certificates, or to use a free, open Certificate Authority, if certificates were previously self-signed.

By defining the location of a trusted certificate the client connection may be authorized by the server:

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      trustCerts: ['my-root-ca.crt.pem']
    }
  }
);

In addition, the client may also read trusted certificates from PKCS#12 or PFX format key stores:

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      cryptoStore: {
        path: 'my-truststore.p12',
        passphrase: 'secret'
      }
    }
  }
);

In addition, the client may be configured with encrypted authentication. To configure authentication it is necessary to provide the location of the private key, the passphrase, and the certificate key of the client:

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      trustCerts: ['my-root-ca.crt.pem'],
      clientAuth: {
        key: 'privkey.pem',
        passphrase: 'secret',
        cert: 'cert.pem'
      }
    }
  }
);

The client may also indicate which hostname it is attempting to connect to at the start of the TLS/SNI handshaking process by including the sniHostName directive:

var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
  {
    ssl: {
      enabled: true,
      trustCerts: ['my-root-ca.crt.pem']
      sniHostName: 'example.com'
    }
  }
);
Note

If no sniHostName is provided then the client will send localhost as the SNI parameter. If the server’s default realm does not match localhost an error will be thrown.

25.8. The Security Audit Logger

25.8.1. The Security Audit Logger

Red Hat JBoss Data Grid includes a logger to audit security logs for the cache, specifically whether a cache or a cache manager operation was allowed or denied for various operations.

The default audit logger is org.infinispan.security.impl.DefaultAuditLogger. This logger outputs audit logs using the available logging framework (for example, JBoss Logging) and provides results at the TRACE level and the AUDIT category.

To send the AUDIT category to either a log file, a JMS queue, or a database, use the appropriate log appender.

25.8.2. Configure the Security Audit Logger (Library Mode)

Use the following to configure the audit logger in Red Hat JBoss Data Grid:

GlobalConfigurationBuilder global = new GlobalConfigurationBuilder();
   global.security()
      .authorization()
         .auditLogger(new DefaultAuditLogger());

25.8.3. Custom Audit Loggers

Users can implement custom audit loggers in Red Hat JBoss Data Grid Library and Remote Client-Server Mode. The custom logger must implement the org.infinispan.security.AuditLogger interface. If no custom logger is provided, the default logger (DefaultAuditLogger) is used.