Enhancing Spring MVC applications with Web Flow
5.8 Securing web flows
PREREQUISITES
Understanding of Spring security (see chapter 6)
KEY TECHNOLOGIES
Spring Security, SWF
Background
In chapter 6 (recipes 6.1 and 6.2), you’ll learn how to set up Spring Security to protect resources as well as provide a customized login page to authenticate users.
Problem
Now that you have a mechanism to authenticate users, you would like to secure spe-cific web flows so that they can only be accessed by authorized users.
Solution
Once you’ve configured Spring Security for your application, authorizing individual flows is pretty straightforward. First we’ll cover the three basic steps required to con-figure Spring Security. Then we’ll look at how easy it is to secure individual flows, states, and transitions.
CONFIGURING SPRING SECURITY
Just as you’ll do in recipe 6.1, you need to configure the DelegatingFilterProxy that will be used to load the Spring Security filter chain. The following listing focuses on the configuration relevant to Spring Security.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Source project: sip05, branch: 08 (Maven Project) -->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/applicationContext-security.xml </param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</
com.opensymphony.sitemesh.webapp.SiteMeshFilter </filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<filter-mapping>
org.springframework.web.context.ContextLoaderListener </listener-class>
</listener>
<servlet>
<servlet-name>springSoccer</servlet-name>
<servlet-class>org.springframework.
➥ web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/web/
➥ dispatcherServlet-context.xml</param-value>
You load a file containing your Spring Security configuration at
B
. We’ll look at this in a moment. AtC
, you configure the DelegatingFilterProxy, which will be used by Spring Security. AtD
, you configure the filter to be applied to all URLs.Here are the contents of the applicationContext-security.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Source project: sip05, branch: 08 (Maven Project) -->
<beans:beans
authentication-failure-url="/login.jsp?error=true"/>
<intercept-url pattern="/account/**" access="ROLE_USER"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
Listing 5.19 \WEB-INF\spring\applicationContext-security.xml
</http>
<user name="[email protected]"
password="password"
authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Here you’re configuring Spring Security. Most of the items in this file will be covered by recipes 6.1 and 6.2, so we’ll be brief here. Starting at
B
, you enable Spring Secu-rity’s auto-config, which sets up Spring Security to use several defaults. AtC
, you customize your login page. See recipe 6.2 for more details.At
D
, you protect a URL-based resource by creating an intercept-url definition.Remember that flows, specifically parent flows, are also URL-based resources.
Although you could protect them here, we’ll talk about a better solution to specifically secure a flow in a moment.
Starting at
E
, you create a simple in-memory UserDetailService with two accounts for testing.CONFIGURING THE SECURITYFLOWEXECUTIONLISTENER
Now that you have Spring Security up and running, let’s start plugging it into SWF. You do this by updating the webflowContext.xml file we discussed earlier with a new flow-execution-listener.
<flow:flow-executor id="flowExecutor">
<flow:flow-execution-listeners>
<flow:listener ref="securityFlowExecutionListener" />
</flow:flow-execution-listeners>
</flow:flow-executor>
<bean id="securityFlowExecutionListener"
class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
You add the SecurityFlowExecutionListener defined at
C
to your collection of lis-teners defined atB
. Spring Security is now aware of your SWF application. To secure an entire web flow or a specific state in a flow, you use the <secured> element; we’ll talk more about this next.SECURING FLOWS, TRANSITIONS, AND STATES
With SWF configured to use Spring Security, you can use the <secured> element to secure a flow, transition, or state. The <secured> element is placed in the element you
Listing 5.20 \WEB-INF\config\webflowContext.xml
want to secure. It should appear before any other elements. The following listing secures a view state.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Source project: sip05, branch: 08 (Maven Project) -->
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
start-state="unsecured">
<view-state id="secured">
<secured attributes="ROLE_USER"/>
<transition on="next" to="end" />
</view-state>
<view-state id="unsecured">
<secured attributes="ROLE_ANONYMOUS, ROLE_USER" match="any"/>
<transition on="next" to="secured" />
</view-state>
<end-state id="end"
view="externalRedirect:contextRelative:/registration"/>
</flow>
B
uses the <secured> element to secure the secured view state, whereas the unse-cured view state atC
can be accessed by those with either a ROLE_USER or ROLE_ANONYMOUS role. Here you see that the attributes attribute can take a comma-separated list of roles. The match attribute specifies how they’re interpreted. Valid val-ues are any and all.You can click through this example by pointing your browser at the following address (adjusting for host name and port number): http://localhost:8080/sip/
securityDemo.
When you’re asked for an email (username) and password, you can use the values we generated and hardcoded (see www.fakenamegenerator.com) in the application-Context-security.xml file:
Email: [email protected] Password: password
As you’ve seen, with an existing Spring Security configuration in place, adding a SecurityFlowExecutionListener to SWF’s list of flow-execution-listeners is all that is required to make Spring Security aware of SWF. Securing entire flows, individ-ual states, and transitions using the <secured> element is straightforward. Don’t worry about the details of listing 5.19 just yet; we’ll take a much deeper dive into Spring Security in the next few chapters.
Listing 5.21 \WEB-INF\flows\securityDemo\security-demo-flow.xml
Secures specific state
B
Valid values:
any, all
C
5.9 Summary
SWF’s narrow focus on addressing the problem of navigation in the web tier makes SWF intuitive to use and easy to learn. In this chapter, we introduced you to SWF and familiarized you with its features and functionality.
You started by learning about defining flows, states, how to use transitions, and managing flow data. Next you learned how to extend your existing Spring MVC appli-cation by installing and configuring SWF. Then we looked at using action classes, how to bind and validate form data, flow inheritance, and, finally, securing web flows. Our goal was to show how you can use this framework to complement your existing Spring MVC application and simplify the work required to design, maintain, and understand complex page flows in an application.
We touched briefly on using Spring Security to authorize individual states and flows in this chapter. Chapter 6 takes you much deeper into using Spring Security for authorizing user requests.
173