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
the section called “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.