Saturday, 10 June 2017

How to enable Spring Security in Java Web application?

Spring Security is one of the most popular frameworks to implement security in Java web application in a declarative way. It provides several essential security features e.g. LDAP authentication, authorization, role-based access control,  remembers the password, URL protection, concurrent active sessions management etc. In order to enable Spring security in Java Web application, you need to do configure three things, declare a delegating proxy filter in web.xml, add the ContextLoaderListener in web.xml and provide actual security constraints on applicationContext-Security.xml file. Since Spring security uses a chain of filters to implement various security constraints, also known as Spring's "security chain filter", it relies on web container for the initialization of delegating filter proxy.
If you remember, filters are created, maintained and destroyed by Servlet container. You declare filters in web.xml and web container initializes them by calling their init(FilterConfig config) method.  This filter then delegates the actual pre-processing and post-processing task to Spring aware Filter implementations provided by Spring Security framework.

Oracle Java Certifications, Java Web application

Every time a request or response comes and matches the URL pattern of the filter then Servlet container calls DelegatingFilterProxy's doFilter() method for the request and response filtering. This method has access to ServletRequest, ServletResponse, and a FilterChain object, which means it can modify request headers, response headers, and response body before sending the request to Servlet or response to Client. The FilterChain object is used to route the request to another filter in the chain for further processing.

Steps to Activate Spring Security in Web Application.


Here are the essential steps to enable Spring Security features in your Java web application:

1) Declare DelegatingFilterProxy filter in web.xml
2) Specify the Spring application context file to ContextLoaderListener
3) Specify Spring Security intercept URL pattern in the applicationContext-Security.xml file

Here is how a DelegatingFilterProxy filter declaration looks like in 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 then picked up by Servlet container and initialized and when a request comes upon it call the doFilter() method of DelegatingSpringSecurity. The filter is initialized by calling the init() method. The DelegatingFilterProxy extends GenricFilterBean, which implements init(FilterConfig filterConfig) method and give a call back to initFilterBean() to allow subclasses to perform their initialization.

By default, the DelegatingFilterProxy class will look for a Spring bean with the same name as the filter-name tag in the Spring application context file during initialization as shown below in the code from the DelegatingFilterProxy class from Spring Security JAR file.

protected void initFilterBean() throws ServletException {
    synchronized (this.delegateMonitor) {
      if (this.delegate == null) {

        // If no target bean name specified, use filter name.
        if (this.targetBeanName == null) {
          this.targetBeanName = getFilterName();
        }

        // Fetch Spring root application context and initialize the
        // delegate early, if possible.
        // If the root application context will be started
        // after this filter proxy, we'll have to resort to lazy
        // initialization.

        WebApplicationContext wac = findWebApplicationContext();
        if (wac != null) {
          this.delegate = initDelegate(wac);
        }
      }
    }
  }

If you want to customize this behavior you can provide the name of the bean class using targetBeanName via a FilterConfig object. If you don't then this will use the filter-name which is "springSecurityFilterChain". It then searches for this bean in both applicationContext.xml and applicationContext-Security.xml file for initialization. But, when you search for this in your configuration file, there is a good chance that you won't find it because of <http auto-config="true">, which hides a lot of complexity by using default values. You can further read Pro Spring Security to learn more about how exactly delegating filter proxy works in Spring security and how to customize and configure its behavior.

Here is how you load the Spring security configuration file in a Java web application:

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      /WEB-INF/applicationContext.xml
        /WEB-INF/applicationContext-security.xml
    </param-value>
</context-param>

The configuration file name is applicationContext-security.xml and it should be placed inside WEB-INF directory.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    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.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <security:http auto-config="true">
        <security:intercept-url pattern="/admin"
            access="ROLE_ADMIN" />
    </security:http>
    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user authorities="ROLE_ADMIN" name="admin"
                    password="admin" />
                <security:user authorities="ROLE_ADMIN" name="root"
                    password="root" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

By doing this simple configuration, you have now protected all URLs ending with /admin to be only accessible with username and password. The two user which have access to this are now admin and root. In short, you didn't need to code any Spring security filter or bean, all is done magically by using existing Spring security filters and <http auto-config="true"> tag.

Now, if you hit the URL to login into admin section, you will be asked to enter username and password and only after correct credentials you will be allowed to access the protected section or pages.

The order on which this <intercept-url> patterns are delcared matters a lot and they must be declared in the order of most specific to least specific because these patterns are evaluated in the order they are declared in the spring security application context file and once a match is found, other patterns are not evaluated.

That's all about how to enable or activate Spring security in a Java Web application. It's really simple to configure and use but very powerful and gives you a lot of options to implement complex security constraints. You can also see that we have introduced security in rather unobtrusive and declarative way. we haven't written any code, we just did some XML configuration to make an insecure web application to a secure one.