Skip Headers
Oracle® Coherence Security Guide
Release 3.7

Part Number E18681-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

3 Using the Access Controller

The Access Controller security framework in Coherence is based on the concept of a clustered access controller, which can be turned on (activated) by a configurable parameter or command line attribute.

The following sections are included in this chapter:

Note:

This chapter does not cover SSL. See Chapter 5, "Using SSL to Secure Communication," for detailed instructions for using SSL.

3.1 Overview of the Access Controller

The Access Controller manages access to clustered resources, such as clustered services and caches and controls operations that include (but are not limited to) the following:

The Access Controller serves three purposes:

Coherence uses a local Login Module (see JAAS Reference Guide for details) to authenticate the caller and an Access Controller on one or more cluster nodes to verify the caller's access rights.

The Access Controller is a pluggable component that could be declared in the Coherence deployment descriptor, tangosol-coherence.xml. The specified class must implement the com.tangosol.net.security.AccessController interface.

Coherence provides a default Access Controller implementation that is based on the Key Management infrastructure that is shipped as a standard part of Sun's JDK. See"Enabling the Default Access Controller Implementation".

Each clustered service in Coherence maintains a concept of a senior service member (cluster node), which serves as a controlling agent for a particular service. While the senior member does not have to consult anyone when accessing a clustered resource, any junior node willing to join that service has to request and receive a confirmation from the senior member, which in turn notifies all other cluster nodes about the joining node.

Since Coherence is a system providing distributed data management and computing, the security subsystem is designed to operate in a partially hostile environment. We assume that when there is data shared between two cluster nodes either node could be a malicious one - lacking sufficient credentials to join a clustered service or obtain access to a clustered resource.

Let's call a cluster node that may try to gain unauthorized access to clustered resources by using nonstandard means as a "malicious" node. The means of such an access could vary. They could range from attempts to get protected or private class data using reflection, replacing classes in the distribution (coherence.jar or other application binaries), modifying classes on-the-fly using custom class loader(s) and so on. Alternatively, a cluster node that never attempts to gain unauthorized access to clustered resources by using nonstandard means is called a "trusted" node. It's important to note that even a trusted node may attempt to gain access to resources without having sufficient rights, but it does so in a standard way by using the exposed standard API.

File system mechanisms (the same that is used to protect the integrity of the Java run-time libraries) and standard Java security policy could be used to resolve an issue of guarantying the trustworthiness of a given single node. In a case of inter-node communications there are two dangers to consider:

To prevent either of these two scenarios from occurring Coherence uses two-way encryption algorithm: all client requests must be accompanied by the proof of identity and all service responses must be accompanied by the proof of trustworthiness.

Proof of Identity

In the case of an active Access Controller, the client code can use the following construct to authenticate the caller and perform necessary actions:

import com.tangosol.net.security.Security;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;

...

Subject subject = Security.login(sName, acPassword);
PrivilegedAction action = new PrivilegedAction()
    {
    public Object run()
        {
        // all processing here is taking place with access
        // rights assigned to the corresponding Subject
        ...
        }
    };
Security.runAs(subject, action);

During the login call, Coherence uses JAAS that runs on the caller's node to authenticate the caller. In a case of successful authentication, it uses the local Access Controller to:

The encrypt step (above) serves the role of the proof of identity for the responder preventing a malicious node pretending to pass the local access check phase.

There are two alternative ways to provide the client authentication information. First, a reference to a CallbackHandler could be passed instead of the user name and password. Second, a previously authenticated Subject could be used, which could become handy when Coherence is used by a Java EE application that could retrieve an authenticated Subject from the application container.

If a caller's request comes without any authentication context, Coherence instantiates and call a CallbackHandler implementation declared in the Coherence operational descriptor to retrieve the appropriate credentials. However, that "lazy" approach is much less efficient, since without externally defined call scope, every access to a protected clustered resource forces repetitive authentication calls.

Proof of Trustworthiness

Every clustered resource in Coherence is created by an explicit API call. A senior service member retains the private credentials that are presented during that call as a proof of trustworthiness. When the senior service member receives an access request to a protected clustered resource, it use the local Access Controller to:

Since the requester accepts the response as valid only after decrypting it, the last step in this cycle serves a role of the proof of trustworthiness for the requester preventing a malicious node pretending to be a valid service senior.

3.2 Enabling the Default Access Controller Implementation

Coherence ships with a default Access Controller implementation that uses a standard Java keystore. The implementation class is the com.tangosol.net.security.DefaultController class and is configured in the Coherence operational deployment descriptor.

<security-config>
  <enabled system-property="tangosol.coherence.security">false</enabled>
  <login-module-name>Coherence</login-module-name>
  <access-controller>
    <class-name>com.tangosol.net.security.DefaultController</class-name>
    <init-params>
      <init-param id="1">
        <param-type>java.io.File</param-type>
        <param-value>./keystore.jks</param-value>
      </init-param>
      <init-param id="2">
        <param-type>java.io.File</param-type>
        <param-value>./permissions.xml</param-value>
      </init-param>
    </init-params>
  </access-controller>
  <callback-handler>
    <class-name/>
  </callback-handler>
</security-config>

The default access controller implementation is not enabled by default. To enable the default implementation, override the <enabled> element within the <security-config> node in an operational override file and set it to true. For example:

<security-config>
   <enabled>true</enabled>
</security-config>

The default access controller implementation can also by enabled by setting the tangosol.coherence.security system property to true.

Note:

When Coherence security is enabled, every call to the CacheFactory.getCache() or ConfigurableCacheFactory.ensureCache() API causes a security check. This can negatively impact an application's performance if these calls are made very frequently. The best practice is for the application to hold on to the cache reference and reuse it so that the security check is only performed on the initial call. When using this approach, it is the application's responsibility to ensure that those references are only used in an authorized way.

The <login-module-name> element serves as the application name in a login configuration file (see JAAS Reference Guide for complete details). Coherence is shipped with a Java keystore (JKS) based login module that is contained in the coherence-login.jar, which depends only on standard Java run-time classes and could be placed in the JRE's lib/ext (standard extension) directory. The corresponding login module declaration would look like:

// LoginModule Configuration for Oracle Coherence(TM)
Coherence {
    com.tangosol.security.KeystoreLogin required
      keyStorePath="${user.dir}${/}keystore.jks";
};

The <access-controller> element defines the Access Controller implementation that takes two parameters to instantiate.

The <callback-handler> is an optional element that defines a custom implementation of the javax.security.auth.callback.CallbackHandler interface that would be instantiated and used by Coherence to authenticate the client when all other means are exhausted.

Two more steps have to be performed to make the default Access Controller implementation usable in your application:

  1. Create a keystore with necessary principals.

  2. Create the permissions file that would declare the access right for the corresponding principals.

Consider the following example that creates three principals: admin to be used by the Java Security framework; manager and worker to be used by Coherence:

keytool -genkey -v -keystore ./keystore.jks -storepass password -alias admin
-keypass password -dname CN=Administrator,O=MyCompany,L=MyCity,ST=MyState

keytool -genkey -v -keystore ./keystore.jks -storepass password -alias manager
-keypass password -dname CN=Manager,OU=MyUnit

keytool -genkey -v -keystore ./keystore.jks -storepass password -alias worker
-keypass password -dname CN=Worker,OU=MyUnit

Consider the following example that assigns all rights to the Manager principal, only join rights to the Worker principal for caches that have names prefixed by common and all rights to the Worker principal for the invocation service named invocation:

<?xml version='1.0'?>
<permissions>
  <grant>
    <principal>
      <class>javax.security.auth.x500.X500Principal</class>
      <name>CN=Manager,OU=MyUnit</name>
    </principal>

    <permission>
      <target>*</target>
      <action>all</action>
    </permission>
  </grant>

  <grant>
    <principal>
      <class>javax.security.auth.x500.X500Principal</class>
      <name>CN=Worker,OU=MyUnit</name>
    </principal>

    <permission>
      <target>cache=common*</target>
      <action>join</action>
    </permission>
    <permission>
      <target>service=invocation</target>
      <action>all</action>
    </permission>
  </grant>
</permissions>