16. Securing Flows

Security is an important concept for any application. End users should not be able to access any portion of a site by simply 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 focuses on securing flow execution.spring-doc.cn

16.1. How Do I Secure a Flow?

Securing a flow is a three-step process:spring-doc.cn

  1. Configure Spring Security with authentication and authorization rules.spring-doc.cn

  2. Annotate the flow definition with the secured element to define the security rules.spring-doc.cn

  3. Add the SecurityFlowExecutionListener to process the security rules.spring-doc.cn

Each of these steps must be completed, or flow security rules are not applied.spring-doc.cn

16.2. The secured Element

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

Three phases of a flow 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 secures. For example, to secure a state, the secured element occurs directly inside that state, as follows:spring-doc.cn

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

16.2.1. Security Attributes

The value of attributes 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.spring-doc.cn

<secured attributes="ROLE_USER" />

By default, an authority-based AuthorizationManager is used to determine if the user is allowed access. This needs to be overridden if your application is not using authorization roles.spring-doc.cn

16.2.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 is granted to the user.spring-doc.cn

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

This attribute is optional. If not defined, the default value is any.spring-doc.cn

The match attribute is respected only if the default access decision manager is used.spring-doc.cn

16.3. The SecurityFlowExecutionListener

Defining security rules in the flow by themselves does not protect the flow. You must also define a SecurityFlowExecutionListener in the webflow configuration and apply it to the flow executor, as follows:spring-doc.cn

<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 is thrown. This exception is later 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.spring-doc.cn

16.3.1. Custom Authorization Managers

If your application uses authorities that are not role-based, you need to configure a custom AuthorizaitonManager. You can override the AuthorityAuthorizationManager used by default through the authorizationManagerInitializer property on the security listener. For example:spring-doc.cn

@Bean
SecurityFlowExecutionListener securityFlowExecutionListener() {
	SecurityFlowExecutionListener listener = new SecurityFlowExecutionListener();
	listener.setAuthorizationManagerInitializer(securityRule -> {
		// ...
	});
	return listener;
}

16.3.2. Custom Access Decision Managers

Spring Security’s AccessDecisionManager is deprecated and will be removed in a future version. Therefore, it is recommended to configure an AuthorizationManager instead. However, if you must use an AccessDecisionManager, you can either set the accessDecisionManager property of the security listener, or override the createAccessDecisionManager(SecurityRule) protected method.spring-doc.cn

To learn more about Spring Security’s AuthorizationManager API, see Spring Security reference documentation.spring-doc.cn

16.4. 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.spring-doc.cn

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

16.4.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. The following example configures Spring Security for a web flow:spring-doc.cn

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

16.4.2. web.xml Configuration

In the web.xml file, a filter is defined to intercept all requests. This filter listens for login and logout requests and processes them accordingly. It also catches AccesDeniedException instances and redirects the user to the login page. The following example defines such filters:spring-doc.cn

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