This guide provides instructions on how to add Spring Security to an existing Spring MVC application without the use of XML.
Setting up the sample
This section outlines how to setup a workspace within STS so that you can follow along with this guide. The next section outlines generic steps for how to apply Spring Security to your existing application. While you could simply apply the steps to your existing application, we encourage you to follow along with this guide as is to reduce the complexity.
Obtaining the sample projects
There are multiple ways in which you can obtain the source. We have highlighted a few ways below:
Downloading from github
You can download the source from github.
Extract the zip to a known location and remember it as SPRING_SECURITY_HOME. You are now ready to Import the insecuremvc sample application
Cloning from github
If you wish you can also obtain the source by cloning from github. For example, if you have a git client installed you can type the following:
cd ~/git/ git clone https://github.com/SpringSource/spring-security.git
In this example, the code will be placed at "~/git/spring-security". Remember this location as SPRING_SECURITY_HOME.
Import the insecuremvc sample application
In oder to follow along, we encourage you to import the insecuremvc sample application into your IDE. You may use any IDE you prefer, but the instructions in the guide will assume you are using Spring Tool Suite (STS).
The completed sample application can be found at SPRING_SECURITY_HOME/hellomvc-jc |
-
If you do not have STS installed, download STS from http://www.springsource.org/spring-tool-suite-download For performance reasons, we prefer the release based on Eclipse Juno.
-
Start STS and import the sample applications into STS using the following steps:
-
File→Import
-
Existing Maven Projects
-
Click Next >
-
Click Browse…
-
Navigate to the samples (i.e. SPRING_SECURITY_HOME/samples/insecuremvc) and click OK
-
Click Finish
-
Running the insecuremvc application
In the following exerecise we will be modifying the spring-security-samples-insecuremvc application. Before we make any changes, it is best to verify that the sample works properly. Perform the following steps to ensure that spring-security-samples-insecuremvc works.
-
Right click on the spring-security-samples-insecuremvc application
-
Select Run As→Run on Server
-
Select the latest tc Server (i.e. v2.9)
-
Click Finish
Verify the application is working:
-
A page displaying a user’s inbox can be seen at http://localhost:8080/sample/
-
Try clicking on the Compose link and creating a message. The message details should be displayed.
-
Now click on the Inbox link and see the message listed. You can click on the summary link to see the details displayed again.
Once you have verified the application runs, stop the application server using the following steps:
-
In the Servers view select the latest tc Server
-
Click the stop button (a red square) to stop the application server
Securing the application
Before securing your application, it is important to ensure that the existing application works as we did in Running the insecuremvc application. Now that the application runs without security, we are ready to add security to our application. This section demonstrates the minimal steps to add Spring Security to a Spring MVC application.
Updating your dependencies
You will need to ensure you have added the dependencies. Spring Security milestones and release canidates are available in the Spring Milestone Repository. In short, if you are using Maven and using a milestone or release canidate ensure you have the following repository in your pom.xml:
<repositories>
<!-- ... possibly other repository elements ... -->
<repository>
<id>spring-libs-milestone</id>
<name>Spring Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</repository>
</repositories>
You will then need to include the Spring Security dependencies
<dependencies>
<!-- ... other dependency elements ... -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.RC1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.0.RC1</version>
</dependency>
</dependencies>
After you have completed this, you need to ensure that STS knows about the updated dependencies by:
-
Right click on the spring-security-samples-insecuremvc application
-
Select Maven→Update project…
-
Ensure the project is selected, and click OK
Creating your Spring Security configuration
The next step is to create a Spring Security configuration.
-
Right click the spring-security-samples-insecuremvc project the Package Explorer view
-
Select New→Class
-
Enter org.springframework.security.samples.config for the Package
-
Enter SecurityConfig for the Name
-
Click Finish
-
Replace the file with the following contents:
package org.springframework.security.samples.config;
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
The SecurityConfig
will:
-
Require authentication to every URL in your application
-
Generate a login form for you
-
Allow the user with the Username user and the Password password to authenticate with form based authentication
-
Allow the user with the Username user and the Password password to authenticate with HTTP basic authentication
-
Allow the user to logout
-
CSRF attack prevention
-
Session Fixation protection
-
Security Header integration
-
HTTP Strict Transport Security for secure requests
-
X-Content-Type-Options integration
-
Cache Control (can be overridden later by your application to allow caching of your static resources)
-
X-XSS-Protection integration
-
X-Frame-Options integration to help prevent Clickjacking
-
-
Integrate with the following Servlet API methods
Registering Spring Security with the war
We have created the Spring Security configuration, but we still need to register it with the war. This can be done using the following steps:
-
Right click the spring-security-samples-insecuremvc project the Package Explorer view
-
Select New→Class
-
Enter org.springframework.security.samples.config for the Package
-
Enter SecurityWebApplicationInitializer for the Name
-
Click Finish
-
Replace the file with the following contents:
package org.springframework.security.samples.config;
import org.springframework.core.annotation.*;
import org.springframework.security.web.context.*;
@Order(2)
public class MessageSecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
The MessageSecurityWebApplicationInitializer
will automatically register the springSecurityFilterChain Filter for every URL in your application. We add @Order(2)
so the springSecurityFilterChain is inserted before our Sitemesh Filter declared in MessageWebApplicationInitializer.java
Verify SecurityConfig is loaded
Just because SecurityConfig
exists, does not mean that our Spring application knows about it. In this instance, our Spring root application context is initialized using MessageWebApplicationInitializer which is included with our spring-security-samples-messages-jc project. You can find a snippet of it below:
@Order(1)
public class MessageWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfiguration.class };
}
// ... other overrides ...
}
You will notice it is loading the RootConfiguration
class which is also included in our spring-security-samples-messages-jc project.
@Configuration
@ComponentScan(value = "org.springframework.security.samples.config",
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = RootConfiguration.class))
public class RootConfiguration {
}
The @ComponentScan
is loading all configuration in the org.springframework.security.samples.config package. Since SecurityConfig
is in this package, it will be loaded with our existing setup and there is nothing more to do.
Had SecurityConfig not been loaded, we could have used an @Import(SecurityConfig) above the class definition of RootConfiguration or added SecurityConfig as one of the results for getRootConfigClasses() .
|
Exploring the secured application
Start the server as we did in Running the insecuremvc application Now when you visit http://localhost:8080/sample/ you will be prompted with a login page that is automatically generated by Spring Security.
Authenticating to the secured application
Try entering an invalid username and password:
-
Username invalid
-
Password invalid
You should see an error message stating that authentication failed. Now try entering a valid username and password:
-
Username user
-
Password password
You should now see the page that we wanted to secure.
The reason we can successfully authenticate with Username user and Password password is because that is what we configured in our SecurityConfig .
|
Displaying the user name
Now that we have authenticated, let’s update the application to display the username if the user is authenticated. Update main.jsp to contain the following snippet:
<div class="nav-collapse collapse">
<c:if test="${pageContext.request.remoteUser != null}">
<p class="navbar-text pull-right">
<c:out value="${pageContext.request.remoteUser}"/>
</p>
</c:if>
<ul class="nav">
<c:url var="inboxUrl" value="/"/>
<li><a href="${inboxUrl}">Inbox</a></li>
<c:url var="composeUrl" value="/?form"/>
<li><a href="${composeUrl}">Compose</a></li>
</ul>
</div>
The <c:out /> tag ensures the username is escaped to avoid XSS vulnerabilities Regardless of how an application renders user inputed values, it should ensure that the values are properly escaped.
|
Refresh the page at http://localhost:8080/sample/ and you will see the user name displayed. This works because Spring Security integrates with the Servlet API methods
Logging out
Now that we can view the user name, let’s update the application to allow logging out. Update the body of index.jsp to contain a log out link as shown below:
<div class="nav-collapse collapse">
<c:if test="${pageContext.request.remoteUser != null}">
<c:url var="logoutUrl" value="/logout"/>
<form:form class="navbar-form pull-right" action="${logoutUrl}" method="post">
<input type="submit" value="Log out" />
</form:form>
</c:if>
<p class="navbar-text pull-right">
<c:out value="${pageContext.request.remoteUser}"/>
</p>
<ul class="nav">
<c:url var="inboxUrl" value="/"/>
<li><a href="${inboxUrl}">Inbox</a></li>
<c:url var="composeUrl" value="/?form"/>
<li><a href="${composeUrl}">Compose</a></li>
</ul>
</div>
In order to help protect against CSRF attacks, by default, Spring Security Java Configuration log out requires:
-
the HTTP method must be a POST
-
the CSRF token must be added to the request. Since we are using Spring MVC, the CSRF token is automatically added as a hidden input for you (view the source to see it). If you were not using Spring MVC, you can access the CsrfToken on the ServletRequest using the attribute _csrf
Refresh the page at http://localhost:8080/sample/ and you will see the log out button. Click the button and see that the application logs you out successfully.
Basic authentication
We stated that Spring Security supported both form and HTTP Basic authentication, but how does Spring Security know when to use one and not the other? When using HTTP Basic, the user should receive a HTTP 401 response, but when we visit our application in our web browser we are redirected to a login page. The reason for this is because Spring Security uses content negotiation to determine which type of authentication to use. For example, if we specified our Accept header to be application/json the result would be an HTTP 401.
You can use any tool you prefer (i.e. curl), but the instructions in this section we will use Google Chrome and the Postman - REST Client to make an application/json request to our application.
-
Open Google Chrome and launch the Postman - REST Client extension
-
Enter http://localhost:8080/sample/ into the request URL field
-
Select the Headers button
-
Enter Accept into the Header input
-
Enter application/json into the Value field
-
Presss the Send button
Observe that we get an HTTP Status of 401 instead of our redirect. Now lets try entering our user name and password.
-
Select the Basic Auth tab
-
Enter user for the Username
-
Enter password for the Password
-
Click the Refresh headers button
-
Click the Send button
This time you should see the HTML of our secured page.
Conclusion
You should now now how to secure your application using Spring Security without using any XML. Next, we will see how to customize our login form.