Java Authentication and Authorization Service (JAAS) Provider

21.1 Overview

Spring Security provides a package able to delegate authentication requests to the Java Authentication and Authorization Service (JAAS). This package is discussed in detail below.

21.2 AbstractJaasAuthenticationProvider

The AbstractJaasAuthenticationProvider is the basis for the provided JAAS AuthenticationProvider implementations. Subclasses must implement a method that creates the LoginContext. The AbstractJaasAuthenticationProvider has a number of dependencies that can be injected into it that are discussed below.

21.2.1 JAAS CallbackHandler

Most JAAS LoginModules require a callback of some sort. These callbacks are usually used to obtain the username and password from the user.

In a Spring Security deployment, Spring Security is responsible for this user interaction (via the authentication mechanism). Thus, by the time the authentication request is delegated through to JAAS, Spring Security's authentication mechanism will already have fully-populated an Authentication object containing all the information required by the JAAS LoginModule.

Therefore, the JAAS package for Spring Security provides two default callback handlers, JaasNameCallbackHandler and JaasPasswordCallbackHandler. Each of these callback handlers implement JaasAuthenticationCallbackHandler. In most cases these callback handlers can simply be used without understanding the internal mechanics.

For those needing full control over the callback behavior, internally AbstractJaasAuthenticationProvider wraps these JaasAuthenticationCallbackHandlers with an InternalCallbackHandler. The InternalCallbackHandler is the class that actually implements JAAS’ normal CallbackHandler interface. Any time that the JAAS LoginModule is used, it is passed a list of application context configured InternalCallbackHandlers. If the LoginModule requests a callback against the InternalCallbackHandlers, the callback is in-turn passed to the JaasAuthenticationCallbackHandlers being wrapped.

21.2.2 JAAS AuthorityGranter

JAAS works with principals. Even "roles" are represented as principals in JAAS. Spring Security, on the other hand, works with Authentication objects. Each Authentication object contains a single principal, and multiple GrantedAuthoritys. To facilitate mapping between these different concepts, Spring Security's JAAS package includes an AuthorityGranter interface.

An AuthorityGranter is responsible for inspecting a JAAS principal and returning a set of Strings, representing the authorities assigned to the principal. For each returned authority string, the AbstractJaasAuthenticationProvider creates a JaasGrantedAuthority (which implements Spring Security’s GrantedAuthority interface) containing the authority string and the JAAS principal that the AuthorityGranter was passed. The AbstractJaasAuthenticationProvider obtains the JAAS principals by firstly successfully authenticating the user’s credentials using the JAAS LoginModule, and then accessing the LoginContext it returns. A call to LoginContext.getSubject().getPrincipals() is made, with each resulting principal passed to each AuthorityGranter defined against the AbstractJaasAuthenticationProvider.setAuthorityGranters(List) property.

Spring Security does not include any production AuthorityGranters given that every JAAS principal has an implementation-specific meaning. However, there is a TestAuthorityGranter in the unit tests that demonstrates a simple AuthorityGranter implementation.

21.3 DefaultJaasAuthenticationProvider

The DefaultJaasAuthenticationProvider allows a JAAS Configuration object to be injected into it as a dependency. It then creates a LoginContext using the injected JAAS Configuration. This means that DefaultJaasAuthenticationProvider is not bound any particular implementation of Configuration as JaasAuthenticationProvider is.

21.3.1 InMemoryConfiguration

In order to make it easy to inject a Configuration into DefaultJaasAuthenticationProvider, a default in memory implementation named InMemoryConfiguration is provided. The implementation constructor accepts a Map where each key represents a login configuration name and the value represents an Array of AppConfigurationEntrys. InMemoryConfiguration also supports a default Array of AppConfigurationEntry objects that will be used if no mapping is found within the provided Map. For details, refer to the class level javadoc of InMemoryConfiguration.

21.3.2 DefaultJaasAuthenticationProvider Example Configuration

While the Spring configuration for InMemoryConfiguration can be more verbose than the standarad JAAS configuration files, using it in conjuction with DefaultJaasAuthenticationProvider is more flexible than JaasAuthenticationProvider since it not dependant on the default Configuration implementation.

An example configuration of DefaultJaasAuthenticationProvider using InMemoryConfiguration is provided below. Note that custom implementations of Configuration can easily be injected into DefaultJaasAuthenticationProvider as well.

<bean id="jaasAuthProvider"
   class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
 <property name="configuration">
  <bean class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
   <constructor-arg>
    <map>
     <!--
       SPRINGSECURITY is the default loginContextName
       for AbstractJaasAuthenticationProvider
     -->
     <entry key="SPRINGSECURITY">
      <array>
       <bean class="javax.security.auth.login.AppConfigurationEntry">
        <constructor-arg value="sample.SampleLoginModule" />
         <constructor-arg>
          <util:constant static-field=
            "javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED"/>
         </constructor-arg>
         <constructor-arg>
          <map></map>
         </constructor-arg>
        </bean>
       </array>
      </entry>
     </map>
    </constructor-arg>
   </bean>
  </property>
  <property name="authorityGranters">
   <list>
    <!-- You will need to write your own implementation of AuthorityGranter -->
    <bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
   </list>
  </property>
</bean>

21.4 JaasAuthenticationProvider

The JaasAuthenticationProvider assumes the default Configuration is an instance of ConfigFile. This assumption is made in order to attempt to update the Configuration. The JaasAuthenticationProvider then uses the default Configuration to create the LoginContext.

Let’s assume we have a JAAS login configuration file, /WEB-INF/login.conf, with the following contents:

JAASTest {
    sample.SampleLoginModule required;
};

Like all Spring Security beans, the JaasAuthenticationProvider is configured via the application context. The following definitions would correspond to the above JAAS login configuration file:

<bean id="jaasAuthenticationProvider"
   class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
 <property name="loginConfig" value="/WEB-INF/login.conf"/>
 <property name="loginContextName" value="JAASTest"/>
 <property name="callbackHandlers">
  <list>
   <bean
     class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler"/>
   <bean
     class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler"/>
  </list>
  </property>
  <property name="authorityGranters">
    <list>
      <bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
    </list>
  </property>
</bean>

21.5 Running as a Subject

If configured, the JaasApiIntegrationFilter will attempt to run as the Subject on the JaasAuthenticationToken. This means that the Subject can be accessed using:

            Subject subject = Subject.getSubject(AccessController.getContext());

This integration can easily be configured using the jaas-api-provision attribute. This feature is useful when integrating with legacy or external API's that rely on the JAAS Subject being populated.