View on GitHub

Single Sign-On for the Web

Service Management

The CAS service management facility allows CAS server administrators to declare and configure which services (CAS clients) may make use of CAS in which ways. The core component of the service management facility is the service registry, provided by the ServiceRegistryDao component, that stores one or more registered services containing metadata that drives a number of CAS behaviors:

The service management console is a Web application that may be deployed along side CAS that provides a GUI to manage service registry data.

Demo

The Service Management web application is available for demo at https://jasigcasmgmt.herokuapp.com

Considerations

It is not required to use the service management facility explicitly. CAS ships with a default configuration that is suitable for deployments that do not need or want to leverage the capabilities above. The default configuration allows any service contacting CAS over https/imaps to use CAS and receive any attribute configured by an IPersonAttributeDao bean.

A premier consideration around service management is whether to leverage the user interface. If the service management console is used, then a ServiceRegistryDao that provides durable storage (e.g. JpaServiceRegistryDaoImpl) must be used to preserve state across restarts.

It is perfectly acceptable to avoid the service management console Web application for managing registered service data. In fact, configuration-driven methods (e.g. XML, JSON) may be preferable in environments where strict configuration management controls are required.

Registered Services

Registered services present the following metadata:

Persisting Registered Service Data

InMemoryServiceRegistryDaoImpl

CAS uses in-memory services management by default, with the registry seeded from registration beans wired via Spring.

<bean id="serviceRegistryDao"
      class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"
      p:registeredServices-ref="registeredServicesList" />

<util:list id="registeredServicesList">
    <bean class="org.jasig.cas.services.RegexRegisteredService"
          p:id="1"
          p:name="HTTPS and IMAPS services on example.com"
          p:serviceId="^(https|imaps)://([A-Za-z0-9_-]+\.)*example\.com/.*"
          p:evaluationOrder="0" />
</util:list>

This component is NOT suitable for use with the service management console since it does not persist data. On the other hand, it is perfectly acceptable for deployments where the XML configuration is authoritative for service registry data and the UI will not be used.

LdapServiceRegistryDao

Service registry implementation which stores the services in a LDAP Directory. Uses an instance of LdapRegisteredServiceMapper, that by default is DefaultLdapServiceMapper in order to configure settings for retrieval, search and persistence of service definitions. By default, entries are assigned the objectclass casRegisteredService attribute and are looked up by the ui attribute.

<bean id="serviceRegistryDao"
      class="org.jasig.cas.adaptors.ldap.services.LdapServiceRegistryDao"
      p:connectionFactory-ref="pooledLdapConnectionFactory"
      p:searchRequest-ref="searchRequest"
      p:ldapServiceMapper-ref="ldapMapper" />

<bean id="ldapMapper"
      class="org.jasig.cas.adaptors.ldap.services.DefaultLdapServiceMapper"/>

DefaultLdapServiceMapper

The default mapper has support for the following items:

JpaServiceRegistryDaoImpl

Stores registered service data in a database; the preferred choice when using the service management console. The following configuration template may be applied to deployerConfigContext.xml to provide for persistent registered service storage. The configuration assumes a dataSource bean is defined in the context.

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

<bean id="factoryBean"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="dataSource"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:packagesToScan-ref="packagesToScan">
    <property name="jpaProperties">
      <props>
        <prop key="hibernate.dialect">${database.dialect}</prop>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
        <prop key="hibernate.jdbc.batch_size">${database.batchSize}</prop>
      </props>
    </property>
</bean>

<bean id="jpaVendorAdapter"
      class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
      p:generateDdl="true"
      p:showSql="true" />

<bean id="serviceRegistryDao"
      class="org.jasig.cas.services.JpaServiceRegistryDaoImpl" />

<bean id="transactionManager"
      class="org.springframework.orm.jpa.JpaTransactionManager"
      p:entityManagerFactory-ref="factoryBean" />

<!--
   | Injects EntityManager/Factory instances into beans with
   | @PersistenceUnit and @PersistenceContext
-->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<!--
   Configuration via JNDI
-->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
    p:jndiName="java:comp/env/jdbc/cas-source" />   

If you prefer a direct connection to the database, here’s a sample configuration of the dataSource:

 <bean
        id="dataSource"
        class="com.mchange.v2.c3p0.ComboPooledDataSource"
        p:driverClassName="org.hsqldb.jdbcDriver"
        p:jdbcUrl-ref="database"
        p:password=""
        p:username="sa" />

The data source will need to be modified for your particular database (i.e. Oracle, MySQL, etc.), but the name dataSource should be preserved. Here is a MYSQL sample:

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

You will also need to change the property hibernate.dialect in adequacy with your database in cas.properties and deployerConfigContext.xml.

For example, for MYSQL the setting would be:

In cas.properties:

database.hibernate.dialect=org.hibernate.dialect.MySQLDialect

In deployerConfigContext.xml:

<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>

You will also need to ensure that the xml configuration file contains the tx namespace:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

Finally, when adding a new source new dependencies may be required on Hibernate, commons-dbcp. Be sure to add those to your pom.xml. Below is a sample configuration for MYSQL. Be sure to adjust the version elements for the appropriate version number.

<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>${commons.dbcp.version}</version>
    <scope>runtime</scope>
</dependency>
 
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>${hibernate.version}</version>
    <scope>compile</scope>
</dependency>
 
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.entitymgmr.version}</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>${mysql.connector.version}</version>
</dependency>

Installing the Services Management Webapp

The services management webapp is no more part of the CAS server and is a standalone web application: cas-management-webapp.

Nonetheless, one must keep in mind that both applications (the CAS server and the services management webapp) share the same configuration for the CAS services:

You can install the services management webapp in your favourite applications server, there is no restriction. Though, you need at first to configure it according to your environment. Towards that goal, the best way to proceed is to create your own services management webapp using a Maven overlay based on the CAS services management webapp:

<dependency>
  <groupId>org.jasig.cas</groupId>
  <artifactId>cas-management-webapp</artifactId>
  <version>${cas.version}</version>
  <type>war</type>
  <scope>runtime</scope>
</dependency>

Authentication method

By default, the cas-management-webapp is configured to authenticate against a CAS server. We assume that it’s the case in this documentation. However, you could change the authentication method by overriding the WEB-INF/spring-configuration/securityContext.xml file.

Securing Access and Authorization

Access to the management webapp is controlled via Spring Security. Rules are defined in the /cas-management-webapp/src/main/webapp/WEB-INF/managementConfigContext.xml file.

Static List of Users

By default, access is limited to a static list of users whose credentials may be specified in a user-details.properties file that should be available on the runtime classpath.

<sec:user-service id="userDetailsService" 
   properties="${user.details.file.location:classpath:user-details.properties}" />

You can change the location of this file, by uncommenting the following key in your cas-management.properties file:

##
# User details file location that contains list of users
# who are allowed access to the management webapp:
# 
# user.details.file.location = classpath:user-details.properties

The format of the file should be as such:

# The syntax of each entry should be in the form of:
# 
# username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]

# Example:
# casuser=notused,ROLE_ADMIN

LDAP-managed List of Users

If you wish allow access to the services management application via an LDAP group/server, open up the deployerConfigContext file of the management web application and adjust for the following:

<sec:ldap-server id="ldapServer" url="ldap://myserver:13060/"
                 manager-dn="cn=adminusername,cn=Users,dc=london-scottish,dc=com"
                 manager-password="mypassword" />
<sec:ldap-user-service id="userDetailsService" server-ref="ldapServer"
            group-search-base="cn=Groups,dc=mycompany,dc=com" group-role-attribute="cn"
            group-search-filter="(uniquemember={0})"
            user-search-base="cn=Users,dc=mycompany,dc=com"
            user-search-filter="(uid={0})"/>

You will also need to ensure that the spring-security-ldap dependency is available to your build at runtime:

<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-ldap</artifactId>
   <version>${spring.security.ldap.version}</version>
   <exclusions>
     <exclusion>
             <groupId>org.springframework</groupId>
             <artifactId>spring-aop</artifactId>
     </exclusion>
     <exclusion>
             <groupId>org.springframework</groupId>
             <artifactId>spring-tx</artifactId>
     </exclusion>
     <exclusion>
             <groupId>org.springframework</groupId>
             <artifactId>spring-beans</artifactId>
     </exclusion>
     <exclusion>
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
     </exclusion>
     <exclusion>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
     </exclusion>
   </exclusions>
</dependency>

Urls configuration

The urls configuration of the CAS server and management applications can be done by overriding the default WEB-INF/cas-management.properties file:

# CAS
cas.host=http://localhost:8080
cas.prefix=${cas.host}/cas
cas.securityContext.casProcessingFilterEntryPoint.loginUrl=${cas.prefix}/login
cas.securityContext.ticketValidator.casServerUrlPrefix=${cas.prefix}
# Management
cas-management.host=${cas.host}
cas-management.prefix=${cas-management.host}/cas-management
cas-management.securityContext.serviceProperties.service=${cas-management.prefix}/j_spring_cas_security_check
cas-management.securityContext.serviceProperties.adminRoles=ROLE_ADMIN

When authenticating against a CAS server, the services management webapp will be processed as a regular CAS service and thus, needs to be defined in the services registry (of the CAS server).

Services registry

You also need to define the common services registry by overriding the WEB-INF/managementConfigContext.xml file and set the appropriate serviceRegistryDao (see above: Persisting Registered Service Data). It should be the same configuration you already use in your CAS server (in the WEB-INF/deployerConfigContext.xml file).

UI

The services management webapp is pretty simple to use: