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 Reference Documentation. 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:
<security:ldap-server />
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
ldap-server
element and the user is isolated from worrying about which beans they need to be set on and
what the bean property names are.
[1]. 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
SpringSource Tool Suite
as it has special features for working with the Spring portfolio namespaces.
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:
<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-2.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd"> ... </beans>
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 context 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
<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-2.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd"> ... </beans:beans>
We'll assume this syntax is being used from now on in this chapter.
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 largely based around the large-scale dependencies within the framework, and can be divided up into the following areas:
Web/HTTP Security - 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.
Business Object (Method) Security - options for securing the service layer.
AuthenticationManager - handles authentication requests from other parts of the framework. A default instance will be registered internally by the namespace.
AccessDecisionManager - 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.
AuthenticationProviders - 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.
UserDetailsService - closely related to authentication providers, but often also required by other beans.
We'll see how these work together in the following sections.
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.
The first thing you need to do is add the following filter declaration to your
web.xml
file:
<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>
This provides a hook into the Spring Security web infrastructure. DelegatingFilterProxy
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 "springSecurityFilterChain", 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 web.xml
, you're ready to start editing your application
context file. Web security services are configured using the <http>
element.
All you need to enable web security to begin with is
<http auto-config='true'> <intercept-url pattern="/**" access="ROLE_USER" /> </http>
Which says that we want all URLs within our application to be secured, requiring the role
ROLE_USER
to access them.
You can use multiple <intercept-url>
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.
To add some users, you can define a set of test data directly in the namespace:
<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>
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 properties
attribute on
user-service
. See the section on
in-memory authentication for more details.
Using the <authentication-provider>
element means that the user information will be used by the authentication
manager to process authentication requests.
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 "tutorial" sample application
that comes with the project. The above configuration actually adds quite a few services to
the application because we have used the
auto-config
attribute. For example, form login processing and "remember-me" services are automatically
enabled.
The auto-config
attribute, as we have used it above, is just a
shorthand syntax for:
<http> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login /> <anonymous /> <http-basic /> <logout /> <remember-me /> </http>
These other elements are responsible for setting up form-login, anonymous authentication, basic authentication, logout handling and remember-me services respectively. They each have attributes which can be used to alter their behaviour.
auto-config
Requires a UserDetailsServiceAn error can occur when using auto-config without a UserDetailsService
in
your application context (for example, if you are using LDAP authentication).
This is because remember-me is automatically enabled when auto-config="true"
and it requires
an authentication mechanism which uses a UserDetailsService
to function (see
the Remember-me chapter for more details). If you have an error caused
by a missing UserDetailsService
then try removing the auto-config
setting (and any remember-me
setting you might have).
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 and so on. However, the namespace offers plenty of suppport to allow you to customize these options. For example, if you want to supply your own login page, you could use:
<http auto-config='true'> <intercept-url pattern="/login.jsp*" filters="none"/> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login login-page='/login.jsp'/> </http>
Note that you can still use auto-config
. The form-login
element just overrides the
default settings. Also note that we've added an extra intercept-url
element to say that any requests
for the login page should be excluded from processing by the security filters. Otherwise the request would be matched by
the pattern /**
and it wouldn't be possible to access the login page itself!
If you want to use basic authentication instead of form login, then change the configuration to
<http auto-config='true'> <intercept-url pattern="/**" access="ROLE_USER" /> <http-basic /> </http>
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.
If a form login isn't prompted by an attempt to access a protected resource, the default-target-url
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 always ends up at this page (regardless of whether
the login was "on-demand" or they explicitly chose to log in) by setting the
always-use-default-target
attribute to "true". This is useful if your application always
requires that the user starts at a "home" page, for example:
<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>
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 LDAP chapter, so we won't cover it here. If you have a
custom implementation of Spring Security's UserDetailsService
, called "myUserDetailsService" in your
application context, then you can authenticate against this using
<authentication-provider user-service-ref='myUserDetailsService'/>
If you want to use a database, then you can use
<authentication-provider> <jdbc-user-service data-source-ref="securityDataSource"/> </authentication-provider>
Where "securityDataSource" is the name of a DataSource
bean in the application context,
pointing at a database containing the standard Spring Security user data tables. Alternatively, you could configure
a Spring Security JdbcDaoImpl
bean and point at that using the user-service-ref
attribute:
<authentication-provider user-service-ref='myUserDetailsService'/> <beans:bean id="myUserDetailsService" class="org.springframework.security.userdetails.jdbc.JdbcDaoImpl"> <beans:property name="dataSource" ref="dataSource"/> </beans:bean>
You can also use standard AuthenticationProvider
beans by adding the
<custom-authentication-provider>
element within the bean definition. See
Section 2.6, “The Default Authentication Manager” for more on this.
Often your password data will be encoded using a hashing algorithm. This is supported by the <password-encoder>
element. With SHA encoded passwords, the original authentication provider configuration would look like this:
<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>
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 UserDetails
object which is loaded by your UserDetailsService
. For example, to use the username
property, you would use
<password-encoder hash="sha"> <salt-source user-property="username"/> </password-encoder>
You can use a custom password encoder bean by using the ref
attribute of password-encoder
. This should
contain the name of a bean in the application context which is an instance of Spring Security's PasswordEncoder
interface.
See the separate Remember-Me chapter for information on remember-me namespace configuration.
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 requires-channel
attribute on <intercept-url>
:
<http> <intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/> <intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/> ... </http>
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.
If your application uses non-standard ports for HTTP and/or HTTPS, you can specify a list of port mappings as follows:
<http> ... <port-mappings> <port-mapping http="9080" https="9443"/> </port-mappings> </http>
You can find a more in-depth discussion of channel security in Chapter 7, Channel Security.
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 web.xml
file to keep Spring Security updated about
session lifecycle events:
<listener> <listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class> </listener>
Then add the following line to your application context:
<http> ... <concurrent-session-control max-sessions="1" /> </http>
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
<http> ... <concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true"/> </http>
The second login will then be rejected.
The namespace supports OpenID login either instead of, or in addition to normal form-based login, with a simple change:
<http> <intercept-url pattern="/**" access="ROLE_USER" /> <openid-login /> </http>
You should then register yourself with an OpenID provider (such as myopenid.com), and
add the user information to your in-memory <user-service>
:
<user name="http://jimi.hendrix.myopenid.com/" password="notused" authorities="ROLE_USER" />
You should be able to login using the myopenid.com
site to authenticate.
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 AuthenticationProcessingFilter
which is created by the
<form-login>
element, taking advantage of some of the extra configuration options which are
available by using defining the bean directly. How can you do this with namespace configuration,
since the filter chain is not directly exposed?
The order of the filters is always strictly enforced when using the namespace. Each Spring Security
filter implements the Spring Ordered
interface and the filters created by the namespace
are sorted during initialization. The standard Spring Security filters each have an alias in the namespace. The filters, aliases
and namespace elements/attributes which create the filters are shown in Table 2.1, “Standard Filter Aliases and Ordering”.
Table 2.1. Standard Filter Aliases and Ordering
Alias | Filter Class | Namespace Element or Attribute |
---|---|---|
CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter
| http/concurrent-session-control |
SESSION_CONTEXT_INTEGRATION_FILTER | HttpSessionContextIntegrationFilter | http |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509PreAuthenticatedProcessigFilter | http/x509 |
PRE_AUTH_FILTER | AstractPreAuthenticatedProcessingFilter Subclasses | N/A |
CAS_PROCESSING_FILTER | CasProcessingFilter | N/A |
AUTHENTICATION_PROCESSING_FILTER | AuthenticationProcessingFilter | http/form-login |
BASIC_PROCESSING_FILTER | BasicProcessingFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter | http/@servlet-api-provision |
REMEMBER_ME_FILTER | RememberMeProcessingFilter | http/remember-me |
ANONYMOUS_FILTER | AnonymousProcessingFilter | http/anonymous |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
NTLM_FILTER | NtlmProcessingFilter | N/A |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
SWITCH_USER_FILTER | SwitchUserProcessingFilter | N/A |
You can add your own filter to the stack, using the custom-filter
element and one of these
names to specify the position your filter should appear at:
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"> <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/> </beans:bean>
You can also use the after
or before
attribtues 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
position
attribute to indicate that you want your filter to appear before or after the entire stack, respectively.
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
auto-config
attribute and remove any elements which create filters whose functionality you want to replace.
Note that you can't replace filters which are created by the use of the <http>
element itself - HttpSessionContextIntegrationFilter
, ExceptionTranslationFilter
or
FilterSecurityInterceptor
.
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.
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 AuthenticationEntryPoint
can be set using the
entry-point-ref
attribute on the <http>
element.
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 technical overview chapter.
Session fixation
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
session-fixation-protection
attribute on <http>
, which
has three options
migrateSession
- creates a new session and copies the existing
session attributes to the new session. This is the default.
none
- Don't do anything. The original session will be retained.
newSession
- Create a new "clean" session, without copying the existing session data.
Spring Security 2.0 has improved support substantially for adding security to your service layer methods. If you are
using Java 5 or greater, then support for JSR-250 security annotations is provided, as well as the framework's native
@Secured
annotation. You can apply security to a single bean, using the intercept-methods
element to decorate the bean declaration, or you can secure multiple beans across the entire service layer using the
AspectJ style pointcuts.
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 <global-method-security>
element.
The following declaration would enable support for both Spring Security's @Secured
, and JSR-250 annotations:
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled"/>
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 AccessDecisionManager
for it to make the actual decision.
This example is taken from the tutorial sample, which is a good
starting point if you want to use method security in your application:
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); }
The use of protect-pointcut
is particularly powerful, as it allows you to
apply security to many beans with only a simple declaration. Consider the following example:
<global-method-security> <protect-pointcut expression="execution(* com.mycompany.*Service.*(..))" access="ROLE_USER"/> </global-method-security>
This will protect all methods on beans declared in the application context whose classes
are in the com.mycompany
package and whose class names end in "Service".
Only users with the ROLE_USER
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.
This alternative syntax allows you to specify security for a specific bean by adding this element within the bean itself.
<bean:bean id="target" class="com.mycompany.myapp.MyBean"> <intercept-methods> <protect method="set*" access="ROLE_ADMIN" /> <protect method="get*" access="ROLE_ADMIN,ROLE_USER" /> <protect method="doSomething" access="ROLE_USER" /> </intercept-methods> </bean:bean>
This allows you to configure security attributes for individual methods on the bean or simple wildcarded patterns.
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.
When you use a namespace configuration, a default instance of AccessDecisionManager
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 intercept-url
and
protect-pointcut
declarations (and in annotations if you are using annotation secured methods).
The default strategy is to use an AffirmativeBased
AccessDecisionManager
with a RoleVoter
and an AuthenticatedVoter
.
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.
For method security, you do this by setting the access-decision-manager-ref
attribute
on global-method-security
to the Id of the appropriate
AccessDecisionManager
bean in the application context:
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean"> ... </global-method-security>
The syntax for web security is the same, but on the http
element:
<http access-decision-manager-ref="myAccessDecisionManagerBean"> ... </http>
We've touched on the idea that the namespace configuration automatically registers an authentication manager bean for
you. This is an instance of Spring Security's ProviderManager
class, which you may already
be familiar with if you've used the framework before. You can't use a custom AuthenticationProvider
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 AuthenticationProvider
s that are used.
You may want to register additional AuthenticationProvider
beans with the ProviderManager
and you can do this using the <custom-authentication-provider>
element within the bean. For example:
<bean id="casAuthenticationProvider" class="org.springframework.security.providers.cas.CasAuthenticationProvider"> <security:custom-authentication-provider /> ... </bean>
Another common requirement is that another bean in the context may require a reference to the AuthenticationManager
.
There is a special element which lets you register an alias for the AuthenticationManager
and you can then
use this name elsewhere in your application context.
<security:authentication-manager alias="authenticationManager"/> <bean id="customizedFormLoginFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter"> <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER "/> <property name="authenticationManager" ref="authenticationManager"/> ... </bean>