Featured Posts

ExtJS, Spring MVC 3 and Hibernate 3.5: CRUD DataGrid... This tutorial will walk through how to implement a CRUD (Create, Read, Update, Delete) DataGrid using ExtJS, Spring MVC 3 and Hibernate 3.5. What do we usually want to...

Readmore

ExtJS plugin: PagingToolbarResizer Well, this is my first ExtJS plugin. Though it is not an advanced plugin, I'm very happy and it is a big accomplishment for me! The problem: ExtJS PagingToolbar Component...

Readmore

Hibernate 3 Annotations Tutorial This tutorial will walk through how to implement a hello world project using Hibernate Annotations and MySQL database. Requirements Download and unzip Hibernate Core...

Readmore

My DeveloperWorks: What's life like for a female Java... Just wanted to share with you my interview on Valerie's My developerWorks blog: Interview with Loiane Groner, Java developer in Brazil. I'm very happy, because this interview...

Readmore

Getting started with ExtJS in your J2EE project This tutorial will walk through how to get an Ext JS installation up and running quickly in your java (J2EE) project. Level: Basic This is the screenshot of this tutorial: First,...

Readmore

Loiane Groner Rss

Integrating Spring Security with ExtJS Login Page

Posted on : 01-02-2010 | By : Loiane | In : ExtJS, Spring, Spring Security, Uncategorized

13

This tutorial will walk through how to configure ExtJS Login form (Ajax login form) instead of default Spring Security login.jsp.

Instead of using login.jsp from spring security, why do not use an ajax login form?

And How to integrate the ExtJS Login Form with Spring Security?

You did try to do it, the user is successfully authenticated, but the user is not redirected to the application main page. How to fix this situation? How to make it work?

It does not matter if you set the default-target-url in applicationContext-security.xml, or set a redirect URL on server side. It will not work this way.

The issue is that ExtJS make Ajax calls, and no redirect will work on server side. You have to redirect it on the client side, which is the ExtJS/javascript code.

First, you need to create the login form. You can use the javascript code provided by ExtJS and you can modify it to work with spring security.

If you take a look at the login.jsp, you will see three key points:

  1. URL / form action: j_spring_security_check
  2. Username input name: j_username
  3. Password input name: j_password

That is what you need to customize to make ExtJS Login form works! But do not be too comfortable, there are some issues you need to fix to make it work perfectly.

Take a look how login.js looks like (after customization):

Ext.onReady(function(){
	Ext.QuickTips.init();

	// Create a variable to hold our EXT Form Panel.

	// Assign various config options as seen.
	var login = new Ext.FormPanel({
		labelWidth:80,
		url:'j_spring_security_check',
		frame:true,
		title:'Please Login',

		defaultType:'textfield',
		width:300,
		height:150,
		monitorValid:true,
		// Specific attributes for the text fields for username / password.
		// The "name" attribute defines the name of variables sent to the server.

		items:[{
			fieldLabel:'Username',
			name:'j_username',
			allowBlank:false
		},{
			fieldLabel:'Password',

			name:'j_password',
			inputType:'password',
			allowBlank:false
		}],

		// All the magic happens after the user clicks the button
		buttons:[{

			text:'Login',
			formBind: true,
			// Function that fires when user clicks the button
			handler:function(){
			login.getForm().submit({

				method:'POST',

				// Functions that fire (success or failure) when the server responds.
				// The server would actually respond with valid JSON,
				// something like: response.write "{ success: true}" or

				// response.write "{ success: false, errors: { reason: 'Login failed. Try again.' }}"
				// depending on the logic contained within your server script.
				// If a success occurs, the user is notified with an alert messagebox,

				// and when they click "OK", they are redirected to whatever page
				// you define as redirect.

				success:function(){
				Ext.Msg.alert('Status', 'Login Successful!', function(btn, text){

					if (btn == 'ok'){
						window.location = 'main.action';
					}
				});

			},

			// Failure function, see comment above re: success and failure.
			// You can see here, if login fails, it throws a messagebox
			// at the user telling him / her as much.

			failure:function(form, action){
				if(action.failureType == 'server'){
					obj = Ext.util.JSON.decode(action.response.responseText);

					Ext.Msg.alert('Login Failed!', obj.errors.reason);
				}else{
					Ext.Msg.alert('Warning!', 'Authentication server is unreachable : ' + action.response.responseText);

				}
				login.getForm().reset();
			}

			});
		}
		}]
	});

	login.render('login');

});

If you make these changes and try to execute the application with a basic applicationContext-security.xml file, the user will be successfully authenticated, but is not going to be redirected.

What are we missing then?

You need to customize AuthenticationProcessingFilter class for spring security to perform actions on login.

The “onSuccessfulAuthentication” and “onUnsuccessfulAuthentication” methods need to return some JSON content. If user is successfully authenticated, then redirect to main page, otherwise, the application will show an error message.

This is MyAuthenticationProcessingFilter class:

package com.loiane.security;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;

public class MyAuthenticationProcessingFilter extends AuthenticationProcessingFilter {

	protected void onSuccessfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, Authentication authResult)
	throws IOException {
		super.onSuccessfulAuthentication(request, response, authResult);

		HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response);

		Writer out = responseWrapper.getWriter();

		String targetUrl = determineTargetUrl( request );
		out.write("{success:true, targetUrl : \'" + targetUrl + "\'}");
		out.close();

	}

	protected void onUnsuccessfulAuthentication( HttpServletRequest request,
			HttpServletResponse response, AuthenticationException failed )
	throws IOException {

		HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response);

		Writer out = responseWrapper.getWriter();

		out.write("{ success: false, errors: { reason: 'Login failed. Try again.' }}");
		out.close();

	}

}

And this is how applicationContext-security.xml looks like:

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

	<security:global-method-security />

	<security:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
		<security:intercept-url pattern="/index.jsp" filters="none" />
		<security:intercept-url pattern="/*.action" access="ROLE_USER" />
	</security:http>

	<bean id="authenticationProcessingFilter" class="com.loiane.security.MyAuthenticationProcessingFilter">
		<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
		<property name="defaultTargetUrl" value="/main.html" />
		<property name="authenticationManager" ref="authenticationManager" />
	</bean>

	<security:authentication-manager alias="authenticationManager" />

	<bean id="authenticationProcessingFilterEntryPoint"
		class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
		<property name="loginFormUrl" value="/index.jsp" />
		<property name="forceHttps" value="false" />
	</bean>

    <!--
    Usernames/Passwords are
        rod/koala
        dianne/emu
        scott/wombat
        peter/opal
    These passwords are from spring security app example
    -->
    <security:authentication-provider>
        <security:password-encoder hash="md5"/>
        <security:user-service>
            <security:user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
            <security:user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
            <security:user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
            <security:user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
	    </security:user-service>
	</security:authentication-provider>
</beans>

Now you can login using ExtJS login form.

I coded a sample application for this example. If you like it, you can download it from my GitHub: http://github.com/loiane/spring-security-extjs-login

Happy coding!