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.
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.
Most JAAS LoginModule
s 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 JaasAuthenticationCallbackHandler
s 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 InternalCallbackHandler
s. If the LoginModule
requests a callback against the InternalCallbackHandler
s, the callback is in-turn passed to the JaasAuthenticationCallbackHandler
s being wrapped.
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 GrantedAuthority
s. 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 String
s, 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 AuthorityGranter
s 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.
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.
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 AppConfigurationEntry
s. 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
.
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>
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>
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.