For the latest stable version, please use Spring Security 6.4.2! |
Java Authentication and Authorization Service (JAAS) Provider
Spring Security provides a package to delegate authentication requests to the Java Authentication and Authorization Service (JAAS). This section discusses that package.
AbstractJaasAuthenticationProvider
The AbstractJaasAuthenticationProvider
class 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, as discussed in the remainder of this section.
JAAS CallbackHandler
Most JAAS LoginModule
instances 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 (through the authentication mechanism).
Thus, by the time the authentication request is delegated through to JAAS, Spring Security’s authentication mechanism has already fully populated an Authentication
object that contains 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 implements JaasAuthenticationCallbackHandler
.
In most cases, these callback handlers can be used without understanding the internal mechanics.
For those needing full control over the callback behavior, AbstractJaasAuthenticationProvider
internally wraps these JaasAuthenticationCallbackHandler
instances with an InternalCallbackHandler
.
The InternalCallbackHandler
is the class that actually implements the JAAS normal CallbackHandler
interface.
Any time that the JAAS LoginModule
is used, it is passed a list of application contexts configured InternalCallbackHandler
instances.
If the LoginModule
requests a callback against the InternalCallbackHandler
instances, the callback is, in turn, passed to the JaasAuthenticationCallbackHandler
instances being wrapped.
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 GrantedAuthority
instances.
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
objects that represent the authorities assigned to the principal.
For each returned authority string, the AbstractJaasAuthenticationProvider
creates a JaasGrantedAuthority
(which implements Spring Security’s GrantedAuthority
interface) that contains the authority string and the JAAS principal that the AuthorityGranter
was passed.
The AbstractJaasAuthenticationProvider
obtains the JAAS principals by first successfully authenticating the user’s credentials by 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
instances, 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.
DefaultJaasAuthenticationProvider
The DefaultJaasAuthenticationProvider
lets a JAAS Configuration
object be injected into it as a dependency.
It then creates a LoginContext
by using the injected JAAS Configuration
.
This means that DefaultJaasAuthenticationProvider
is not bound to any particular implementation of Configuration
, as JaasAuthenticationProvider
is.
InMemoryConfiguration
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
instances.
InMemoryConfiguration
also supports a default Array
of AppConfigurationEntry
objects that is used if no mapping is found within the provided Map
.
For details, see the Javadoc of InMemoryConfiguration
.
DefaultJaasAuthenticationProvider Example Configuration
While the Spring configuration for InMemoryConfiguration
can be more verbose than the standard JAAS configuration files, using it in conjunction with DefaultJaasAuthenticationProvider
is more flexible than JaasAuthenticationProvider
, since it not dependent on the default Configuration
implementation.
The next example provides a configuration of DefaultJaasAuthenticationProvider
that uses InMemoryConfiguration
.
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>
JaasAuthenticationProvider
The JaasAuthenticationProvider
assumes that the default Configuration
is an instance of ConfigFile
.
This assumption is made in order to try to update the Configuration
.
The JaasAuthenticationProvider
then uses the default Configuration
to create the LoginContext
.
Assume that 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 through 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>
Running as a Subject
If configured, the JaasApiIntegrationFilter
tries to run as the Subject
on the JaasAuthenticationToken
.
This means that the Subject
can be accessed using:
Subject subject = Subject.getSubject(AccessController.getContext());
You can configure this integration by 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.