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.
16.1. How Do I Secure a Flow?
Securing a flow 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 flow security rules are not applied.
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.
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:
<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.
<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.
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.
<secured attributes="ROLE_USER, ROLE_ANONYMOUS" match="any" />
This attribute is optional.
If not defined, the default value is any
.
The match
attribute is respected only if the default access decision manager is used.
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:
<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.
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:
@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.
To learn more about Spring Security’s AuthorizationManager
API, see
Spring Security reference documentation.
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.
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.
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:
<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:
<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>