SEC-1178: New manual chapters

This commit is contained in:
Luke Taylor 2009-06-16 12:47:26 +00:00
parent c6b9371029
commit 67a90b36ee
4 changed files with 782 additions and 0 deletions

View File

@ -0,0 +1,54 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0"
xml:id="concurrent-sessions" xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Concurrent Session Handling</title>
</info>
<!-- TODO: Expand and refer to namespace options -->
<para>Spring Security is able to prevent a principal from concurrently authenticating to the
same application more than a specified number of times. Many ISVs take advantage of this to
enforce licensing, whilst network administrators like this feature because it helps prevent
people from sharing login names. You can, for example, stop user "Batman" from logging onto
the web application from two different sessions.</para>
<para>To use concurrent session support, you'll need to add the following to
<literal>web.xml</literal>: <programlisting><![CDATA[
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener> ]]>
</programlisting></para>
<para>In addition, you will need to add the
<literal>org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter</literal>
to your <classname>FilterChainProxy</classname>. The
<classname>ConcurrentSessionFilter</classname> requires two properties,
<literal>sessionRegistry</literal>, which generally points to an instance of
<literal>SessionRegistryImpl</literal>, and <literal>expiredUrl</literal>, which points to
the page to display when a session has expired.</para>
<para>The <literal>web.xml</literal>
<literal>HttpSessionEventPublisher</literal> causes an <literal>ApplicationEvent</literal> to
be published to the Spring <literal>ApplicationContext</literal> every time a
<literal>HttpSession</literal> commences or terminates. This is critical, as it allows the
<classname>SessionRegistryImpl</classname> to be notified when a session ends.</para>
<para>You will also need to wire up the <classname>ConcurrentSessionControllerImpl</classname>
and refer to it from your <literal>ProviderManager</literal> bean:</para>
<para>
<programlisting><![CDATA[
<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<!-- your providers go here -->
</property>
<property name="sessionController" ref="concurrentSessionController"/>
</bean>
<bean id="concurrentSessionController" class=
"org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl">
<property name="maximumSessions" value="1"/>
<property name="sessionRegistry">
<bean
class="org.springframework.security.authentication.concurrent.SessionRegistryImpl"/>
<property>
</bean>
]]></programlisting>
</para>
</chapter>

View File

@ -0,0 +1,307 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="core-web-filters"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Core Security Filters</title>
<para> There are some key filters which will always be used in a web application which uses
Spring Security, so we'll look at these and their supporting classes and interfaces them
first. We won't cover every feature, so be sure to look at the Javadoc for them if you want
to get the complete picture.</para>
<section xml:id="filter-security-interceptor">
<title><classname>FilterSecurityInterceptor</classname></title>
<para>We've already seen <classname>FilterSecurityInterceptor</classname> briefly when
discussing access-control in general (see<link xlink:href="#tech-intro-access-control"
/>), and we've already used it with the namespace where the
<literal>&lt;intercept-url></literal> elements are combined to configure it
internally. Now we'll see how to explicitly configure it for use with a
<classname>FilterChainProxy</classname>, along with its companion filter
<classname>ExceptionTranslationFilter</classname>. A typical configuration example
is shown below: <programlisting language="xml"><![CDATA[
<bean id="filterSecurityInterceptor"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource">
<security:filter-security-metadata-source>
<security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
<security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
</security:filter-security-metadata-source>
</property>
</bean>]]></programlisting></para>
<para><classname>FilterSecurityInterceptor</classname> is responsible for handling the
security of HTTP resources. It requires a reference to an
<interfacename>AuthenticationManager</interfacename> and an
<interfacename>AccessDecisionManager</interfacename>. It is also supplied with
configuration attributes that apply to different HTTP URL requests. Refer back to <link
xlink:href="#tech-intro-config-attributes"/> where we saw these originally.</para>
<para>The <classname>FilterSecurityInterceptor</classname> can be configured with
configuration attributes in two ways. The first, which is shown above, is using the
<literal>&lt;filter-security-metadata-source&gt;</literal> namespace element. This
is similar to the <literal>&lt;filter-chain-map&gt;</literal> used to configure a
<classname>FilterChainProxy</classname> but the
<literal>&lt;intercept-url&gt;</literal> child elements only use the
<literal>pattern</literal> and <literal>access</literal> attributes. Commas are used
to delimit the different configuration attributes that apply to each HTTP URL. The
second option is to write your own
<interfacename>SecurityMetadataSource</interfacename>, but this is beyond the scope of
this document. Irrespective of the approach used, the
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning a
<literal>List&lt;ConfigAttribute&gt;</literal> containing all of the configuration
attributes associated with a single secure HTTP URL.</para>
<para>It should be noted that the
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal> method
actually expects an instance of
<interfacename>FilterSecurityMetadataSource</interfacename>. This is a marker
interface which subclasses <interfacename>SecurityMetadataSource</interfacename>. It
simply denotes the <interfacename>SecurityMetadataSource</interfacename> understands
<classname>FilterInvocation</classname>s. In the interests of simplicity we'll
continue to refer to the <interfacename>FilterInvocationDefinitionSource</interfacename>
as a <interfacename>SecurityMetadataSource</interfacename>, as the distinction is of
little relevance to most users.</para>
<para>The <interfacename>SecurityMetadataSource</interfacename> created by the namespace
syntax obtains the configuration attributes for a particular
<classname>FilterInvocation</classname> by matching the request URL against the
configured <literal>pattern</literal> attributes. This behaves in the same way as it
does for namespace configuration. The default is to treat all expressions as Apache Ant
paths and regular expressions are also supported for more complex cases. The
<literal>path-type</literal> attribute is used to specify the type of pattern being
used. It is not possible to mix expression syntaxes within the same definition. As an
example, the previous configuration using regular expressions instead of Ant paths would
be written as follows:</para>
<programlisting language="xml"><![CDATA[
<bean id="filterInvocationInterceptor"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="runAsManager" ref="runAsManager"/>
<property name="securityMetadataSource">
<security:filter-security-metadata-source path-type="regex">
<security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
<security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
</security:filter-security-metadata-source>
</property>
</bean>]]> </programlisting>
<para>Patterns are always evaluated in the order they are defined. Thus it is important that
more specific patterns are defined higher in the list than less specific patterns. This
is reflected in our example above, where the more specific
<literal>/secure/super/</literal> pattern appears higher than the less specific
<literal>/secure/</literal> pattern. If they were reversed, the
<literal>/secure/</literal> pattern would always match and the
<literal>/secure/super/</literal> pattern would never be evaluated.</para>
<!--
TODO: Put in FAQ instead. Or drop.
<para>As with other security interceptors, the <literal>validateConfigAttributes</literal>
property is observed. When set to <literal>true</literal> (the default), at startup time
the <classname>FilterSecurityInterceptor</classname> will evaluate if the provided
configuration attributes are valid. It does this by checking each configuration
attribute can be processed by either the
<interfacename>AccessDecisionManager</interfacename> or the
<literal>RunAsManager</literal>. If neither of these can process a particular
configuration attribute, an exception is thrown.</para>
-->
</section>
<section xml:id="exception-translation-filter">
<title>
<classname>ExceptionTranslationFilter</classname></title>
<para>The <classname>ExceptionTranslationFilter</classname> sits above the <classname>FilterSecurityInterceptor</classname>
in the security filter stack. It doesn't do any actual security enforcement itself,
but handles exceptions thrown by the security interceptors and provides suitable
and HTTP responses.
<programlisting language="xml"><![CDATA[
<bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
<property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</bean>
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
</bean>
<bean id="accessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.htm"/>
</bean>
]]></programlisting>
</para>
<section xml:id="auth-entry-point">
<title><interfacename>AuthenticationEntryPoint</interfacename></title>
<para>
The <interfacename>AuthenticationEntryPoint</interfacename> will be
called if the user requests a secure HTTP resource but they are not authenticated. An
appropriate <exceptionname>AuthenticationException</exceptionname> or
<exceptionname>AccessDeniedException</exceptionname> will be thrown by a security
interceptor further down the call stack, triggering the
<methodname>commence</methodname> method on the entry point. This does the job of
presenting the appropriate response to the user so that authentication can begin. The
one we've used here is <classname>LoginUrlAuthenticationEntryPoint</classname>, which
redirects the request to a different URL (typically a login page). The actual
implementation used will depend on the authentication mechanism you want to be used in
your application. </para>
</section>
<section xml:id="access-denied-handler">
<title><interfacename>AccessDeniedHandler</interfacename></title>
<para>What happens if a user is already authenticated an they try to access a protected
resource? In normal usage, this shouldn't happen because the application workflow
should be restricted to operations to which a user has access. For example, an HTML
link to an administration page might be hidden from users who do not have an admin
role. You can't rely on hiding links for security though, as there's always a
possibility that a user will just enter the URL directly in an attempt to bypass the
restrictions. Or they might modify a RESTful URL to change some of the argument
values. Your application must be protected against these scenarios or it will
definitely be insecure. You will typically use simple web layer security to apply
constraints to basic URLs and use more specific method-based security on your
service layer interfaces to really nail down what is permissible.</para>
<para>If an <exceptionname>AccessDeniedException</exceptionname> is thrown and a user
has already been authenticated, then this means that an operation has been attempted
for which they don't have enough permissions. In this case,
<classname>ExceptionTranslationFilter</classname> will invoke a second strategy,
the <interfacename>AccessDeniedHandler</interfacename>. By default, an
<classname>AccessDeniedHandlerImpl</classname> is used, which just sends a 403 (Forbidden)
response to the client. Alternatively you can configure an instance explicitly (as in
the above example) and set an error page URL which it will forwards the request to
<footnote><para>We use a forward so that the SecurityContextHolder still contains details of the principal,
which may be useful for displaying to the user. In old releases of Spring Security we relied upon the servlet
container to handle a 403 error message, which lacked this useful contextual information.</para></footnote>.
This can be a simple <quote>access denied</quote> page, such as a JSP, or it could be
a more complex handler such as an MVC controller. And of course, you can implement the
interface yourself and use your own implementation.
</para>
<para>It's also possible to supply a custom <interfacename>AccessDeniedHandler</interfacename> when you're
using the namespace to configure your application. See <link xlink:href="#nsa-access-denied-handler"/>.</para>
</section>
<section xml:id="security-context-persistence-filter">
<title><classname>SecurityContextPersistenceFilter</classname></title>
<para>
We covered the purpose of this all-important filter in <link xlink:href="#tech-intro-sec-context-persistence"/> so
you might want to re-read that section at this point. Let's first take a look at how you would configure it
for use with a <classname>FilterChainProxy</classname>. A basic configuration only requires the bean itself
<programlisting><![CDATA[
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
]]></programlisting>
As we saw previously, this filter has two main tasks. It is responsible for storage of the <classname>SecurityContext</classname>
contents between HTTP requests and for clearing the <classname>SecurityContextHolder</classname> when a request is completed.
Clearing the <classname>ThreadLocal</classname> in which the context is stored is essential, as it might otherwise be possible for
a thread to be replaced into the servlet container's thread pool, with the security context for a particular user still
attached. This thread might then be used at a later stage, performing operations with the wrong credentials.
</para>
<section xml:id="security-context-repository">
<title><interfacename>SecurityContextRepository</interfacename></title>
<para>From Spring Security 3.0, the job of loading and storing the security context is now delegated
to a separate strategy interface:
<programlisting language="java">
public interface SecurityContextRepository {
SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);
void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response);
}
</programlisting>
The <classname>HttpRequestResponseHolder</classname> is simply a container for the incoming request and
response objects, allowing the implementation to replace these with wrapper classes. The
returned contents will be passed to the filter chain.
</para>
<para>
The default implementation is <classname>HttpSessionSecurityContextRepository</classname>, which
stores the security context as an <interfacename>HttpSession</interfacename> attribute
<footnote><para>In Spring Security 2.0 and earlier, this filter was called
<classname>HttpSessionContextIntegrationFilter</classname> and performed all the work of
storing the context was performed by the filter itself. If you were familiar with this class,
then most of the configuration options which were available can now be found on
<classname>HttpSessionSecurityContextRepository</classname>.
</para></footnote>.
The most important configuration parameter for this implementation is the
<literal>allowSessionCreation</literal> property, which defaults to <literal>true</literal>, thus
allowing the class to create a session if it needs one to store the security context for an authenticated
user (it won't create one unless authentication has taken place and the contents of the security context have changed).
If you don't want a session to be created, then you can set this property to <literal>false</literal>:
<programlisting language="xml"><![CDATA[
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='false' />
</bean>
</property>
</bean>
]]></programlisting>
Alternatively you could provide a null implementation of the <interfacename>SecurityContextRepository</interfacename> interface.
</para>
</section>
</section>
<section xml:id="form-login-filter">
<title><classname>UsernamePasswordAuthenticationProcessingFilter</classname></title>
<para>We've now seen the three main filters which are always present in a Spring Security web configuration. These
are also the three which are automatically created by the namespace <literal>&lt;http&gt;</literal> element and
cannot be substituted with alternatives. The only thing that's missing now is an actual authentication mechanism, something
that will allow a user to authenticate. This filter is the most commonly used authentication filter and the one
that is most often customized
<footnote><para>For historical reasons, prior to Spring Security 3.0, this filter was called
<classname>AuthenticationProcessingFilter</classname> and the entry point was called
<classname>AuthenticationProcessingFilterEntryPoint</classname>. Since the framework now supports
many different forms of authentication, they have both been given more specific names in 3.0.</para></footnote>.
It also provides the implementation used by the &lt;form-login&gt; element from the namespace.
There are three stages required to configure it.
<orderedlist>
<listitem><para>Configure a <classname>LoginUrlAuthenticationEntryPoint</classname> with the URL
of the login page, just as we did above, and set it on the <classname>ExceptionTranslationFilter</classname>.
</para>
</listitem>
<listitem><para>Implement the login page (using a JSP or MVC controller).</para></listitem>
<listitem><para>Configure an instance of <classname>UsernamePasswordAuthenticationProcessingFilter</classname> in the application context</para></listitem>
<listitem><para>Add the filter bean to your filter chain proxy (making sure you pay attention to the order). <!-- TODO: link --></para></listitem>
</orderedlist>
The login form simply contains <literal>j_username</literal> and
<literal>j_password</literal> input fields, and posts to the URL that is
monitored by the filter (by default this is <literal>/j_spring_security_check</literal>).
The basic filter configuration looks something like this:
<programlisting><![CDATA[
<bean id="authenticationProcessingFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean> ]]>
</programlisting>
</para>
<section xml:id="form-login-flow-handling">
<title>Application Flow on Authentication Success and Failure</title>
<para>
The filter calls the configured <interfacename>AuthenticationManager</interfacename>
processes each authentication request. The destination following a successful authentication
or an authentication failure is controlled by the <interfacename>AuthenticationSuccessHandler</interfacename>
and <interfacename>AuthenticationFailureHandler</interfacename> strategy interfaces, respectively.
The filter has properties which allow you to set these so you can customize the behaviour as
much as you want
<footnote><para>In versions prior to 3.0, the application flow at this point had evolved to a stage
was controlled by a mix of properties on this class and strategy plugins. The
decision was made for 3.0 to refactor the code to make these two strategies entirely responsible.
</para></footnote>.
Some standard implementations are supplied such as
<classname>SimpleUrlAuthenticationSuccessHandler</classname>,
<classname>SavedRequestAwareAuthenticationSuccessHandler</classname>,
<classname>SimpleUrlAuthenticationFailureHandler</classname> and
<classname>ExceptionMappingAuthenticationFailureHandler</classname>. Have a look at the Javadoc
for these classes to see how they work.
</para>
<para>If authentication is successful, the resulting
<interfacename>Authentication</interfacename> object will be placed into the
<classname>SecurityContextHolder</classname>.
The configured AuthenticationSuccessHandler will then be called to either redirect or forward
the user to the approprate destination. By default a <classname>SavedRequestAwareAuthenticationSuccessHandler</classname>
is used, which means that the user will be redirected to the original destination they requested before they were asked to
login.
<note>
<para>
The <classname>ExceptionTranslationFilter</classname> caches the original request a user makes.
When the user authenticates, the request handler makes use of this cached request to obtain the original
URL and redirect to it. The original request is then rebuilt and used as an alternative.
</para>
</note>
If authentication fails, the configured <interfacename>AuthenticationFailureHandler</interfacename> will be invoked.
</para>
</section>
</section>
</section>
</chapter>

View File

@ -0,0 +1,169 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="core-services"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Core Services</title>
<para> Now that we have a high-level overview of the Spring Security architecture and its core
classes, let's take a closer look at one or two of the core interfaces and their
implementations, in particular the <interfacename>AuthenticationManager</interfacename>,
<interfacename>UserDetailsService</interfacename> and the
<interfacename>AccessDecisionManager</interfacename>. These crop up regularly throughout
the remainder of this document so it's important you know how they are configured and how
they operate. </para>
<section xml:id="authentication-manager">
<title>The <interfacename>AuthenticationManager</interfacename>,
<classname>ProviderManager</classname> and
<classname>AuthenticationProvider</classname>s</title>
<para>The <interfacename>AuthenticationManager</interfacename> is just an interface, so the
implementation can be anything we choose, but how does it work in practice? What if we
need to check multiple authentication databases or a combination of different
authentication services such as a database and an LDAP server?</para>
<para>The default implementation in Spring Security is called
<classname>ProviderManager</classname> and rather than handling the authentication
request itself, it delegates to a list of configured
<classname>AuthenticationProvider</classname>s, each of which is queried in turn to
see if it can perform the authentication. Each provider will either throw an exception
or return a fully populated <interfacename>Authentication</interfacename> object.
Remember our good friends, <interfacename>UserDetails</interfacename> and
<interfacename>UserDetailsService</interfacename>? If not, head back to the previous
chapter and refresh your memory. The most common approach to verifying an authentication
request is to load the corresponding <interfacename>UserDetails</interfacename> and
check the loaded password against the one that has been entered by the user. This is the
approach used by the <classname>DaoAuthenticationProvider</classname>, which wraps a
<interfacename>UserDetailsService</interfacename> to implement an
<interfacename>AuthenticationProvider</interfacename>. The loaded
<interfacename>UserDetails</interfacename> object - and particularly the
<literal>GrantedAuthority</literal>s it contains - will be used when building the
fully populated <interfacename>Authentication</interfacename> object which is returned
from a successful authentication and stored in the
<classname>SecurityContext</classname>. </para>
<para> If you are using the namespace, an instance of
<classname>ProviderMananger</classname> is created and maintained internally, and
you add providers to it either by using the namespace authentication provired elements,
or by adding the <literal>&lt;custom-authentication-provider&gt;</literal> element to a
bean (see <link xlink:href="#ns-auth-manager">the namespace chapter</link>). In this
case, you should not declare a <classname>ProviderManager</classname> bean in your
application context. However, if you are not using the namespace then you would declare
it like so: <programlisting language="xml"><![CDATA[
<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
<ref local="anonymousAuthenticationProvider"/>
<ref local="ldapAuthenticationProvider"/>
</list>
</property>
</bean>]]></programlisting></para>
<para>In the above example we have three providers. They are tried in the order shown (which
is implied by the use of a <literal>List</literal>), with each provider able to attempt
authentication, or skip authentication by simply returning <literal>null</literal>. If
all implementations return null, the <literal>ProviderManager</literal> will throw a
<exceptionname>ProviderNotFoundException</exceptionname>. If you're interested in
learning more about chaining providers, please refer to the
<literal>ProviderManager</literal> JavaDocs.</para>
<para> Authentication mechanisms such as a web form-login processing filter are injected
with a reference to the <interfacename>ProviderManager</interfacename> and will call it
to handle their authentication requests. The providers you require will sometimes be
interchangeable with the authentication mechanisms, while at other times they will
depend on a specific authentication mechanism. For example,
<classname>DaoAuthenticationProvider</classname> and
<classname>LdapAuthenticationProvider</classname> are compatible with any mechanism
which submits a simple username/password authentication request and so will work with
form-based logins or HTTP Basic authentication. On the other hand, some authentication
mechanisms create an authentication request object which can only be interpreted by a
single type of <classname>AuthenticationProvider</classname>. An example of this would
be JA-SIG CAS, which uses the notion of a service ticket and so can therefore only be
authenticated by a <classname>CasAuthenticationProvider</classname>. You needn't be too
concerned about this, because if you forget to register a suitable provider, you'll
simply receive a <literal>ProviderNotFoundException</literal> when an attempt to
authenticate is made.</para>
</section>
<section>
<title><interfacename>UserDetailsService</interfacename> Implementations</title>
<para>As mentioned in the earlier in this reference guide, most authentication providers
take advantage of the <interfacename>UserDetails</interfacename> and
<interfacename>UserDetailsService</interfacename> interfaces. Recall that the
contract for <interfacename>UserDetailsService</interfacename> is a single
method:</para>
<para>
<programlisting>
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
</programlisting>
</para>
<para>The returned <interfacename>UserDetails</interfacename> is an interface that provides
getters that guarantee non-null provision of authentication information such as the
username, password, granted authorities and whether the user account is enabled or
disabled. Most authentication providers will use a
<interfacename>UserDetailsService</interfacename>, even if the username and password
are not actually used as part of the authentication decision. They may use the returned
<interfacename>UserDetails</interfacename> object just for its
<literal>GrantedAuthority</literal> information, because some other system (like
LDAP or X.509 or CAS etc) has undertaken the responsibility of actually validating the
credentials.</para>
<para>Given <interfacename>UserDetailsService</interfacename> is so simple to implement, it
should be easy for users to retrieve authentication information using a persistence
strategy of their choice. Having said that, Spring Security does include a couple of
useful base implementations, which we'll look at below.</para>
<section xml:id="in-memory-service">
<title>In-Memory Authentication</title>
<para>Is easy to use create a custom <interfacename>UserDetailsService</interfacename>
implementation that extracts information from a persistence engine of choice, but
many applications do not require such complexity. This is particularly true if
you're building a prototype application or just starting integrating Spring
Security, when you don't really want to spend time configuring databases or writing
<interfacename>UserDetailsService</interfacename> implementations. For this sort
of situation, a simple option is to use the <literal>user-service</literal> element
from the security <link xlink:href="#namespace-minimal">namespace</link>: <programlisting><![CDATA[
<user-service id="userDetailsService">
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
]]>
</programlisting> This also supports the use of an external properties
file: <programlisting><![CDATA[
<user-service id="userDetailsService" properties="users.properties"/>
]]></programlisting> The properties file should contain entries in the form
<programlisting>username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]</programlisting>
For example
<programlisting>
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled</programlisting></para>
</section>
<section xml:id="jdbc-service">
<title><literal>JdbcDaoImpl</literal></title>
<para>Spring Security also includes a <interfacename>UserDetailsService</interfacename>
that can obtain authentication information from a JDBC data source. Internally
Spring JDBC is used, so it avoids the complexity of a fully-featured object
relational mapper (ORM) just to store user details. If your application does use an
ORM tool, you might prefer to write a custom
<interfacename>UserDetailsService</interfacename> to reuse the mapping files
you've probably already created. Returning to <literal>JdbcDaoImpl</literal>, an
example configuration is shown below:</para>
<para>
<programlisting language="xml"><![CDATA[
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> ]]> </programlisting>
</para>
<para>You can use different relational database management systems by modifying the
<literal>DriverManagerDataSource</literal> shown above. You can also use a
global data source obtained from JNDI, as with any other Spring configuration. </para>
<!--
<para>If the default schema is unsuitable for your needs, <literal>JdbcDaoImpl</literal>
provides properties that allow customisation of the SQL statements. Please refer to the
JavaDocs for details, but note that the class is not intended for complex custom
subclasses. If you have a complex schema or would like a custom
<interfacename>UserDetails</interfacename> implementation returned, you'd be better off
writing your own <interfacename>UserDetailsService</interfacename>. The base
implementation provided with Spring Security is intended for typical situations, rather
than catering for all possible requirements.</para>
-->
</section>
</section>
</chapter>

View File

@ -0,0 +1,252 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Web Application Infrastructure</title>
</info>
<section xml:id="filters">
<title>The Security Filter Chain</title>
<para>Spring Security's web infrastructure is based entirely on standard servlet filters. It
doesn't use servlets or any other servlet-based frameworks (such as Spring MVC) internally, so
it has no strong links to any particular web technology. It deals in
<classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
and doesn't care whether the requests come from a browser, a web service client, an
<classname>HttpInvoker</classname> or an AJAX application. </para>
<para> Spring Security maintains a filter chain internally where each of the filters has a
particular responsibility and filters are added or removed from the configuration depending on
which services are required. The ordering of the filters is important as there are
dependencies between them. If you have been using <link xlink:href="#ns-config">namespace
configuration</link>, then the filters are automatically configured for you and you don't
have to define any Spring beans explicitly but here may be times when you want full control
over the security filter chain, either because you are using features which aren't supported
in the namespace, or you are using your own customized versions of classes.</para>
<section xml:id="delegating-filter-proxy">
<title><classname>DelegatingFilterProxy</classname></title>
<para> When using servlet filters, you obviously need to declare them in your
<filename>web.xml</filename>, or they will be ignored by the servlet container. In Spring
Security, the filter classes are also Spring beans defined in the application context and
thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle
interfaces. Spring's <classname>DelegatingFilterProxy</classname> provides the link between
<filename>web.xml</filename> and the application context. </para>
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like
this in the <filename>web.xml</filename> file: <programlisting><![CDATA[
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>]]>
</programlisting> Notice that the filter is actually a
<literal>DelegatingFilterProxy</literal>, and not the class that will actually implement
the logic of the filter. What <classname>DelegatingFilterProxy</classname> does is delegate
the <interfacename>Filter</interfacename>'s methods through to a bean which is obtained from
the Spring application context. This enables the bean to benefit from the Spring web
application context lifecycle support and configuration flexibility. The bean must implement
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that
in the <literal>filter-name</literal> element. Read the Javadoc for
<classname>DelegatingFilterProxy</classname> for more information</para>
</section>
<section xml:id="filter-chain-proxy">
<title><classname>FilterChainProxy</classname></title>
<para> It should now be clear that you can declare each Spring Security filter bean that you
require in your application context file and add a corresponding
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for
each filter, making sure that they are ordered correctly. This is a cumbersome approach and
clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We
would prefer to just add a single entry to <filename>web.xml</filename> and deal entirely
with the application context file for managing our web security beans. This is where Spring
Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a
<literal>DelegatingFilterProxy</literal>, just like in the example above, but with the
<literal>filter-name</literal> set to the bean name <quote>filterChainProxy</quote>. The
filter chain is then declared in the application context with the same bean name. Here's an
example: <programlisting language="xml"><![CDATA[
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters="
securityContextPersistenceFilterWithASCFalse,
basicProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
<sec:filter-chain pattern="/**" filters="
securityContextPersistenceFilterWithASCTrue,
authenticationProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
</sec:filter-chain-map>
</bean>
]]>
</programlisting> The namespace element <literal>filter-chain-map</literal> is
used to set up the security filter chain(s) which are required within the application<footnote>
<para>Note that you'll need to include the security namespace in your application context
XML file in order to use this syntax.</para>
</footnote>. It maps a particular URL pattern to a chain of filters built up from the bean
names specified in the <literal>filters</literal> element. Both regular expressions and Ant
Paths are supported, and the most specific URIs appear first. At runtime the
<classname>FilterChainProxy</classname> will locate the first URI pattern that matches the
current web request and the list of filter beans specified by the <literal>filters</literal>
attribute will be applied to that request. The filters will be invoked in the order they are
defined, so you have complete control over the filter chain which is applied to a particular
URL.</para>
<para>You may have noticed we have declared two
<classname>SecurityContextPersistenceFilter</classname>s in the filter chain
(<literal>ASC</literal> is short for <literal>allowSessionCreation</literal>, a property
of <classname>SecurityContextPersistenceFilter</classname>). As web services will never
present a <literal>jsessionid</literal> on future requests, creating
<literal>HttpSession</literal>s for such user agents would be wasteful. If you had a
high-volume application which required maximum scalability, we recommend you use the
approach shown above. For smaller applications, using a single
<classname>SecurityContextPersistenceFilter</classname> (with its default
<literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
sufficient.</para>
<para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will always
delegate <methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
methods through to the underlaying <interfacename>Filter</interfacename>s if such methods
are called against <classname>FilterChainProxy</classname> itself. In this case,
<classname>FilterChainProxy</classname> guarantees to only initialize and destroy each
<literal>Filter</literal> bean once, no matter how many times it is declared in the filter
chain(s). You control the overall choice as to whether these methods are called or not via
the <literal>targetFilterLifecycle</literal> initialization parameter of
<literal>DelegatingFilterProxy</literal>. By default this property is
<literal>false</literal> and servlet container lifecycle invocations are not delegated
through <literal>DelegatingFilterProxy</literal>.</para>
<para> When we looked at how to set up web security using <link
xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
<literal>DelegatingFilterProxy</literal> with the name
<quote>springSecurityFilterChain</quote>. You should now be able to see that this is the
name of the <classname>FilterChainProxy</classname> which is created by the namespace. </para>
<section>
<title>Bypassing the Filter Chain</title>
<para> As with the namespace, you can use the attribute <literal>filters = "none"</literal>
as an alternative to supplying a filter bean list. This will omit the request pattern from
the security filter chain entirely. Note that anything matching this path will then have
no authentication or authorization services applied and will be freely accessible. If you
want to make use of the contents of the <classname>SecurityContext</classname> contents
during a request, then it must have passed through the security filter chain. Otherwise
the <classname>SecurityContextHolder</classname> will not have been populated and the
contents will be null.</para>
</section>
</section>
<section>
<title>Filter Ordering</title>
<para>The order that filters are defined in the chain is very important. Irrespective of which
filters you are actually using, the order should be as follows:
<orderedlist>
<listitem>
<para><classname>ChannelProcessingFilter</classname>, because it might need to redirect
to a different protocol</para>
</listitem>
<listitem>
<para><classname>ConcurrentSessionFilter</classname>, because it doesn't use any
<classname>SecurityContextHolder</classname> functionality but needs to update the
<interfacename>SessionRegistry</interfacename> to reflect ongoing requests from the
principal</para>
</listitem>
<listitem>
<para><classname>SecurityContextPersistenceFilter</classname>, so a
<interfacename>SecurityContext</interfacename> can be set up in the
<classname>SecurityContextHolder</classname> at the beginning of a web request, and
any changes to the <interfacename>SecurityContext</interfacename> can be copied to the
<literal>HttpSession</literal> when the web request ends (ready for use with the
next web request)</para>
</listitem>
<listitem>
<para>Authentication processing mechanisms -
<classname>UsernamePasswordAuthenticationProcessingFilter</classname>,
<classname>CasProcessingFilter</classname>,
<classname>BasicProcessingFilter</classname> etc - so that the
<classname>SecurityContextHolder</classname> can be modified to contain a valid
<interfacename>Authentication</interfacename> request token</para>
</listitem>
<listitem>
<para>The <literal>SecurityContextHolderAwareRequestFilter</literal>, if you are using
it to install a Spring Security aware <literal>HttpServletRequestWrapper</literal>
into your servlet container</para>
</listitem>
<listitem>
<para><classname>RememberMeProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, and the request presents a cookie that
enables remember-me services to take place, a suitable remembered
<interfacename>Authentication</interfacename> object will be put there</para>
</listitem>
<listitem>
<para><classname>AnonymousProcessingFilter</classname>, so that if no earlier
authentication processing mechanism updated the
<classname>SecurityContextHolder</classname>, an anonymous
<interfacename>Authentication</interfacename> object will be put there</para>
</listitem>
<listitem>
<para><classname>ExceptionTranslationFilter</classname>, to catch any Spring Security
exceptions so that either an HTTP error response can be returned or an appropriate
<interfacename>AuthenticationEntryPoint</interfacename> can be launched</para>
</listitem>
<listitem>
<para><classname>FilterSecurityInterceptor</classname>, to protect web URIs and raise
exceptions when access is denied</para>
</listitem>
</orderedlist></para>
</section>
<section>
<title>Use with other Filter-Based Frameworks</title>
<para>If you're using some other framework that is also filter-based, then you need to make
sure that the Spring Security filters come first. This enables the
<classname>SecurityContextHolder</classname> to be populated in time for use by the other
filters. Examples are the use of SiteMesh to decorate your web pages or a web framework like
Wicket which uses a filter to handle its requests. </para>
</section>
</section>
<!--
<section xml:id="taglib">
<info>
<title>Tag Libraries</title>
</info>
<para>Spring Security comes bundled with several JSP tag libraries which provide a range of
different services.</para>
<section xml:id="taglib-config">
<info>
<title>Configuration</title>
</info>
<para>All taglib classes are included in the core
<literal>spring-security-taglibs-&lt;version>.jar</literal> file, with the
<literal>security.tld</literal> located in the JAR's <literal>META-INF</literal>
directory. This means for JSP 1.2+ web containers you can simply include the JAR in the
WAR's <literal>WEB-INF/lib</literal> directory and it will be available.</para>
</section>
<section xml:id="taglib-usage">
<info>
<title>Usage</title>
</info>
<para>Now that you've configured the tag libraries, refer to the individual reference guide
sections for details on how to use them. Note that when using the tags, you should include
the taglib reference in your JSP:
<programlisting>
&lt;%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %&gt;
</programlisting></para>
</section>
</section>
<section xml:id="authentication-taglibs">
<info>
<title>Authentication Tag Libraries</title>
</info>
<para><literal>AuthenticationTag</literal> is used to simply output a property of the current
<interfacename>Authentication</interfacename> object to the web page.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AuthenticationTag</literal>:</para>
<para>
<programlisting>&lt;security:authentication property="principal.username"/&gt;</programlisting>
</para>
<para>This tag would cause the principal's name to be output. Here we are assuming the
<literal>Authentication.getPrincipal()</literal> is a
<interfacename>UserDetails</interfacename> object, which is generally the case when using
one of Spring Security's stadard <classname>AuthenticationProvider</classname>
implementations.</para>
</section>
-->
</chapter>