MrBool
You must be logged in to give feedback. Click here to login
[Close]

You must be logged to download.

Click here to login

[Close]

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

[Close]

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Servlet security with Spring AOP and Annotations: Authentication

In this article, we will see a simple login mechanism that uses a user database, and how we can add fields to the user database to control access to individual types of operation.

[close]

You didn't like the quality of this content?

Would you like to comment what you didn't like?

Introduction

Most non-trivial web applications require some kind of authentication and authorization system. These two security requirements are closely related, but do represent separate requirements:

  • Authentication is the process of determining who the user of the system is
  • Authorization is the process of deciding, based on our knowledge of a request, whether a requested action should be performed or not.

We usually make use of the information obtained during authentication as part of the process of authorization, but other forms of authorization could be possible (e.g. only allowing users to visit a part of the site if they are visiting from particular IP addresses). However, before I can describe that, we first require method of authentication.

I assume that the reader is familiar with various subjects that I have previously written about. If you are not familiar with any of these, I suggest you read the listed articles:

  • Configuring servlets with Spring’s dependency injection container
  • Using Spring’s Aspect Oriented Programming support to intercept requests to servlets
  • The Data Access Object (or Table Gateway) pattern

Implementing Authentication

To support authentication, it is necessary to add a few new features to the application:

  • We need some source of user information. I have chosen to create a table “users” and create a User class and associated UserDAO class to communicate with the database. Alternative implementations would include communicating with existing infrastructure, e.g. using LDAP.
  • We need to establish a standard way of storing the identity of authenticated users. I have chosen to use the servlet’s session management facility to store the User object corresponding to the authenticated user.
  • We need a servlet to allow the user to log in, which I have implemented using a traditional username/password form. You could also use systems like OAuth2, or a challenge/response protocol of some kind.

In a full system, additional functions may be needed (log out, use of cookies to identify returning users, user registration, password changing, lost password recovery, and so on). I have not implemented these, but all are reasonably simple.

Let’s get started by defining the User class. We’ll need a few basic pieces of information - username and password, plus to support my authorization scheme I’ll also include a few flags for defining what access the user has to the system.

Here’s the basic class definition:

Listing 1: Starting the User class

 
public class User
{
	private final int id;
	private String username, password;
	private boolean canCreateCustomers, canCreateAccounts;

	public boolean isValidLoginRequest (HttpServletRequest req)
{
		return req.getParameter ("password") != null && 
				req.getParameter ("password").equals (password);
}
	
}

I’ve defined the isValidLoginRequest to check that the correct password has been specified. Deferring the decision to the User object rather than getting the password and checking in the login controller allows more flexibility: I could later add a new type of user that has a different authentication mechanism, and the login controller would not have to identify the difference between the two. In addition to the code shown above, we’ll also need getter and setter methods for all of the fields. I automatically generate these using Eclipse’s Source/Generate getters and setters menu command.

The UserDAO class is responsible for persisting Users to the database and finding them when we need them. It looks like this:

Listing 2: The Data Access Object for Users

 
public class UserDAO
{
	private ConnectionManager connectionManager;

	private Connection getConnection()
	{
		return connectionManager.getConnection();
	}

	public void setConnectionManager(ConnectionManager connectionManager)
	{
		this.connectionManager = connectionManager;
	}

	private User makeUser(ResultSet resultSet) throws SQLException
	{
		User result = new User(resultSet.getInt("user_id"));
		result.setUsername(resultSet.getString("user_username"));
		result.setPassword(resultSet.getString("user_password"));
		result.setCanCreateCustomers(resultSet
				.getBoolean("user_canCreateCustomers"));
		result.setCanCreateAccounts(resultSet
				.getBoolean("user_canCreateAccounts"));
		return result;
	}

	public User getByUsername(String username) throws SQLException
	{
		try (PreparedStatement s = getConnection().prepareStatement(
				"select " + projection() + " from users where username=?"))
		{
			s.setString(1, username);
			try (ResultSet r = s.executeQuery())
			{
				if (r.next())
					return makeUser(r);
				return null;
			}
		}
	}

	static String projection()
	{
		return "id user_id, username user_username, password user_password, "
				+ "canCreateCustomers user_canCreateCustomers, "
				+ "canCreateAccounts user_canCreateAccounts";
	}
}

The general pattern for this class is the same as before - the ConnectionManager is supplied by Spring and provides one unique connection per thread; makeUser() converts the current row of a ResultSet into a single User object, getByUsername() performs a query and we have a static projection() method that provides the definition of the columns we use so that it can be shared between queries and (if necessary) other DAOs that might want to perform a join with the users table. We only support one access method tight now - search by username - and have not defined any methods for storing users. I will add users to the database by hand for now, and we don’t have any need to retrieve them in any other way at the moment. Other methods can easily be added later.

Now we need to create the database table and populate it with some example users:

Listing 3: The user database

 
create table users (
   id int primary key auto_increment not null,
   username varchar(255) not null,
   password varchar(255) not null,
   canCreateCustomers tinyint not null,
   canCreateAccounts tinyint not null,
   unique (username)
) engine=innodb;
insert into users values (1, 'customermgr', 'password', 1, 0);
insert into users values (2, 'accountmgr', 'password', 0, 1);
insert into users values (3, 'supervisor', 'password', 1, 1);
insert into users values (4, 'unpriveleged', 'password', 0, 0);

I’ve created one user for each combination of the two access level flags I set up. This will help when we come to test the authorization mechanism later.

Now we just need the Login servlet, which is relatively simple:

Listing 4: Logging in

 
public class Login extends HttpServlet
{
	UserDAO userDAO;

	public void setUserDAO(UserDAO userDAO)
	{
		this.userDAO = userDAO;
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
	{
		req.getRequestDispatcher("/templates/login.jsp").forward(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
	{
		try
		{
			String username = req.getParameter("username");
			if (username == null)
				throw new ServletException("Required parameter 'username' missing");
			User user = userDAO.getByUsername(username);
			if (user == null || !user.isValidLoginRequest(req))
				req.getRequestDispatcher("/templates/login-failed.jsp")
						.forward(req, resp);
			else
			{
				req.getSession(true).setAttribute("user", user);
				resp.sendRedirect("customers");
			}
		} catch (SQLException e)
		{
			throw new ServletException(e);
		}
	}
}

The servlet is provided with a UserDAO object by Spring. On a GET request, this servlet simply forwards the request to a login.jsp file that displays a form with appropriate fields for username and password that will be POSTed back to the same servlet. The POST request is where the interesting stuff happens: we get the username the user has supplied, and attempt to fetch a corresponding User object. If we fail to get one, or if the object rejects the login attempt, we forward the request to the login-failed.jsp file, which displays an appropriate error message and gives the user another chance to log in. Otherwise, the User object has accepted the attempt, so we store it in the servlet session (creating a new one if necessary) and send the User to the main entry point of the site.

A number of improvements on this design would be possible:

  • We should probably be logging successful and unsuccessful attempts to log in. It would be tempting to create a UserLoginManager object which is notified of successful and unsuccessful attempts.
  • This also helps with one other issue I have with this design, which is that this class has two responsibilities: determining the details of new user login sessions and storing this information in the session. The Single Responsibility Principle suggests that a class should have only one reason to change, but we have two. Deferring the storage of the logged in user to the UserLoginManager would remove one (and logging could then be added to the UserLoginManager using AOP, meaning that no class has multiple concerns).
We do not, however, have any immediate need to make these changes, and they can be performed later if we ever need to work on this code again, so I’d defer these changes to a later date.

This is all for this article. See you next time.

Also see



My main area of specialization is Java and J2EE. I have worked on many international projects like Recorders,Websites,Crawlers etc.Also i am an Oracle Certified java professional as well as DB2 certified

What did you think of this post?
Services
Know how to keep MrBool Online
SUPPORT US
SUPPORT US
With your help, we can keep providing free content and helping you to be a better professional
support us
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually � in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits � in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login