123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- <?xml version="1.0" encoding="UTF-8"?>
- <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="preauth"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <info>
- <title>Pre-Authentication Scenarios</title>
- </info>
- <para> 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 <quote>pre-authenticated</quote> scenarios.
- Examples include X.509, Siteminder and authentication by the J2EE container in which the
- application is running. When using pre-authentication, Spring Security has to <orderedlist>
- <listitem>
- <para>Identify the user making the request. </para>
- </listitem>
- <listitem>
- <para>Obtain the authorities for the user.</para>
- </listitem>
- </orderedlist>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 <methodname>getUserPrincipal()</methodname> 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 <interfacename>UserDetailsService</interfacename>. </para>
- <section>
- <title>Pre-Authentication Framework Classes</title>
- <para> 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 <link linkend="x509">X.509 authentication</link>, 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
- <package>org.springframework.security.web.authentication.preauth</package>. We just
- provide an outline here so you should consult the Javadoc and source where appropriate. </para>
- <section>
- <title>AbstractPreAuthenticatedProcessingFilter</title>
- <para> 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 <interfacename>AuthenticationManager</interfacename>. Subclasses override the
- following methods to obtain this information:
- <programlisting language="java">
- protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
- protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
- </programlisting>
- After calling these, the filter will create a
- <classname>PreAuthenticatedAuthenticationToken</classname> containing the returned
- data and submit it for authentication. By <quote>authentication</quote> here, we
- really just mean further processing to perhaps load the user's authorities, but the
- standard Spring Security authentication architecture is followed. </para>
- <para> Like other Spring Security authentication filters, the pre-authentication filter
- has an <literal>authenticationDetailsSource</literal> property which by default will
- create a <classname>WebAuthenticationDetails</classname> object to store additional
- information such as the session-identifier and originating IP address in the
- <literal>details</literal> property of the
- <interfacename>Authentication</interfacename> 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
- <interfacename>GrantedAuthoritiesContainer</interfacename> 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. </para>
- <section xml:id="j2ee-preauth-details">
- <title>J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource</title>
- <para> If the filter is configured with an
- <literal>authenticationDetailsSource</literal> which is an instance of this
- class, the authority information is obtained by calling the
- <methodname>isUserInRole(String role)</methodname> method for each of a
- pre-determined set of <quote>mappable roles</quote>. The class gets these from a
- configured <interfacename>MappableAttributesRetriever</interfacename>. Possible
- implementations include hard-coding a list in the application context and
- reading the role information from the <literal><security-role></literal>
- information in a <filename>web.xml</filename> file. The pre-authentication
- sample application uses the latter approach.</para>
- <para>There is an additional stage where the roles (or attributes) are mapped to
- Spring Security <interfacename>GrantedAuthority</interfacename> objects using a
- configured <interfacename>Attributes2GrantedAuthoritiesMapper</interfacename>.
- The default will just add the usual <literal>ROLE_</literal> prefix to the
- names, but it gives you full control over the behaviour. </para>
- </section>
- </section>
- <section>
- <title>PreAuthenticatedAuthenticationProvider</title>
- <para> The pre-authenticated provider has little more to do than load the
- <interfacename>UserDetails</interfacename> object for the user. It does this by
- delegating to a <interfacename>AuthenticationUserDetailsService</interfacename>. The
- latter is similar to the standard <interfacename>UserDetailsService</interfacename>
- but takes an <interfacename>Authentication</interfacename> object rather than just
- user name:
- <programlisting language="java">
- public interface AuthenticationUserDetailsService {
- UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
- }
- </programlisting>
- This interface may have also other uses but with pre-authentication it allows access
- to the authorities which were packaged in the
- <interfacename>Authentication</interfacename> object, as we saw in the previous
- section. The
- <classname>PreAuthenticatedGrantedAuthoritiesUserDetailsService</classname> class
- does this. Alternatively, it may delegate to a standard
- <interfacename>UserDetailsService</interfacename> via the
- <classname>UserDetailsByNameServiceWrapper</classname> implementation. </para>
- </section>
- <section>
- <title>Http403ForbiddenEntryPoint</title>
- <para> The <interfacename>AuthenticationEntryPoint</interfacename> was discussed in the
- <link linkend="tech-intro-auth-entry-point">technical overview</link> chapter.
- Normally it 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
- <classname>ExceptionTranslationFilter</classname> 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
- <classname>AbstractPreAuthenticatedProcessingFilter</classname> resulting in a null
- authentication. It always returns a <literal>403</literal>-forbidden response code
- if called. </para>
- </section>
- </section>
- <section>
- <title>Concrete Implementations</title>
- <para> X.509 authentication is covered in its <link linkend="x509">own chapter</link>.
- Here we'll look at some classes which provide support for other pre-authenticated
- scenarios. </para>
- <section>
- <title>Request-Header Authentication (Siteminder)</title>
- <para> 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 <literal>SM_USER</literal>.
- This mechanism is supported by the class
- <classname>RequestHeaderAuthenticationFilter</classname> which simply extracts the
- username from the header. It defaults to using the name <literal>SM_USER</literal>
- as the header name. See the Javadoc for more details. </para>
- <tip>
- <para>Note that when using a system like this, the framework performs no
- authentication checks at all and it is <emphasis>extremely</emphasis> 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. </para>
- </tip>
- <section>
- <title>Siteminder Example Configuration</title>
- <para> A typical configuration using this filter would look like this: <programlisting language="xml"><![CDATA[
- <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>
- ]]>
- </programlisting> We've assumed here that the <link linkend="ns-config">security namespace</link>
- is being used for configuration. It's also assumed that you have added a
- <interfacename>UserDetailsService</interfacename> (called
- <quote>userDetailsService</quote>) to your configuration to load the user's
- roles. </para>
- </section>
- </section>
- <section>
- <title>J2EE Container Authentication</title>
- <para> The class <classname>J2eePreAuthenticatedProcessingFilter</classname> will
- extract the username from the <literal>userPrincipal</literal> property of the
- <interfacename>HttpServletRequest</interfacename>. Use of this filter would usually
- be combined with the use of J2EE roles as described above in <xref
- linkend="j2ee-preauth-details"/>. </para>
- <para> There is a sample application in the codebase which uses this approach, so get
- hold of the code from subversion and have a look at the application context file if
- you are interested. The code is in the <filename>samples/preauth</filename>
- directory. </para>
- </section>
- </section>
- </chapter>
|