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