Unfortunately, even as this book is being written, testing subflows is still cumbersome and there are a lot of bugs opened and unresolved.8

When the scope is to test the subflows too, the getModelResources method of AbstractXmlFlowExecutionTests must be overridden. Add the subflow definition to the flow resources being tested:

import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.test.MockExternalContext;
import org.springframework.webflow.test.MockFlowBuilderContext;
import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests;

 public class NewPersonFlowTest extends AbstractXmlFlowExecutionTests {
...
  @Override
    protected FlowDefinitionResource
    getModelResources(FlowDefinitionResourceFactory resourceFactory) {
        FlowDefinitionResource flowDefinitionResources =
                new FlowDefinitionResource2;
        flowDefinitionResources0 = resourceFactory.createResource
                ("src/main/webapp/WEB-INF/persons/newPerson/newPerson-flow.xml");
        flowDefinitionResources1 = resourceFactory.createResource
                ("src/main/webapp/WEB-INF/hospitals/newHospital/newHospital-flow.xml");
        return flowDefinitionResources;
    }
    ...
}

Image !  Considering that the subflows are not a topic for the exam, there is no practice project with configurations missing, but a project was created that you can run and inspect to see the subflow to add a Hospital instance running:

 13-pr-webflow-subflow-solution.

Image ?  As a proposed exercise, if you want to test your understanding of subflows, you can try to turn the creating of an Account instance into a subflow.

Flow Definition Inheritance

Flow definitions can be organized in hierarchies in a way similar way to bean definitions. Organizing them in hierarchies allows global transitions, common states, and actions to be shared among parent and children flows.

The child flow and the parent flow are both registered in the same flow registry.

There are a few things regarding flow definition inheritance that are interesting and worth covering. One of them is that multiple inheritance is supported, because inheritance between web flow definitions is more like a composition; basically, a child flow definition inherits all configuration elements form its parents, and elements with the same id are merged. Multiple parents are specified using comma as a separator:

<flow ... parent="parentFlow1, parentFlow2" />
 ...
</flow>

Parent flow definitions can also be abstract. In this case, these flows cannot be instantiated and executed; their purpose in the code is to wrap up common definition elements for multiple child flow definitions, to respect the DRY principle.9

<flow ... abstract="true" />
 ...
</flow>

Flow inheritance is analogous to bean definition inheritance. It is more a composition than inheritance, as parent and child are merged together to create a new flow.

Another interesting thing is that flow definition inheritance can be selective, meaning there is a way that only certain state definitions can be inherited, instead of the whole parent flow definition:

<flow ... parent="parentFlowName"/>
        <view-state id="childState" parent="parentFlowName#stateId">
</flow>

The restriction here is that the child flow can inherit only from one parent when restrictions are defined at the state level. Also, the child state definition type must be one and the same with the parent state definition. In the preceding example, the state element with stateId must be of type view-state in the parent too; otherwise, the web flow configuration is invalid.

Securing Web Flows

Before talking about how to secure web flows, a detailed introduction into Spring Security is necessary, because you need to understand core security concepts and how they can be configured with Spring Security.

Introduction to Spring Security

Spring Security is a framework that can be used to secure web applications. It is very easy to use and highly customizable, providing access control over units of an application. When writing secure Spring web applications, this is the default tool that developers go to because configuration follows the same standard with all the Spring projects. Infrastructure beans are provided out of the box for multiple types of authentication and they are clearly compatible with other Spring projects. Spring Security provides a wide set of capabilities that can be grouped in four areas of interest: authentication, authorizing web requests, authorizing methods calls, and authorizing access to individual domain objects.

The following are Spring Security’s core features:

  • Authentication (user identification) and authorization (managing access to resources); comprehensible and extensible support is provided.
  • It is easy to configure.
  • It is highly customizable.
  • Protection against session fixation, clickjacking, cross-site request forgery, and other type of attacks is provided via simple and flexible configurations.
  • It can be integrated with the Servlet API.

Of course, there are more. You can read more about them on the official page of this project.10

There are five security concepts that you have to familiarize yourself with and understand to use Spring Security:

  • Credentials are identification keys that an entity presents to the application to confirm their identity( a password or a token).
  • Principal represents an authenticated entity that was recognized by the application based on its credentials.
  • Authentication is the process that determines if the credentials of an entity are valid.
  • Authorization is the process that determines if a principal is allowed access to a resource or performs a certain action. The decision process is often based on roles. The following are the most common roles:
    • GUEST, usually can just view data
    • MEMBER (or USER), can insert data
    • ADMIN, can insert and delete data
  • Secured item is a resource that is being secured.

The Spring Security version used in the book is 4.0.2.RELEASE and it is compatible with Spring 4. In the Gradle configuration of the 14-pr-web-security-practice module project, notice that the following libraries have been added:

springSecurityVersion = '4.0.2.RELEASE'
...
securityConfig : "org.springframework.security:spring-security-config:
                                   $springSecurityVersion",
securityWeb    : "org.springframework.security:spring-security-web:
                                  $springSecurityVersion",
securityTaglibs: "org.springframework.security:spring-security-taglibs:
                                 $springSecurityVersion",
...
}

Why Spring Security Is Awesome

The spring-security-config module provides security namespace parsing code and is needed when using XML configuration. As some developers still prefer to use XML configuration, the minimum configuration needed in XML is explained in the book alongside the Java Configuration. The spring-security-web provides filters and related web-security infrastructure beans. This library is needed for web-based authentication. The spring-security-taglibs provides security tags that can be used to secure elements in JSP pages.

The main reason why Spring Security is preferred when developing web applications is portability. Spring Security does not need a special container to run in; it can be deployed as a secured archive (WAR or EAR) and can run in stand-alone environments. For example, a secured web application archived as a WAR can be deployed on a JBoss or an Apache Tomcat application server. And as long as the underlying method of storing credentials is configured, the application will run exactly the same in any of these application servers.

When it comes to authentication and credential storage, Spring Security is very flexible. All common authentication mechanisms are supported (Basic, Form, OAuth, X.509, cookies, single sign-on). Regarding support storage for credentials databases, Spring Security supports anything—LDAP, properties file, custom DAOs, and even beans, among many others.11

Configuring Spring Security is easy. A common practice is to define a separate file when using XML and a separate configuration class when using Java Configuration. Infrastructure beans can be used to customize the following:

  • How a principal is defined
  • Where authentication information is stored
  • How authorization decisions are made
  • Where security constraints are stored

As we have seen so far when using Spring, anything can be done by keeping components as decoupled as possible. Spring Security respects the principle of separation of concerns (SoC). Restrictions are applied using an interceptor-based approach. It was mentioned at the beginning of the book that AOP is used when securing resources. Also, authentication and authorization are decoupled; changing the authentication method and credentials support does not affect authorization.

Spring Security is consistent. The authentication purpose is to create a security context with the principal’s information; it does not depend on the mechanism used. The authorization process has the same purpose, regardless of the resource type: consult resource properties, consult the principal’s role, and decide to grant or deny access.

The way Spring Security works and the core components are depicted in Figure 7-24.

9781484208090_Fig07-24.jpg

Figure 7-24. Spring Security anatomy

The following explains the flow described in Figure 7-24:

  1. The user makes a login request. (Introduces credentials in a login form and submits it.)
  2. The user logs into the application and the Authentication Manager populates the security information of the user into the security context.
  3. When the user makes resource requests (requests to view a page, starts a flow, requests a document) after logging in, the security interceptor intercepts them before they invoke a protected/secured resource.
  4. The Security Interceptor then retrieves the user information from the context.
  5. The Access Decision Manager polls a list of voters to return a decision regarding the rights the authenticated user has on system resources
  6. The Spring Interceptor consults the resource attributes that are configured in the application.
  7. Access is granted or denied to the resource based on the user rights (5) and the resource attributes (6).

Spring Security XML Configuration

When using XML to configure Spring Security, any tag can be used by adding the security namespace to the Spring configuration file at http://www.springframework.org/schema/

security/spring-security.xsd. The recommended practice is to have a separate configuration file that contains only the security-related configurations.

To log in to the Personal Records Manager application, a separate file should be created, named security-config.xml. This file should define the users and credentials needed to access the application and which resources these users can access:

<!-- security-config.xml -->
<beans xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- styling&internationalization resources do not need to be secured -->
    <sec:http pattern="/images/*" security="none"/>
    <sec:http pattern="/styles/*" security="none"/>
    <sec:http pattern="/resources/*" security="none"/>

    <sec:http auto-config="true">
        <sec:intercept-url pattern="/auth*" access="permitAll"/>
        <sec:intercept-url pattern="/persons/newPerson"
                           access="ROLE_ADMIN"/>
        <sec:intercept-url pattern="/**"
                           access="ROLE_USER, ROLE_ADMIN"/>
        <sec:form-login login-page="/auth"
                           authentication-failure-url="/auth?auth_error=1"
                           default-target-url="/"/>
        <sec:logout logout-url="/j_spring_security_logout"
           logout-success-url="/home />
    </sec:http>

    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user name="john" password="doe"
                          authorities="ROLE_USER"/>
                <sec:user name="jane" password="doe"
                          authorities="ROLE_USER,ROLE_ADMIN"/>
                <sec:user name="admin" password="admin"
                          authorities="ROLE_ADMIN"/>
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

The configuration presented earlier uses basic authentication, without any password encryption. The auto-config="true" is a legacy attribute that automatically registers a login form, BASIC authentication, and a logout URL and logout services. It is not meant to be used for production applications, as the level of security required is higher than the default one provided by Spring Security out of the box for educational purposes.

The <intercept-url /> elements are evaluated in the order they are listed into the configuration, so the most restrictive ones need to be at the top of the list; otherwise, the result might not be the expected one.

Three users are defined with different roles. Access to the newPerson flow has been restricted to users having the ROLE_ADMIN role, to test the configuration. This file is Spring Security 3.0–specific and it won’t work in a Spring Security 4 environment, because this version has introduced a lot of changes.

The <sec:logout /> logout element is used to customize logout details. The logout-url attribute specifies the URL that will cause a logout. Spring Security initializes a filter that responds to this particular URL. The logout-success-url attribute is used to define where the user is redirected after logging out.

In the <sec:form-login /> the URL of the page used for authentication is set as a value for the login-page attribute. After successfully logging in, the user is redirected to the page set as a value for the default-target-url attribute. In case of failure, the user is redirected to the login view, and using the auth_error parameter, a proper value is displayed to the user. The auth.jsp template file presents to the user a login form looks like this for Spring Security 3:

<!-- auth.jsp -->
 <form action="<c:url value='/j_spring_security_check'/>" method="post">
       <table>
           <tr>
               <td>
                  <label for="j_username">
                    <spring:message code="login.username"/>
                  </label>
               </td>
               <td>
                  <input type='text' id='j_username' name='j_username'
                      value='<c:out value="${user}"/>'/>
               </td>
           </tr>
           <tr>
               <td>
                  <label for="j_password">
                      <spring:message code="login.password"/>
                  </label>
               </td>
                <td><input type='j_password' id='password'
                     name='j_password'/></td>
           </tr>
           <tr>
               <td colspan="2">
                   <button type="submit">
                       <spring:message code="login.submit"/>
                   </button>
               </td>
           </tr>
       </table>
        <c:if test="${not empty param.auth_error}">
       <div id="errors" class="error">
<!-- detailed security exception message is printed for development purposes -->
<!-- obviously, not recommended to be used in a production application -->
        <p><spring:message code="login.fail"/>:
           ${SPRING_SECURITY_LAST_EXCEPTION.message}
       </p>
      </div>
    </c:if>
</form>

There is another way to specify access by using Spring Security Expressions, but they must be enabled by declaring the use-expressions="true" attribute on the <sec:http /> configuration element. So, the access attributes under the <sec:http /> configuration element become this:

<sec:http auto-config="true" use-expressions="true">
    <sec:intercept-url pattern="/auth*" access="permitAll"/>
     <sec:intercept-url pattern="/persons/newPerson"
           access="hasRole('ROLE_ADMIN')"/>
    <sec:intercept-url pattern="/**"
           access="hasAnyRole('ROLE_USER, ROLE_ADMIN')"/>
    <sec:form-login login-page="/auth"
          authentication-failure-url="/auth?auth_error=1"
          default-target-url="/"/>
    <sec:logout logout-url="/j_spring_security_logout"/>
</sec:http>

Image !  Mixing expression style configuration with direct configuration is not permitted. You either use expressions or you don’t. Mixing them will make your configuration file invalid.

Spring Security Expressions are quite easy to use and understand:

  • hasRole('role') checks whether the principal has the given role.
  • hasAnyRole('role1', 'role2', ?) checks whether the principal has any of the given roles.
  • isAuthenticated() allows access for authenticated or remembered principals.
  • permitAll allows unauthenticated users access to a resource. In the previous example, this is used to make sure that the login form is accessible so a user can insert his credentials for authentication to take place.
  • Expressions can be aggregated hasRole('ROLE_ADMIN') and hasRole('ROLE_MANAGER').

The preceding configuration is relative to the beans namespace. Considering that the configuration file contains only security tags, the file could be created relative to the security namespace, and so the sec prefix would not be necessary, which makes the file more readable:

 <?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/security
             http://www.springframework.org/schema/security/spring-security.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd">

    <http pattern="/images/*" security="none"/>
    <http pattern="/styles/*" security="none"/>
    <http pattern="/resources/*" security="none"/>

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/auth*" access="permitAll"/>
        <intercept-url pattern="/persons/newPerson"
              access="hasRole('ROLE_ADMIN')"/>
        <intercept-url pattern="/**"
              access="hasAnyRole('ROLE_USER, ROLE_ADMIN')"/>
        <form-login login-page="/auth"
            authentication-failure-url="/auth?auth_error=1"
                        default-target-url="/"/>
        <logout logout-url="/j_spring_security_logout"/>
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="john" password="doe" authorities="ROLE_USER"/>
                <user name="jane" password="doe"
                       authorities="ROLE_USER,ROLE_ADMIN"/>
                <user name="admin" password="admin" authorities="ROLE_ADMIN"/>
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

Spring Security 4 has introduced a few critical changes that need coverage in this book; because by the time this book is published, Spring Security 4 might be a subject on the exam.

Image !  Spring Security 4 has introduced the possibility of using CSFR tokens in Spring forms to prevent cross-site request forgery.12 A configuration without a <csrf /> element configuration is invalid, and any login requests direct you to a 403 error page stating:

 Invalid CSRF Token 'null' was found on the request parameter
 '_csrf' or header 'X-CSRF-TOKEN'.

To migrate from Spring Security 3 to version 4, you have to add a configuration for that element, even if all you do is disable using CSRF tokens.

<http auto-config="true" use-expressions="true">
      <csrf disabled="true"/>
      <intercept-url pattern="/auth*" access="permitAll"/>
      <intercept-url pattern="/persons/newPerson" access="hasRole('ADMIN')"/>
      <intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')"/>
      <form-login login-page="/auth"
                  authentication-failure-url="/auth?auth_error=1"
                  default-target-url="/"/>
      <logout logout-url="/logout"
                  delete-cookies="JSESSIONID"
                  logout-success-url="/"/>
</http>

The delete-cookies attribute can be used to specify a list of cookies to delete at logout time. In the previous configuration, only one is specified, named JSESSIONID; but if the application uses more cookies, they can be specified as a value for this attribute using their names separated by commas.

Image !  Other critical changes are related to the login form default Spring resources, such as the login URL (that indicates an authentication request) and names of the request parameters (expected keys for generation of an authentication token).13 These were changed to match JavaConfig. The login form in the auth.jsp view became the following:

<form action="<c:url value='/login'/>" method="post">
     <table>
         <tr>
             <td>
               <label for="username">
                 <spring:message code="login.username"/>
               </label>
               </td>
            <td>
              <input type='text' id='username' name='username'
                  value='<c:out value="${user}"/>'/>
            </td>
        </tr>
        <tr>
            <td>
                <label for="password">
                    <spring:message code="login.password"/>
                </label>
           </td>
            <td><input type='password' id='password' name='password'/></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">
                   <spring:message code="login.submit"/>
                </button>
            </td>
        </tr>
    </table>
</form>

Image !  All previous examples used default values for the login URL and the authentication key names j_spring_security_check, j_username, j_password (in Spring Security 3), login, username, password (in Spring Security 4). Keep in mind that all of them can be redefined using Spring configuration.

If you are interested in keeping your form as secure as possible, you can configure CSRF usage and add the token generated by Spring to your form. The following are the required modifications:

  • First you must enable CSRF generation in your security-config.xml file by adding a <csrf /> configuration element and a repository to generate the value for it. Modify the logout element appropriately; the third bullet in this list tells you why.
    <beans:beans .../>
       <beans:bean id="tokenRepo"
    class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
            <beans:property name="sessionAttributeName" value="_csrf"/>
        </beans:bean>

       <http auto-config="true" use-expressions="true">
            <csrf token-repository-ref="tokenRepo"/>
            <intercept-url pattern="/auth*" access="permitAll"/>
            <intercept-url pattern="/persons/newPerson" access="hasRole('ADMIN')"/>
            <intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')"/>
            <form-login login-page="/auth"
                 authentication-failure-url="/auth?auth_error=1"
                            default-target-url="/"/>
           <logout logout-url="/logout"
           delete-cookies="JSESSIONID"
           invalidate-session="true"
            logout-success-url="/"/>
        </http>
        ...
    </beans:beans>
  • Second, you must add a hidden parameter in every form that you are interested in protecting form cross-site request forgery.
    <form action="<c:url value='/login'/>" method="post">
     <input type="hidden"
        name="${_csrf.parameterName}" value="${_csrf.token}"/>
     <table>
         <tr>
             <td>
               <label for="username">
                 <spring:message code="login.username"/>
               </label>
                   </td>
                <td>
                  <input type='text' id='username' name='username'
                      value='<c:out value="${user}"/>'/>
                </td>
            </tr>
            <tr>
                <td>
                    <label for="password">
                       <spring:message code="login.password"/>
                    </label>
               </td>
                <td><input type='password' id='password' name='password'/></td>
            </tr>
            <tr>
                <td colspan="2">
                    <button type="submit">
                       <spring:message code="login.submit"/>
                    </button>
                </td>
            </tr>
        </table>
    </form>
  • And last, logging out becomes a pain when CSRF is enabled, because you need to log out using a POST request. Thus, you cannot just use a link build like this (like in Spring Security 3):
    <a href="<spring:url value="/j_spring_security_logout"/>">
       <spring:message code="menu.logout"/>
    </a>

    You need to add a logout form to the page and submit it using JavaScript:

    <spring:url value="/logout" var="logoutUrl" />
      <form action="${logoutUrl}" id="logout" method="post">
             <input type="hidden" name="${_csrf.parameterName}"
                  value="${_csrf.token}"/>
      </form>
    <a href="#" onclick="document.getElementById('logout').submit();">
        <spring:message code="menu.logout"/>
    </a>

Also, as we’ve been mentioning logout, you probably noticed the extra attributes of the <logout /> element; their names are quite obvious, and if specified at logout, the specific resources are cleaned accordingly:

<logout logout-url="/logout"
                delete-cookies="JSESSIONID"
                invalidate-session="true"
                logout-success-url="/"/>

Also, a handler can be used instead of the logout-success-url that takes care of redirecting to the proper page and eventually cleaning up any resources:

<logout logout-url="/logout"
               delete-cookies="JSESSIONID"
                success-handler-ref="logoutSuccessHandler"/>

To view the token Spring Security has generated, you can use Firebug to view the contents of your login request. You should see something similar to what is depicted in Figure 7-25.

9781484208090_Fig07-25.jpg

Figure 7-25. Spring Security CSRF token

Image !  Another simplification change that can be done to this file is provided by a new feature introduced in Spring Security 4 that allows access expressions to be specified without the ROLE_ prefix in front of them; thus, the preceding configuration becomes this:

<http auto-config="true" use-expressions="true">
   <csrf disabled="true"/>
   <intercept-url pattern="/auth*" access="permitAll"/>
   <intercept-url pattern="/persons/newPerson" access="hasRole('ADMIN')"/>
   <intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')"/>
     <form-login login-page="/auth" authentication-failure-url="/auth?auth_error=1"
                     default-target-url="/"/>
    <logout logout-url="/j_spring_security_logout"/>
</http>

 <authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="john" password="doe" authorities="ROLE_USER"/>
            <user name="jane" password="doe" authorities="ROLE_USER,ROLE_ADMIN"/>
            <user name="admin" password="admin" authorities="ROLE_ADMIN"/>
        </user-service>
    </authentication-provider>
 </authentication-manager>

Another part of configuration needs to be added in the web.xml file, if used. A security filter needs to be added to intercept all requests to the application. springSecurityFilterChain is a mandatory name and refers to an infrastructure bean with the same name. This bean is responsible for all the security within the application (protecting the application URLs, validating submitted usernames and passwords, redirecting to the log in form, etc.).

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

Configure Authentication

It was mentioned that authentication can be configured to work with almost any credential support technology. In this subsection, a few of them are covered. By default, in Spring Security the DAO authentication provider is used, as well as a specific UserDetailsService implementation to provide credentials and authorities. In the examples so far, the credentials were basically read from the configuration file and stored into memory. The credentials were not encrypted, so even if Spring Security is used, the application is not that secure. To encrypt credentials, the configuration must be modified to specify the encryption type:

 <!-- spring-config.xml -->
<authentication-manager>
   <authentication-provider>
         <password-encoder hash="md5" >
                 <salt-source system-wide="MySalt"/>
         </password-encoder>
         <user-service properties="/WEB-INF/users.properties" />
   </authentication-provider>
</authentication-manager>

#/WEB-INF/users.properties
john=a1c093d7a2742f0afef7720883a59016,ROLE_USER
#password: john

jane=a1c093d7a2742f0afef7720883a59016,ROLE_USER,ROLE_ADMIN
#password: jane

admin=5a693853b2958ecb256db46b808ac488,ROLE_ADMIN
#password: admin

In the preceding configuration, the md514 algorithm is used to encrypt the passwords and a method called password-salting is used to increase the security passwords by adding a well-known string to them. The string added to the password can be an application-wide string, like in the previous example where the String is "MySalt", or it can be a property of the entity—something that won’t change, like its unique identifier in the system, for example. A combination of properties can be used as salt too, but all the properties must be constant for the duration of the entity; if any of the property values changes, the user won’t be able to log in anymore because the authentication system won’t be able to create the correct hash.

The preceding encrypted strings were generated using an instance of org.springframework.security.authentication.encoding.Md5PasswordEncoder:

import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
public class PasswordGenerator {

    public static void main(String args) {
        Md5PasswordEncoder encoder = new Md5PasswordEncoder();
        String encrypted = encoder.encodePassword("doe", "MySalt");
        System.out.println(encrypted);
        encrypted = encoder.encodePassword("admin", "MySalt");
        System.out.println(encrypted);
    }
}

To use an entity property as salt, the previous configuration must be modified like this:

<authentication-manager>
    <authentication-provider>
        <password-encoder hash="md5">
           <salt-source user-property="id" />
       </password-encoder>
     </authentication-provider>
</authentication-manager>

The credentials were decoupled from the configuration by isolating them in a property file, which can be easily edited without needing to recompile the application. The credentials property file has a specific syntax:

[username] = [password(encrypted)],[role1,role2...]

But credentials in memory storage is not a solution for production applications; this is only suitable for very small and educational applications. For production application, the most common storage for credentials is a database. To provide these credentials to the authentication manager, a data source is needed:

<authentication-manager>
  <authentication-provider>
          <jdbc-user-service data-source-ref="authDataSource" />
     </provider>
</authentication-manager>

Two tables must be accessible using the authDataSource: one named users containing user credentials and one named authorities continuing user-role correspondences. The following queries are run by the authentication provider and must execute successfully:

SELECT username, password, enabled FROM users WHERE username = ?
SELECT username, authority FROM authorities WHERE username = ?

Another way to provide credentials is to write a custom implementation for an authentication provider:

  <authentication-manager>
    <authentication-provider user-service-ref="customCredentialsProvider" />
</authentication-manager>

The provider class can delegate to a DAO implementation to retrieve principals from a database using a data source and customized queries. The information is returned into a format recognized in the application. In the following example, an instance of type UserInfo is used as a principal in the application:

 [commandchars=*
@Repository
public class CustomCredentialsProvider {
    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public UserInfo getUserInfo(String username){
            String sql = "SELECT u.username name, u.password pass,"+
                    a.authority role FROM "+
                     "users u INNER JOIN authorities a" +
                    on u.username=a.username WHERE "+
                     "u.enabled =1 and u.username = ?";
            UserInfo userInfo =
           (UserInfo)jdbcTemplate.queryForObject(sql, new Object{username},
                    new RowMapper<UserInfo>() {
                    public UserInfo mapRow(ResultSet rs, int rowNum)
                      throws SQLException {
                        UserInfo user = new UserInfo();
                        user.setUsername(rs.getString("name"));
                        user.setPassword(rs.getString("pass"));
                        user.setRole(rs.getString("role"));
                        return user;
                    }
        });
            return userInfo;
    }
}
//UserInfo.java
public class UserInfo {
        private String username;
        private String password;
        private String role;
        //setter and getters for fields
}

No web.xml Configuration

As the official documentation says, if Spring Security is used with Spring MVC, you need an extra empty class that extends org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer, a class provided by Spring Security that ensures that the springSecurityFilterChain gets registered. Also, you need to include the Spring Security XML configuration file in the Java Configuration, as depicted in the following code sample:

import org.springframework.security.web.context.
         AbstractSecurityWebApplicationInitializer;
// Empty class needed to register the springSecurityFilterChain bean
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
public class WebInitializer extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        XmlWebApplicationContext ctx = new XmlWebApplicationContext();
        ctx.setConfigLocation("/WEB-INF/spring/security-config.xml");
        return ctx;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        XmlWebApplicationContext ctx = new XmlWebApplicationContext();
        ctx.setConfigLocations("/WEB-INF/spring/mvc-config.xml",
                "/WEB-INF/spring/app-config.xml",
                "/WEB-INF/spring/webflow-config.xml");
        return ctx;
    }
    ...
}

But as Java Configuration and web initializer classes were introduced to simplify configuration and get rid of all XML, all the preceding configurations will soon be deprecated.

Spring Security Java Configuration

The XML configuration style is close to its death, as Java Configuration gains popularity. So it was expected that Spring Security adapt, and they did. The Java Configuration is super-simple and intuitive. When working with Spring MVC and Spring Security to develop a working security configuration, you need to do the following:

  1. Create an empty class extending AbstractSecurityWebApplicationInitializer to get the springSecurityFilterChain registered (as mentioned at the end of the previous section).
  2. Create a security configuration class that extends WebSecurityConfigurerAdapter so that the developer can write the minimum amount of code for a valid security configuration. The security configuration class equivalent to the XML configuration presented in the previous section is depicted in following code snippet:
    package com.pr.config;
    ...
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation
            .authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation
            .web.builders.HttpSecurity;
    import org.springframework.security.config.annotation
            .web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation
            .web.configuration.WebSecurityConfigurerAdapter;

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

            @Autowired
            public void configureGlobal(AuthenticationManagerBuilder auth) {
                try {
                    auth.inMemoryAuthentication()
                            .withUser("john").password("doe").roles("USER").and()
                            .withUser("jane").password("doe").roles("USER,ADMIN").and()
                            .withUser("admin").password("admin").roles("ADMIN");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                        .authorizeRequests()
                        .antMatchers("/resources/**","/images/**","/styles/**")
                             .permitAll()
                        .antMatchers("/persons/newPerson").hasRole("ADMIN")
                        .antMatchers("/**").hasAnyRole("ADMIN","USER")
                        .anyRequest()
                        .authenticated()
                        .and()
                     .formLogin()
                        .usernameParameter("username") // customizable
                        .passwordParameter("password") // customizable
                        .loginProcessingUrl("/login")  // customizable
                        .loginPage("/auth")
                        .failureUrl("/auth?auth_error=1")
                        .defaultSuccessUrl("/home")
                        .permitAll()
                        .and()
                    .logout()
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/")
                    .and()
                    .csrf().disable();
        }
    }

    To enable CSRF usage, the preceding configuration must also define a CSRF provider bean and use it in the configuration:

    ...
    import org.springframework.security.web.csrf.CsrfTokenRepository;
    import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;

     @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
        public CsrfTokenRepository repo() {
            HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository();
            repo.setParameterName("_csrf");
            repo.setHeaderName("X-CSRF-TOKEN");
            return repo;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
           http.
           ...
            .and()
            .csrf().csrfTokenRepository(repo());
        }
    }

No web.xml Configuration

Add the Security configuration class to the root context in the class taking care of loading all the MVC environment components:

 package com.pr.config;
 ...
 import com.pr.config.MvcConfig;
import com.pr.config.SecurityConfig;
import com.pr.config.WebFlowConfig;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet
      .support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;

public class WebInitializer
         extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?> getRootConfigClasses() {
        return new Class<?>{
                SecurityConfig.class
        };
    }

    @Override
    protected Class<?> getServletConfigClasses() {
        return new Class<?>{
                MvcConfig.class,
                WebFlowConfig.class
        };
    }
...
}

Image !  The SecurityConfig.class (and the Spring Security XML config file) were added to the root context because they define beans that can be used by other servlets and services in the same application. The getServletConfigClasses() is used only to instantiate the servlet-related beans.

Spring Security Tag Library

Security tags can be used in JSP directly to secure elements in the page and prevent their rendering if the authenticated user is not allowed to see them. To use them, the Spring Security Tag library must be declared in the JSP page:

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

In the examples attached to this chapter, two elements were secured in JSP:

  • The logout link must be visible only when a user is authenticated; the following is the syntax to do this:
    <!-- layout.jsp, tiles main template file -->
     <sec:authorize access="isAuthenticated()">
       <li>
       <!-- we are using Security for with CSRF enabled -->
              <spring:url value="/logout" var="logoutUrl" />
                 <form action="${logoutUrl}" id="logout" method="post">
                     <input type="hidden" name="${_csrf.parameterName}"
                         value="${_csrf.token}"/>
                 </form>
              <a href="#" onclick="document.getElementById('logout').submit();">
                  <spring:message code="menu.logout"/>
              </a>
       </li>
    </sec:authorize>

    So basically, the same expressions used when configuring Spring Security are used for the access attribute.

  • The NewPerson link must be visible only to users with the ADMIN role:
    <!-- templates/layout.jsp -->
    <sec:authorize access="hasRole('ADMIN')">
          <li>
          <!--menuTab is a tiles attribute -->
                <c:if test="${menuTab eq 'newPerson'}">
                      <strong>
                          <a href="<c:url value="/persons/newPerson"/>">
                               <spring:message code="menu.new.person"/>
                          </a>
                       </strong>
                    </c:if>
                        <c:if test="${menuTab != 'newPersons'}">
                          <a href="<c:url value="/persons/newPerson"/>">
                              <spring:message code="menu.new.person"/>
                           </a>
                    </c:if>
          </li>
    </sec:authorize>

And another tag was used to display information about the user being logged in:

<!-- layout.jsp, tiles main template file -->
 <div class="footer">
        <sec:authorize access="isAuthenticated()">
            <p><spring:message code="user.loggedin"/>:
                <sec:authentication property="principal.username"/>
            </p>
        </sec:authorize>
            <p><spring:message code="footer.text"/></p>
    </div>

Using the Spring Tag library and intercept-url definitions, access to resources can be centralized in the Spring Security configuration file or class, because the access attribute can be replaced with the url attribute that is set with URLs that are intercepted by Spring Security.

<!-- layout.jsp, tiles main template file -->
<sec:authorize access="hasRole('ADMIN')">
                //New Person link
</sec:authorize>
// can be written as
<sec:authorize url="/persons/newPerson">
              //New Person link
</sec:authorize>

Securing Methods

Spring Security uses AOP to secure method calls. The Spring Security namespace can be used to configure method security using XML. But the most commonly used and easy-to-understand way to secure methods is through annotations. Spring Security provides its own annotations, but JSR-250 annotations are supported too. Samples for all ways of securing methods are covered.

Assuming you want to secure all action methods involved in the newPerson flow, this is how it is done using XML:

<!-- security-config.xml -->
<security:global-method-security>
  <security:protect-pointcut
    expression="execution(* com.pr..*Actions.*(..))?
         access="hasRole('ROLE_ADMIN')" />
</security:global-method-security>

Of course, method security must be enabled, which can be done by adding the following element in the security configuration file:

<!-- security-config.xml -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/security
             http://www.springframework.org/schema/security/spring-security.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd">

<global-method-security
               secured-annotations="enabled" />
                ..
</beans:beans>

Securing an action method using annotations can be done using the @Secured Spring annotation, which is activated when the global-method-security element is present in the configuration.

//AccountActions.java
...
import org.springframework.security.access.annotation.Secured;

@WebFlowAction
public class AccountActions extends MultiAction {

    @Secured("ROLE_ADMIN")
    public Event saveAccount(RequestContext context) {
       ...
    }
}

The equivalent of the global-method-security XML configuration is @EnableGlobalMethodSecurity(securedEnabled = true) , which can be placed on any configuration class annotated with @Configuration:

//SpringConfig.java
...
import org.springframework.security.config.annotation.
      method.configuration.EnableGlobalMethodSecurity;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}

To enable JSR-250 annotations, and especially the @RolesAllowed annotation (that is an equivalent for Spring @Secured), the following configurations must be made:

<!-- security-config.xml -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/security
             http://www.springframework.org/schema/security/spring-security.xsd
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd">

<global-method-security
                 jsr250-annotations="enabled" />

                  ..
 </beans:beans>
//SpringConfig.java
...
import org.springframework.security.config.annotation.
      method.configuration.EnableGlobalMethodSecurity;
@Configuration
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}

Usage of @RolesAllowed is the same as @Secure, so the preceding code would become this:

//AccountActions.java
...
import javax.annotation.security.RolesAllowed;

@WebFlowAction
public class AccountActions extends MultiAction {

    @RolesAllowed("ROLE_ADMIN")
    public Event saveAccount(RequestContext context) {
       ...
    }
}

Spring Security also provides the @PreAuthorize annotation, which is used to set an expression that is evaluated to decide if the method is invoked or not. (Basically, the equivalent of the <intercept /> XML configuration element.) Being a Spring Security annotation, it supports SpEL. This annotation can be used if it has been enabled using the @EnableGlobalMethodSecurity annotation. The code snippet depicts the configuration and usage for this specific case:

//SpringConfig.java
...
import org.springframework.security.config.annotation.
      method.configuration.EnableGlobalMethodSecurity;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...

//AccountActions.java
...
import org.springframework.security.access.prepost.PreAuthorize;

@WebFlowAction
public class AccountActions extends MultiAction {
  @PreAuthorize("hasAuthority('ROLE_ADMIN')")
  public Event saveAccount(RequestContext context) {
     ...
  }
}

Securing Flow Definitions

Any component of a flow definition—states, subflows, transitions—can be considered resources and thus secured. So far, we have secured the web-flow link by using a <sec:authorize /> element in the templates/layout.jsp tiles template and setting up authentication and authorization. But flow components can be secured using a org.springframework.webflow.security.SecurityFlowExecutionListener and by adding <secured> elements in the flow definition. Considering that authentication and authorization rules have been set up as described earlier, the next step is to configure a SecurityFlowExecutionListener. This can be done using XML configuration by adding the bean definition in the configuration file setting up the web flow environment, webflow-config.xml.

<!--webflow-config.xml-->
 <flow ...>
     <!-- Executes web flows -->
    <webflow:flow-executor id="flowExecutor" >
        <webflow:flow-execution-listeners>
            <webflow:listener ref="auditExecutionListener"/>
            <webflow:listener ref="securityFlowExecutionListener"/>
        </webflow:flow-execution-listeners>
    </webflow:flow-executor>

    <bean id="auditExecutionListener"
      class="com.pr.audit.AuditFlowExecutorListener"/>

<bean id="securityFlowExecutionListener"
   class="org.springframework.webflow.security.SecurityFlowExecutionListener"/>
   ... // other flow infrastrucure beans
</flow>

Image !  The AuditFlowExecutorListener bean is a developer helper bean: that is it prints information when a web flow event is triggered, when states are entered, and when exceptions are thrown. The class is present in the sample project for this chapter, but its code is not relevant for this topic.

This bean can be configured using Java Configuration by declaring it in the web flows configuration class:

//WebFlowConfig.java
...
import org.springframework.webflow.security.SecurityFlowExecutionListener;

@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {

    @Bean
    public SecurityFlowExecutionListener securityFlowExecutionListener(){
        return new SecurityFlowExecutionListener();
  }
    @Bean
    public FlowExecutor flowExecutor() {
        return getFlowExecutorBuilder(flowRegistry())
                .addFlowExecutionListener(new AuditFlowExecutorListener(), "*")
                .addFlowExecutionListener(securityFlowExecutionListener())
                .setMaxFlowExecutions(5)
                .setMaxFlowExecutionSnapshots(30)
                .build();
    }
    ...
}

Declaring this bean and setting it up as a flow execution listener ensures that any <secured /> elements in the flow definition are picked up and interpreted accordingly at flow execution time. This bean can define its own decision manager, which overrides the default AccessDecisionManager in the system, by setting up the desired bean reference to the accessDecisionManager property.

<!--webflow-config.xml-->
<bean id="securityFlowExecutionListener" class=
  "org.springframework.webflow.security.SecurityFlowExecutionListener">
    <property name="accessDecisionManager"
                  ref="customDecisionManager" />
</bean>

//WebFlowConfig.java
org.springframework.security.access.vote.UnanimousBased;
...
@Bean
    public SecurityFlowExecutionListener securityFlowExecutionListener(){
        SecurityFlowExecutionListener sfel = new SecurityFlowExecutionListener();
        sfel.setAccessDecisionManager(customDecisionManager());
        return sfel;
    }

    @Bean
    AccessDecisionManager customDecisionManager(){
    //assume List<AccessDecisionVoter<? extends Object>> voterList is initialized
            return new UnanimousBased(voterList);
    }

The UnanimousBased is a simple concrete implementation of the AccessDecisionManager provided by Spring Security; it requires all voters to abstain or grant access.

The SecurityFlowExecutionListener bean throws AccessDeniedException when the user is not authorized to access a flow resource. The exception is caught by Spring Security servlet filter. Catching or suppressing this exception is not recommended. When extending SimpleMappingExceptionResolver, doResolveException should be implemented so that this exception is rethrown.

import
 org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

public class CustomExceptionResolver
              extends SimpleMappingExceptionResolver {

   @Override
  protected ModelAndView doResolveException
       (HttpServletRequest req, HttpServletResponse res,
        Object handler, Exception ex) {

      return super.doResolveException(req, res, handler, ex);
    }
}

The following example depicts the specific points where the secured element can appear in a flow definition:

<!--webflow-config.xml-->

<!-- 1. Under the flow element, securing the whole flow definition -->
<flow ...>
        <secured attributes="ROLE_ADMIN" />
</flow>

<!-- 2. Securing a view-state -->
<flow ...>
        <view-state id="enterPersonInfo" model="person">
                <secured attributes="ROLE_ADMIN" />
        </view-state>
</flow>

<!-- or a decision state -->
 <decision-state id="isNewPerson">
    <secured attributes="IS_AUTHENTICATED_FULLY"/>
        <if test="personService.isNewPerson(person)"
            then="enterIdentityCardInfo" else="reviewExistingPerson"/>
</decision-state>

<!-- 3. Securing a transition -->
<flow ...>
        <view-state id="enterPersonInfo" model="person">
                ...
                 <transition on="next" to="isNewPerson" >
                 <secured attributes="ROLE_ADMIN" />
                 </transition>
        </view-state>
</flow>

The attributes attribute is a comma-separated list of Spring Security authorization attributes. Often, these are specific security roles. But, when using a custom access decision manager, the syntax can vary; for example, SpEL can be used when the custom access manager is a Spring bean that supports them.

Spring Security is a wide subject; if you intend to use it in your projects, there is a lot of good documentation available online. Often, complete code samples are provided to help the curious developer understand how it works and how to use it. And, of course, the starting point is the Spring Security Reference at http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/. All that is covered in this book should suffice in helping a developer understand the basic concepts that might be in the certification exam.

Spring Security with OAuth

OAuth15 is an open standard for authorization. It is an open protocol to allow secure authorization in a simple and standard method for web, mobile, and desktop applications. It is designed to work with HTTP and basically allows access tokens to be generated by a server, which can then be used by the client to access resources on another server. It’s like there is an authentication provider that guarantees that you are who you say you are (it vouches for you) to a different service provider.

When talking about OAuth2 (because it is the most commonly used at the moment), the following components need to be mentioned:

  • Resource owner: An entity that grants or denies access to a protected resource.
  • Resource server: The server that hosts protected resources; it is capable of accepting and responding to requests done with an access token.
  • Client: The entity that requests protected resources on behalf of the owner. It can be a web application, a mobile application, or a client-side application (JavaScript).
  • AuthorizationServer: A server that provides access tokens to the client after a successful authentication.

For example, if you have a Google account, you can install Runtastic (a sport tracker application) on your phone and access that application using your Google account without exposing the Google password process, as shown in Figure 7-26.

9781484208090_Fig07-26.jpg

Figure 7-26. Google as authentication provider for Runtastic

In the previous example, Google is the authorization server, the user is the client, the Runtastic application is the resource owner/resource server. But most applications—like Facebook, Twitter, LinkedIn, and GitHub—implement the authorization and resource server role.

Currently, Spring Security can be integrated with OAuth (1a) and OAuth2. A library is provided for each version; it needs to be included in the classpath of the application: spring-security-oauth for OAuth(1a) and spring-security-oauth2 for OAuth2. OAuth is a simple way to publish and interact with protected data. A lot of information about OAuth and what it can be used for can be found by searching the Internet. The main idea is that using OAuth can give certain resources access without providing a username and password to the server.

To configure a Spring application as an authorization server, in a @Configuration class extending org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter, the configure method must be overridden with an implementation that sets up the clients that can access the server. Extending the previously mentioned class provides empty method implementations for definitions inherited from the AuthorizationServerConfigurer interface (same package as the implementing class), making the job easier for the developer. The class must be annotated with @EnableAuthorizationServer, which is a convenient annotation provided by Spring to enable an authorization server.

Also, the Spring Security authentication manager (configured in the Spring Security configuration class annotated with @EnableWebSecurity) is injected here to secure the authorization end point.

import o.s.security.oauth2.config.annotation.web.configuration.*;
import o.s.security.oauth2.config.annotation.web.configurers.*;

 @Configuration
 @EnableAuthorizationServer
 protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
        @Autowired
        private AuthenticationManager authenticationManager;

        @Override (1)
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
             throws Exception {
             endpoints.authenticationManager(authenticationManager);
       }

       @Override (2)
       public void configure(ClientDetailsServiceConfigurer clients)
            throws Exception {
         clients.inMemory()
             // client Id is used by OAuth to identify the client
             .withClient("client-with-secret")
             // grant types that are authorized for the client to use,
             //by default value is empty.
            .authorizedGrantTypes("password", "client_credentials")
            // roles that client must have in order to access the resource
            .authorities("ROLE_USER")
            //comma separated rights to the resource, by default none is specified
            .scopes("read", "trust")
            //The secret associated with the resource, by default, no secret is empty
            .secret("12#23$");
        }
}

The first configure method (1) injects the Spring Security authentication manager (set up in @EnableWebSecurity as in normal Spring Security), which is needed for the password grant defined tin the second method.

The second configure method (2) sets up the clients that can access the server, and their properties.

To implement the resource server, another configuration class is needed; this one must be annotated with @EnableResourceServer, which is a convenient annotation for OAuth2 resource servers, enabling a Spring Security filter that authenticates requests via an incoming OAuth2 token. The class is recommended to extend the org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter, which provides empty implementation for methods inherited from the ResourceServerConfigurer interface (same package), making a developer’s job easier.

import o.s.security.oauth2.config.annotation.web.configuration.*;
import o.s.security.oauth2.config.annotation.web.configurers.*;

@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(HttpSecurity http) throws Exception {
             http
                .requestMatchers().antMatchers("/","/admin/beans").and()
                .authorizeRequests()
                .anyRequest().access("#oauth2.hasScope('read')");
        }
}

The configure method is used to set up resources for OAuth2 protection. Access to the resources is set up using the HttpSecurity bean, which is not something new, as it was used in previous examples to secure resources. But what is new here is the fact that access to resources can be configured using Spring Security Expressions that are applied on the oauth2 security object. For example, the expression #oauth2.hasScope('read') tests the resource reading rights for the client the oauth2 object is associated with. The expression handler is enabled by the @EnableResourceServer annotation.

The authorization and resource server application is usually an application that receives REST requests; there is really no need for an interface of any kind. The client application can be any type of application, but most of the time it is a web or mobile application.

When opening the Runtastic site or mobile application, a method of authentication can be selected. If authentication using a Google account is selected, the user must provide its Google credentials, which are sent to the Google authentication server to confirm their validity and send the confirmation to Runtastic. But Runtastic needs to access the user account information and use it to customize its interface to the user’s preferences on the Google account. The confirmation received earlier is actually an access code that can be used to exchange for an access token that defines what information Google is willing to share about the user.

Technically speaking, the OAuth2 interaction between a web application and an authorization server implies the following steps:

  1. User accesses the web client application. The web client application redirects the user to the authorization server. The user logs in and the authorization server approves client access to the resource.
  2. Authorization redirects back to the web client with the access code
  3. The web client application exchanges the access code for the access token from the authorization server.
  4. The web client application uses the access token to get resources from the resource server.

Spring Security OAuth is not part of the certification exam as this book is being written, but most web and mobile applications require integration with popular social network applications and OAuth is the communication protocol that makes this interaction quite practical and easier for the end user. So it is best to have a basic idea on how this can be done. If you are interested in expanding your knowledge about it, there are some very good resources available at projects.spring.io/spring-security-oauth/docs/oauth2.html.

Spring Social Projects

The beginning of this book presented a list of the Spring projects currently in development. By the time this book is published, that list will likely be deprecated: some of the projects were dropped, some were split into smaller projects, and some matured into solid frameworks. One the projects that matured into a solid framework is Spring Social, which provides an API to connect Spring applications to third-party APIs for social networks like Facebook, Twitter, and others. In the century of Web 2.0 and Big Data, connecting applications and sharing information in a practical way is a necessity. So Spring decided to start this project to help web applications developed in Spring integrate with SaaS (Software as a Service) API providers such as Facebook, Twitter, and LinkedIn. Currently under work, there are also integration modules for GitHub and Tripit. The communication is done using the service type provided by any of the mentioned applications. Most of them use REST. Facebook uses its own type of communication called the Facebook Graph. Figure 7-27 depicts all Spring Social projects, the application they communicate with, and with which protocol.

9781484208090_Fig07-27.jpg

Figure 7-27. The Spring Social projects

Spring Social provides a lot of features designed to make the process of connecting local user accounts to hosted provider accounts easy to implement: a controller that handles authorization between the Java/Spring application and the service provider, a controller that enables user authentication by signing into a service provider, connection factory classes, real-time callback handlers, and much more.

More information on how Spring Social can be used is on the official page of this project at http://projects.spring.io/spring-social/.

Summary

After completing this chapter, you should be able to

  • Describe what Web Flow is and what problems it solves.
  • Describe the Web Flow architecture.
  • Understand how Web Flow processes a request.
  • Configure Web Flow with Spring MVC.
  • Describe the typical flow implementation guidelines.
  • List the elements of a flow definition.
  • Define flows using the XML language.
  • Test flow execution outside the container.
  • Flow definition best practices.
  • Describe branching.
  • Describe an action-state and how it should be used.
  • Describe a decision state.
  • Describe how exceptions are handled in Spring Web Flow.
  • Describe and use subflows.
  • Describe and use flow inheritance.
  • Configure Spring Security using XML and Java Config.
  • Use Spring Security to secure parts of JSP pages and methods.
  • Use Spring Security to secure your flows.

Quick Quiz

Question 1: What problems can be avoided using flows for web navigation?

  • duplicate submissions
  • state collisions between browser windows
  • stale session state
  • none of the above

Question 2: How do the DispatcherServlet and Spring MVC Flow Controller work together?

  • Spring MVC Flow Controller intercepts and resolves all requests
  • DispatcherServlet intercepts all requests and forwards the flow requests to the Flow Controller

Question 3: What are the main components that need to be configured to have a working Web Flow environment?

  • a flow executor
  • a flow registry
  • a SecurityFlowExecutionListener bean
  • a flow adapter
  • a flow mapping
  • an MvcViewFactoryCreator creator

Question 4: Which of the following affirmations is true about FlowExecutor?

  • It is the central facade and entry-point service interface into the Spring Web Flow system.
  • It does not need a FlowRegistry to function properly.
  • It handles managing flow executions.

Question 5: Which of the following affirmations is true about FlowDefinitionRegistry?

  • To configure a Spring Web Flow environment, a bean of this type is not mandatory.
  • It requires a mandatory FlowBuilderServices bean as an argument so it can be instantiated.
  • It is a container of flow definitions.

Question 6: What can you say about the following code snippet?

<button id="newPersonButton" name="_eventId_proceed" type="submit">
              <spring:message code="command.proceed" />
</button>
  • It is the JSP definition of a button used to resume a flow that has an event named proceed associated with it.
  • It is a simple JSP definition of a button that is named _eventId_proceed.
  • It is a simple JSP definitiod of a button used to submit a form.

Question 7: How many requests does a flow interaction imply?

  • one
  • two
  • three
  • none, because it uses session

Question 8: What can be said about the following web flow configuration class?

@Configuration
  public class WebFlowConfig {
   ...
}
  • To be valid, the @EnableWebFlows is necessary.
  • The class could extend the AbstractFlowConfiguration class that is provided by Spring Web Flow  to provide access to builders for the Web Flow environment.

Question 9: What can be said about the FlowController?

  • It is the controller that intercepts and resolves flow requests.
  • It is the adapter between the Spring MVC Controller layer and the Spring Web Flow engine
  • It should be configured by the developer to define how flow requests are handled.

Question 10: Which of the following are elements of a flow definition?

  • beans
  • states
  • transitions
  • converters
  • data

Question 11: Which of the following are valid states types in a flow definition?

  • start state
  • action state
  • decision state
  • view state
  • persistence state
  • end state
  • conversion state

Question 12: Which of the following affirmations is true about a flow definition?

  • It must have exactly one end state.
  • It must have at least one decision state.
  • It can have as many end states as the logic requires.
  • It is a flow defined in a single XML file.

Question 13: What triggers a transition?

  • user events in view states
  • user events in any kind of state
  • the result of evaluation an expression in an action and decision state

Question 14: Which of the following is true?

  • A flow definition has its own internationalization resources.
  • Each view state has a corresponding view.
  • Decisions states are more complex view states.

Question 15: Consider the following flow definition:

<view-state id="enterIdentityCardInfo" model="identityCard">
     <binder>
         ...
   </binder>
   <transition on="save" to="confirmAdult">
      <evaluate expression="personBuilder.savePersonEntity(person, identityCard)"
          result="flowScope.existingPerson" />
   </transition>
</view-state>

Which of the following is true?

  • The view template logical name is the same with the view state id, enterIdentityCardInfo in this case.
  • The view template logical name can be anything as long as it is linked in the web flow configuration file or class to the state id.
  • Transitioning to the confirmAdult can be prevented by an exception being thrown when executing the personBuilder.savePersonEntity expression.

Question 16: What can you say about global transitions?

  • Only one can be declared in a web flow definition
  • One or more can be declared in a web flow definition
  • It is a transition type that can be used to cancel the flow execution at any point in the execution

Question 17: Choose the proper order of the following steps in creating a flow:

  1. Add the actions and states behavior.
  2. Create mock views to test the connection of the states.
  3. Define view states and end states.
  4. Define transition between states.
    • 4, 1, 3, 2
    • 3, 4, 2, 1
    • 3, 4, 1, 2
    • 1, 3, 4, 2

Question 18: Which of the following affirmations are true about testing web flows?

  • The test class must be annotated with @RunWith(SpringJUnit4ClassRunner.class).
  • The test class must extend the AbstractXmlFlowExecutionTests.
  • Mock views can be used to test the flow navigation during development.

Question 19: Which of the following is true about flow scope?

  • This scope is shared between parent flows and subflows.
  • This scope lasts until the flow ends.
  • Flow scoped variables can be declared by evaluate elements in the following manner:
    <evaluate expression="service.computeResult()"
         result="flowScope.result" />

Question 20: Which of the following is true about view scope?

  • View scoped variables are available to all view states.
  • View scoped variables can only be defined inside a view-state element.
  • View scoped variables are created when entering the view state and destroyed when transition to the next flow occurs.

Question 21: Which of the following is true about request scope?

  • Request scope lasts for only one request.
  • This scope is useless; it exists just for compatibility with request-response mechanisms on the Web.
  • Variables in this scope can be used for view initialization.
  • Variables in this scope are fetched only once, and subsequent browser refresh button-pressing won’t affect the initial fetched value.

Question 22: Which of the following is true about flash scope?

  • This scope lasts for the entire flow.
  • This scope lasts for the entire flow, but is cleared every time a view is rendered, making it perfect for exchanging data between flow execution steps.
  • This scope involves two requests.

Question 23: Which of the following is true about conversation scope?

  • This scope is the widest web flow scope.
  • Variables defined in this scope are available to subflows too.
  • Variables defined in this scope introduce a dependency between subflows and parent flows.

Question 24: Considering the following two code snippets:

1. <flow ...>
          <on-start>
              <evaluate expression="hospitalManager.findAll()"
                  result="flowScope.hospitalList" />
           </on-start>
      <view-state id="enterPersonInfo" model="person">
           ...
     </view-state>
   </flow>

2. <flow ...>
      <view-state id="enterPersonInfo" model="person">
           <on-render>
              <evaluate expression="hospitalManager.findAll()"
                  result="requestScope.hospitalList" />
           </on-start>
     </view-render>
   </flow>

Which of the code snippets is recommended to initialize a hospital list when the enterPersonInfo view is rendered?

  • 1, because the hospitalList should be initialized only once
  • 2, because the hospitalList should be refetched every time the enterPersonInfo view is rendered, so the most recent information is available in the flow execution
  • either of them

Question 25: At which points in the flow can actions be executed?

  • on flow start
  • on state entry
  • on view render
  • on transition execution
  • during transition execution
  • on state exit
  • on flow end
  • after flow end

Question 26: Which of the following Spring expressions are valid?

  • <evaluate expression="searchService.suggestHospital(externalContext.sessionMap.mostUsed)"result="viewScope.hospitals" />

  • <set name="flowScope.personName" value="sessionScope.name" />
  • <set name="flashScope.successMessage" value="resourceBundle.successMessage" />

Question 27: Which of the following are valid types for an action state?

  • Boolean, true or false
  • Boolean, always just “yes” or “no”
  • Any value that evaluates to “success”
  • Any String that can be matched to a trigger event name

Question 28: Select the way in which a developer can define an action.

  • Extend the Action class
  • Extend the MultiAction class
  • Add call business methods directly in the web flow definition

Question 29: What can be said about authentication and authorization?

  • They are tightly coupled, changing configuration for authentication will require changes in the authorization configuration as well.
  • They are fully decoupled; changing configuration for authentication will not affect authorization.
  • They are both synonyms for application security.

Question 30: What is needed to configure Spring Security with Spring MVC using Java Configuration?

  • The security beans AuthenticationManager and HttpSecurity have to be defined in a class annotated with @Configuration.
  • Create a class that extends AbstractSecurityWebApplicationInitializer to register the springSecurityFilterChain.
  • Create a configuration class that extends WebSecurityConfigurerAdapter that is annotated with EnableWebSecurity.
  • Add the Security configuration class to the root context.

Practical Exercise

The practical exercise for this chapter involves configuring Spring Security. The project you have to complete is named 14-pr-web-security-practice. The project contains a view named login.jsp, which is a custom login form designed to work with Spring Security 4. There are a few TODO tasks that you must be able to complete if you have been paying enough attention when reading the Security section.

The first one, (TODO 47) requests you to add a new filter of type org.springframework.web.filter.DelegatingFilterProxy with the filter name springSecurityFilterChain. The class that will do this is already in place and is called com.pr.init.SecurityWebApplicationInitializer; you just have to modify it to register the filter. Afterward, you can start the application using the appStart Gradle task for this submodule project; for reference, see Figure 7-28.

9781484208090_Fig07-28.jpg

Figure 7-28. Reference for subproject

You are not done yet, though. When starting the application, you see in the console that there was some trouble creating your security context and your login page is not visible. This is what you should see in the console:

00:35:40 WARN Failed startup of context o.a.g.JettyWebAppContext@2da59753
{/security,file:
/.../personal-records/14-pr-web-security-practice/build/inplaceWebapp/,STARTING}
...
Caused by: java.lang.IllegalArgumentException: An AuthenticationManager is required
        at org.springframework.util.Assert.notNull(Assert.java:115) ~na:na
...

If you remember, the security section well, you already suspect what is missing. The previous task just defines the filter. Now you need to create a Spring Security configuration class to provide your users their roles and overall details such as the location of the login form, if a CSRF token is used. All this is marked as TODO 48. A part of the class is already set up for you, providing the bean that generates a CSRF token. You can find the partial implementation in com.pr.config.SecurityConfig. The comments in the TODO task instruct you on what is further needed. After all the configuration is in place, you can try to start the application again. And unfortunately, it won’t start. This is what you see if you try to open http://localhost:8080/security/.

HTTP ERROR 500
Problem accessing /security/auth. Reason:
    Server Error
Caused by:
org.springframework.web.util.NestedServletException:
Request processing failed; nested exception is java.lang.IllegalStateException:
No WebApplicationContext found: no ContextLoaderListener registered?

This is because there is still one little detail to take care of: adding the SecurityConfig class to the root context of the application. To do this, go to com.pr.init.WebInitializer and complete the getRootConfigClasses method body (TODO 49). After restarting the application, you should see something really similar to Figure 7-29.

9781484208090_Fig07-29.jpg

Figure 7-29. The login form displayed when Spring Security is properly configured

If the previous task is resolved correctly, the login form should be visible. But wait, the New Person menu option is visible. You want only users with the ADMIN role to see that menu item. Something is clearly missing. So go to 14-pr-web-security-practice/src/main/webapp/WEB-INF/templates/layout.jsp and secure that menu item. Do not forget to reference the proper taglib!

After solving the last TODO item, the New Person menu item should not be visible on the main page when a user is not logged in. Log in using john. If you see the New Person link, something is wrong in the configuration of the HttpSecurity, because john has a USER role, and only users with an ADMIN role can view and access that menu item. Log in with jane or admin. If you see that option, then your configuration is correct and you have completed this lab.

As a bonus exercise, try playing with the security tag library and use the URL to configure access. Or remove the tag altogether and secure the flow.

The proposed solution can be found in subproject 14-pr-web-security-solution. Try not to look before developing your own solution, and use it only for comparison.

__________________________

1The official site of the project (http://projects.spring.io/spring-webflow/) is usually updated late, so it might show an earlier version; the most recent release can be found on the Maven public repositpry site at http://mvnrepository.com.

2The code for the class is publicly available on GitHub at https://github.com/spring-projects/spring-webflow/blob/master/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/FlowController.java.

3The GOTO statement (see https://en.wikipedia.org/wiki/Goto).

4See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-language-ref.

51. False. This variable is defined in the first requestScope and a state has two requests. Rendering the view is done in the second request. 2. True. As explained earlier. 3. True. var1 and var4 are defined in flashScope; var3 and var5 are defined in the scope of the rendering requestScope. 4. True. var1 is lost because it is defined when entering the state, and if the page is reloaded, entering the page is done only once. So when the page is reloaded, the flash scope is cleaned and var1 is lost.

6If you want more information about validation groups, the official documentation is a great start; it can be found at https://docs.oracle.com/javaee/7/tutorial/index.html.

7See https://en.wikipedia.org/wiki/International_Bank_Account_Number.

8A bug related to mocking subflows; still open and unresolved since version 2.0.6. See https://jira.spring.io/browse/SWF-1079.

9Don’t Repeat Yourself.

10Spring Security page at http://spring.io/spring-security.

11A full list of authentication technologies that Spring Security integrates with; it can be found at http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#what-is-acegi-security.

12This type of attack consists of hacking an existing session to execute unauthorized commands in a web application. You can read more about it at https://en.wikipedia.org/wiki/Cross-site_request_forgery.

13The full list of configuration changes that were made to match Java Configuration is at https://jira.spring.io/browse/SEC-2783.

14Read more about MD5 at https://en.wikipedia.org/wiki/MD5.

15The project’s official page is at http://projects.spring.io/spring-security-oauth/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.136.63