Home > Java, JPA, JSF, Spring, Spring Security, Spring Web Flow > Open Lane – Supporting a User Part 2

Open Lane – Supporting a User Part 2

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.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: