123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- <?xml version="1.0" encoding="UTF-8"?>
- <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="ns-config"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <info>
- <title>Security Namespace Configuration</title>
- </info>
- <section>
- <title>Introduction</title>
- <para> Namespace configuration has been available since version 2.0 of the Spring framework. It
- allows you to supplement the traditional Spring beans application context syntax with elements
- from additional XML schema. You can find more information in the Spring <link
- xlink:href="http://static.springframework.org/spring/docs/2.5.x/reference/xsd-config.html">
- Reference Documentation</link>. A namespace element can be used simply to allow a more
- concise way of configuring an individual bean or, more powerfully, to define an alternative
- configuration syntax which more closely matches the problem domain and hides the underlying
- complexity from the user. A simple element may conceal the fact that multiple beans and
- processing steps are being added to the application context. For example, adding the following
- element from the security namespace to an application context will start up an embedded LDAP
- server for testing use within the application: <programlisting><![CDATA[
- <security:ldap-server />
- ]]></programlisting> This is much simpler than wiring up the equivalent Apache Directory Server
- beans. The most common alternative configuration requirements are supported by attributes on
- the <literal>ldap-server</literal> element and the user is isolated from worrying about which
- beans they need create and what the bean property names are. <footnote><para>You can find out
- more about the use of the <literal>ldap-server</literal> element in the chapter on <link
- xlink:href="#ldap">LDAP</link>.</para></footnote>. Use of a good XML editor while
- editing the application context file should provide information on the attributes and elements
- that are available. We would recommend that you try out the <link
- xlink:href="http://www.springsource.com/products/sts">SpringSource Tool Suite</link> as it
- has special features for working with standard Spring namespaces. </para>
- <para> To start using the security namespace in your application context, all you need to do is
- add the schema declaration to your application context file: <programlisting language="xml">
- <![CDATA[
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:security="http://www.springframework.org/schema/security"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/security
- http://www.springframework.org/schema/security/spring-security-3.0.xsd">
- ...
- </beans>
- ]]></programlisting> In many of the examples you will see (and in the sample) applications, we
- will often use "security" as the default namespace rather than "beans", which means we can
- omit the prefix on all the security namespace elements, making the content easier to read. You
- may also want to do this if you have your application context divided up into separate files
- and have most of your security configuration in one of them. Your security application context
- file would then start like this <programlisting language="xml"><![CDATA[
- <beans:beans xmlns="http://www.springframework.org/schema/security"
- xmlns:beans="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/security
- http://www.springframework.org/schema/security/spring-security-3.0.xsd">
- ...
- </beans:beans>
- ]]></programlisting> We'll assume this syntax is being used from now on in this chapter. </para>
- <section>
- <title>Design of the Namespace</title>
- <para> The namespace is designed to capture the most common uses of the framework and provide
- a simplified and concise syntax for enabling them within an application. The design is based
- around the large-scale dependencies within the framework, and can be divided up into the
- following areas: <itemizedlist><listitem><para>
- <emphasis>Web/HTTP Security</emphasis> - the most complex part. Sets up the filters
- and related service beans used to apply the framework authentication mechanisms, to
- secure URLs, render login and error pages and much
- more.</para></listitem><listitem><para>
- <emphasis>Business Object (Method) Security</emphasis> - options for securing the
- service layer.</para></listitem><listitem><para>
- <emphasis>AuthenticationManager</emphasis> - handles authentication requests from
- other parts of the framework.</para></listitem><listitem><para>
- <emphasis>AccessDecisionManager</emphasis> - provides access decisions for web and
- method security. A default one will be registered, but you can also choose to use a
- custom one, declared using normal Spring bean
- syntax.</para></listitem><listitem><para>
- <emphasis>AuthenticationProvider</emphasis>s - mechanisms against which the
- authentication manager authenticates users. The namespace provides supports for
- several standard options and also a means of adding custom beans declared using a
- traditional syntax. </para></listitem><listitem><para>
- <emphasis>UserDetailsService</emphasis> - closely related to authentication providers,
- but often also required by other beans.</para></listitem>
- <!-- todo: diagram and link to other sections which describe the interfaces -->
- </itemizedlist></para>
- <para>We'll see how these work together in the following sections.</para>
- </section>
- </section>
- <section xml:id="ns-getting-started">
- <title>Getting Started with Security Namespace Configuration</title>
- <para> In this section, we'll look at how you can build up a namespace configuration to use some
- of the main features of the framework. Let's assume you initially want to get up and running
- as quickly as possible and add authentication support and access control to an existing web
- application, with a few test logins. Then we'll look at how to change over to authenticating
- against a database or other security information repository. In later sections we'll introduce
- more advanced namespace configuration options. </para>
- <section xml:id="ns-web-xml">
- <title><literal>web.xml</literal> Configuration</title>
- <para> The first thing you need to do is add the following filter declaration to your
- <literal>web.xml</literal> file: <programlisting language="xml"><![CDATA[
- <filter>
- <filter-name>springSecurityFilterChain</filter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- </filter>
-
- <filter-mapping>
- <filter-name>springSecurityFilterChain</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>]]>
- </programlisting> This provides a hook into the Spring Security web
- infrastructure. <classname>DelegatingFilterProxy</classname> is a Spring Framework class
- which delegates to a filter implementation which is defined as a Spring bean in your
- application context. In this case, the bean is named
- <quote>springSecurityFilterChain</quote>, which is an internal infrastructure bean created
- by the namespace to handle web security. Note that you should not use this bean name
- yourself. Once you've added this to your <filename>web.xml</filename>, you're ready to start
- editing your application context file. Web security services are configured using the
- <literal><http></literal> element. </para>
- </section>
- <section xml:id="ns-minimal">
- <title>A Minimal <literal><http></literal> Configuration</title>
- <para> All you need to enable web security to begin with is <programlisting language="xml"><![CDATA[
- <http auto-config='true'>
- <intercept-url pattern="/**" access="ROLE_USER" />
- </http>
- ]]>
- </programlisting> Which says that we want all URLs within our application to be secured,
- requiring the role <literal>ROLE_USER</literal> to access them.</para>
- <note>
- <para>You can use multiple <literal><intercept-url></literal> elements to define
- different access requirements for different sets of URLs, but they will be evaluated in
- the order listed and the first match will be used. So you must put the most specific
- matches at the top.</para>
- </note>
- <para> To add some users, you can define a set of test data directly in the namespace: <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider>
- <user-service>
- <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
- <user name="bob" password="bobspassword" authorities="ROLE_USER" />
- </user-service>
- </authentication-provider>
- </authentication-manager>
- ]]>
- </programlisting></para>
- <sidebar>
- <para>If you are familiar with pre-namespace versions of the framework, you can probably
- already guess roughly what's going on here. The <http> element is responsible for
- creating a <classname>FilterChainProxy</classname> and the filter beans which it uses.
- Common issues like incorrect filter ordering are no longer an issue as the filter
- positions are predefined.</para>
- <para>The <literal><authentication-provider></literal> element creates a
- <classname>DaoAuthenticationProvider</classname> bean and the
- <literal><user-service></literal> element creates an
- <classname>InMemoryDaoImpl</classname>. All <literal>authentication-provider</literal>
- elements must be within the <literal>authentication-manager</literal> element, which
- creates a <classname>ProviderManager</classname> and registers the authentication
- providers with it. You can find more detailed information on the beans that are created in
- the <link xlink:href="#appendix-namespace">namespace appendix</link>. It's worth
- cross-checking this if you want to start understanding what the important classes in the
- framework are and how they are used, particularly if you want to customise things
- later.</para>
- </sidebar>
- <para> The configuration above defines two users, their passwords and their roles within the
- application (which will be used for access control). It is also possible to load user
- information from a standard properties file using the <literal>properties</literal>
- attribute on <literal>user-service</literal>. See the section on <link
- xlink:href="#core-services-in-memory-service">in-memory authentication</link> for more
- details on the file format. Using the <literal><authentication-provider></literal>
- element means that the user information will be used by the authentication manager to
- process authentication requests. You can have multiple
- <literal><authentication-provider></literal> elements to define different
- authentication sources and each will be consulted in turn.</para>
- <para> At this point you should be able to start up your application and you will be required
- to log in to proceed. Try it out, or try experimenting with the <quote>tutorial</quote>
- sample application that comes with the project. The above configuration actually adds quite
- a few services to the application because we have used the <literal>auto-config</literal>
- attribute. For example, form-based login processing is automatically enabled. </para>
- <section xml:id="ns-auto-config">
- <title>What does <literal>auto-config</literal> Include?</title>
- <para> The <literal>auto-config</literal> attribute, as we have used it above, is just a
- shorthand syntax for: <programlisting language="xml"><![CDATA[
- <http>
- <form-login />
- <http-basic />
- <logout />
- </http>
- ]]></programlisting> These other elements are responsible for setting up form-login, basic
- authentication and logout handling services respectively <footnote><para>In versions prior
- to 3.0, this list also included remember-me functionality. This could cause some
- confusing errors with some configurations and was removed in 3.0. In 3.0, the addition
- of an <classname>AnonymousAuthenticationFilter</classname> is part of the default
- <literal><http></literal> configuration, so the <literal><anonymous
- /></literal> element is added regardless of whether <literal>auto-config</literal>
- is enabled.</para></footnote> . They each have attributes which can be used to alter
- their behaviour. </para>
- </section>
- <section xml:id="ns-form-and-basic">
- <title>Form and Basic Login Options</title>
- <para> You might be wondering where the login form came from when you were prompted to log
- in, since we made no mention of any HTML files or JSPs. In fact, since we didn't
- explicitly set a URL for the login page, Spring Security generates one automatically,
- based on the features that are enabled and using standard values for the URL which
- processes the submitted login, the default target URL the user will be sent to after
- loggin in and so on. However, the namespace offers plenty of support to allow you to
- customize these options. For example, if you want to supply your own login page, you could
- use: <programlisting language="xml"><![CDATA[
- <http auto-config='true'>
- <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
- <intercept-url pattern="/**" access="ROLE_USER" />
- <form-login login-page='/login.jsp'/>
- </http>
- ]]>
- </programlisting> Note that you can still use <literal>auto-config</literal>. The
- <literal>form-login</literal> element just overrides the default settings. Also note
- that we've added an extra <literal>intercept-url</literal> element to say that any
- requests for the login page should be available to anonymous users <footnote><para>See the
- chapter on <link xlink:href="#anonymous">anonymous authentication</link> for more
- details.</para></footnote>. Otherwise the request would be matched by the pattern
- <literal>/**</literal> and it wouldn't be possible to access the login page itself! This
- is a common configuration error and will result in an infinite loop in the application.
- Spring Security will emit a warning in the log if your login page appears to be secured.
- It is also possible to have all requests matching a particular pattern bypass the security
- filter chain completely: <programlisting language="xml"><![CDATA[
- <http auto-config='true'>
- <intercept-url pattern="/css/**" filters="none"/>
- <intercept-url pattern="/login.jsp*" filters="none"/>
- <intercept-url pattern="/**" access="ROLE_USER" />
- <form-login login-page='/login.jsp'/>
- </http>
- ]]>
- </programlisting> Note that these requests will be completely oblivious to Spring
- Security, so you will not be able to access information on the current user or call
- secured methods during the request. </para>
- <para>If you want to use basic authentication instead of form login, then change the
- configuration to <programlisting language="xml"><![CDATA[
- <http auto-config='true'>
- <intercept-url pattern="/**" access="ROLE_USER" />
- <http-basic />
- </http>
- ]]>
- </programlisting> Basic authentication will then take precedence and will be used to
- prompt for a login when a user attempts to access a protected resource. Form login is
- still available in this configuration if you wish to use it, for example through a login
- form embedded in another web page. </para>
- <section xml:id="ns-form-target">
- <title>Setting a Default Post-Login Destination</title>
- <para> If a form login isn't prompted by an attempt to access a protected resource, the
- <literal>default-target-url</literal> option comes into play. This is the URL the user
- will be taken to after logging in, and defaults to "/". You can also configure things so
- that they user <emphasis>always</emphasis> ends up at this page (regardless of whether
- the login was "on-demand" or they explicitly chose to log in) by setting the
- <literal>always-use-default-target</literal> attribute to "true". This is useful if
- your application always requires that the user starts at a "home" page, for example: <programlisting language="xml"><![CDATA[
- <http>
- <intercept-url pattern='/login.htm*' filters='none'/>
- <intercept-url pattern='/**' access='ROLE_USER' />
- <form-login login-page='/login.htm' default-target-url='/home.htm'
- always-use-default-target='true' />
- </http>
- ]]>
- </programlisting></para>
- </section>
- </section>
- </section>
- <section xml:id="ns-auth-providers">
- <title>Using other Authentication Providers</title>
- <para> In practice you will need a more scalable source of user information than a few names
- added to the application context file. Most likely you will want to store your user
- information in something like a database or an LDAP server. LDAP namespace configuration is
- dealt with in the <link xlink:href="#ldap">LDAP chapter</link>, so we won't cover it here.
- If you have a custom implementation of Spring Security's
- <classname>UserDetailsService</classname>, called "myUserDetailsService" in your
- application context, then you can authenticate against this using <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider user-service-ref='myUserDetailsService'/>
- </authentication-manager>
- ]]>
- </programlisting> If you want to use a database, then you can use <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider>
- <jdbc-user-service data-source-ref="securityDataSource"/>
- </authentication-provider>
- </authentication-manager>
- ]]>
- </programlisting> Where "securityDataSource" is the name of a
- <classname>DataSource</classname> bean in the application context, pointing at a database
- containing the standard Spring Security <link xlink:href="#db_schema_users_authorities">user
- data tables</link>. Alternatively, you could configure a Spring Security
- <classname>JdbcDaoImpl</classname> bean and point at that using the
- <literal>user-service-ref</literal> attribute: <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider user-service-ref='myUserDetailsService'/>
- </authentication-manager>
-
- <beans:bean id="myUserDetailsService"
- class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
- <beans:property name="dataSource" ref="dataSource"/>
- </beans:bean>
- ]]>
- </programlisting> You can also use standard
- <interfacename>AuthenticationProvider</interfacename> beans as follows <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider ref='myAuthenticationProvider'/>
- </authentication-manager>
- ]]>
- </programlisting> where <literal>myAuthenticationProvider</literal> is the name of a
- bean in your application context which implements
- <interfacename>AuthenticationProvider</interfacename>. See <xref linkend="ns-auth-manager"
- /> for more on information on how the Spring Security
- <interfacename>AuthenticationManager</interfacename> is configured using the namespace. </para>
- <section xml:id="ns-password-encoder">
- <title>Adding a Password Encoder</title>
- <para> Often your password data will be encoded using a hashing algorithm. This is supported
- by the <literal><password-encoder></literal> element. With SHA encoded passwords,
- the original authentication provider configuration would look like this: <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider>
- <password-encoder hash="sha"/>
- <user-service>
- <user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f"
- authorities="ROLE_USER, ROLE_ADMIN" />
- <user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f"
- authorities="ROLE_USER" />
- </user-service>
- </authentication-provider>
- </authentication-manager>
- ]]>
- </programlisting></para>
- <para> When using hashed passwords, it's also a good idea to use a salt value to protect
- against dictionary attacks and Spring Security supports this too. Ideally you would want
- to use a randomly generated salt value for each user, but you can use any property of the
- <classname>UserDetails</classname> object which is loaded by your
- <classname>UserDetailsService</classname>. For example, to use the
- <literal>username</literal> property, you would use <programlisting><![CDATA[
- <password-encoder hash="sha">
- <salt-source user-property="username"/>
- </password-encoder>
- ]]></programlisting> You can use a custom password encoder bean by using the
- <literal>ref</literal> attribute of <literal>password-encoder</literal>. This should
- contain the name of a bean in the application context which is an instance of Spring
- Security's <interfacename>PasswordEncoder</interfacename> interface. </para>
- </section>
- </section>
- </section>
- <section xml:id="ns-web-advanced">
- <title>Advanced Web Features</title>
- <section xml:id="ns-remember-me">
- <title>Remember-Me Authentication</title>
- <para>See the separate <link xlink:href="#remember-me">Remember-Me chapter</link> for
- information on remember-me namespace configuration.</para>
- </section>
- <section xml:id="ns-requires-channel">
- <title>Adding HTTP/HTTPS Channel Security</title>
- <para>If your application supports both HTTP and HTTPS, and you require that particular URLs
- can only be accessed over HTTPS, then this is directly supported using the
- <literal>requires-channel</literal> attribute on <literal><intercept-url></literal>: <programlisting language="xml"><![CDATA[
- <http>
- <intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/>
- <intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/>
- ...
- </http>]]>
- </programlisting>With this configuration in place, if a user attempts to access
- anything matching the "/secure/**" pattern using HTTP, they will first be redirected to an
- HTTPS URL. The available options are "http", "https" or "any". Using the value "any" means
- that either HTTP or HTTPS can be used. </para>
- <para>If your application uses non-standard ports for HTTP and/or HTTPS, you can specify a
- list of port mappings as follows: <programlisting><![CDATA[
- <http>
- ...
- <port-mappings>
- <port-mapping http="9080" https="9443"/>
- </port-mappings>
- </http>]]>
- </programlisting><!--You can find a more in-depth discussion of channel security
- in <xref xlink:href="#channel-security"/--></para>
- </section>
- <section xml:id="ns-session-mgmt">
- <title>Session Management</title>
- <section>
- <title>Detecting Timeouts</title>
- <para> You can configure Spring Security to detect the submission of an invalid session ID
- and redirect the user to an appropriate URL. This is achieved through the
- <literal>session-management</literal> element:<![CDATA[
- <http>
- ...
- <session-management invalid-session-url="/sessionTimeout.htm" />
- </http>]]></para>
- </section>
- <section xml:id="ns-concurrent-sessions">
- <title>Concurrent Session Control</title>
- <para>If you wish to place constraints on a single user's ability to log in to your
- application, Spring Security supports this out of the box with the following simple
- additions. First you need to add the following listener to your
- <filename>web.xml</filename> file to keep Spring Security updated about session
- lifecycle events: <![CDATA[
- <listener>
- <listener-class>
- org.springframework.security.web.session.HttpSessionEventPublisher
- </listener-class>
- </listener>
- ]]> Then add the following lines to your application context: <programlisting language="xml"><![CDATA[
- <http>
- ...
- <session-management>
- <concurrency-control max-sessions="1" />
- </session-management>
- </http>]]>
- </programlisting> This will prevent a user from logging in multiple times - a
- second login will cause the first to be invalidated. Often you would prefer to prevent a
- second login, in which case you can use <programlisting language="xml"><![CDATA[
- <http>
- ...
- <session-management>
- <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
- </session-management>
- </http>]]>
- </programlisting>The second login will then be rejected. By
- <quote>rejected</quote>, we mean that the user will be sent to the
- <literal>authentication-failure-url</literal> if form-based login is being used. If the
- second authentication takes place through another non-interactive mechanism, such as
- <quote>remember-me</quote>, an <quote>unauthorized</quote> (402) error will be sent to
- the client. If instead you want to use an error page, you can add the attribute
- <literal>session-authentication-error-url</literal> to the
- <literal>session-management</literal> element. </para>
- <para>If you are using a customized authentication filter for form-based login, then you
- have to configure concurrent session control support explicitly. More details can be found
- in the <link xlink:href="#session-mgmt">Session Management chapter</link>. </para>
- </section>
- <section xml:id="ns-session-fixation">
- <title>Session Fixation Attack Protection</title>
- <para>
- <link xlink:href="http://en.wikipedia.org/wiki/Session_fixation">Session fixation</link>
- attacks are a potential risk where it is possible for a malicious attacker to create a
- session by accessing a site, then persuade another user to log in with the same session
- (by sending them a link containing the session identifier as a parameter, for example).
- Spring Security protects against this automatically by creating a new session when a user
- logs in. If you don't require this protection, or it conflicts with some other
- requirement, you can control the behaviour using the
- <literal>session-fixation-protection</literal> attribute on
- <literal><session-management></literal>, which has three options
- <itemizedlist><listitem><para><literal>migrateSession</literal> - creates a new
- session and copies the existing session attributes to the new session. This is the
- default.</para></listitem><listitem><para><literal>none</literal> - Don't do
- anything. The original session will be
- retained.</para></listitem><listitem><para><literal>newSession</literal> - Create
- a new "clean" session, without copying the existing session
- data.</para></listitem></itemizedlist></para>
- </section>
- </section>
- <section xml:id="ns-openid">
- <title>OpenID Login</title>
- <para>The namespace supports <link xlink:href="http://openid.net/">OpenID</link> login either
- instead of, or in addition to normal form-based login, with a simple change: <programlisting language="xml"><![CDATA[
- <http>
- <intercept-url pattern="/**" access="ROLE_USER" />
- <openid-login />
- </http>
- ]]></programlisting> You should then register yourself with an OpenID provider (such as
- myopenid.com), and add the user information to your in-memory
- <literal><user-service></literal>: <programlisting><![CDATA[
- <user name="http://jimi.hendrix.myopenid.com/" password="notused"
- authorities="ROLE_USER" />
- ]]></programlisting> You should be able to login using the <literal>myopenid.com</literal> site to
- authenticate. </para>
- </section>
- <section xml:id="ns-custom-filters">
- <title>Adding in Your Own Filters</title>
- <para>If you've used Spring Security before, you'll know that the framework maintains a chain
- of filters in order to apply its services. You may want to add your own filters to the stack
- at particular locations or use a Spring Security filter for which there isn't currently a
- namespace configuration option (CAS, for example). Or you might want to use a customized
- version of a standard namespace filter, such as the
- <literal>UsernamePasswordAuthenticationFilter</literal> which is created by the
- <literal><form-login></literal> element, taking advantage of some of the extra
- configuration options which are available by using the bean explicitly. How can you do this
- with namespace configuration, since the filter chain is not directly exposed? </para>
- <para>The order of the filters is always strictly enforced when using the namespace. When the
- application context is being created, the filter beans are sorted by the namespace handling
- code and the standard Spring Security filters each have an alias in the namespace and a
- well-known position.<note><para>In previous versions, the sorting took place after the
- filter instances had been created, during post-processing of the application context. In
- version 3.0+ the sorting is now done at the bean metadata level, before the classes have
- been instantiated. This has implications for how you add your own filters to the stack
- as the entire filter list must be known during the parsing of the
- <literal><http></literal> element, so the syntax has changed slightly in
- 3.0.</para></note>The filters, aliases and namespace elements/attributes which create
- the filters are shown in <xref linkend="filter-stack"/>. The filters are listed in the order
- in which they occur in the filter chain. <table xml:id="filter-stack"><title>Standard Filter
- Aliases and Ordering</title><tgroup cols="3" align="left"><thead><row><entry
- align="center">Alias</entry><entry align="center">Filter Class</entry><entry
- align="center">Namespace Element or
- Attribute</entry></row></thead><tbody><row><entry>
- CHANNEL_FILTER</entry><entry><literal>ChannelProcessingFilter</literal></entry><entry><literal>http/intercept-url@requires-channel</literal></entry></row><row><entry>
- CONCURRENT_SESSION_FILTER</entry><entry><literal>ConcurrentSessionFilter</literal>
- </entry><entry><literal>session-management/concurrency-control</literal></entry></row><row><entry>
- SECURITY_CONTEXT_FILTER</entry><entry><classname>SecurityContextPersistenceFilter</classname></entry><entry><literal>http</literal></entry></row><row><entry>
- LOGOUT_FILTER
- </entry><entry><literal>LogoutFilter</literal></entry><entry><literal>http/logout</literal></entry></row><row><entry>
- X509_FILTER
- </entry><entry><literal>X509AuthenticationFilter</literal></entry><entry><literal>http/x509</literal></entry></row><row><entry>
- PRE_AUTH_FILTER
- </entry><entry><literal>AstractPreAuthenticatedProcessingFilter</literal>
- Subclasses</entry><entry>N/A</entry></row><row><entry> CAS_FILTER
- </entry><entry><literal>CasAuthenticationFilter</literal></entry><entry>N/A</entry></row><row><entry>
- FORM_LOGIN_FILTER
- </entry><entry><literal>UsernamePasswordAuthenticationFilter</literal></entry><entry><literal>http/form-login</literal></entry></row><row><entry>
- BASIC_AUTH_FILTER
- </entry><entry><literal>BasicAuthenticationFilter</literal></entry><entry><literal>http/http-basic</literal></entry></row><row><entry>
- SERVLET_API_SUPPORT_FILTER</entry><entry><literal>SecurityContextHolderAwareFilter</literal></entry><entry><literal>http/@servlet-api-provision</literal></entry></row><row><entry>
- REMEMBER_ME_FILTER
- </entry><entry><classname>RememberMeAuthenticationFilter</classname></entry><entry><literal>http/remember-me</literal></entry></row><row><entry>
- ANONYMOUS_FILTER
- </entry><entry><literal>AnonymousAuthenticationFilter</literal></entry><entry><literal>http/anonymous</literal></entry></row><row><entry>
- SESSION_MANAGEMENT_FILTER</entry><entry><literal>SessionManagementFilter</literal></entry><entry><literal>session-management</literal></entry></row><row><entry>EXCEPTION_TRANSLATION_FILTER
- </entry><entry><classname>ExceptionTranslationFilter</classname></entry><entry><literal>http</literal></entry></row><row><entry>
- FILTER_SECURITY_INTERCEPTOR
- </entry><entry><classname>FilterSecurityInterceptor</classname></entry><entry><literal>http</literal></entry></row><row><entry>
- SWITCH_USER_FILTER
- </entry><entry><literal>SwitchUserFilter</literal></entry><entry>N/A</entry></row></tbody></tgroup></table>
- You can add your own filter to the stack, using the <literal>custom-filter</literal> element
- and one of these names to specify the position your filter should appear at: <programlisting language="xml"><![CDATA[
- <http>
- <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
- </http>
-
- <beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>
- ]]>
- </programlisting> You can also use the <literal>after</literal> or <literal>before</literal>
- attributes if you want your filter to be inserted before or after another filter in the
- stack. The names "FIRST" and "LAST" can be used with the <literal>position</literal>
- attribute to indicate that you want your filter to appear before or after the entire stack,
- respectively. </para>
- <tip>
- <title>Avoiding filter position conflicts</title>
- <para> If you are inserting a custom filter which may occupy the same position as one of the
- standard filters created by the namespace then it's important that you don't include the
- namespace versions by mistake. Avoid using the <literal>auto-config</literal> attribute
- and remove any elements which create filters whose functionality you want to replace. </para>
- <para> Note that you can't replace filters which are created by the use of the
- <literal><http></literal> element itself -
- <classname>SecurityContextPersistenceFilter</classname>,
- <classname>ExceptionTranslationFilter</classname> or
- <classname>FilterSecurityInterceptor</classname>. </para>
- </tip>
- <para> If you're replacing a namespace filter which requires an authentication entry point
- (i.e. where the authentication process is triggered by an attempt by an unauthenticated user
- to access to a secured resource), you will need to add a custom entry point bean too. </para>
- <section xml:id="ns-entry-point-ref">
- <title>Setting a Custom <interfacename>AuthenticationEntryPoint</interfacename></title>
- <para> If you aren't using form login, OpenID or basic authentication through the namespace,
- you may want to define an authentication filter and entry point using a traditional bean
- syntax and link them into the namespace, as we've just seen. The corresponding
- <interfacename>AuthenticationEntryPoint</interfacename> can be set using the
- <literal>entry-point-ref</literal> attribute on the <literal><http></literal>
- element. </para>
- <para> The CAS sample application is a good example of the use of custom beans with the
- namespace, including this syntax. If you aren't familiar with authentication entry points,
- they are discussed in the <link xlink:href="#tech-intro-auth-entry-point">technical
- overview</link> chapter. </para>
- </section>
- </section>
- </section>
- <section xml:id="ns-method-security">
- <title>Method Security</title>
- <para>From version 2.0 onwards Spring Security has improved support substantially for adding
- security to your service layer methods. It provides support for JSR-250 security as well as
- the framework's native <literal>@Secured</literal> annotation. You can apply security to a
- single bean, using the <literal>intercept-methods</literal> element to decorate the bean
- declaration, or you can secure multiple beans across the entire service layer using the
- AspectJ style pointcuts. </para>
- <section xml:id="ns-global-method">
- <title>The <literal><global-method-security></literal> Element</title>
- <para> This element is used to enable annotation-based security in your application (by
- setting the appropriate attributes on the element), and also to group together security
- pointcut declarations which will be applied across your entire application context. You
- should only declare one <literal><global-method-security></literal> element. The
- following declaration would enable support for both Spring Security's
- <literal>@Secured</literal>, and JSR-250 annotations: <programlisting><![CDATA[
- <global-method-security secured-annotations="enabled" jsr250-annotations="enabled"/>
- ]]>
- </programlisting> Adding an annotation to a method (on an class or interface) would then limit
- the access to that method accordingly. Spring Security's native annotation support defines a
- set of attributes for the method. These will be passed to the
- <interfacename>AccessDecisionManager</interfacename> for it to make the actual decision.
- This example is taken from the <link xlink:href="#tutorial-sample">tutorial sample</link>,
- which is a good starting point if you want to use method security in your application:
- <programlisting language="java">
- public interface BankService {
-
- @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
- public Account readAccount(Long id);
-
- @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
- public Account[] findAccounts();
-
- @Secured("ROLE_TELLER")
- public Account post(Account account, double amount);
- }
- </programlisting></para>
- <section xml:id="ns-protect-pointcut">
- <title>Adding Security Pointcuts using <literal>protect-pointcut</literal></title>
- <para> The use of <literal>protect-pointcut</literal> is particularly powerful, as it allows
- you to apply security to many beans with only a simple declaration. Consider the following
- example: <programlisting language="xml"><![CDATA[
- <global-method-security>
- <protect-pointcut expression="execution(* com.mycompany.*Service.*(..))"
- access="ROLE_USER"/>
- </global-method-security>
- ]]>
- </programlisting> This will protect all methods on beans declared in the application
- context whose classes are in the <literal>com.mycompany</literal> package and whose class
- names end in "Service". Only users with the <literal>ROLE_USER</literal> role will be able
- to invoke these methods. As with URL matching, the most specific matches must come first
- in the list of pointcuts, as the first matching expression will be used. </para>
- </section>
- </section>
- </section>
- <section xml:id="ns-access-manager">
- <title>The Default AccessDecisionManager</title>
- <para> This section assumes you have some knowledge of the underlying architecture for
- access-control within Spring Security. If you don't you can skip it and come back to it later,
- as this section is only really relevant for people who need to do some customization in order
- to use more than simple role based security. </para>
- <para> When you use a namespace configuration, a default instance of
- <interfacename>AccessDecisionManager</interfacename> is automatically registered for you and
- will be used for making access decisions for method invocations and web URL access, based on
- the access attributes you specify in your <literal>intercept-url</literal> and
- <literal>protect-pointcut</literal> declarations (and in annotations if you are using
- annotation secured methods). </para>
- <para> The default strategy is to use an <classname>AffirmativeBased</classname>
- <interfacename>AccessDecisionManager</interfacename> with a <classname>RoleVoter</classname>
- and an <classname>AuthenticatedVoter</classname>. </para>
- <section xml:id="ns-custom-access-mgr">
- <title>Customizing the AccessDecisionManager</title>
- <para> If you need to use a more complicated access control strategy then it is easy to set an
- alternative for both method and web security. </para>
- <para> For method security, you do this by setting the
- <literal>access-decision-manager-ref</literal> attribute on
- <literal>global-method-security</literal> to the Id of the appropriate
- <interfacename>AccessDecisionManager</interfacename> bean in the application context: <programlisting language="xml"><![CDATA[
- <global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
- ...
- </global-method-security>
- ]]></programlisting></para>
- <para> The syntax for web security is the same, but on the <literal>http</literal> element: <programlisting language="xml"><![CDATA[
- <http access-decision-manager-ref="myAccessDecisionManagerBean">
- ...
- </http>
- ]]></programlisting></para>
- </section>
- </section>
- <section xml:id="ns-auth-manager">
- <title>The Authentication Manager and the Namespace</title>
- <para> The main interface which provides authentication services in Spring Security is the
- <interfacename>AuthenticationManager</interfacename>. This is usually an instance of Spring
- Security's <classname>ProviderManager</classname> class, which you may already be familiar
- with if you've used the framework before. If not, it will be covered later, in <link
- xlink:href="#tech-intro-authentication"/>. The bean instance is registered using the
- <literal>authentication-manager</literal> namespace element. You can't use a custom
- <classname>AuthenticationManager</classname> if you are using either HTTP or method security
- through the namespace, but this should not be a problem as you have full control over the
- <classname>AuthenticationProvider</classname>s that are used.</para>
- <para> You may want to register additional <classname>AuthenticationProvider</classname> beans
- with the <classname>ProviderManager</classname> and you can do this using the
- <literal><authentication-provider></literal> element with the <literal>ref</literal>
- attribute, where the value of the attribute is the name of the provider bean you want to add.
- For example: <programlisting language="xml"><![CDATA[
- <authentication-manager>
- <authentication-provider ref="casAuthenticationProvider"/>
- </authentication-manager>
- <bean id="casAuthenticationProvider"
- class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
- <security:custom-authentication-provider />
- ...
- </bean>
- ]]></programlisting></para>
- <para> Another common requirement is that another bean in the context may require a reference to
- the <interfacename>AuthenticationManager</interfacename>. There is a special element which
- lets you register an alias for the <interfacename>AuthenticationManager</interfacename> and
- you can then use this name elsewhere in your application context. <programlisting language="xml"><![CDATA[
- <security:authentication-manager alias="authenticationManager">
- ...
- </security:authentication-manager>
- <bean id="customizedFormLoginFilter"
- class="com.somecompany.security.web.CustomFormLoginFilter">
- <property name="authenticationManager" ref="authenticationManager"/>
- ...
- </bean>
- ]]></programlisting></para>
- </section>
- </chapter>
|