8. Securing Flows

8.1. Introduction

Security is an important concept for any application. End users should not be able to access any portion of a site simply by guessing the URL. Areas of a site that are sensitive must ensure that only authorized requests are processed. Spring Security is a proven security platform that can integrate with your application at multiple levels. This section will focus on securing flow execution.

8.2. How do I secure a flow?

Securing flow execution is a three step process:

  • Configure Spring Security with authentication and authorization rules

  • Annotate the flow definition with the secured element to define the security rules

  • Add the SecurityFlowExecutionListener to process the security rules.

Each of these steps must be completed or else flow security rules will not be applied.

8.3. The secured element

The secured element designates that its containing element should apply the authorization check before fully entering. This may not occur more then once per stage of the flow execution that is secured.

Three phases of flow execution can be secured: flows, states and transitions. In each case the syntax for the secured element is identical. The secured element is located inside the element it is securing. For example, to secure a state the secured element occurs directly inside that state:

<view-state id="secured-view">
    <secured attributes="ROLE_USER" />
    ...
</view-state>
		

8.3.1. Security attributes

The attributes attribute is a comma separated list of Spring Security authorization attributes. Often, these are specific security roles. The attributes are compared against the user's granted attributes by a Spring Security access decision manager.

<secured attributes="ROLE_USER" />
			

By default, a role based access decision manager is used to determine if the user is allowed access. This will need to be overridden if your application is not using authorization roles.

8.3.2. Matching type

There are two types of matching available: any and all. Any, allows access if at least one of the required security attributes is granted to the user. All, allows access only if each of the required security attributes are granted to the user.

<secured attributes="ROLE_USER, ROLE_ANONYMOUS" match="any" />
			

This attribute is optional. If not defined, the default value is any.

The match attribute will only be respected if the default access decision manager is used.

8.4. The SecurityFlowExecutionListener

Defining security rules in the flow by themselves will not protect the flow execution. A SecurityFlowExecutionListener must also be defined in the webflow configuration and applied to the flow executor.

<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-listeners>
        <webflow:listener ref="securityFlowExecutionListener" />
    </webflow:flow-execution-listeners>
</webflow:flow-executor>

<bean id="securityFlowExecutionListener" 
      class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
		

If access is denied to a portion of the application an AccessDeniedException will be thrown. This exception will later be caught by Spring Security and used to prompt the user to authenticate. It is important that this exception be allowed to travel up the execution stack uninhibited, otherwise the end user may not be prompted to authenticate.

8.4.1. Custom Access Decision Managers

If your application is using authorities that are not role based, you will need to configure a custom AccessDecisionManager. You can override the default decision manager by setting the accessDecisionManager property on the security listener. Please consult the Spring Security reference documentation to learn more about decision managers.

<bean id="securityFlowExecutionListener"
      class="org.springframework.webflow.security.SecurityFlowExecutionListener">
    <property name="accessDecisionManager" ref="myCustomAccessDecisionManager" />
</bean>
			

8.5. Configuring Spring Security

Spring Security has robust configuration options available. As every application and environment has its own security requirements, the Spring Security reference documentation is the best place to learn the available options.

Both the booking-faces and booking-mvc sample applications are configured to use Spring Security. Configuration is needed at both the Spring and web.xml levels.

8.5.1. Spring configuration

The Spring configuration defines http specifics (such as protected URLs and login/logout mechanics) and the authentication-provider. For the sample applications, a local authentication provider is configured.

<security:http auto-config="true">
    <security:form-login login-page="/spring/login" 
                         login-processing-url="/spring/loginProcess"
                         default-target-url="/spring/main" 
                         authentication-failure-url="/spring/login?login_error=1" />  
    <security:logout logout-url="/spring/logout" logout-success-url="/spring/logout-success" />
</security:http>

<security:authentication-provider>
    <security:password-encoder hash="md5" />
    <security:user-service>
        <security:user name="keith" password="417c7382b16c395bc25b5da1398cf076" 
                       authorities="ROLE_USER,ROLE_SUPERVISOR" />
        <security:user name="erwin" password="12430911a8af075c6f41c6976af22b09" 
                       authorities="ROLE_USER,ROLE_SUPERVISOR" />
        <security:user name="jeremy" password="57c6cbff0d421449be820763f03139eb" 
                       authorities="ROLE_USER" />
        <security:user name="scott" password="942f2339bf50796de535a384f0d1af3e" 
                       authorities="ROLE_USER" />
    </security:user-service>
</security:authentication-provider>
			

8.5.2. web.xml Configuration

In the web.xml file, a filter is defined to intercept all requests. This filter will listen for login/logout requests and process them accordingly. It will also catch AccesDeniedExceptions and redirect the user to the login page.

<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>