Examples include X.509, Siteminder, and authentication by the Java EE container in which the application runs. When using pre-authentication, Spring Security must:
Identify the user making the request.
Obtain permissions for the user.
The details will depend on the external authentication mechanism. The user can be identified by their
certificate information in the case of X.509, or by the HTTP request header in the case of Siteminder. If you rely
on container authentication, the user will be identified by calling the getUserPrincipal()
method on
the incoming HTTP request. In some cases, an external mechanism can provide information about the user's
role/permissions, but in other cases, permissions must be obtained from a separate source, such as UserDetailsService
.
Pre-authentication framework classes
Since most pre-authentication mechanisms follow the same pattern,
Spring Security contains a set of classes that provide a back-end framework for implementing pre-authentication
providers. This allows you to eliminate duplication and add new implementations in a structured way, without having
to write everything from scratch. You don't need to know anything about these classes if you want to use something
like X.509-based authentication, since it already provides a namespace configuration option that is easier to use
and easier to get started with. If you need to use explicit bean configuration or plan to write your own
implementation, then understanding how passed-in implementations work will be helpful. You can find the classes in
org.springframework.security.web.authentication.preauth
. We'll only give a general description here, so
you should refer to the Javadoc and sources whenever needed.
AbstractPreAuthenticatedProcessingFilter
This class checks the current contents of the security context and, if empty, attempts to retrieve user information
from the HTTP request and pass it to AuthenticationManager
. Subclasses override the following methods
to obtain this information:
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
protected abstract fun getPreAuthenticatedPrincipal(request: HttpServletRequest): Any?
protected abstract fun getPreAuthenticatedCredentials(request: HttpServletRequest): Any?
After calling them, the filter will create a PreAuthenticatedAuthenticationToken
containing returned data, and will send it for authentication. By "authentication" here we really only mean further
processing to possibly load the user's credentials, but while respecting the standard Spring Security authentication
architecture.
Like other Spring Security authentication filters, the pre-authentication filter has a authenticationDetailsSource
,
which by default creates a WebAuthenticationDetails
object to store additional information, such as the
session ID and source IP address, in the details
property of the Authentication
object.
In cases where user role information can be obtained from a pre-authentication mechanism, this information will also
be stored in this property, taking into account information that implements the
GrantedAuthoritiesContainer
interface. This allows the authentication provider to read the credentials
that have been allocated to the user externally. We'll look at a specific example next.
J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
If the filter is configured with an authenticationDetailsSource
that is an instance of this class, the credentials information is obtained by calling the isUserInRole(String
role)
for each "mapped role" from a predefined set. The class receives them from the configured MappableAttributesRetriever
.
Possible implementations include hard-coding the list in the application context and reading the role information
from the information in the <security-role>
section of the web.xml
file. The sample
pre-authentication application uses the latter approach.
There is an additional step where roles (or
attributes) are mapped to GrantedAuthority
objects from Spring Security via a configured Attributes2GrantedAuthoritiesMapper
.
By default, names are simply prefixed with the usual ROLE_
prefix, but this gives full control
over the operating logic.
PreAuthenticatedAuthenticationProvider
The pre-authenticated provider only
needs to load UserDetails
object for the user. It does this by delegating authority to the AuthenticationUserDetailsService
service. The latter is similar to the standard UserDetailsService
, but accepts a
Authentication
object rather than just a username:
public interface AuthenticationUserDetailsService {
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
}
This interface may have other uses, but when pre-authenticated, it allows access to the credentials that have
been packaged in the Authentication
, which could be observed in the previous section. This is
done by the PreAuthenticatedGrantedAuthoritiesUserDetailsService
class. Alternatively, it can delegate
authority to the standard UserDetailsService
through the UserDetailsByNameServiceWrapper
implementation.
Http403ForbiddenEntryPoint
AuthenticationEntryPoint
is responsible for
starting the authentication process for an unauthenticated user (if he is trying to access a protected resource),
but does not apply in the case of pre-authentication. You can configure ExceptionTranslationFilter
using an instance of this class only if you are not using pre-authentication in combination with other
authentication mechanisms. It will be called if the user is rejected by AbstractPreAuthenticatedProcessingFilter
,
resulting in null authentication. Calling it always returns a response code of 403-forbidden
.
Specific implementations
X.509-based authentication is described in a separate chapter. Here we'll look at some classes that provide support for other pre-authentication scenarios.
Request Header Authentication (Siteminder)
An external authentication system can pass information to the application by setting certain
headers in the HTTP request . A good example of such a system is Siteminder, which passes the username in the SM_USER
header. This mechanism is supported by the RequestHeaderAuthenticationFilter
class, which simply
extracts the username from the header. By default, the header name is SM_USER
. For more information,
see javadoc
.
Note that when using a system like this, the framework does not perform any There are no authentication checks, so it is critical that the external system is properly configured to protect any access to the application. If an attacker can forge the headers in the original request in such a way that it cannot be detected, then he can choose any username at his discretion.
Example configuration using Siteminder
A typical configuration using this filter looks like this:
<security:http>
<!-- Additional http configuration omitted -->
<security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
</security:http>
<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>
Here we have assumed that the security namespace is used for configuration. It also assumes that UserDetailsService
has been added (named "userDetailsService") to the configuration to load user roles.
Java EE Container Level Authentication
Class The J2eePreAuthenticatedProcessingFilter
will retrieve the username from
the userPrincipal
property for the HttpServletRequest
. The use of this filter is typically
combined with the use of Java EE roles, as described above in the
J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource subsection.
The sample project has sample app that uses this approach, so grab the code from GitHub and look at the app context file if you're interested.
GO TO FULL VERSION