Configuration for the CAS/OAuth/OpenID client support in CAS server version >= 4.0.0

Configuration for the CAS/OAuth/OpenID client support in CAS server version >= 4.0.0

I. How to use CAS/OAuth/OpenID client support in CAS applications ?

1) Information returned by authentication

Once you have configured (see information below) your CAS server to support OAuth, CAS or OpenID client, users will be able from the CAS login page to authenticate at OAuth/CAS/OpenID provider(s) like Facebook instead of authenticating directly in CAS server (login page).

In CAS server, after this kind of delegated authentication, users have a specific Authentication information.

The Authentication object has :

  • the attribute AuthenticationManager.AUTHENTICATION_METHOD_ATTRIBUTE (authenticationMethod) set to org.jasig.cas.support.pac4j.authentication.handler.support.ClientAuthenticationHandler

  • the attribute clientName set to the type of the provider used during authentication process.

The Principal object of the Authentication object has :

  • an id which is the profile type + # + the identifier of the user for this provider (example : FacebookProfile#0000000001).

  • attributes populated by the data retrieved from the provider (first name, last name, birthdate...)

2) How to send profile attributes to CAS client applications

In CAS applications, through service ticket validation, some of these information will be pushed to the CAS client and therefore to the application itself.

The identifier of the user is always pushed to the CAS client. For user attributes, it involves both the configuration at the server and the way of validating service tickets.

On CAS server side, to push attributes to the CAS client, it should be configured in the deployerConfigContext.xml file for the wanted service:

 

<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"> <property name="registeredServices"> <list> <bean class="org.jasig.cas.services.RegisteredServiceImpl"> <property name="id" value="0" /> <property name="name" value="HTTP" /> <property name="description" value="Only Allows HTTP Urls" /> <property name="serviceId" value="http://**" /> <property name="evaluationOrder" value="10000001" /> <property name="allowedAttributes"> <list> <!-- facebook --> <value>name</value> <value>first_name</value> <value>middle_name</value> ...

On CAS client side, to receive attributes, you need to use SAML validation or a customized CAS validation.

 

3) How to recreate user profiles in CAS client applications

In CAS server, the complete user profile is known but when attributes are sent back to the CAS client applications, there is some kind of "CAS serialization" which makes data uneasy to be restored at their original state.

Though, you can now completely rebuild the original user profile from data returned in the CAS Assertion.

After validating the service ticket, an Assertion is available in CAS client from which you can get the identifier and the attributes of the authenticated user using the pac4j library :

 

AttributePrincipal principal = assertion.getPrincipal(); String id = principal.getName(); Map<String, Object> attributes = principal.getAttributes();

As the identifier stores the kind of profile in its definition (clientName#idAtProvider), you can use the org.pac4j.core.profile.ProfileHelper.buildProfile(id, attributes) method to recreate the original profile :

 

FacebookProfile rebuiltProfileOnCasClientSide = (FacebookProfile) ProfileHelper.buildProfile(id, attributes);

and use it !

 


II. How to add CAS/OAuth/OpenID client support in CAS server ?

1) Add the CAS dependency

First step is to add the dependency to the cas-server-support-pac4j module in the CAS server webapp pom.xml :

<dependency> <groupId>org.jasig.cas</groupId> <artifactId>cas-server-support-pac4j</artifactId> <version>${project.version}</version> </dependency>

2) Add the pac4j-* libraries

To add CAS client support, add the following dependency :

<dependency> <groupId>org.pac4j</groupId> <artifactId>pac4j-cas</artifactId> <version>1.4.0</version> </dependency>

To add OAuth client support, add the following dependency :

<dependency> <groupId>org.pac4j</groupId> <artifactId>pac4j-oauth</artifactId> <version>1.4.0</version> </dependency>

To add OpenID client support, add the following dependency :

<dependency> <groupId>org.pac4j</groupId> <artifactId>pac4j-openid</artifactId> <version>1.4.0</version> </dependency>

3) Add the clients needed

A provider is a server which can authenticate user (like Google, Yahoo...) instead of a CAS server. If you want to delegate the CAS authentication to Twitter for example, you have to add an OAuth provider for Twitter. Providers are defined in the pac4j library :

All the clients to authenticate against providers must be declared in applicationContext.xml :

<bean id="facebook1" class="org.pac4j.oauth.client.FacebookClient"> <property name="key" value="fbkey" /> <property name="secret" value="fbsecret" /> <property name="scope" value="email,user_likes,user_about_me,user_birthday,user_education_history,user_hometown,user_relationship_details,user_location,user_religion_politics,user_relationships,user_work_history,user_website,user_photos,user_events,user_groups,user_actions.music" /> <property name="fields" value="id,name,first_name,middle_name,last_name,gender,locale,languages,link,username,third_party_id,timezone,updated_time,verified,bio,birthday,education,email,hometown,interested_in,location,political,favorite_athletes,favorite_teams,quotes,relationship_status,religion,significant_other,website,work,friends,movies,music,books,likes,albums,events,groups,music.listens,picture" /> </bean> <bean id="twitter1" class="org.pac4j.oauth.client.TwitterClient"> <property name="key" value="twkey" /> <property name="secret" value="twsecret" /> </bean> <bean id="caswrapper1" class="org.pac4j.oauth.client.CasOAuthWrapperClient"> <property name="key" value="this_is_the_key" /> <property name="secret" value="this_is_the_secret" /> <property name="casOAuthUrl" value="http://mycasserver2/oauth2.0" /> </bean> <bean id="cas1" class="org.pac4j.cas.client.CasClient"> <property name="casLoginUrl" value="http://mycasserver2/login" /> </bean> <bean id="myopenid1" class="org.pac4j.openid.client.MyOpenIdClient" />

For each OAuth provider, the CAS server is considered an OAuth client and therefore should be declared to the OAuth provider. After declaration, a key and a secret is given by the OAuth provider which has to be defined in the beans (the_key_for_xxx and the_secret_for_xxx values for key and secret properties).

For the CAS OAuth wrapping, the casOAuthUrl property must be set to the OAuth wrapping url of the other CAS server which is using OAuth wrapping.

To ease configuration definition, all clients and the CAS server login url are gathered in the same Clients configuration bean :

<bean id="clients" class="org.pac4j.core.client.Clients"> <property name="callbackUrl" value="http://localhost:8080/cas/login" /> <property name="clients"> <list> <ref bean="facebook1" /> <ref bean="twitter1" /> <ref bean="caswrapper1" /> <ref bean="cas1" /> <ref bean="myopenid1" /> </list> </property> </bean>

4) Add the client action in webflow

In the login-webflow.xml file, the ClientAction must be added at the beginning of the webflow. Its role is to intercept callback calls from providers (like Facebook, Twitter...) after remote authentication :

<action-state id="clientAction"> <evaluate expression="clientAction" /> <transition on="success" to="sendTicketGrantingTicket" /> <transition on="error" to="ticketGrantingTicketCheck" /> <transition on="stop" to="stopWebflow" /> </action-state> <view-state id="stopWebflow" />

This ClientAction has to be defined in cas-servlet.xml with all the clients needed :

<bean id="clientAction" class="org.jasig.cas.support.pac4j.web.flow.ClientAction"> <constructor-arg index="0" ref="centralAuthenticationService"/> <constructor-arg index="1" ref="clients"/> </bean>

This ClientAction uses the centralAuthenticationService bean to play the CAS authentication and references the configuration.

5) Add the handler and the metadata populator (optional) for authentication

To be able to authenticate user in the CAS server after remote authentication by the provider, you have to add the ClientAuthenticationHandler class and might add the ClientAuthenticationMetaDataPopulator class in the deployerConfigContext.xml file :

<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager"> <constructor-arg> <map> </map> </constructor-arg> <property name="authenticationMetaDataPopulators"> <util:list> <bean class="org.jasig.cas.support.pac4j.authentication.ClientAuthenticationMetaDataPopulator" /> </util:list> </property> <property name="authenticationPolicy"> <bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" /> </property> </bean> <bean id="primaryAuthenticationHandler" class="org.jasig.cas.support.pac4j.authentication.handler.support.ClientAuthenticationHandler"> <constructor-arg index="0" ref="clients"/> </bean>

 

7) Add links on the login page to authenticate on remote providers

To start authentication on a remote provider, links must be added on the login page casLoginView.jsp (ClientNameUrl attributes are automatically created by the ClientAction) :

<a href="${FacebookClientUrl}">Authenticate with Facebook</a> <br /> <br /> <a href="${TwitterClientUrl}">Authenticate with Twitter</a><br /> <br /> <a href="${CasOAuthWrapperClientUrl}">Authenticate with another CAS server using OAuth v2.0 protocol</a><br /> <br /> <a href="${CasClientUrl}">Authenticate with another CAS server using CAS protocol</a><br /> <br /> <form action="${MyOpenIdClientUrl}" method="POST"> <input type="text" name="openIdUser" value="http://xxx.myopenid.com/" /> <input type="submit" value="Authenticate with myopenid.com" /> </form>

 


III. Technical presentation

1) Dependencies

a) org.scribe / pac4j / 1.4.0

b) org.jasig.cas / cas-server-core / ${project.version}

2) Classes

a) ClientAuthenticationMetaDataPopulator (org.jasig.cas.support.pac4j.authentication)

This class is a meta data populator for authentication. The client name associated to the authentication is added to the authentication attributes.

b) ClientAuthenticationHandler (org.jasig.cas.support.pac4j.authentication.handler.support)

This handler authenticates the client credentials : it uses them to get the user profile returned by the provider for an authenticated user.

c) ClientCredential (org.jasig.cas.support.pac4j.authentication.principal)

This class represents client credentials and (after authentication) a user profile.

d) ClientAction (org.jasig.cas.support.pac4j.web.flow)

This class represents an action to put at the beginning of the webflow.
Before any authentication, redirection urls are computed for the different clients defined as well as the theme, locale, method and service are saved into the web session.
After authentication, appropriate information are expected on this callback url to finish the authentication process with the provider.