Credential to Principal Resolver and Attribute Repository

In this blog I will share my experience with Credential to Principal Resolver of CAS.

After the user has been successfully authenticated by the Custom Authentication Handler (as provided in the previous blog), then there comes the Credential to Principal Resolver of CAS.

Now before going into the architecture of Credential to Principal Resolver of CAS we have to get some idea regarding AuthenticationManager of CAS which corresponds to bean id "authenticationManager" and class "org.jasig.cas.authentication.AuthenticationManagerImpl" of the deployerConfigContext.xml of CAS war.

This authenticationManager at first lopps through all the registered list Authentication Handlers configured in the deployerConfigContext.xml holding the property name "authenticationHandlers" of the bean "authenticationManager" to get the user authetication and then it loops through all the registered list of Credential to Principal Resolver configured in the deployerConfigContext.xml holding the property name "credentialsToPrincipalResolvers" of the bean "authenticationManager" to resolve the credential obtained during authentication process to a well formed Principal  with attributes(if necessary) by calling the method resolvePrincipal() of Credential to Principal Resolver.

This resolvePrincipal() method first extract the principal id i.e. username here with the help of extractPrincipalId() method and on the basis of the fetched principal id it fetches person attributes from the attribute repository.The custom attributes to be fetched is entirely configurable with "attributeRepository" property of the Credential to Principal Resolver class.


So the Custom Credential to Principal Resolver reolver I have used here is:
package com.cas.customCredToPrinResolver;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.jasig.cas.authentication.principal.Credentials;
import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;
import org.jasig.cas.authentication.principal.Principal;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.jasig.services.persondir.IPersonAttributeDao;
import org.jasig.services.persondir.IPersonAttributes;
public class CustomCredentialToPrincipalResolver implements
  CredentialsToPrincipalResolver {
 private Logger logger = Logger.getLogger(this.getClass().getName());
 private IPersonAttributeDao attributeRepository;



 @Override
 public Principal resolvePrincipal( final Credentials credentials) {
  // TODO Auto-generated method stub
  logger.debug(" In resolvePrincipal() of CustomCredentialToPrincipalResolver class ");
   final String principalId = extractPrincipalId(credentials);
          
           if (principalId == null) {
               return null;
           }
          
           logger.debug(" *** The principalId:"+principalId);
          
           final IPersonAttributes personAttributes = this.attributeRepository.getPerson(principalId);
          
           final Map<String, List<Object>> attributes;
          
           if (personAttributes == null) {
               attributes = null;
           } else {
               attributes = personAttributes.getAttributes();
           }
          
           logger.debug(" *** The attributes found are:"+attributes);
          
           if (attributes == null ) {
               return new SimplePrincipal(principalId);
           }
         
          
           final Map<String, Object> convertedAttributes = new HashMap<String, Object>();
          
           for (final Map.Entry<String, List<Object>> entry : attributes.entrySet()) {
               final String key = entry.getKey();
               final Object value = entry.getValue().size() == 1 ? entry.getValue().get(0) : entry.getValue();
               convertedAttributes.put(key, value);
           }
          
          
           logger.debug(" *** The Finally Converted Attributes are:"+convertedAttributes);
           return new SimplePrincipal(principalId, convertedAttributes);
       }
 @Override
 public boolean supports(Credentials credentials) {
  // TODO Auto-generated method stub
  return UsernamePasswordCredentials.class.isAssignableFrom(credentials.getClass());
 }


 public void setAttributeRepository(IPersonAttributeDao attributeRepository) {
  this.attributeRepository = attributeRepository;
 }
 private  String extractPrincipalId(Credentials credentials)
 {
  UsernamePasswordCredentials usernamePasswordCredentials = (UsernamePasswordCredentials)credentials;
     return usernamePasswordCredentials.getUsername();
 }

}

and the related configurations in the deployerConfigContext.xml are:

Under "credentialsToPrincipalResolvers" list property of Authentication Manager configure the following bean,  comment the existing UsernamePasswordCredentialsToPrincipalResolver.

<bean class="com.cas.customCredToPrinResolver.CustomCredentialToPrincipalResolver">
     <property name="attributeRepository" ref="attributeRepository"/>
    </bean>
  
The configurations of attributeRepository are as follows.
<bean id="attributeRepository" class="com.cas.customAttrRepository.CustomAttributeReposiory">
  <property  name="queryAttributeMapping">
    <map>           
    <entry key="name" value="subha" />       
   </map>
  </property>

  <property  name="resultAttributeMapping">
   <map>           
    <entry key="NAME" value="NAME" />
    <entry key="ROLE" value="ROLE" />   
   </map>
  </property>

  <property  name="queryTemplate" value="select * from users where {0}" />
  <property  name="simpleJdbcTemplate" ref="jdbcTemplate" />
 </bean>

 There are lots of In built attribute repository available, but for my own understanding i have used here a Custom One.
I have modeled my Attribute Repository on org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao"

 The principal behind my custom attribute repository is:
 Based on the "queryTemplate" property and the "queryAttributeMapping" property I will fetch the required details and the map the required details to the entries mentioned in "resultAttributeMapping" property.
 The getPerson() method of Atrribute repository is get called from CustomCredentialToPrincipalResolver which returns a Data Structure of containing the required details and that is being used in CustomCredentialToPrincipalResolver to form a Principal Object.

 One Important point I want to mention here regarding the custom configured attributes to be returned from the server.
 1) Now the attributes (as mentioned in resultAttributeMapping) are required to be properly configured while forming the principal object in CustomCredentialToPrincipalResolver
 2) This custom attributes are returned bu the Ticket Validator (CAS20 or SAML) when the ticket returned by the CAS server to application is again submitted by the application to the CAS server for cross verification
 3) So, that the custom attributes as configured are properly returned to the application after the Ticket Validator performs a successful validation, the following configurations in CAS Server are required to be carried out.
   a) Got to the URL https://localhost:8443/cas/services/ submit the credentials and enter
   b) In the Service Management ---> Manage Srvices tab click the edit link of the existing service, if any more additional services are not configured.
   c) Now in the Attributes block, select all the attribites with Shift+click and check the Ignore Attribute Management via this Tool option.
 
 This will help you to Publish all the configure custom attributes.

 I am not providing here my CustomAttribute Repository code.
 If anyone needs, Please Add a Comment Stating the Same. I will Post it.

 If anybody faces any Problem regarding the any of the above mentioned configurations, Please feel free to share by adding your comments in the comment section of the blog.

In my Next Blog I will share my experience with Ticket Validator and Custom Configuration of Log4j2 configurations which was discussed earlier in my blog.

Comments

Popular posts from this blog

Use of @Configurable annotation.

Spring WS - Part 5

Spring WS - Part 4