Thursday, July 12, 2012

Single sign on with spring security and Siteminder

Enviorment-Spring version-3.0.5,Siteminder

Goal-Integrating Single sign on using site minder with spring security.


1.What is Single Sign On?
Single sign on is a property/concept means login once into a web portal and navigate to other supported independent portals without being prompted login again.
Say you login into portal A once, now you can navigate to supported independent portal b,portal c without need to login again.

2.what is Site minder?
Site minder is single sign on system that authenticates the user and puts a token in http request header(SM_USER).
Overview of the request request processing-
1. Consider a user say user1 in your system logs in, on successfull authentication siteminder would put a header(SM_USER) in the httprequest with value say smuser1.
2. User clicks on a link on your web page to navigate to SSO supported portalb(siteminder will again populate the request with SM_USER header token,we will not get into details here).
3. Portalb will check if the SM_USER header is available. In our sample case here SM_USER=SMUSER1.
4. portalb can further check for further check say if the SMUSER1 mapps to any user in there system if yes consider authentication done move for aurthorization check.

Spring security Support for Siteminder
Spring provide out of box support for SSO/Pre-Authentication scenarios. Refer Spring PreAuthentication documents section16.2.1 for siminder related configurations
Step 1. Create a bean to handel sso/pre-authentication,
<bean id="siteminderFilter" class="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>

step 2. Specify the above bean to be used as preauth filter. Make following entry in <http.... tag


step 3. Create a Preauth provider bean,
<beans:bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService">
<beans:bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">

<beans:property name="userDetailsService" ref="myUserDetailsService"/>
</beans:bean>
</beans:property>

<beans:property name="userDetailsChecker" ref="myUserDetailsChecker"/>
</beans:bean>

step 4. Add the preauthAuthProvider to the provider list in the authentication-manager tag.

step 5. Specify org.springframework.security.core.AuthenticationException in web.xml to handel the exceptions and show appropriate view
<error-page>
<exception-type>org.springframework.security.core.AuthenticationException</exception-type>
<location>/myportal/error</location>
</error-page>

Spring framework internal processing and hooks to put extra checks

RequestHeaderPreAuthenticatedProcessingFilter- Handles the request ,
1. checks if the header is not available throws the PreAuthenticatedCredentialsNotFoundException.
2. Iterates over the providers, as we have specified preauthAuthProvider on the top of provider list this is the first provider to be evaluated.
preauthAuthProvider calls the loadUserByUsername function of myUserDetailsService.
Note -This is the point to perform any extra check on the value coming in from the header and evaluate if value in header maps to a user in our system.
Typical implementation is

public UserDetails loadUserByUsername(String smHeadervalue) throws UsernameNotFoundException, DataAccessException {

// find it the user in my system maps to smHeadervalue
//if user is null throw exception
if (user == null) {
throw new UsernameNotFoundException("No such user");
}
return user;
}

3.Next the frame work call check function of the myUserDetailsChecker. As now we know the user exist in our system, check for various states as per your requirement ,throw exception to abort and show the error page.
This step is optional and can be avoided by removing from preauthprovider configuration.


public void check(UserDetails user) {
if (!user.isAccountNonLocked()) {
throw new LockedException( "User account is locked", user);
}
if (!user.isEnabled()) {
throw new DisabledException( "User is disabled", user);
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException("User account has expired", user);
}

}
4. if no exception is thrown in the above steps (Authentication is successfull) , user will be checked for aurthorization . If the user hae appropriate roles
the requested page will be displayed.

2 comments:

  1. Hey Amit,

    Thanks for this detail implementation.
    I am little bit confused how my login page will call my siteminder URL and pass authentication parameter.

    ReplyDelete
  2. Hi Amit, How did you configure pre auth filter inside tag? Could you please publish more details on step 2 mentioned above?

    ReplyDelete