Attributes

New CAS documentation site

CAS documentation has moved over to apereo.github.io/cas, starting with CAS version 4.x. The wiki will no longer be maintained. For the most recent version of the documentation, please refer to the aforementioned link.

Topics

Attributes

Attributes are controlled by the JA-SIG Person Directory project and returned to scoped services via the SAML 1.1 protocol. The Person Directory dependency is automatically bundled with the CAS server. Therefor, declaring an additional dependency will not be required. This Person Directory project supports both LDAP and JDBC attribute release, caching, attribute aggregation from multiple attribute sources, etc.

An example configuration of Person Directory is provided here, which is used by the uPortal project and demonstrates a range of feature the library provides. You may be able to use this as a starting point when configuring your attribute policy with CAS.

Overview

A PersonDirectory IPersonAttributeDao attribute source is defined and configured to describe the global set of attributes to be fetched for each authenticated principal. That global set of attributes is then filtered by the service manager according to service-specific attribute release rules. More about the Person Directory and its configurable sources can be found here.

 

Attribute Filtering

You must explicitly configure attribute release for services in order for the resolved attributes to be released to a service in the SAML response. In the service manager web application, either select (shift-click/control-click) explicit attributes in the "Attributes" form field, or click the "Ignore Attribute Management via this Tool" checkbox, which causes all attributes to be released to a particular service.

The attached screenshot below demonstrates how the "ssbPNumber" is selected to be released for all services that match the pattern "https://**":

Static configuration of allowed attributes per sercice

To statically define the set of allowed attributes per service, you can modify the deployerConfigContext.xml file for a given service declaration as such:

Allowed Attributes for a Service
<bean class="org.jasig.cas.services.RegisteredServiceImpl">
  <property name="id" value="0" />
  <property name="name" value="HTTPS Services" />
  <property name="description" value="YOUR HTTP Service" />
  <property name="serviceId" value="https://**" />
  <property name="evaluationOrder" value="0" />
  <property name="allowedAttributes">
    <list>
      <value>yourAttributeName</value>
    </list>              
  </property>
</bean>

Specify the username attribute for a registered service (optional)

Starting in CAS 3.5.x, the service registry component of CAS has the ability to allow for configuration of a usernameAttribute to be returned for the given registered service. When this property is set for a service, CAS will return the value of the configured attribute as part of its validation process. 

The configuration of this behavior is as follows:

  1. Configure the attribute in the attributeRepository bean
  2. For a given service:
    1. Specify the attribute in its list of allowed attributes
    2. Set the usernameAttribute property of the given service to the attribute you defined above

 

usernameAttribute of a registered service
<bean class="org.jasig.cas.services.RegisteredServiceImpl">
  <property name="id" value="0" />
  <property name="name" value="HTTPS Services" />
  <property name="description" value="YOUR HTTP Service" />
  <property name="serviceId" value="https://**" />
  <property name="evaluationOrder" value="0" />
  <property name="usernameAttribute" value="someAttributeName" />
  <property name="allowedAttributes">
    <list>
      <value>someAttributeName</value>
    </list>              
  </property>
</bean>

 

Populate Principal's attributes with LDAP repository

CredentialsToLDAPAttributePrincipalResolver lets you create and populate the principal with attributes extracted by JA-SIG Person Directory. Person Directory can rely on different types of context source (Database, LDAP, etc). 

We'll describe the LDAP way: 

  1. CredentialsToLDAPAttributePrincipalResolver first calls a credentialsToPrincipalResolverto initiate the Principal from the credentials: 
    1. If username/password is used, UsernamePasswordCredentialsToPrincipalResolver is OK. 
    2. If client certificates are used, you should define a  x509CertifcateCredentialsToPrincipal

    Depending on the class you used, the temporary Principal will be initiated with a login or a certificate attribute as ID.

  2. This Principal ID is then used to search a repository (here an LDAP server) for a corresponding entry. Based on the filter property, a LDAP request is forged to find the entry corresponding to the prinicpal's ID (i.e. login or certificate attribute).
  3. The Principal ID is replaced with the principalAttributeName extracted from the LDAP entry: usually uid or cn LDAP attribute is used to create the new principal ID.
  4. We now have a Principal corresponding to an LDAP entry. We now can populate this Principal with attributes. These attributes can come from the same repository or a different one. This repository is defined as attributeRepository of  the CredentialsToLDAPAttributePrincipalResolver.

The mapping between LDAP attributes and their names in principal's attributes map are defined in ldapAttributesToPortalAttributes of attributeRepository.  You'll define here that the "name" attribute of the principal must be set by the "cn" attribute of the LDAP entry.

Example CAS 3.3.3 deployerConfigContext.xml for LDAP
<bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl">
  <property name="credentialsToPrincipalResolvers">
    <list>
    <bean class="org.jasig.cas.authentication.principal.CredentialsToLDAPAttributePrincipalResolver">
      <!-- The Principal resolver form the credentials -->
      <property name="credentialsToPrincipalResolver">
           <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" />
      </property>
      <!--
      The query made to find the Principal ID.
      "%u" will be replaced by the resolved Principal
      -->
      <property name="filter" value="(uid=%u)" />

      <!-- The attribute used to define the new Principal ID -->
      <property name="principalAttributeName" value="uid" />

      <property name="searchBase" value="ou=people,o=company,c=fr" />
      <property name="contextSource" ref="contextSource" />

      <property name="attributeRepository">
            <ref bean="attributeRepository" />
      </property>
    </bean>

    <!--
    .....
     the rest of the credentials to principal resolvers
    .....
    +-->
    </list>
  </property>
</bean>

<!--
Define the contextSource and the attributeRepository.
NOTE:
org.jasig.cas.adaptors.ldap.util.AuthenticatedLdapContextSource is deprecated as of CAS 3.3.3.
Use org.springframework.ldap.core.support.LdapContextSource instead.
-->
<bean id="contextSource"
  class="org.springframework.ldap.core.support.LdapContextSource">
  <property name="urls">
    <list>
    <value>ldaps://ldap1/</value>
    <value>ldaps://ldap2/</value>
    </list>
  </property>
  <property name="userName" value="cn=manager,c=fr" />
  <property name="password" value="xxxxxxxxxxxxx" />
</bean>

<bean id="attributeRepository"  class="org.jasig.services.persondir.support.ldap.LdapPersonAttributeDao">
  <property name="baseDN" value="ou=people,o=company,c=fr" />
   <!-- 
   This query is used to find the entry for populating attributes. 
   {0} will be replaced by the new Principal ID extracted from the ldap 
   -->
  <property name="query" value="(uid={0})" />

  <property name="contextSource" ref="contextSource" />
  <property name="ldapAttributesToPortalAttributes">
    <map>
      <!-- Mapping beetween LDAP entry's attributes (key) and Principal"s (value) -->
      <entry key="cn" value="Name"/>
      <entry value="Telephone" key="telephoneNumber" />
      <entry value="Fax" key="facsimileTelephoneNumber" />
    </map>
  </property>
</bean>

Changes for CAS 3.3.4 and Later

CAS 3.3.4 and later uses Person Directory 1.5.0, which has changed substantially from previous versions. This affects the LdapPersonAttributeDao bean definition. The above example is repeated below for a CAS 3.3.4 configuration and later.

CAS 3.3.4 & later LdapPersonAttributeDao Example
<!-- Modify the UsernamePasswordCredentialsToPrincipalResolver bean to reference the attributeRepository -->
<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver">
    <property name="attributeRepository" ref="attributeRepository" />
</bean>
 
<bean id="attributeRepository" class="org.jasig.services.persondir.support.ldap.LdapPersonAttributeDao">
  <property name="contextSource" ref="contextSource" />
  <property name="baseDN" value="ou=people,o=company,c=fr" />
  <property name="requireAllQueryAttributes" value="true" />

  <!--
  Attribute mapping between principal (key) and LDAP (value) names
  used to perform the LDAP search.  By default, multiple search criteria
  are ANDed together.  Set the queryType property to change to OR.
  -->
  <property name="queryAttributeMapping">
    <map>
      <entry key="username" value="uid" />
    </map>
  </property>

  <property name="resultAttributeMapping">
    <map>
      <!-- Mapping beetween LDAP entry attributes (key) and Principal's (value) -->
      <entry value="Name" key="cn" />
      <entry value="Telephone" key="telephoneNumber" />
      <entry value="Fax" key="facsimileTelephoneNumber" />
    </map>
  </property>
</bean>

Accessing attributes using the CAS client for java

Using the org.jasig.cas.client.validation.Saml11TicketValidator class for ticket validation will populate attributes that can be retrieved from the HttpServletRequest.

See this Java CAS Client page for some basic example code.

Accessing attributes using phpCAS

phpCAS attempts to extract attributes from the CAS server's XML response for authentication success. However, even if you have configured the metadata populators, by default, Jasig CAS does not include attributes as a part of its response. For phpCAS to access them we must configure the XML response to include these attributes. To do this, open casServiceValidationSuccess.jsp (located at WEB-INF/view/jsp/protocol/2.0) and insert the following after you see the line <cas:user> ... </cas:user>

<cas:attributes>
<c:forEach var="auth" items="${assertion.chainedAuthentications}">
	<c:forEach var="attr" items="${auth.principal.attributes}" >
        <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>
	</c:forEach>
</c:forEach>
</cas:attributes>

phpCAS should automatically pick up these attributes via the internal method readExtraAttributesCas20(). Individual attributes can be accessed by calling phpCAS::getAttribute('key').

 

Configuring multi-valued key support for attributes

Say you have an ldap user attribute called myPersonId and you need to expose it to apps via different names.  For example, app1's service configuration will specify that it should receive this attribute as "myPersonId" and app2 should receive it as "personUid".  Here are the things you'd do in deployerConfigContext.xml:

  1. In the namespace mapping section at the top of the file, add a reference to:

     xmlns:util="http://www.springframework.org/schema/util"
  2. Nearby in the xsi:schemalocation section, add the following two references:

    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
  3. Anywhere further down in the file, add the following:

    <!-- multi-valued key support for the myPersonId attribute -->
        <util:set id="myPersonIdSet">
            <value>myPersonId</value>
            <value>personUid</value>
        </util:set>
  4. In your attributeRepository bean, in the resultAttributeMapping map section add an entry that references the new set:

    <entry key="myPersonId" value-ref="myPersonIdSet"/> 
  5. Configure the allowedAttributes list for each app normally:

    app1 would get:

    <value>myPersonId</value>

    app2 would get:

    <value>personUid</value>

    This method was developed and tested with CAS 3.4.12 with Person Directory API 1.5

     

Specify an attribute filter for a registered service (optional)

As of CAS 4, the service registry component of CAS has the ability to allow for configuration of an attribute filter. Filters have the ability to do execute additional processes on the set of attributes that are allocated to the final principal for a given user id. For instance, you might want to decide that certain attribute need to be removed from the final resultset based on a user role, etc. 

Currently, there's support for a RegisteredServiceRegexAttributeFilter that is regex filter responsible to make sure only attributes that match a certain regex pattern are released for a given service. If you of course wish to write your own filter, you need to design a Java class that implements the RegisteredServiceAttributeFilter interface and as such, plug that custom instance into the specific service registry entry you intend to use. 

A sample configuration of RegisteredServiceRegexAttributeFilter follows below. You may use the below template to configure your custom attribute filters as well. This example also demonstrates the configuration of an attribute filter that only allows for attributes whose length is 3.

 

attribute filter for a registered service
<bean class="org.jasig.cas.services.RegexRegisteredService">
   <property name="id" value="1" />
   <property name="name" value="HTTP and IMAP on example.com" />
   <property name="description" value="Allows HTTP(S) and IMAP(S) protocols on example.com" />
   <property name="serviceId" value="^(https?|imaps?)://([A-Za-z0-9_-]+\.)*example\.com/.*" />
   <property name="evaluationOrder" value="0" />
   <property name="attributeFilter">
      <bean class="org.jasig.cas.services.support.RegisteredServiceRegexAttributeFilter" c:regex="^\w{3}$" /> 
   </property>
</bean>