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 create 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
Spring Tool Suite as it has special features for working with standard Spring namespaces.
To start using the security namespace in your application context, you need to have the spring-security-config
jar on your classpath. Then 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-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.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 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
<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.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 based around the large-scale dependencies within the framework, and can be divided up into the following areas:
We’ll see how to configure these 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 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> <intercept-url pattern="/**" access="hasRole('USER')" /> <form-login /> <logout /> </http>
Which says that we want all URLs within our application to be secured, requiring the role ROLE_USER
to access them, we want to log in to the application using a form with username and password, and that we want a
logout URL registered which will allow us to log out of the application. <http>
element is the parent for all web-related namespace functionality. The <intercept-url>
element defines a pattern
which is matched
against the URLs of incoming requests using an ant path style syntax [2]. You can also use regular-expression matching as an alternative (see the namespace appendix for more details). The access
attribute defines the access requirements for requests matching
the given pattern. With the default configuration, this is typically a comma-separated list of roles, one of which a user must have to be allowed to make the request. The prefix"ROLE_" is a marker which indicates that a
simple comparison with the user’s authorities should be made. In other words, a normal role-based check should be used. Access-control in Spring Security is not limited to the use of simple roles (hence the use of the
prefix to differentiate between different types of security attributes). We’ll see later how the interpretation can vary footnote:[The interpretation of the comma-separated values in the access
attribute depends on the
implementation of the 1 which is used. In Spring Security 3.0, the attribute can also be populated with an 2.
Note | |
---|---|
You can use multiple |
To add some users, you can define a set of test data directly in the namespace:
<authentication-manager> <authentication-provider> <user-service> <!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that NoOpPasswordEncoder should be used. This is not safe for production, but makes reading in samples easier. Normally passwords should be hashed using BCrypt --> <user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager>
This is an example of a secure way of storing the same passwords. The password is prefixed
with {bcrypt}
to instruct DelegatingPasswordEncoder
, which supports any configured
PasswordEncoder
for matching, that the passwords are hashed using
BCrypt:
<authentication-manager> <authentication-provider> <user-service> <user name="jimi" password="{bcrypt}$2a$10$ddEWZUl8aU0GdZPPpy7wbu82dvEw/pBpbRvDQRqA41y6mK1CoH00m" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="{bcrypt}$2a$10$/elFpMBnAYYig6KRR5bvOOYeZr1ie1hSogJryg9qDlhza4oCw1Qka" authorities="ROLE_USER" /> <user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager>
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 on the file format. Using the <authentication-provider>
element means that the user information will be used by the authentication manager to process authentication requests. You can have multiple <authentication-provider>
elements to define different authentication sources and each will be consulted in turn.
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.
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 logging 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:
<http> <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login login-page='/login.jsp'/> </http>
Also note that we’ve added an extra intercept-url
element to say that any requests for the login page should be available to anonymous users [3] and also
the AuthenticatedVoter class for more details on how the value IS_AUTHENTICATED_ANONYMOUSLY
is processed.]. Otherwise the request would be matched by the pattern /** 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, by defining a separate http
element for the pattern like this:
<http pattern="/css/**" security="none"/> <http pattern="/login.jsp*" security="none"/> <http use-expressions="false"> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login login-page='/login.jsp'/> </http>
From Spring Security 3.1 it is now possible to use multiple http
elements to define separate security filter chain configurations for different request patterns. If the pattern
attribute is omitted from an http
element, it matches all requests. Creating an unsecured pattern is a simple example of this syntax, where the pattern is mapped to an empty filter chain [4]. We’ll look at this new syntax in more detail in the chapter on the Security Filter Chain.
It’s important to realise that these unsecured requests will be completely oblivious to any Spring Security web-related configuration or additional attributes such as requires-channel
, so you will not be able to access information on the current user or call secured methods during the request. Use access='IS_AUTHENTICATED_ANONYMOUSLY'
as an alternative if you still want the security filter chain to be applied.
If you want to use basic authentication instead of form login, then change the configuration to
<http use-expressions="false"> <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 successfully logging in, and defaults to "/". You can also configure things so that the 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 pattern="/login.htm*" security="none"/> <http use-expressions="false"> <intercept-url pattern='/**' access='ROLE_USER' /> <form-login login-page='/login.htm' default-target-url='/home.htm' always-use-default-target='true' /> </http>
For even more control over the destination, you can use the authentication-success-handler-ref
attribute as an alternative to default-target-url
. The referenced bean should be an instance of AuthenticationSuccessHandler
. You’ll find more on this in the Core Filters chapter and also in the namespace appendix, as well as information on how to customize the flow when authentication fails.
The logout
element adds support for logging out by navigating to a particular URL. The default logout URL is /logout
, but you can set it to something else using the logout-url
attribute. More information on other available attributes may be found in the namespace appendix.
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-manager> <authentication-provider user-service-ref='myUserDetailsService'/> </authentication-manager>
If you want to use a database, then you can use
<authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="securityDataSource"/> </authentication-provider> </authentication-manager>
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-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>
You can also use standard AuthenticationProvider
beans as follows
<authentication-manager> <authentication-provider ref='myAuthenticationProvider'/> </authentication-manager>
where myAuthenticationProvider
is the name of a bean in your application context which implements AuthenticationProvider
. You can use multiple authentication-provider
elements, in which case the providers will be queried in the order they are declared. See Section 6.6, “The Authentication Manager and the Namespace” for more information on how the Spring Security AuthenticationManager
is configured using the namespace.
Passwords should always be encoded using a secure hashing algorithm designed for the purpose (not a standard algorithm like SHA or MD5). This is supported by the <password-encoder>
element. With bcrypt encoded passwords, the original authentication provider configuration would look like this:
<beans:bean name="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> <authentication-manager> <authentication-provider> <password-encoder ref="bcryptEncoder"/> <user-service> <user name="jimi" password="$2a$10$ddEWZUl8aU0GdZPPpy7wbu82dvEw/pBpbRvDQRqA41y6mK1CoH00m" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="$2a$10$/elFpMBnAYYig6KRR5bvOOYeZr1ie1hSogJryg9qDlhza4oCw1Qka" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager>
bcrypt is a good choice for most cases, unless you have a legacy system which forces you to use a different algorithm. If you are using a simple hashing algorithm or, even worse, storing plain text passwords, then you should consider migrating to a more secure option like bcrypt.
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 [5]. 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>
Note that in order to be truly secure, an application should not use HTTP at all or switch between HTTP and HTTPS. It should start in HTTPS (with the user entering an HTTPS URL) and use a secure connection throughout to avoid any possibility of man-in-the-middle attacks.
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 session-management
element:
<http> ... <session-management invalid-session-url="/invalidSession.htm" /> </http>
Note that if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler:
<http> <logout delete-cookies="JSESSIONID" /> </http>
Unfortunately this can’t be guaranteed to work with every servlet container, so you will need to test it in your environment
Note | |
---|---|
If you are running your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server. For example, using Apache HTTPD’s mod_headers, the following directive would delete the <LocationMatch "/tutorial/logout"> Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT" </LocationMatch> |
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.web.session.HttpSessionEventPublisher </listener-class> </listener>
Then add the following lines to your application context:
<http> ... <session-management> <concurrency-control max-sessions="1" /> </session-management> </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> ... <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> </session-management> </http>
The second login will then be rejected. By "rejected", we mean that the user will be sent to the authentication-failure-url
if form-based login is being used. If the second authentication takes place through another non-interactive mechanism, such as "remember-me", an "unauthorized" (401) error will be sent to the client. If instead you want to use an error page, you can add the attribute session-authentication-error-url
to the session-management
element.
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 Session Management 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 or otherwise changing the session ID when a user logs in. If you don’t require this protection, or it conflicts with some other requirement, you can control the behavior using the session-fixation-protection
attribute on <session-management>
, which has four options
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-related attributes will still be copied).
migrateSession
- Create a new session and copy all existing session attributes to the new session. This is the default in Servlet 3.0 or older containers.
changeSessionId
- Do not create a new session. Instead, use the session fixation protection provided by the Servlet container (HttpServletRequest#changeSessionId()
). This option is only available in Servlet 3.1 (Java EE 7) and newer containers. Specifying it in older containers will result in an exception. This is the default in Servlet 3.1 and newer containers.
When session fixation protection occurs, it results in a SessionFixationProtectionEvent
being published in the application context. If you use changeSessionId
, this protection will also result in any javax.servlet.http.HttpSessionIdListener
s being notified, so use caution if your code listens for both events. See the Session Management chapter for additional information.
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/" authorities="ROLE_USER" />
You should be able to login using the myopenid.com
site to authenticate. It is also possible to select a specific UserDetailsService
bean for use OpenID by setting the user-service-ref
attribute on the openid-login
element. See the previous section on authentication providers for more information. Note that we have omitted the password attribute from the above user configuration, since this set of user data is only being used to load the authorities for the user. A random password will be generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration.
Support for OpenID attribute exchange. As an example, the following configuration would attempt to retrieve the email and full name from the OpenID provider, for use by the application:
<openid-login> <attribute-exchange> <openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/> <openid-attribute name="name" type="http://axschema.org/namePerson"/> </attribute-exchange> </openid-login>
The "type" of each OpenID attribute is a URI, determined by a particular schema, in this case http://axschema.org/. If an attribute must be retrieved for successful authentication, the required
attribute can be set. The exact schema and attributes supported will depend on your OpenID provider. The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code:
OpenIDAuthenticationToken token = (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(); List<OpenIDAttribute> attributes = token.getAttributes();
The OpenIDAttribute
contains the attribute type and the retrieved value (or values in the case of multi-valued attributes). We’ll see more about how the SecurityContextHolder
class is used when we look at core Spring Security components in the technical overview chapter. Multiple attribute exchange configurations are also be supported, if you wish to use multiple identity providers. You can supply multiple attribute-exchange
elements, using an identifier-matcher
attribute on each. This contains a regular expression which will be matched against the OpenID identifier supplied by the user. See the OpenID sample application in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers.
For additional information on how to customize the headers element refer to the Chapter 21, Security HTTP Response Headers section of the reference.
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 UsernamePasswordAuthenticationFilter
which is created by the <form-login>
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?
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 | |
---|---|
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 |
The filters, aliases and namespace elements/attributes which create the filters are shown in Table 6.1, “Standard Filter Aliases and Ordering”. The filters are listed in the order in which they occur in the filter chain.
Table 6.1. Standard Filter Aliases and Ordering
Alias | Filter Class | Namespace Element or Attribute |
---|---|---|
CHANNEL_FILTER |
|
|
SECURITY_CONTEXT_FILTER |
|
|
CONCURRENT_SESSION_FILTER |
|
|
HEADERS_FILTER |
|
|
CSRF_FILTER |
|
|
LOGOUT_FILTER |
|
|
X509_FILTER |
|
|
PRE_AUTH_FILTER |
| N/A |
CAS_FILTER |
| N/A |
FORM_LOGIN_FILTER |
|
|
BASIC_AUTH_FILTER |
|
|
SERVLET_API_SUPPORT_FILTER |
|
|
JAAS_API_SUPPORT_FILTER |
|
|
REMEMBER_ME_FILTER |
|
|
ANONYMOUS_FILTER |
|
|
SESSION_MANAGEMENT_FILTER |
|
|
EXCEPTION_TRANSLATION_FILTER |
|
|
FILTER_SECURITY_INTERCEPTOR |
|
|
SWITCH_USER_FILTER |
| 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:
<http> <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" /> </http> <beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>
You can also use the after
or before
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 position
attribute to indicate that you want your filter to appear before or after the entire stack, respectively.
Avoiding filter position conflicts | |
---|---|
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. 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 |
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.
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 annotation security as well as the framework’s original @Secured
annotation. From 3.0 you can also make use of new expression-based annotations. 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 Spring Security’s @Secured
:
<global-method-security secured-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:
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); }
Support for JSR-250 annotations can be enabled using
<global-method-security jsr250-annotations="enabled" />
These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security’s native annotations. To use the new expression-based syntax, you would use
<global-method-security pre-post-annotations="enabled" />
and the equivalent Java code would be
public interface BankService { @PreAuthorize("isAnonymous()") public Account readAccount(Long id); @PreAuthorize("isAnonymous()") public Account[] findAccounts(); @PreAuthorize("hasAuthority('ROLE_TELLER')") public Account post(Account account, double amount); }
Expression-based annotations are a good choice if you need to define simple rules that go beyond checking the role names against the user’s list of authorities.
Note | |
---|---|
The annotated methods will only be secured for instances which are defined as Spring beans (in the same application context in which method-security is enabled). If you want to secure instances which are not created by Spring (using the |
Note | |
---|---|
You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behaviour will not be well-defined otherwise. If two annotations are found which apply to a particular method, then only one of them will be applied. |
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. Security annotations take precedence over pointcuts.
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
. You can find out more about these in the chapter on authorization.
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>
The main interface which provides authentication services in Spring Security is the AuthenticationManager
. This is usually an instance of Spring Security’s ProviderManager
class, which you may already be familiar with if you’ve used the framework before. If not, it will be covered later, in the technical overview chapter. The bean instance is registered using the authentication-manager
namespace element. You can’t use a custom AuthenticationManager
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 <authentication-provider>
element with the ref
attribute, where the value of the attribute is the name of the provider bean you want to add. For example:
<authentication-manager> <authentication-provider ref="casAuthenticationProvider"/> </authentication-manager> <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> ... </bean>
Another common requirement is that another bean in the context may require a reference to the AuthenticationManager
. You can easily register an alias for the AuthenticationManager
and use this name elsewhere in your application context.
<security:authentication-manager alias="authenticationManager"> ... </security:authentication-manager> <bean id="customizedFormLoginFilter" class="com.somecompany.security.web.CustomFormLoginFilter"> <property name="authenticationManager" ref="authenticationManager"/> ... </bean>
[1] You can find out more about the use of the ldap-server
element in the chapter on Chapter 30, LDAP Authentication.
[2] See the section on Section 14.4, “Request Matching and HttpFirewall” in the Web Application Infrastructure chapter for more details on how matches are actually performed.
[3] See the chapter on Chapter 23, Anonymous Authentication
[4] The use of multiple <http>
elements is an important feature, allowing the namespace to simultaneously support both stateful and stateless paths within the same application, for example. The previous syntax, using the attribute filters="none"
on an intercept-url
element is incompatible with this change and is no longer supported in 3.1.
[5] For more details on how channel-processing is implemented, see the Javadoc for ChannelProcessingFilter
and related classes.