151 lines
9.2 KiB
Plaintext
151 lines
9.2 KiB
Plaintext
[[servlet-preauth]]
|
|
== Pre-Authentication Scenarios
|
|
There are situations where you want to use Spring Security for authorization, but the user has already been reliably authenticated by some external system prior to accessing the application.
|
|
We refer to these situations as "pre-authenticated" scenarios.
|
|
Examples include X.509, Siteminder and authentication by the Java EE container in which the application is running.
|
|
When using pre-authentication, Spring Security has to
|
|
|
|
* Identify the user making the request.
|
|
|
|
* Obtain the authorities for the user.
|
|
|
|
|
|
The details will depend on the external authentication mechanism.
|
|
A user might be identified by their certificate information in the case of X.509, or by an HTTP request header in the case of Siteminder.
|
|
If relying on container authentication, the user will be identified by calling the `getUserPrincipal()` method on the incoming HTTP request.
|
|
In some cases, the external mechanism may supply role/authority information for the user but in others the authorities must be obtained from a separate source, such as a `UserDetailsService`.
|
|
|
|
|
|
=== Pre-Authentication Framework Classes
|
|
Because most pre-authentication mechanisms follow the same pattern, Spring Security has a set of classes which provide an internal framework for implementing pre-authenticated authentication providers.
|
|
This removes duplication and allows new implementations to be added in a structured fashion, without having to write everything from scratch.
|
|
You don't need to know about these classes if you want to use something like <<servlet-x509,X.509 authentication>>, as it already has a namespace configuration option which is simpler to use and get started with.
|
|
If you need to use explicit bean configuration or are planning on writing your own implementation then an understanding of how the provided implementations work will be useful.
|
|
You will find classes under the `org.springframework.security.web.authentication.preauth`.
|
|
We just provide an outline here so you should consult the Javadoc and source where appropriate.
|
|
|
|
|
|
==== AbstractPreAuthenticatedProcessingFilter
|
|
This class will check the current contents of the security context and, if empty, it will attempt to extract user information from the HTTP request and submit it to the `AuthenticationManager`.
|
|
Subclasses override the following methods to obtain this information:
|
|
|
|
.Override AbstractPreAuthenticatedProcessingFilter
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
|
|
|
|
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
protected abstract fun getPreAuthenticatedPrincipal(request: HttpServletRequest): Any?
|
|
|
|
protected abstract fun getPreAuthenticatedCredentials(request: HttpServletRequest): Any?
|
|
----
|
|
====
|
|
|
|
|
|
After calling these, the filter will create a `PreAuthenticatedAuthenticationToken` containing the returned data and submit it for authentication.
|
|
By "authentication" here, we really just mean further processing to perhaps load the user's authorities, but the standard Spring Security authentication architecture is followed.
|
|
|
|
Like other Spring Security authentication filters, the pre-authentication filter has an `authenticationDetailsSource` property which by default will create a `WebAuthenticationDetails` object to store additional information such as the session-identifier and originating IP address in the `details` property of the `Authentication` object.
|
|
In cases where user role information can be obtained from the pre-authentication mechanism, the data is also stored in this property, with the details implementing the `GrantedAuthoritiesContainer` interface.
|
|
This enables the authentication provider to read the authorities which were externally allocated to the user.
|
|
We'll look at a concrete example next.
|
|
|
|
|
|
[[j2ee-preauth-details]]
|
|
===== J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
|
If the filter is configured with an `authenticationDetailsSource` which is an instance of this class, the authority information is obtained by calling the `isUserInRole(String role)` method for each of a pre-determined set of "mappable roles".
|
|
The class gets these from a configured `MappableAttributesRetriever`.
|
|
Possible implementations include hard-coding a list in the application context and reading the role information from the `<security-role>` information in a `web.xml` file.
|
|
The pre-authentication sample application uses the latter approach.
|
|
|
|
There is an additional stage where the roles (or attributes) are mapped to Spring Security `GrantedAuthority` objects using a configured `Attributes2GrantedAuthoritiesMapper`.
|
|
The default will just add the usual `ROLE_` prefix to the names, but it gives you full control over the behaviour.
|
|
|
|
|
|
==== PreAuthenticatedAuthenticationProvider
|
|
The pre-authenticated provider has little more to do than load the `UserDetails` object for the user.
|
|
It does this by delegating to an `AuthenticationUserDetailsService`.
|
|
The latter is similar to the standard `UserDetailsService` but takes an `Authentication` object rather than just user name:
|
|
|
|
[source,java]
|
|
----
|
|
public interface AuthenticationUserDetailsService {
|
|
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
|
|
}
|
|
----
|
|
|
|
This interface may have also other uses but with pre-authentication it allows access to the authorities which were packaged in the `Authentication` object, as we saw in the previous section.
|
|
The `PreAuthenticatedGrantedAuthoritiesUserDetailsService` class does this.
|
|
Alternatively, it may delegate to a standard `UserDetailsService` via the `UserDetailsByNameServiceWrapper` implementation.
|
|
|
|
==== Http403ForbiddenEntryPoint
|
|
The <<servlet-authentication-authenticationentrypoint,`AuthenticationEntryPoint`>> is responsible for kick-starting the authentication process for an unauthenticated user (when they try to access a protected resource), but in the pre-authenticated case this doesn't apply.
|
|
You would only configure the `ExceptionTranslationFilter` with an instance of this class if you aren't using pre-authentication in combination with other authentication mechanisms.
|
|
It will be called if the user is rejected by the `AbstractPreAuthenticatedProcessingFilter` resulting in a null authentication.
|
|
It always returns a `403`-forbidden response code if called.
|
|
|
|
|
|
=== Concrete Implementations
|
|
X.509 authentication is covered in its <<servlet-x509,own chapter>>.
|
|
Here we'll look at some classes which provide support for other pre-authenticated scenarios.
|
|
|
|
|
|
==== Request-Header Authentication (Siteminder)
|
|
An external authentication system may supply information to the application by setting specific headers on the HTTP request.
|
|
A well-known example of this is Siteminder, which passes the username in a header called `SM_USER`.
|
|
This mechanism is supported by the class `RequestHeaderAuthenticationFilter` which simply extracts the username from the header.
|
|
It defaults to using the name `SM_USER` as the header name.
|
|
See the Javadoc for more details.
|
|
|
|
[TIP]
|
|
====
|
|
Note that when using a system like this, the framework performs no authentication checks at all and it is __extremely__ important that the external system is configured properly and protects all access to the application.
|
|
If an attacker is able to forge the headers in their original request without this being detected then they could potentially choose any username they wished.
|
|
====
|
|
|
|
===== Siteminder Example Configuration
|
|
A typical configuration using this filter would look like this:
|
|
|
|
[source,xml]
|
|
----
|
|
<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>
|
|
----
|
|
|
|
We've assumed here that the <<ns-config,security namespace>> is being used for configuration.
|
|
It's also assumed that you have added a `UserDetailsService` (called "userDetailsService") to your configuration to load the user's roles.
|
|
|
|
|
|
==== Java EE Container Authentication
|
|
The class `J2eePreAuthenticatedProcessingFilter` will extract the username from the `userPrincipal` property of the `HttpServletRequest`.
|
|
Use of this filter would usually be combined with the use of Java EE roles as described above in <<j2ee-preauth-details>>.
|
|
|
|
There is a {gh-old-samples-url}/xml/preauth[sample application] in the samples project which uses this approach, so get hold of the code from GitHub and have a look at the application context file if you are interested.
|