Wednesday, August 13, 2014

Spring Security GWT Integration

GWT version- 2.1

To integrate GWT with Spring security, just look at Spring security on its own. Another advantage of pulling the login page out of GWT framework is that the load time of initial page becomes much smaller. This also helps in DOS kind of attacks.

To integrate Spring first pull the required jars into maven. Here I am assuming the Spring is available in your environment otherwise you will have to pull extra jars for Spring core and others dependency

    <dependency>                               <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.version}</version>
</dependency>

Now put a login page in your web app root, which looks like as follows. Note that the form should be posted on /j_spring_security_check and the username name should be j_username and password should be j_password

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Lalit Bhatt</title>
    <link rel="shortcut icon" type="image/x-icon" href="resources/favicon.ico">
  </head>
  <body>
    <form method="post" action="/j_spring_security_check">
      <label for="j_username">Username:</label> 
      <input type="text" name="j_username" />
      <br />
      <label for="j_password">Password:</label> 
      <input type="password" name="j_password" /> 
      <br />
      <input type="submit" value="Login" />
    </form>
  </body>
</html>

Put the Spring application context for security configuration at a suitable location, may be inside META-INF under webapps. A typical context file would look like

<?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:util="http://www.springframework.org/schema/util"
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/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
                        http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security-3.0.xsd">

<!-- HTTP security configurations -->
<http auto-config='true'>
<intercept-url pattern="/login.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/resources/favicon.ico" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<logout logout-success-url="/login.html" />
<form-login login-page="/login.html" default-target-url="/index.gwt.html"
always-use-default-target="true" />
<session-management invalid-session-url="/login.html"
session-authentication-error-url="/login.html"
session-fixation-protection="newSession">
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="false" />
</session-management>
</http>

<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" />
</authentication-provider>
</authentication-manager>
</beans:beans>

This is a very very basic context XML. It assumes everything as per defaults. It assumes that you have the user table and authorities table as per the need of spring security. Any difference would need a customization of Spring security which again has nothing to do with GWT.

The final thing is to register the configurations in web.xml, to start the Spring container and to hook the security filters in place

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/application*.xml</param-value>
</context-param>

<!-- Creates the Spring Container -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

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

If everything is fallen in place, then accessing the application will take you to login page first.

Handling session time out

This is quite tricky as when session time out happens, the GWT rpc call returns back the login page. The one way that I found non intrusive to handle is to first make an adapter to AsyncCallback and all the instantiations of AsyncCallback should happen using the adapter. This is a good way to handle all the failures in a common place.

public abstract class AsyncCallbackAdapter<T> implements AsyncCallback<T> {
    @Override
    public void onFailure(Throwable caught) {

        if (caught instanceof InvocationException) {
            InvocationException ie = (InvocationException) caught;
            if(ie.getMessage().contains("j_spring_security_check"))
            {
                Window.alert("Session is timed out. Please login again");
                Window.open(GWT.getHostPageBaseURL() + "login.jsp", "_self", null);
                return;
            }
        }

      //Do other error handling here
    
    }
}

Spring GWT Integration                 More Articles/Tutorials on Spring                More Posts on Java

No comments:

Post a Comment