Search This Blog

Sunday, 11 August 2013

Spring Security

All projects I have worked on included login. And roles. They were built using database tables or third party applications like LDAP or service based authentication. However the new projects starting now are going ahead with Spring Security. As I have no idea about it, I decided to give a go at understanding Spring Security.
I decided to first do a small simple web application and enable the security for it. Not spring based, simple Servlet style security.
Consider my web.xml for a simple application:
<display-name>SimpleWeb</display-name>
  <servlet>
    <servlet-name>all</servlet-name>
    <jsp-file>//WEB-INF//index.jsp</jsp-file>
  </servlet>

  <servlet-mapping>
    <servlet-name>all</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

  <security-constraint>
    <display-name>CompleteSecurityConstraint</display-name>
    <web-resource-collection>
      <web-resource-name>AllResources</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>

    <auth-constraint>
      <description>Only authenticated users must proceed from here</description>
      <role-name>USER</role-name>
    </auth-constraint>
  </security-constraint>

  <security-role>
    <role-name>USER</role-name>
  </security-role>

  <login-config>
    <auth-method>BASIC</auth-method>
  </login-config>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
As seen all urls to my new web site SimpleWeb have been redirected to the file index.jsp. I have added a security constraint to this url pattern too. The constraint requires that an authentication is performed for all urls who try to navigate to the site. Only users with role USER can visit the site. But where is the role configuration?
The security mechanism provided by Servlets is container dependent. As I am using a Tomcat servlet container, I shall provide the authentication details in tomcat. This is done via the tomcat-users.xml (located in the TOMCAT_HOME/conf folder)
<tomcat-users>
  <role rolename="USER" />
  <user username="robin" password="robin" roles="USER" />
</tomcat-users>
Here I have defined the role of type USER. I have also specified the credentials needed to authorize a client who claims to posess this role. If I run the application and simply try to navigate to, say http://localhost:8080/SimpleWeb/
Then I get a popup asking for credentials.
 The popup was shown as the auth-method specified was BASIC. Only valid credentials will take me to index.jsp or allow my request to complete successfully.
 I decided to try the same with Spring Security. I used the same application, but rather than use container managed authentication and authorization, let Spring Security to do the tasks.
The first step was to update my web.xml file.
<display-name>SimpleWeb</display-name>
  <servlet>
    <servlet-name>all</servlet-name>
    <jsp-file>/WEB-INF/index.jsp</jsp-file>
  </servlet>

  <servlet-mapping>
    <servlet-name>all</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      /WEB-INF/spring-security.xml
    </param-value>
  </context-param>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
As seen all the security information has been stripped out. SimpleWeb is - as the name indicates - a simple web application. As there is no dispatcher servlet here, I need to ensure that my spring beans are loaded to the web context. So I had to provide the listener based configuration.
Any beans defined will be placed in spring-scurity.xml. As stated earlier, security from Spring comes through filters. So I decided to add my first filter:
<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>
As per documentation:
This provides a hook into the Spring Security web infrastructure. DelegatingFilterProxy is 
a Spring Framework class which delegates to a filter implementation which is defined as 
a Spring bean in your application context.
Accordingly I decided to add the beans:
<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.0.xsd
  http://www.springframework.org/schema/security 
  http://www.springframework.org/schema/security/spring-security.xsd">

  <http auto-config='true'>
    <intercept-url pattern="/**" access="ROLE_USER" />
  </http>
</beans:beans>
This bean is equivalent to all the security code we had written in web.xml. It states that all URLs must be available only to users with role "USER" (In the role ROLE_USER, ROLE_ is only a marker used within Spring.)
Spring security also frees me from having to work with Tomcat for role management. Instead I added another bean:
<authentication-manager>
    <authentication-provider>
      <user-service>
        <user name="robin" password="robin" authorities="ROLE_USER" />
      </user-service>
    </authentication-provider>
  </authentication-manager>
The authentication-provider element here includes the credential and role information for my users. This will be used by the authentication manager to process authentication requests.
The jars needed for the project are:

If I run this code now, any attempt to access a resource will redirect me to http://localhost:8080/SimpleWeb/spring_security_login;jsessionid=01DD842C74C95A6380550F7FA2A5BD37

This is because the auto-config attribute when set to true uses form login. On submitting the form,
  1. Spring processed it, 
  2. validated the credentials and on success, 
  3. redirected me to the correct page 
If I want to use basic authentication as I did in the simple application then a slight tweaking is needed in the spring configuration:
<http auto-config='true'>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <http-basic/>
  </http>
The http-basic element will ensure that BASIC authentication is used. Thus with Spring security it is possible to even secure non spring applications.

4 comments:

  1. very good stuff, thanks for your sharing. Keep the good work. I'm starting digging into Spring security now and your posts help me a lot. Thanks again.

    ReplyDelete
  2. I thought haven’t read such distinctive material anywhere else on-line.firstsecurityservices

    ReplyDelete
  3. can we exclude JSESSIONID being appended to the url when login in. I tried to set cookie secure for servlet version 2.5 via filter java class and once the HttpOnly and Secure flags were added to JSession cookie using setHeader, the application after login in has JSESSIONID appended to url and on next click to any tab, session expires.

    ReplyDelete