Archive

Posts Tagged ‘Spring’

Open Lane – Supporting a User Part 2

April 14, 2012 Leave a comment

Having added some user authentication to my open lane application the next step involved associating the user with a profile. Things can start to get complex quickly when you need more than simple authentication and authorization. At lot of applications do not need their own form of user management because they’re part of a larger solution that already has it. Those application tap into the existing service for authentication and authorization. In our case we don’t have that. So there are a couple of options. I could add a separate user management service from another provider into the solution or I could write my own user management service.

At this point I don’t want to get into integrating with another solution. I’m sure that day will come but not today. For now I’m going to write some code that supports Spring Security and gives me enough of what I need to continue building out the application.

So what do I really need:

  1. My core user is a swimmer. Someone who will apply for an open lane swim. I’ll also need operational users such as an administrator but that can wait. I need to gather and store enough information about a swimmer to process the application. I’ll call this the user’s profile.
  2. A means to authentication a user via a login. I’ll be working with Spring Security to implement this.
  3. A means to secure pages and actions to authorized users. Again I’ll use Spring Security to implement this.
  4. A registration process to add new user.

In the previous post I used Spring’s in-memory UserDetailsService to handle authentication.

<security:authentication-manager>
	<security:authentication-provider>
		<security:password-encoder hash="md5" />
		<security:user-service>
			<security:user name="keith" password="417c7382b16c395bc25b5da1398cf076" authorities="ROLE_USER, ROLE_SUPERVISOR" />
			<security:user name="erwin" password="12430911a8af075c6f41c6976af22b09" authorities="ROLE_USER, ROLE_SUPERVISOR" />
			<security:user name="jeremy" password="57c6cbff0d421449be820763f03139eb" authorities="ROLE_USER" />
			<security:user name="scott" password="942f2339bf50796de535a384f0d1af3e" authorities="ROLE_USER" />
		</security:user-service>
	</security:authentication-provider>
</security:authentication-manager>

Given the Spring centricity of this application I’ll stick with Spring Security. The question is how to get authentication/authorization with customized user management. I’ve got specific profile information that I need to capture and store.

I could continue to use a Spring Security implementation and create a look aside table but this mean creating/updating two distinct elements when a change occurs. Or, I could subclass UserDetailsService but I’m concerned that this could be a rabbit hole that I don’t want to go down right now. Instead I’ll take a look at Spring Security’s JdbcDaoImpl. JdbcDaoImpl is an implementation of UserDetailsService which uses a database to fetch the authentication and authorization data.

<security:authentication-manager>
	<security:authentication-provider>
		<security:jdbc-user-service data-source-ref="dataSource"/>
		<security:password-encoder hash="md5" />
	</security:authentication-provider>
</security:authentication-manager>

When using JdbcDaoImpl you must ensure that you’ve correctly configured the database tables. You can find details on this here. I created two JPA entities – User,  and Authority. I’m using Hibernate on the backside.

User combines the fields that JdbcDaoImpl requires with user profile fields that the application needs.

User.java

package org.bwgz.swim.openlane.model;

import java.io.Serializable;
import java.util.Collection;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "Users")
public class User implements Serializable {
	private static final long serialVersionUID = -3475658623185783516L;

	private String username;
	private String password;
	private Boolean enabled;
	private String name;
	private String email;
	private String usasId;

	private Collection<Authority> authorities;

	public User() {
	}

	public User(String username, String name) {
		this.username = username;
		this.name = name;
	}

	@Id
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getUsasId() {
		return usasId;
	}

	public void setUsasId(String usasId) {
		this.usasId = usasId;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Boolean getEnabled() {
		return enabled;
	}

	public void setEnabled(Boolean enabled) {
		this.enabled = enabled;
	}

    @OneToMany(mappedBy = "username", fetch=FetchType.EAGER)
    public Collection<Authority> getAuthorities() {
        return authorities;
    }

	public void setAuthorities(Collection<Authority> authorities) {
		this.authorities = authorities;
	}

    @Override
    public String toString() {
    	return String.format("%s@%x; Username: %s; Password: %s; Enabled: %s; Authorities: %s; Name: %s; Email: %s; UsasId: %s;",
    			this.getClass().getName(), this.hashCode(),
    			getUsername(), getPassword(), getEnabled(), getAuthorities(),
    			getName(), getEmail(), getUsasId());
    }

}

Authority.java

package org.bwgz.swim.openlane.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Authorities")
public class Authority implements Serializable {
	private static final long serialVersionUID = -3475658623185783516L;

	private String username;
	private String authority;

	public Authority() {
	}

	public Authority(String username, String authority) {
		this.username = username;
		this.setAuthority(authority);
	}

	@Id
        public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getAuthority() {
		return authority;
	}

	public void setAuthority(String authority) {
		this.authority = authority;
	}

    @Override
    public String toString() {
    	return String.format("%s@%x; Username: %s; Authority: %s;", this.getClass().getName(), this.hashCode(), getUsername(), getAuthority());
    }

}

For now I’ll use an in-memory instance of HSQLDB to store my data. I initialize the tables with a SQL file that Hibernate loads when the application starts up.

import.sql

insert into Users (username, password, enabled, name, email, usasId) values ('keith', '417c7382b16c395bc25b5da1398cf076', TRUE, 'Keith Lee', 'keith@email.com', 'leemkei0891' )

insert into Authorities (username, authority) values ('keith', 'ROLE_USER, ROLE_SUPERVISOR, ROLE_SWIMMER' )

Now when I go to the profile page I can see that SWF’s currentUser and the user’s profile are set.

Current User: Name: keith
Credentials: [ROLE_USER, ROLE_SUPERVISOR, ROLE_SWIMMER]
Principal: org.springframework.security.core.userdetails.User@0: Username: keith; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER, ROLE_SUPERVISOR, ROLE_SWIMMER
Autorities: [ROLE_USER, ROLE_SUPERVISOR, ROLE_SWIMMER]
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: 543BB337D17562B62F8CFFC8428272FB
User Profile: Object: org.bwgz.swim.openlane.model.User@3c8c7; Username: keith; Password: 417c7382b16c395bc25b5da1398cf076; Enabled: true; Authorities: [org.bwgz.swim.openlane.model.Authority@14bda9d; Username: keith; Authority: ROLE_USER, ROLE_SUPERVISOR, ROLE_SWIMMER;]; Name: Keith Lee; Email: keith@email.com; UsasId: leemkei0891;
Username: keith
Name: Keith Lee
Email: keith@email.com
UsasId: leemkei0891

Source code is available at github.

Open Lane – Supporting a User Part 1

April 13, 2012 Leave a comment

Open lane applications are restricted to swimmers already entered into the meet. A swimmer wanting to use the application first needs to establish their identity (register and login). The next iteration of the application adds the concept of a user to the application. User management, authentication, and authorization is a domain unto itself. This can become quite complex. At this early stage I’ll keep things simple and refactor as necessary later.

Spring Web Flow (SWF) provides a currentUser variable to access the authenticated principal. In this case principal relates to a Java object (UsernamePasswordAuthenticationToken) that Spring Security provides.  In order to take advantage of currentUser I have to be in a flow. Most examples like booking-faces start the user on a non-flow page and then provides a link into a flow. I want to use currentUser on the home page so I’ll route the user directly into a flow.

index.html

<html>
<head>
  <meta http-equiv="Refresh" content="0; URL=spring/home">
</head>
</html>

home-flow.xml

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/webflow
	http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

	<view-state id="home"></view-state>
</flow>

home.xhtml

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:c="http://java.sun.com/jsp/jstl/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core">

<f:view contentType="text/html">

<h:head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>Open Lane</title>
</h:head>
<h:body>
<h1>Open Lane</h1>
<table border="1">
	<tr>
	<td>
		<b>Date:</b>
	</td>
	<td>
		${currentDate}
	</td>
	</tr>

	<tr>
		<td>
			<b>Current User:</b>
		</td>
		<td>
			<c:if test="${not empty currentUser.name}">
			  	<b>Name:</b> ${currentUser.name}
			  	<br/>
				<b>Credentials:</b> ${currentUser.authorities}
			  	<br/>
				<b>Principal:</b> ${currentUser.principal}
			  	<br/>
				<b>Autorities:</b> ${currentUser.authorities}
			  	<br/>
				<b>Details:</b> ${currentUser.details}
			</c:if>
			<c:if test="${empty currentUser.name}">
				Name: none
			</c:if>
		</td>
	</tr>

	<tr>
		<td>
			<b>User Actions:</b>
		</td>
		<td>
			<c:if test="${not empty currentUser.name}">
				Logout
			</c:if>
			<c:if test="${empty currentUser.name}">
			   	Login | Register
			</c:if>
		</td>
	</tr>
</table>
</h:body>
</f:view>
</html>

When a user is logged in this JSF produces a informational table such as this:

Date: Thu Apr 12 16:48:04 CDT 2012
Current User: Name: keith
Credentials: [ROLE_SUPERVISOR, ROLE_USER]
Principal: org.springframework.security.core.userdetails.User@fd0ef400: Username: keith; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_SUPERVISOR,ROLE_USER
Autorities: [ROLE_SUPERVISOR, ROLE_USER]
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 127.0.0.1; SessionId: 627E651937975B65B3248F7AD3ED6F78
User Actions: Logout

Integrating SWF with Spring Security requires adding security configurations to the application. Here’s the important part.

<security:http auto-config="true" use-expressions="true">
    <security:form-login login-page="/spring/login" login-processing-url="/spring/loginProcess"
        default-target-url="/spring/home" authentication-failure-url="/spring/login?login_error=1" />
    <security:logout logout-url="/spring/logout" logout-success-url="/spring/home" />
    <security:intercept-url pattern="/secure" method="POST" access="hasRole('ROLE_SUPERVISOR')"/>
</security:http>

A call to /spring/loginProcess will route the flow to a login.xhtmllogin.xhtml presents the user with a login form. If the login is successful the flow is routed to /spring/home. A user will be logged out if the flow is later routed to /spring/logout. Here is the login.xhtml I took from booking-faces.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

<f:view contentType="text/html">

<h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Open Lane</title>
</h:head>
<h:body>
<div>
    <p>Valid username/passwords are:</p>
    <ul>
        <li>keith/melbourne</li>
        <li>erwin/leuven</li>
        <li>jeremy/atlanta</li>
        <li>scott/rochester</li>
    </ul>
</div>
<div>
    <c:if test="${not empty param.login_error}">
        <div class="error">
            Your login attempt was not successful, try again.<br />
            Reason: #{sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
        </div>
    </c:if>
    <form name="f" action="${request.contextPath}/spring/loginProcess" method="post">
        <fieldset>
            <legend>Login Information</legend>
                <p>
                    User:
                    <br />
                    <c:if test="${not empty param.login_error}">
                        <c:set var="username" value="${sessionScope.SPRING_SECURITY_LAST_USERNAME}"/>
                    </c:if>
                    <input type="text" name="j_username" value="#{username}"/>
                </p>
                <p>
                    Password:
                    <br />
                    <input type="password" name="j_password" />
                </p>
                <p>
                    <input type="checkbox" name="_spring_security_remember_me"/>
                    Don't ask for my password for two weeks:
                </p>
                <p>
                    <input name="submit" type="submit" value="Login" />
                </p>
        </fieldset>
    </form>
</div>
</h:body>
</f:view>
</html>

With all this in place I’ll now change to the “User Action” on my home page to present either a login or logout link based on the currentUser. Here’s is the change to home.xhtml.

<tr>
    <td>
        <b>User Actions:</b>
    </td>
    <td>
        <c:if test="${not empty currentUser.name}">
            Welcome, ${currentUser.name} | <a href="${request.contextPath}/spring/logout">Logout</a>
        </c:if>
        <c:if test="${empty currentUser.name}">
             <a href="${request.contextPath}/spring/login">Login</a>
        </c:if>
    </td>
</tr>

Now I can login and logout at user. Source code is available at github.

Open Lane: Starting Out With Spring Web Flow

April 11, 2012 Leave a comment

My son’s swim club hosts Minnesota’s largest swim meet. Swim meets such as this provide an opportunity for swimmers already entered into the meet to apply for an exhibition entry into events that do not use all the lanes the pool provides. In Minnesota this is called an open lane swim. The process for managing open lane entries can be quite time consuming. An online system for handling open lanes applications would significantly reduce this.

The initial requirements are:

  • User self service:
    • Create a user.
    • User login and logout.
    • Edit user profile.
    • Search for an event.
    • Manage open lane entry applications (i.e. view, add, delete).
  • Reporting:
    • List all open lane entries by swimmer and event.
  • Data initialization utility – loads meet information into the application’s database.

Since I’ve been using the Spring  framework on and off for some time now I decided to use Spring Web Flow (SWF) to build this application.

Spring Web Flow is a Spring MVC extension that allows implementing the “flows” of a web application. A flow encapsulates a sequence of steps that guide a user through the execution of some business task. It spans multiple HTTP requests, has state, deals with transactional data, is reusable, and may be dynamic and long-running in nature.

The sweet spot for Spring Web Flow are stateful web applications with controlled navigation such as checking in for a flight, applying for a loan, shopping cart checkout, or even adding a confirmation step to a form.

That sounds like just the kind of framework I need. I’ll be using a full open source stack that includes:

  • Apache Tomcat
  • Spring Web Flow
  • JSF using Primefaces
  • Hibernate
  • BIRT
  • An open source RDBMS such as MySQL
Eclipse is my IDE of choice and I should be able to build everything using Maven. While I could use an IDE such as SpringSource Tools Suite (STS) to auto generate and build much of my application I’ve decided to take a ground up approach. I don’t want an auto-magically development environment hiding the minutia from me.  That scenario is great once you’re fluent with the technology. It can be deadly when you first attempt to do something practical with it. When something doesn’t work it’s often frustrating and time consuming to resolve it.
Spring Faces- Hotel Booking Sample Application

Spring Faces- Hotel Booking Sample Application

I start out by downloading the latest version of Spring Web Flow 2.3.1. It contains a sample application called booking-faces. I built the application (to ensure it would in fact build) and then generated an eclipse project using maven:

  • mvn package
  • mvn eclipse:clean
  • mvn eclipse:eclipse

From Eclipse I imported the application into a workspace and using a Tomcat server started up the application. It all worked! I now had a reference point from which I could start coding my application.

Creating Dynamic Web Application

Creating Dynamic Web Application

Using Eclipse Java EE IDE for Web Developers (Indigo SR2) I created a dynamic web project call open-lane.  This gave me an blank web application to start from. I dropped a simple “hello word” static index.html file into webapp, ran it up with Tomcat, and successfully opened the link from from my browser. Now comes the fun part of getting all the necessary SWF bits into the project.

In general, a SWF application contains one or more flows. Flows are comprised of states (steps). SWF is based on a finite-state machine. The idea being that the application can transition (navigate) from one state to another based upon an event. A state typically has a view. I’ll start with the most primitive of applications – an application with one state. My flow definition will look like this.

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

<flow xmlns="http://www.springframework.org/schema/webflow"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/webflow
	http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

	<view-state id="test"></view-state>
</flow>

To successfully launch an SWF application I need to create a configuration that fulfills the following:

SWF components

Spring Web Flow Components¹

Spring MVC’s DispatcherServlet will be configured to route incoming flow requests to SWF.

<!-- The master configuration file for this Spring web application -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/config/web-application-config.xml
	</param-value>
</context-param>

<!-- The front controller of this Spring Web application, responsible for
	handling all application requests -->
<servlet>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value></param-value>
	</init-param>
	<load-on-startup>2</load-on-startup>
</servlet>

The configuration coming from web-application-config.xml maps DispatcherServlet requests to a application resource handler.

<!-- Enables FlowHandler URL mapping -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
    <property name="flowExecutor" ref="flowExecutor" />
</bean>

Next I define how FlowHandlerAdapter will map a resource path it receives from DispatcherServlet to a flow id. The normal convention has FlowHandlerAdapter searching the flow registry for a matching id. If it finds one then it will either start a new flow or continue an existing one.

<!-- Maps request paths to flows in the flowRegistry;
     e.g. a path of /a/b looks for a flow with id "a/b" -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
    <property name="flowRegistry" ref="flowRegistry"/>
    <property name="order" value="0"/>
</bean>

In order to query a flow from the flow registry one has to exist. This directs the registry to use flows defined in /WEB-INF/flows. For example, WEB-INF/flows/testing/test/test-flow.xml. It also defines the id of the service used to build these flows.

<!-- Register all Web Flow definitions under /WEB-INF/flows/**/*-flow.xml -->
<webflow:flow-registry id="flowRegistry"
    base-path="/WEB-INF/flows"
    flow-builder-services="flowBuilderServices">
    <webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>

Now things get interesting. SWF provides several flow builder services and you can create your own. The one you choice will bring in the conventions and overhead associated with the service. For example, using a JSF builder service means that:

  • All the necessary JSF libraries and dependencies must be available to the application. This usually means including them in the application packaging.
  • The application is configured for JSF.
  • Views (pages) will be written in JSF.

In other words, welcome to the world of JSF.

To get things started I didn’t want to complicate my first application with JSF or JSP. I’m just trying to ensure that the plumbing is working. While that meant writing a bit of Java code I decided it was the lesser of two evils.

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.bwgz.test.TestUrlBasedView"/>
</bean>

<!-- Deploy a flow executor -->
<webflow:flow-executor id="flowExecutor" />

<!-- Configure flow builder services -->
<!-- Configure view service -->
<webflow:flow-builder-services id="flowBuilderServices"
    view-factory-creator="mvcViewFactoryCreator" />

<!-- Use the test View Resolver -->
<bean id="mvcViewFactoryCreator"
   class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
   <property name="viewResolvers" ref="viewResolver"/>
</bean>

In this instance the flow builder service will use MvcViewFactoryCreator and it will in turn use UrlBasedViewResolver and my TestUrlBasedView to generate the view. I don’t do much in TestUrlBasedView. Just dump out some variables and get out of Dodge City.

package org.bwgz.test;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

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

import org.springframework.web.servlet.view.AbstractUrlBasedView;

public class TestUrlBasedView extends AbstractUrlBasedView {
	@Override
	protected void renderMergedOutputModel(Map<String, Object> model,
			HttpServletRequest request, HttpServletResponse response) throws Exception {

		Set<?> keys = model.keySet();
		Iterator<?> iterator = keys.iterator();

		System.out.printf("url: %s\n", getUrl());

		while (iterator.hasNext()) {
			Object key = iterator.next();

			System.out.printf("key: %s  value: %s\n", key.toString(), model.get(key));
		}
	}
}

In my browser I go to http://localhost:8080/open-lane/spring/testing/test and Tomcat dumps the following output to the console.

url: test
key: flashScope  value: map[[empty]]
key: flowRequestContext  value: [RequestControlContextImpl@1455cf4 externalContext = org.springframework.webflow.mvc.servlet.MvcExternalContext@d9b071, currentEvent = [null], requestScope = map[[empty]], attributes = map[[empty]], messageContext = [DefaultMessageContext@1ceebfa sourceMessages = map[[null] -> list[[empty]]]], flowExecution = [FlowExecutionImpl@1e6743e flow = 'testing/test', flowSessions = list[[FlowSessionImpl@d9ceea flow = 'testing/test', state = 'test', scope = map['viewScope' -> map[[empty]]]]]]]
key: flowExecutionKey  value: e1s1
key: flowExecutionUrl  value: /open-lane/spring/testing/test?execution=e1s1
key: currentUser  value: null
key: viewScope  value: map[[empty]]

I could get a little fancier by modifying my flow to:

<view-state id="test" view="/index-static.html">

And adding this line to the end of TestUrlBasedView:

request.getRequestDispatcher(getUrl()).forward(request, response);

That forwards my browser to a static html file in my application.

All the plumbing appears to be in place. Here are all the SWF libraries and dependencies I needed.

  • commons-logging-1.1.1.jar
  • spring-asm-3.1.1.RELEASE.jar
  • spring-beans-3.1.1.RELEASE.jar
  • spring-binding-2.3.1.RELEASE.jar
  • spring-context-3.1.1.RELEASE.jar
  • spring-core-3.1.1.RELEASE.jar
  • spring-expression-3.1.1.RELEASE.jar
  • spring-js-2.3.1.RELEASE.jar
  • spring-web-3.1.1.RELEASE.jar
  • spring-webflow-2.3.1.RELEASE.jar
  • spring-webmvc-3.1.1.RELEASE.jar

Time to get out of the minutia. The next post on Open Lane will introduce JSF into the application.

Source code is available at github.

Notes:

¹Spring Web Flow Components diagram from Tutorial: Build a Shopping Cart with Spring Web Flow 2.0.