When one of my project requires well defined authentication & role authorization, I started looking into various options. When I come across Spring Security (formerly ACEGI) , I was impressed with the way we can easily plug in our existing authentication with Spring security framework.
This series of article is intended to explain usage of spring security with my knowledge. Any comments and suggestions are welcome.
This part I is aimed to give the basics of Spring security framework and authentication mechanism provided by Spring security.
Instead of taking u to the theory, let me start with a simple use case and slowly inject more complex scenarios in the later part of the article.
Use Case: User is entering their credentials to login into the web application.
Typically, the developer would have written their code to handle authentication for any web application. As developer doesn't know how much extra effort will take to understand Spring security so, developer may hesitate to change to Spring security's authentication. We will see how much change required to migrate to Spring based authentication.
The user would have written login page with username and password as field(minimum credentials) and a submit button to login to the application i.e taking them to thier Home page.
Spring Basics
To understand or usage of Spring based authentication, the developers are required to know the following components or Spring classes
1. FilterChainProxy
2. AuthenticationProcessingFilter
3. AuthenticationManager
4. AuthenticationProvider
5. UserDetailsService
6. UserDetails
7. SecurityContextHolder
8. SecurityContext
We will discuss about each & every class and its importance in terms of integration with our code.
FilterChainProxy: As the name suggest, this proxy class receives any web request and apply list of filters on the incoming request.
AuthenticationProcessingFilter: Whenever the web request comes to this class with particular URL then this class have responsibilty to do the authentication.
AuthenticationManager: The implemented have responsibility to call list of providers for creating authenticated Authentication object.
AuthenticationProvider: The implemented class have responsibility to create Authentication object with the help of UserDetails object.
UserDetailsService: The implemented class will know how to get the UserDetails object, which will useful to create Authentication object.
UserDetails: The implemented will have details about the logged in user. The details are their granted authorities, whether their account expired, locked, user name, password etc. Most of the time the UserDetails can be their domain object itself.
SecurityContextHolder: The singleton static class to hold security context object.
SecurityContext: This object will be created for each logged in user and holds the Authentication object.
Now, we armed with basic knowledge about the required classes involved in the process of Spring based authentication. We will step back ourself to see the simple use case.
The following are the required changes in your code to integrate with Spring based authentication.
1. Typically the web.xml will have the following filter entry so that the request will undergo through all configured filters.
< filter >
< filter-name >
filterChainProxy
</ filter-name >
< filter-class >
org.springframework.web.filter.DelegatingFilterProxy
</ filter-class >
</ filter >
< filter-mapping >
< filter-name > filterChainProxy </filter-name >
< url-pattern > /* </url-pattern >
< /filter-mapping >
Based on the above entry, whenever the web container receives request, the request will be handed over to FilterChainProxy to apply list of filters.
2. Add the below entry in your service context.xml
< bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
< security:filter-chain-map path-type="ant">
< security:filter-chain pattern="/login**" filters="none"/>
< security:filter-chain pattern="/**" filters="authenticationProcessingFilter"/>
< /security:filter-chain-map>
< /bean>
I have defined two pattern, one doesn't have any filters to apply and another has authenticationProcessingFilter. Whenever the URL pattern has login then it will not apply any filters and take the user to login page. Whenever other than login URL pattern is accessed then the authenticationProcessingFilter will be called.
3. Add the below entry for authenticationProcessingFilter in the service context.xml
< bean id="authenticationProcessingFilter"
class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
< property name="authenticationManager" ref="authenticationManager" />
< property name="authenticationFailureUrl" value="/login.action" />
< property name="defaultTargetUrl" value="/home.action" />
< property name="filterProcessesUrl" value="authenticateUser"/>
< property name="passwordParameter" value="PASSWORD"/>
< property name="usernameParameter" value="USERNAME"/>
< /bean>
Whatever the field name defined in your JSP have to be replaced withe passwordParameter & usernameParameter properties values. The authentication processing filter will retrieve respective parameters from the request and use it for authentication. The property filterProcessesUrl should have the value as where we are submitting the user credentials. This property will be used to decide whether to call AuthenticationManager to create new Authentication object and set it in security context. i.e if the request URL is authenticateUser then the authentication will happen else the user will be taken to authenticationFailureUrl i.e to the login page in our example. If authentication is successful then the user will be taken to defaultTargetUrl i.e home page in our example.
4. Add the below entry for AuthenticationManager in service context.xml
< bean id="authenticationManager"
class="org.springframework.security.providers.ProviderManager">
< property name="providers">
< list>
< ref local="myAppAuthenticationProvider"/>
< /list>
< /property>
< /bean>
When the authentication processing filter decides to do authentication then authentication manager will be called, which in turn call the providers and create Authentication object.
5. Add the below entry for the provider in service context.xml
< bean id="myAppAuthenticationProvider"
class="com.app.MyAppAuthenticationProvider">
< property name="userDetailsService" ref="userDetailsService"/>
< /bean>
When the AuthenticationManager calls this provider, the call will be given to User details service to retrieve user details information.
6. Add the below entry for user details service and moreover this is the first class we are writing it with respect to authentication implementation.
< bean id="userDetailsService"
class="com.app.impl.security.UserDetailsServiceImpl">
< property name="userService" ref="userService"/>
< /bean>
Typically, we would have written User Service class to retrieve the user information i.e user domain object. Use the same class to retrieve the user details object.
7. Either change ur domain object to implement UserDetails interface provided by Spring class or write a wrapper, which implements user details interface and hold reference to user domain object.
When user provided credentials are failed then AuthenticationException will be thrown.
After authentication and if the user credentials are valid then the created Authentication object will be set into the SecurityContext.
To retrieve the user domain object in your code, the following lines of code is sufficient.
Object principal =
SecurityContextHolder.getSecurityContext().getAuthentication().getPrincipal();
User user = null; //Domain object
if(principal instanceof UserDetails){
user = (User) principal; //first case
//user = ((UserWrapper)principal).getUser(); Second case
}
Thats it about migrating non Spring based authentication to Spring based authentication.
Gist of the post: Eventhough we need to do more configuration and write a couple of classes i.e UserDetails, UserDetailsService & Wrapper. It is easy to migrate to Spring based authentication. We can define a seperate context.xml for implementing Spring based security.
In the next part, we can see a simplified configuration and authorization.
Good start!!!
ReplyDeleteBut its ur responsibility to water this plant and grow it further without breaking it..
I would like to share an another nice article for Spring security with your permission :)
http://www.ibm.com/developerworks/java/library/j-acegi1/index.html
Thanks u r information
ReplyDeleteto understand the spring security from scratch this is the best approach and u did really good job.....
ReplyDeleteIts very basic and contains the practical info by this way reader will come to know how to proceed with spring security........ really nice article......
ReplyDeleteArticle is good.
ReplyDeleteBut you need to make it readable and add some colors :)