Friday, 28 September 2012

Securing Web Applications with Spring Security

This post will demonstrate how to configure a web application with Spring Security. In our experience Spring Security provides a far more elegant approach to security than the standard JEE spec.

Assuming a web application has been developed using Spring MVC, there will be a web.xml file and a number of Spring configuration files. To enable Spring Security, we need to configure the Spring DelegatingFilterProxy filter in the web.xml.



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


This filter is a proxy that delegates to a Spring-managed bean that implements the Filter interface. The name of the filter matches the name of the bean in the Spring context file. The security filter chain intercepts requests and enforces any security requirements specified in the Spring context file as shown below:


<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <!-- HTTP security configurations -->
    <http auto-config="true" use-expressions="true">
        <form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
        <logout logout-url="/resources/j_spring_security_logout" />
        <!-- Configure these elements to secure URIs in your application -->


        <intercept-url pattern="/admin/authoriseusers/**" access="hasRole('ROLE_ADMIN')" />

        <intercept-url pattern="/member/**" access="isAuthenticated()" />
        <intercept-url pattern="/resources/**" access="permitAll" />
        <intercept-url pattern="/**" access="permitAll" />
    </http>
    <!-- Configure Authentication mechanism -->
    <authentication-manager alias="authenticationManager">
        <!-- SHA-256 values can be produced using 'echo -n your_desired_password | sha256sum' (using normal *nix environments) -->
        <authentication-provider>
            <password-encoder hash="sha-256" />
            <user-service>
                <user name="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918" authorities="ROLE_ADMIN" />
                <user name="user" password="04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

This shows a sample security configuration with an in-memory userstore. Note that the Spring Security uses its own XML namespace that has been declared as the default namespace at the beginning of the context file. It then sets up the http security with form-based login and a number of intercept-url elements that specify which paths should be secured and which roles granted access. This is where all the access control requirements can be configured. There are additional properties that can specify the HTTP method that needs to be secured for the given URI. Next we configure an authentication manager with an authentication provider that basically controls how users will be authenticated by Spring Security. In this case, it is simply using an in-memory authentication provider where user's have been defined with their name, password and roles.

The http form-login configuration specifies the login-page and the url for the page to display on authentication failure. The excerpt below shows the form from the login page. Note the form's action property.


<form action="/resources/j_spring_security_check" method=post>
  <div>
    <label for="j_username">Please Enter Your Name:</label>
  </div>
  <div>   
    <input id="j_username" type="text" name="j_username" size="25">
  </div>
  <div>
    <label for="j_password">Please Enter Your Password:</label>
  </div>
  <div>
    <input type="password" size="15" name="j_password">
  </div>
  <div>
       <input type="submit" value="Submit">
       <input type="reset" value="Reset">
    </div>
</form>
 


Now whenever an user accesses one of the secured URIs, Spring Security will require the user to login via the configured login page. On submitting the credentials, Spring Security will authenticate using the configured authentication provider.

Using an in-memory user store only serves demonstration purposes and so the following section shows a how a custom authentication provider can be specified that allows control over how users are authenticated.



  <beans:bean id="myAuthenticationProvider" class="javaworkbench.usermanagement.authentication.AuthenticationProvider" />

  <!-- Configure Authentication mechanism -->
  <authentication-manager alias="authenticationManager" >
    <authentication-provider ref="myAuthenticationProvider" />
  </authentication-manager>


The custom AuthenticationProvider class extends a base Spring AuthenticationProvider that responds to UsernamePasswordAuthenticationToken authentication requests.


public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

       @Autowired
       private IdentityManager identityManager;

       @Override
       protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authenticationToken)
                     throws AuthenticationException {

       }

       @Override
       protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authenticationToken)
                     throws AuthenticationException {

              String password = authenticationToken.getCredentials().toString();
              User user = identityManager.authenticateAndRetrieveUser(username, password);

              return user;
       }

}


The custom AuthenticationProvider delegates to an IdentityManager that is an interface with implementations for retrieving user data from LDAP and JDBC relational databases.

We have just scratched the surface of Spring Security by showing a basic example. Spring Security provides a great deal of flexibility through various configuration options.

No comments:

Post a Comment