15 Aug 2012

Role based application modelling using Spring security

8/15/2012

A common requirement in a enterprise web application is Role based access more commonly called Authorization. This is to make sure right data is accessible to right user.

Spring security framework is well capable of achieving the same if modeled within the application correctly. I have been observing various application designs for the past few years and i have not seen it being done correctly in most designs. It has always lead to crappy code snippets patching & hiding the design mistakes later in the development to have things working.

Using Spring security framework for authentication modeling:

Sample Requirement
The application has to have role based access to different pages. Spring security framework offers out of the box URL pattern based access to user roles, which brings in lot of ease to be taken care of both authentication and authorization of the application.

The model





Implementation
The heart of all the spring security configurations in a web application is the file applicationContext-security.xml

There are two important components in this configuration file,
a) HTTP filter configuration

<http auto-config="true" access-denied-page="/accessDenied">
<intercept-url pattern="/login" filters="none" />
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<intercept-url pattern="/staff/**" access="ROLE_STAFF,ROLE_ADMIN" />
<intercept-url pattern="/**" filters="none" />
<form-login authentication-failure-url="/loginfailed"
default-target-url="/" login-page="/login"/>
<logout logout-success-url="/" />
</http>

If you look into detail as to what are we doing in this configuration, we are actually setting up enabling different interceptors to validate access and role.
Take an example of the interceptor for url pattern /staff/** , the interceptor declares here that the url pattern is only accessible to users who are logged in to the system and have user role as wither ROLE_STAFF or ROLE_ADMIN.

We have to even define various other urls for authentication failure, login page url, access denied url etc to make the configurations complete to handle all the scenarios.

b) Authentication manager (with password encoder)
If you go through various examples on internet for the authentication manager, you would get examples using LDAP or web server based authentication

However what we all most deal with is a authentication model where we are having the user credentials in one of our tables, so lets take this example and see how we achieve it using Spring security.
So i have a User table where i am storing the user credentials, username and password & password is MD5 encrypted.

Now lets look at the entry that i had to make in the configuration file for this

<beans:bean id="encoder"  class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
<authentication-manager>
<authentication-provider user-service-ref="cleancodeUserService">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="cleancodeUserService" class="com.web.myapp.serviceImpl.MyAppAuthenticationService" />

This entry simply directs Spring security to use my Authentication service implementation for authentication. Another thing that needs to be noted here is that we have directed the authentication manager to use MD5 encoding model for the password.

Now the most important is to see and understand how do we implement our custom authentication class, so lets jump into it, below is my Authentication service

@Service
public class MyAppAuthenticationService implements UserDetailsService  {

  @Autowired
 UserDAO userDAO;
 
 public UserDetails loadUserByUsername(String userName)
   throws UsernameNotFoundException, DataAccessException {
  User user = userDAO.loadUserByUserName(userName);
  if(user == null)
   throw new UsernameNotFoundException("AbstractSecurityInterceptor.authenticationNotFound");
  
  String status = user.getStatus();
  boolean isEnabled = false;
  if(status.equals(MyAppConstants.USER_ACTIVE)){
   isEnabled = true;
  }
  List authList = new ArrayList(1);
  if(user.getUserType().equals(OPSConstants.USER_TYPE_STAFF))
   authList.add(new GrantedAuthorityImpl("ROLE_STAFF"));
  if(user.getUserType().equals(OPSConstants.USER_TYPE_ADMIN))
         authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
  org.springframework.security.core.userdetails.User user2 = new org.springframework.security.core.userdetails.User(userName, user.getPassword(), isEnabled, true, true, true, authList);
  return user2;
 }
}

The core thing that needs to be taken into account is that your application class where you want to take care of custom behavior for authentication is your class should extend UserDetailsService of spring framework(org.springframework.security.core.userdetails.UserDetailsService) and then implement loadUserByUsername method. Just ensure that the method return right User object with appropriate custructor parameters. Once you populate the User object correctly and return it, during authentication the Spring framework automatically matches the username and password that is entered by the user on the login screen.

Another important aspect of the whole implementation is how to code your login page, as it should have appropriate variable names and POST url, so lets see that too

Firstly where ever you want to show the error message on your page that is returned in case of any authentication failure, use the below code snippet

<c:if test="${not empty error}">

<div class="errorblock">
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
</div>
</c:if>

Secondly this is how the form should be for the login elements, for the request to get posted to Spring and the framework being taking care of the authentication with the custom authentication method that we coded

<form name="f" action="<c:url value='/j_spring_security_check'/>" method="POST" id="loginForm">
<table>
<tr>
<td style="font-weight: bold;padding-right: 10px;">Email</td>
<td><input type='text' name='j_username'/></td>
</tr>
<tr>
<td style="font-weight: bold;padding-right: 10px;">Password</td>
<td><input type='password' name='j_password'></td>
</tr>
<tr >
<td colspan='2' style="text-align: center;padding-top: 10px;"><a href="#" class="button orange" onclick="return login();">Login</a></td>
</tr>
</table>
</form>

Just note the bold items in the above code snippet and that should give you an idea as to what changes. 

The last bit being now how do we logout in this case, Spring security framework also has a logout url that you can refer on a logout link where ever you want it to be, i.e. /j_spring_security_logout


I hope this helps you with role based modelling and implementation, but if you are still stuck somewhere, do post me a comment and i would revert !

Written by

We are Creative Blogger Theme Wavers which provides user friendly, effective and easy to use themes. Each support has free and providing HD support screen casting.

0 comments:

Post a Comment

 

© 2013 NimbleGeek. All rights resevered. Designed by Templateism

Back To Top