Spring Acegi cont-

My tomorrow took forever. Here is the first installment. To do a quick recap; our application's intention was to use Spring 3 security with Struts framework. Our last conversation, we strutsfyied our application with a logon and password. So here we are after that; First step to onboard spring security is to include some of the most catchy, trendy jar files that is to be added to CLASSPATH. Spring 3 security framework can be downloaded from here. The version that we are developing is Spring Securty 3.0.2.

The best book that is available in the market to learn about spring security is here

Moving with our narration; Make sure end CLASSPATH is something similar to this one.

From Spring Acegi

There were lot of CLASSPATH conflicts when this thing was setup initially. But honestly after one gets a hang of CLASSPATH it is very smooth sailing. If you have any issues with configuration, please reach out. It is def not worth trying to self solve it.

Now the first step after configuring is to plumb the configuration pieces;

From Spring Acegi

As shown; you are probably looking at a new xml file for spring security defn in line 9 <springbasic-security.xml>.

Take a note at line 16-19 in the file.

From Spring Acegi

This definition is now telling the system that only one login can be active for anyone logging into the application. All the boiler plate coding to ensure one session logging is all handled by Spring Security. This one piece of information is enough to incorporate Spring Security into apps.

From Spring Acegi

The above entry in spring security config file basically tells the system to be aware that there can be only one open session for this user.

Next information that might interest you is the following one;

From Spring Acegi

Everything in spring security works based of Filters. The DelegatingFilterProxy does the trick for integrating Struts and *.do ending URL's. We are not going to deep dive into struts integration.us

Next screen is the mother of our Spring Security Integration.

From Spring Acegi

Let us now take a closer look at various components in the screen. Line #18 we are asking spring security framework to auto-configure the default items. Then we are requesting the framework to add expression language support.

The line item for remember-me is requesting framework to allow users to remember their user-name and password. This is always a tricky one; but without boilerplate coding, if a battle tested framework like spring can provide, well I can take it.

Next few lines we are discussing about intercept URL information; this is telling the framework to allow login.do,home.do,accessDenied.do to all users without any role or login credential. Remember we asked framework to understand expressions, here we are having an entry that says "permitAll".

Other item in the screen is the ROLE_USER . Suppose let us assume you have a scenario where you want only users with specific roles to view some pages. You have the roles defined in a LDAP or database, we are assuming a role of ROLE_USER in this case. Boom no loops etc to spin thro any information. We are asking the framework to allow users with the ROLE_USER to access the web-pages. All loops gone, framework does the magic for you. This is money, imagine the number of proprietary knowledge saving for a system. Anyone who can read XML can now understand access to various parts of system.

Next item we are going to look at the form-login information. This snippet tells what is the form login page for the system, i.e. upon authentication, what is the first page user is going to land into.
<form-login login-page="/home.do" authentication-failure-url="/accessDenied.do" default-target-url="/checkLogin.do" always-use-default-target="true"/>
As you can see "home.do" is the landing page for application users who have succesfully logged in. We are simplfying the error handling of directing un-authorized users to goto accessDenied.do path. Finally the default target URL is another perk from Spring security, where all users will be directed by default to this path if they are not logged in. Howz that, we finished three workflows in one line for code.

If you deep dive into our spring-security.xml, the following lines are used to define an embded database.
<jdbc:embedded-database id="source">
<jdbc:script location="/schema.sql"/>
<jdbc:script location="/test-data.sql"/>

As one can imagine the direction we are going by introducing the above database is; we are going to maintain our users in this small in-memory database. The couple of sql files we defined here are pretty easy to follow up with. One creates a simple table with an username and password. The second one populates data for the table. This data will be populated when server startsup.
<context:component-scan base-package="com.company.springacegisecurityexampleapp"/>

Now comes another super heavy weight power of Spring Security. We know the best practice is to avoid storing password information without encrypting. But don't bother this boiler plate requirement as it is handled by spring with few changes to our code base.

First decision point is to understand what type of encoding mechanism we are going to use. AES, SHA are few to list. In our case let us take the SHA encoder,  In order to do that add these following lines to the spring-security xml file.
<beans:bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder"/>
We have defined the password encoder, now we would want the password encoder to be active when user information is uploaded to the database.

<beans:bean init-method="secureDatabase" depends-on="source">

<beans:property name="dataSource" ref="source"/>


The java code for the DatabasePasswordEncoder is

public class DatabasePasswordEncoder extends JdbcDaoSupport {
private PasswordEncoder passwordEncoder;
private UserDetailsService userDetailsService;
private SaltSource saltSource;

public void secureDatabase() {
getJdbcTemplate().query("select username, password from users", new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
System.out.println("Password is " + password);
UserDetails user = userDetailsService.loadUserByUsername(username);
String encodedPassword = passwordEncoder.encodePassword(password, saltSource.getSalt(user));
// String encodedPassword = passwordEncoder.encodePassword(password, null);
getJdbcTemplate().update("Update users set Password =? where username = ?", encodedPassword, username);
System.out.println("Updating information for username " + username);

We will try to see how to change password in next few days. As and always the code is the google code base here