Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Overview

This document describes work I did to evaluate CAS. This is intended to be a beginner's introduction. I'm not a member of the CAS team and I don't have a lot of experience with the system, so I imagine there are more efficient ways to go about this - feel free to correct errors or improve the results!

...

Create the ticket registry locks table with the following columns:

No Format
	
CREATE TABLE LOCKS (
  APPLICATION_ID VARCHAR(50) NOT NULL,
  UNIQUE_ID VARCHAR(50) NULL,
  EXPIRATION_DATE TIMESTAMP NULL
);
ALTER TABLE LOCKS ADD CONSTRAINT LOCKS_PK
PRIMARY KEY (APPLICATION_ID);

...

No Format
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
  <property name="anonymousReadOnly" value="false" />
  <property name="userDn" value="CN=lookupAcct,CN=Users,DC=merlin,DC=com" />
  <property name="password" value="secret" />
  <property name="pooled" value="true" />
  <property name="urls">
    <list>
      <value>ldap://ssoserver.merlin.com/</value>
    </list>
  </property>
  <property name="baseEnvironmentProperties">
    <map>
      <entry>
        <key><value>java.naming.security.authentication</value></key>
        <value>simple</value>
      </entry>
    </map>
  </property>
</bean>           

Identify the Attribute Repository

...

No Format
<bean id="attributeRepository"
  class="org.jasig.services.persondir.support.ldap.LdapPersonAttributeDao">
 

  <property name="contextSource" ref="contextSource" />
  <property name="baseDN" value="DC=merlin,DC=com" />
  <property name="requireAllQueryAttributes" value="true" />
  <property name="ldapTemplate" ref="ldapTemplate" />

  <!--
  Attribute mapping between principal (key) and LDAP (value) names
  used to perform the LDAP search.
  -->
  <property name="queryAttributeMapping">
    <map>
      <entry key="username" value="sAMAccountName" />
     </map>
  </property>

  <property name="resultAttributeMapping">
    <map>
      <!-- Mapping between LDAP attributes (key) and Principal's (value) -->
      <entry value="CN" key="cn" />
      <entry value="DN" key="distinguishedName" />
      <entry value="Groups" key="memberOf" />
    </map>
  </property>
</bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
  <constructor-arg ref="contextSource" />
  <property name="ignorePartialResultException" value="true" />
</bean>

...

The authenticationManager bean has a list of credentialsToPrincipalResolvers. This adds one that will do an LDAP lookup based on the sAMAccountName entered by the user, and will define the Principal available to the client application. This uses the context source and the attribute repository defined above.

No Format
<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>

  <!-- "%u" will be replaced by the resolved Principal -->
  <property name="filter" value="(sAMAccountName=%u)" />

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

  <property name="searchBase" value="DC=issinc,DC=com" />
  <property name="contextSource" ref="contextSource" />

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

...

No Format
<bean id="serviceRegistryDao"
   class="org.jasig.cas.services.JpaServiceRegistryDaoImpl"
   p:entityManagerFactory-ref="entityManagerFactory" />

<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

  <property name="dataSource" ref="dataSource"/>
  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
      <property name="generateDdl" value="true"/>
      <property name="showSql" value="true" />
    </bean>
  </property>
  <property name="jpaProperties">
  <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>
  </props>
  </property>
</bean>

<bean id="transactionManager"
   class="org.springframework.orm.jpa.JpaTransactionManager">

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

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="dataSource"
  class="org.apache.commons.dbcp.BasicDataSource"
  p:driverClassName="com.mysql.jdbc.Driver"
  p:url="jdbc:mysql://localhost:3306/cas_sso?autoReconnect=true"
  p:password="secret"
  p:username="root" />

...

No Format
<filter>
  <filter-name>CAS Single Sign Out Filter</filter-name>
  <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter>
  <filter-name>CAS Authentication Filter</filter-name>
  <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
  <init-param>
    <param-name>casServerLoginUrl</param-name>
    <param-value>https://[CAS Server FQDN]:8443/cas/login</param-value>
  </init-param>
  <init-param> 
    <param-name>serverName</param-name> 
    <param-value>https://[Client Server FQDN]:8443</param-value>
   </init-param> 
</filter>
<filter>
  <filter-name>CAS Validation Filter</filter-name>
  <filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>
  <init-param>
    <param-name>casServerUrlPrefix</param-name>
    <param-value>https://[CAS Server FQDN]:8443/cas</param-value>
  </init-param>
  <init-param> 
    <param-name>serverName</param-name>
     <param-value>https://[Client Server FQDN]:8443</param-value> 
  </init-param> 
  <init-param>
     <param-name>redirectAfterValidation</param-name>
     <param-value>true</param-value>
   </init-param>
   <init-param>
    <param-name>tolerance</param-name>
    <param-value>5000</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter> 
  <filter-name>CAS Assertion Thread Local Filter</filter-name> 
  <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>

</filter>

<filter-mapping>
  <filter-name>CAS Single Sign Out Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>CAS Authentication Filter</filter-name>
  <url-pattern>/sso/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>CAS Validation Filter</filter-name>
  <url-pattern>/sso/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <url-pattern>/sso/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>CAS Assertion Thread Local Filter</filter-name>
  <url-pattern>/sso/*</url-pattern>
</filter-mapping>

...the rest of the application...

...

Code Block
// get the user's credentials
Principal p = request.getUserPrincipal();
String userLoginName = request.getRemoteUser(); // or request.getUserPrincipal()p.getName()

// get the released attributes, e.g., LDAP group membership - earlier mapped to 'Groups'
AttributePrincipal principal = (AttributePrincipal)p;
Map attributes = principal.getAttributes();
Object value = attributes.get("Groups");
if (value instanceof String) {
   // memberOf contained one group name
} else if (value instanceof List) {
   // memberOf contained multiple group names
}

...