Monday, January 12, 2015

Adding Tomcat plugin into existing Maven configuration

I have an existing POM which have been configure to use WAS Liberty Profile as my development, and now I'm going to add new configuration that could support Tomcat as well. I'm wondering whether this will harm my project? I'm also worry there will be lot of work need to be done.

Basically I was wrong, and I was so wrong. I did the experiment, it will not harm my existing configuration. All I need to do is to add following pieces into existing POM with the goal clean install tomcat7:run and the web app will fly.
    <build>
        ...

        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.0</version>
            </plugin>

            ...
            ...
        </plugins>
    </build>

Sunday, January 11, 2015

Reading properties file with Spring framework

Good day, I'd learned a new way of reading properties file with Spring. Usually when setting up a project with Spring framework, one common thing should have in Spring is following code:
   <bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:config/application.properties</value>
                <value>classpath:config/database/database.properties</value>
            </list>
        </property>
   </bean>

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="properties" ref="applicationProperties" />

    </bean>

I guess that was the classic design of a Spring project. Let's assume the application.properties file containing following content:

input.path=./
output.path=./

In order to read that properties, this is what I did in a my class:
public class MyClass
   protected Logger log = Logger.getLogger(this.getClass().getName());

   @Value("#{applicationProperties['input.path']}")
   private String filePath;
   ...
   ...
}

How could I unit test inner class?

Given the source code below, how could I effectively unit test the Message class, the inner class of MainMsg? The challenge for this use case is Message class doesn't have any public interface that could access from outside world, the only entry is from MainMsg's addMessage(). How could I return a fake data when getMsgList() is called? Or I shouldn't mock Message class actually, just instantiate a new value is more than enough.
public class MySystem {
 public static void getMessage(MainMsg mm) {
  if( mm.getMsgList().size() > 0 ) {
   … 
   … 
  }
 }
}

public class MainMsg {
 private List<Message> msgList = new ArrayList<Message>();
 public class Message {
  private String str;
  Message(String str) {
   this.str = str;
  }
 }
 public void addMessage(String content) {
  msgList.add(new Message(content));
 }
 public List<Message> getMsgList() {
  return msgList;
 }
}
According to the advice from expert, I shouldn’t mock the inner class, whereas I should create a real value of it. But how? After a long R&D, I found EasyMock could handle this very well. In my unit test class, this is how I did it:
@RunWith(PowerMockRunner.class)
@PrepareForTest({MySystem.class})
public class MySystemTest {
 private MainMsg mm;
 @Test
 public void testSendMessage () throws IOException {
  mm = PowerMock.createPartialMock(MainMsg.class, "getMsgList");
  EasyMock.expect(mm.getMsgList()).andStubAnswer(new IAnswer<List<Message>>() {
   @Override
   public List<Message> answer() throws Throwable {
    Whitebox.setInternalState(mm, new ArrayList<Message>());
    mm.addMessage("message_A");
    List<Message> fakeMsgList = Whitebox.getInternalState(mm, "msgList");
    return fakeMsgList;
   }
  });

  MySystem.getMessage(mm);
 }
}

Sunday, January 4, 2015

Steps to create new cocos2d-x project in Netbeans

Many times when I wanted to create a new Cocos2d-x project in Netbeans, I always forgot the procedure. Thus I decide to write it down for future reference. As of this writing, I'm using Cocos2d-x 3.1.1 and Netbeans 8.

Steps:
  1. Create new project using cocos command.
  2. In Netbeans, goto File > New Project > C/C++ Project with Existing Sources, then click Next button.
  3. Under the Specify the folder that contains existing sources field, navigate to the game project's root path created with cocos command.
  4. Let it build.
A short note, when trying to run the project, there will be a dialog prompt to select an executable. Pick the default selection will do.

Wednesday, December 31, 2014

Homebrew LDAP authorization with Spring Security

Continuing my journey from previous post, I realize that although LDAP authentication has been done successfully, but the user were still have no roles being assign. For this issue, I'm require to implement a custom authorization mechanism in order to assign LDAP user a role.

I found there are plenty of resources on how could an LDAP user is map to a role:
  1. configure LdapAuthenticationProvider in Spring. (read here)
  2. configure user-context-mapper-ref and extends one class with DefaultLdapAuthoritiesPopulator (read here)
  3. confgiure user-context-mapper-ref and extends one class with LdapUserDetailsMapper (read here)
  4. configure BindAuthenticator constructor and implements one class with LdapAuthoritiesPopulator (read here)
Among those resources, I found option 3 would be the most suit for my use case since I don't have the role group define in LDAP. And my requirement is as long as I got the name huahsin detected, then grant him an ROLE_ADMIN. To put nonsense short, I created a class extending LdapUserDetailsMapper:
public class MyAuthorityMapper extends LdapUserDetailsMapper {
 
 @Override
 public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection authority) {
  
  UserDetails userDetails = super.mapUserFromContext(ctx, username, authority);
  
  Collection<grantedauthority> authorities = new ArrayList<grantedauthority>();
  
  if( "huahsin".equalsIgnoreCase(username) ) {
   authorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
  }
  else {
   authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
  }
  
  return new User(userDetails.getUsername(), 
    userDetails.getPassword(),
    true,
    true,
    true,
    true,
    authorities);
 }
 
}
On Spring configuration site, I will have this:
    <authentication-manager alias="authenticationManager">

        <ldap-authentication-provider user-search-filter="cn={0}" group-search-base="ou=Counter Strike,ou=java,dc=homebrew,dc=org" user-context-mapper-ref="myAuthorityMapper"/>

    </authentication-manager>

    <beans:bean class="org.huahsin.WebEngineering.MyAuthorityMapper" id="myAuthorityMapper"/>

    <ldap-server url="ldap://127.0.0.1:10389"/>

Thursday, December 25, 2014

Homebrew LDAP authentication with Spring Security

The Spring Security was so interesting that I can't wait to make my own experiment at home. To do this, I'm using Apache Directory Studio to achieve this mission. For starter, I create the following structure in my LDAP:

dc=org
    |---dc=homebrew
             |---ou=java
                      |---ou=Counter Strike
                               |---cn=huahsin

Take note that when creating a CN object, SN attribute has to be define as well. Otherwise an error will be prompt. On Spring configuration site, I'm required to configure <ldap-server> element to establish connection against which authentication should take place. Following piece is more than enough for this purpose:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.1.xsd">

   ...

   <ldap-server url="ldap://127.0.0.1:10389"/>

</beans:beans>
Also take note that there is additional attributes called manager-dn and manager-password in <ldap-server>, interestingly without these attributes put in <ldap-server> element, it wouldn't fail the authentication. The process were still go on. I think there must be a purpose for these attributes, just put this aside for later. The usage of that 2 attributes are shown below:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.1.xsd">

   ...

   <ldap-server manager-dn="cn=huahsin,ou=Counter Strike,ou=java,dc=homebrew,dc=org" manager-password="abcde" url="ldap://127.0.0.1:10389"/>

</beans:beans>
Once LDAP connection has been established, authentication will start taking place immediately. Now I'll required <ldap-authentication-provider> for this purpose:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.1.xsd">

   ...

   <authentication-manager alias="authenticationManager">
      <ldap-authentication-provider user-search-filter="cn={0}"/>
   </authentication-manager>
</beans:beans>
{0} is a placeholder for CN, it will be replace by real value during runtime. For my case, it would be huahsin. Note the usage of user-search-filter, never put cn={0},ou=Counter Strike,ou=java,dc=homebrew,dc=org for this attribute, the authentication will not get pass. That should be put in user-search-group, as shown below.
   ...
   <authentication-manager alias="authenticationManager">
      < ldap-authentication-provider group-search-base="ou=Counter Strike,ou=java,dc=homebrew,dc=org" user-search-filter="cn={0}"/>
   </authentication-manager>

   ...
Another note on the usage of group-search-base attribute is when I have the LDAP define in such a way:
< beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.1.xsd" >

   ...

   <ldap-server url="ldap://127.0.0.1:10389/dc=homebrew,dc=org"/>

</beans:beans>
I should have the ou=Counter Strike,ou=java define in group-search-base as shown below:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.1.xsd">

   ...

   <authentication-manager alias="authenticationManager">
      <ldap-authentication-provider group-search-base="ou=Counter Strike,ou=java" user-search-filter="cn={0}" />
   </authentication-manager>
</beans:beans>
Otherwise following error would be seen.
 Exception thrown by application class 'org.springframework.ldap.support.LdapUtils.convertLdapException:174'

org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - NO_SUCH_OBJECT: failed for MessageType : SEARCH_REQUEST Message ID : 3 SearchRequest baseDn : 'ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org' filter : '(uniqueMember=2.5.4.3=kok hoe+2.5.4.4=loh,2.5.4.11=Counter Strike,2.5.4.11=java,0.9.2342.19200300.100.1.25=homebrew,0.9.2342.19200300.100.1.25=org)' scope : whole subtree typesOnly : false Size Limit : no limit Time Limit : no limit Deref Aliases : deref Always attributes : 'cn', 'objectClass', 'javaSerializedData', 'javaClassName', 'javaFactory', 'javaCodeBase', 'javaReferenceAddress', 'javaClassNames', 'javaRemoteLocation' org.apache.directory.api.ldap.model.message.SearchRequestImpl@303434e3 ManageDsaITImpl Control Type OID : '2.16.840.1.113730.3.4.2' Criticality : 'false' ' : ERR_648 Invalid search base ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - NO_SUCH_OBJECT: failed for MessageType : SEARCH_REQUEST Message ID : 3 SearchRequest baseDn : 'ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org' filter : '(uniqueMember=2.5.4.3=kok hoe+2.5.4.4=loh,2.5.4.11=Counter Strike,2.5.4.11=java,0.9.2342.19200300.100.1.25=homebrew,0.9.2342.19200300.100.1.25=org)' scope : whole subtree typesOnly : false Size Limit : no limit Time Limit : no limit Deref Aliases : deref Always attributes : 'cn', 'objectClass', 'javaSerializedData', 'javaClassName', 'javaFactory', 'javaCodeBase', 'javaReferenceAddress', 'javaClassNames', 'javaRemoteLocation' org.apache.directory.api.ldap.model.message.SearchRequestImpl@303434e3 ManageDsaITImpl Control Type OID : '2.16.840.1.113730.3.4.2' Criticality : 'false' ' : ERR_648 Invalid search base ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org]; remaining name 'ou=Counter Strike,ou=java,dc=homebrew,dc=org'
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:174)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:306)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:259)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:606)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:524)
at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleAttributeValues(SpringSecurityLdapTemplate.java:173)
at org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator.getGroupMembershipRoles(DefaultLdapAuthoritiesPopulator.java:215)
at org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator.getGrantedAuthorities(DefaultLdapAuthoritiesPopulator.java:185)
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.loadUserAuthorities(LdapAuthenticationProvider.java:197)
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:63)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:195)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:125)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:144)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:194)
at [internal classes]
Caused by: javax.naming.NameNotFoundException: [LDAP: error code 32 - NO_SUCH_OBJECT: failed for MessageType : SEARCH_REQUEST Message ID : 3 SearchRequest baseDn : 'ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org' filter : '(uniqueMember=2.5.4.3=kok hoe+2.5.4.4=loh,2.5.4.11=Counter Strike,2.5.4.11=java,0.9.2342.19200300.100.1.25=homebrew,0.9.2342.19200300.100.1.25=org)' scope : whole subtree typesOnly : false Size Limit : no limit Time Limit : no limit Deref Aliases : deref Always attributes : 'cn', 'objectClass', 'javaSerializedData', 'javaClassName', 'javaFactory', 'javaCodeBase', 'javaReferenceAddress', 'javaClassNames', 'javaRemoteLocation' org.apache.directory.api.ldap.model.message.SearchRequestImpl@303434e3 ManageDsaITImpl Control Type OID : '2.16.840.1.113730.3.4.2' Criticality : 'false' ' : ERR_648 Invalid search base ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3112)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3033)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2840)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1849)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1772)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:386)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:356)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:339)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:267)
at org.springframework.ldap.core.LdapTemplate$4.executeSearch(LdapTemplate.java:253)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:293)
... 27 more
This stack trace gave me a very good hints on what is going on behind the scene. The error has already mention Invalid search base ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org. My common logic sense told me that the value define in user-search-group has been concatenate with the one define in url. To fix this, dc=homebrew,dc=org should be remove either from <ldap-server> or <ldap-authentication-provider>.

Another complex scenario, what if there is another DC object being define in LDAP? For this experiment, I create another DC object named cybertron as shown below:

Root DSE
   |---dc=org
       |---dc=cybertron
   |---dc=org
       |---dc=homebrew
           |---ou=java
               |---ou=Counter Strike
                   |---cn=huahsin

And then I have the LDAP define in this way:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.1.xsd">

   ...

   <ldap-server url="ldap://127.0.0.1:10389/dc=cybertron,dc=org"/>

< /beans:beans >
And I'm using this piece for authentication:
   ...
   <authentication-manager alias="authenticationManager">
      <ldap-authentication-provider group-search-base="ou=Counter Strike,ou=java,dc=homebrew,dc=org" user-search-filter="cn={0}"/>
   </authentication-manager>

   ...
Don't be foo that the above code would get pass, it wouldn't because the searching criteria would become like this ou=Counter Strike,ou=java,dc=homebrew,dc=org,dc=homebrew,dc=org,dc=cybertron,dc=org. That is the reason why it fail.

Monday, December 22, 2014

Authenticate through Active Directory in Spring

There is an web application that use a very basic authentication, or I should said it was pre-code in Spring configuration just as show below:

   


 
    
       
          
            
          
      
    

Assuming the front end code is using JSF:
 
When user is trigger the login, following code will get executed.
 public String doLogin() throws IOException, ServletException {
  
  ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
  RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher("/j_spring_security_check");
  dispatcher.forward((ServletRequest) context.getRequest(), (ServletResponse) context.getResponse());
  FacesContext.getCurrentInstance().responseComplete();
  
  return null;
 }
The code above is a great help, it will do the authentication as what have been define in Spring configuration, and also validate on which URL does allow to access. Thanks Spring save a great effort for me as I don't need to write crazy logic on authentication. Now I want to convert this mechanism to a more elegant way, which is to integrate this application with Active Directory. This sound easy to me as there are plenty of tutorials on Internet talking about Spring security with LDAP. Wait!! It is LDAP, not Active Directory and it was clueless to me. It took me sometime reading the Spring security documentation for few times only I got to realize this -  ActiveDirectoryLdapAuthenticationProvider.
   
      
      
   
Somehow the code above is not yet perfect as it'll search through all the entry which might be a trouble to me if the entries are huge. I haven't got a clue on how could I filter base on certain group. But for now, let's get things work. Since I'm dedicating my work to let Spring handle it for me, it would be easier when comes to exception handling. The code are shown below:
   
      
         
            /faces/badCredential.xhtml
            /faces/credentialsExpired
            /faces/accountLocked
            /faces/accountDisabled
            /faces/unauthorized
         
      
   
Note that I have declare this bean as authenticationFailureHandler. In order to get that piece to work, I need to tied up this bean in authentication-failure-handler-ref as shown below:

 
 

Great! My code able to handle failure result. Let's move on. Upon successfully authenticate, authorization need to be grant. The challenge part is I'm not using the group provided in LDAP to categories access role, instead I'm making a custom one. In other words, I have my data store in database that govern the rules who have access and who don't. The best place to put this code is via authentication-success-handler-ref of form-login, and then tied this up with a Spring bean as shown below:
   
      
      
   

   
   
AuthenticateSuccessHandler is a custom made class that extends from SavedRequestAwareAuthenticationSuccessHandler. It provide me the facility to set the default page to go after a successful login. For my case, I have the user status stored in database. authorizationBo is the guy who responsible to retrieve the user status. If the status return true, I'll grant this user a ROLE_USER, otherwise no role will be granted. And I'm using the Authentication object in onAuthenticationSuccess() to determine which landing page should a user go after the authentication process. The code below reveal the logic behind the scene:
public class AuthenticateSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

 @Override
 public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws ServletException, IOException {
  
  if( authentication.getPrincipal() instanceof LdapUserDetailsImpl ) {
   
   boolean status = authorizationBo.checkAuthorization(authentication.getName());
   
   if( status ) {
    List<grantedauthority> grantedAuth = new ArrayList<>();
    grantedAuth.add(new SimpleGrantedAuthority("ROLE_USER"));
    UserDetails userDetails = new User(authentication.getName(), "", grantedAuth);
    
    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, "", grantedAuth));
   }
  }
  
  if( authentication.getName().equals("admin") )
   setDefaultTargetUrl("/faces/administrative.xhtml");
  else
   setDefaultTargetUrl("/faces/dashboard.xhtml");
  
  super.onAuthenticationSuccess(request, response, authentication);
 }
}
Finally I have cover both the success and failure parts. My initial though is to do some crazy logic in doLogin() such as authenticating a user and then granting a user role, but I don't at the end. Spring is a great assistant in this area, just let Spring handle it all.