<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <title>CAS Authentication</title>
  <section xml:id="cas-overview">
    <title>Overview</title>
    <para>JA-SIG produces an enterprise-wide single sign on system known as CAS. Unlike other
      initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to
      understand, platform independent, and supports proxy capabilities. Spring Security fully
      supports CAS, and provides an easy migration path from single-application deployments of
      Spring Security through to multiple-application deployments secured by an enterprise-wide CAS
      server.</para>
    <para>You can learn more about CAS at <literal>http://www.ja-sig.org/cas</literal>. You will
      also need to visit this site to download the CAS Server files.</para>
  </section>
  <section xml:id="cas-how-it-works">
    <info>
      <title>How CAS Works</title>
    </info>
    <para>Whilst the CAS web site contains documents that detail the architecture of CAS, we present
      the general overview again here within the context of Spring Security. Spring Security 3.0
      supports CAS 3. At the time of writing, the CAS server was at version 3.3.</para>
    <para>Somewhere in your enterprise you will need to setup a CAS server. The CAS server is simply
      a standard WAR file, so there isn't anything difficult about setting up your server. Inside
      the WAR file you will customise the login and other single sign on pages displayed to
      users.</para>
    <para>When deploying a CAS 3.3 server, you will also need to specify an
        <literal>AuthenticationHandler</literal> in the
        <filename>deployerConfigContext.xml</filename> included with CAS. The
        <literal>AuthenticationHandler</literal> has a simple method that returns a boolean as to
      whether a given set of Credentials is valid. Your <literal>AuthenticationHandler</literal>
      implementation will need to link into some type of backend authentication repository, such as
      an LDAP server or database. CAS itself includes numerous
        <literal>AuthenticationHandler</literal>s out of the box to assist with this. When you
      download and deploy the server war file, it is set up to successfully authenticate users who
      enter a password matching their username, which is useful for testing.</para>
    <para>Apart from the CAS server itself, the other key players are of course the secure web
      applications deployed throughout your enterprise. These web applications are known as
      "services". There are two types of services: standard services and proxy services. A proxy
      service is able to request resources from other services on behalf of the user. This will be
      explained more fully later.</para>
    <!--
  <section xml:id="cas-sequence">
    <title>Spring Security and CAS Interaction Sequence</title>

  TODO: Needs reviewed
    <para>The basic interaction between a web browser, CAS server and a
    Spring Security-secured service is as follows:</para>

    <orderedlist inheritnum="ignore" continuation="restarts">
      <listitem>
        <para>The web user is browsing the service's public pages. CAS or
        Spring Security is not involved.</para>
      </listitem>

      <listitem>
        <para>The user eventually requests a page that is either secure or
        one of the beans it uses is secure. Spring Security's
        <classname>ExceptionTranslationFilter</classname> will detect the
        <literal>AuthenticationException</literal>.</para>
      </listitem>

      <listitem>
        <para>Because the user's <interfacename>Authentication</interfacename> object
        (or lack thereof) caused an
        <literal>AuthenticationException</literal>, the
        <classname>ExceptionTranslationFilter</classname> will call the
        configured <interfacename>AuthenticationEntryPoint</interfacename>. If using
        CAS, this will be the
        <literal>CasProcessingFilterEntryPoint</literal> class.</para>
      </listitem>

      <listitem>
        <para>The <literal>CasProcessingFilterEntry</literal> point will
        redirect the user's browser to the CAS server. It will also
        indicate a <literal>service</literal> parameter, which is the
        callback URL for Spring Security service. For example, the URL to
        which the browser is redirected might be
        <literal>https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_spring_cas_security_check</literal>.</para>
      </listitem>

      <listitem>
        <para>After the user's browser redirects to CAS, they will be
        prompted for their username and password. If the user presents a
        session cookie which indicates they've previously logged on, they
        will not be prompted to login again (there is an exception to this
        procedure, which we'll cover later). CAS will use the
        <literal>PasswordHandler</literal> (or
        <literal>AuthenticationHandler</literal> if using CAS 3.0)
        discussed above to decide whether the username and password is
        valid.</para>
      </listitem>

      <listitem>
        <para>Upon successful login, CAS will redirect the user's browser
        back to the original service. It will also include a
        <literal>ticket</literal> parameter, which is an opaque string
        representing the "service ticket". Continuing our earlier example,
        the URL the browser is redirected to might be
        <literal>https://server3.company.com/webapp/j_spring_cas_security_check?ticket=ST-0-ER94xMJmn6pha35CQRoZ</literal>.</para>
      </listitem>

      <listitem>
        <para>Back in the service web application, the
        <literal>CasProcessingFilter</literal> is always listening for
        requests to <literal>/j_spring_cas_security_check</literal> (this
        is configurable, but we'll use the defaults in this introduction).
        The processing filter will construct a
        <literal>UsernamePasswordAuthenticationToken</literal>
        representing the service ticket. The principal will be equal to
        <literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>,
        whilst the credentials will be the service ticket opaque value.
        This authentication request will then be handed to the configured
        <interfacename>AuthenticationManager</interfacename>.</para>
      </listitem>

      <listitem>
        <para>The <interfacename>AuthenticationManager</interfacename> implementation
        will be the <literal>ProviderManager</literal>, which is in turn
        configured with the <literal>CasAuthenticationProvider</literal>.
        The <literal>CasAuthenticationProvider</literal> only responds to
        <literal>UsernamePasswordAuthenticationToken</literal>s containing
        the CAS-specific principal (such as
        <literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>)
        and <literal>CasAuthenticationToken</literal>s (discussed
        later).</para>
      </listitem>

      <listitem>
        <para><literal>CasAuthenticationProvider</literal> will validate
        the service ticket using a <literal>TicketValidator</literal>
        implementation. Spring Security includes one implementation, the
        <literal>CasProxyTicketValidator</literal>. This implementation a
        ticket validation class included in the CAS client library. The
        <literal>CasProxyTicketValidator</literal> makes an HTTPS request
        to the CAS server in order to validate the service ticket. The
        <literal>CasProxyTicketValidator</literal> may also include a
        proxy callback URL, which is included in this example:
        <literal>https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_spring_cas_security_check&amp;ticket=ST-0-ER94xMJmn6pha35CQRoZ&amp;pgtUrl=https://server3.company.com/webapp/casProxy/receptor</literal>.</para>
      </listitem>

      <listitem>
        <para>Back on the CAS server, the proxy validation request will be
        received. If the presented service ticket matches the service URL
        the ticket was issued to, CAS will provide an affirmative response
        in XML indicating the username. If any proxy was involved in the
        authentication (discussed below), the list of proxies is also
        included in the XML response.</para>
      </listitem>

      <listitem>
        <para>[OPTIONAL] If the request to the CAS validation service
        included the proxy callback URL (in the <literal>pgtUrl</literal>
        parameter), CAS will include a <literal>pgtIou</literal> string in
        the XML response. This <literal>pgtIou</literal> represents a
        proxy-granting ticket IOU. The CAS server will then create its own
        HTTPS connection back to the <literal>pgtUrl</literal>. This is to
        mutually authenticate the CAS server and the claimed service URL.
        The HTTPS connection will be used to send a proxy granting ticket
        to the original web application. For example,
        <literal>https://server3.company.com/webapp/casProxy/receptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&amp;pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH</literal>.
        We suggest you use CAS' <literal>ProxyTicketReceptor</literal>
        servlet to receive these proxy-granting tickets, if they are
        required.</para>
      </listitem>

      <listitem>
        <para>The <literal>CasProxyTicketValidator</literal> will parse
        the XML received from the CAS server. It will return to the
        <literal>CasAuthenticationProvider</literal> a
        <literal>TicketResponse</literal>, which includes the username
        (mandatory), proxy list (if any were involved), and proxy-granting
        ticket IOU (if the proxy callback was requested).</para>
      </listitem>

      <listitem>
        <para>Next <literal>CasAuthenticationProvider</literal> will call
        a configured <literal>CasProxyDecider</literal>. The
        <literal>CasProxyDecider</literal> indicates whether the proxy
        list in the <literal>TicketResponse</literal> is acceptable to the
        service. Several implementations are provided with Spring
        Security: <literal>RejectProxyTickets</literal>,
        <literal>AcceptAnyCasProxy</literal> and
        <literal>NamedCasProxyDecider</literal>. These names are largely
        self-explanatory, except <literal>NamedCasProxyDecider</literal>
        which allows a <literal>List</literal> of trusted proxies to be
        provided.</para>
      </listitem>

      <listitem>
        <para><literal>CasAuthenticationProvider</literal> will next
        request a <literal>CasAuthoritiesPopulator</literal> to advise the
        <interfacename>GrantedAuthority</interfacename> objects that apply to the user
        contained in the <literal>TicketResponse</literal>. Spring
        Security includes a <literal>DaoCasAuthoritiesPopulator</literal>
        which simply uses the <interfacename>UserDetailsService</interfacename>
        infrastructure to find the <interfacename>UserDetails</interfacename> and
        their associated <interfacename>GrantedAuthority</interfacename>s. Note that
        the password and enabled/disabled status of
        <interfacename>UserDetails</interfacename> returned by the
        <interfacename>UserDetailsService</interfacename> are ignored, as the CAS
        server is responsible for authentication decisions.
        <literal>DaoCasAuthoritiesPopulator</literal> is only concerned
        with retrieving the <interfacename>GrantedAuthority</interfacename>s.</para>
      </listitem>

      <listitem>
        <para>If there were no problems,
        <literal>CasAuthenticationProvider</literal> constructs a
        <literal>CasAuthenticationToken</literal> including the details
        contained in the <literal>TicketResponse</literal> and the
        <interfacename>GrantedAuthority</interfacename>s. The
        <literal>CasAuthenticationToken</literal> contains the hash of a
        key, so that the <literal>CasAuthenticationProvider</literal>
        knows it created it.</para>
      </listitem>

      <listitem>
        <para>Control then returns to
        <literal>CasProcessingFilter</literal>, which places the created
        <literal>CasAuthenticationToken</literal> into the
        <literal>HttpSession</literal> attribute named
        <literal>HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY</literal>.</para>
      </listitem>

      <listitem>
        <para>The user's browser is redirected to the original page that
        caused the <literal>AuthenticationException</literal>.</para>
      </listitem>

      <listitem>
        <para>As the <interfacename>Authentication</interfacename> object is now in
        the well-known location, it is handled like any other
        authentication approach. Usually the
        <classname>HttpSessionContextIntegrationFilter</classname> will be
        used to associate the <interfacename>Authentication</interfacename> object
        with the <classname>SecurityContextHolder</classname> for the duration
        of each request.</para>
      </listitem>
    </orderedlist>

    <para>It's good that you're still here! It might sound involved, but
    you can relax as Spring Security classes hide much of the complexity.
    Let's now look at how this is configured</para>
  </section>
-->
  </section>
  <section xml:id="cas-client">
    <info>
      <title>Configuration of CAS Client</title>
    </info>
    <para>The web application side of CAS is made easy due to Spring Security. It is assumed you
      already know the basics of using Spring Security, so these are not covered again below. We'll
      assume a namespace based configuration is being used and add in the CAS beans as required. </para>
    <para>You will need to add a <classname>ServiceProperties</classname> bean to your application
      context. This represents your CAS service:</para>
    <para>
      <programlisting><![CDATA[
  <bean id="serviceProperties"
        class="org.springframework.security.cas.ServiceProperties">
    <property name="service"
        value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
    <property name="sendRenew" value="false"/>
  </bean>]]>
    </programlisting>
    </para>
    <para>The <literal>service</literal> must equal a URL that will be monitored by the
        <literal>CasAuthenticationFilter</literal>. The <literal>sendRenew</literal> defaults to
      false, but should be set to true if your application is particularly sensitive. What this
      parameter does is tell the CAS login service that a single sign on login is unacceptable.
      Instead, the user will need to re-enter their username and password in order to gain access to
      the service.</para>
    <para>The following beans should be configured to commence the CAS authentication process
      (assuming you're using a namespace configuration):</para>
    <para>
      <programlisting><![CDATA[
<security:http entry-point-ref="casEntryPoint">
   ...
   <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</security:http>

<bean id="casFilter"
      class="org.springframework.security.cas.web.CasAuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
</bean>

<bean id="casEntryPoint"
    class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
  <property name="loginUrl" value="https://localhost:9443/cas/login"/>
  <property name="serviceProperties" ref="serviceProperties"/>
</bean>
]]>
    </programlisting>
    </para>
    <para> The <classname>CasAuthenticationEntryPoint</classname> should be selected to drive
      authentication using <link xlink:href="ns-entry-point-ref"
        ><literal>entry-point-ref</literal></link>. </para>
    <para>The <classname>CasAuthenticationFilter</classname> has very similar properties to the
        <classname>UsernamePasswordAuthenticationFilter</classname> (used for form-based logins).
    </para>
    <para>For CAS to operate, the <classname>ExceptionTranslationFilter</classname> must have its
        <literal>authenticationEntryPoint</literal> property set to the
        <classname>CasAuthenticationEntryPoint</classname> bean.</para>
    <para>The <classname>CasAuthenticationEntryPoint</classname> must refer to the
        <classname>ServiceProperties</classname> bean (discussed above), which provides the URL to the
      enterprise's CAS login server. This is where the user's browser will be redirected.</para>
    <para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its collaborators: <programlisting><![CDATA[
  <security:authentication-manager alias="authenticationManager">
    <security:authentication-provider ref="casAuthenticationProvider" />
  </security:authentication-manager>

  <bean id="casAuthenticationProvider"
      class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
    <property name="userDetailsService" ref="userService"/>
    <property name="serviceProperties" ref="serviceProperties" />
    <property name="ticketValidator">
      <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
        <constructor-arg index="0" value="https://localhost:9443/cas" />
        </bean>
    </property>
    <property name="key" value="an_id_for_this_auth_provider_only"/>
  </bean>

  <security:user-service id="userService">
    <security:user name="joe" password="joe" authorities="ROLE_USER" />
    ...
  </security:user-service>]]>
      </programlisting> The
        <classname>CasAuthenticationProvider</classname> uses a
        <interfacename>UserDetailsService</interfacename> instance to load the authorities for a
      user, once they have been authentiated by CAS. We've shown a simple in-memory setup here. </para>
    <para>The beans are all reasonable self-explanatory if you refer back to the "How CAS Works"
      section.</para>
  </section>
  <!--
    <para>Note the <literal>CasProxyTicketValidator</literal> has a
    remarked out <literal>trustStore</literal> property. This property
    might be helpful if you experience HTTPS certificate issues. Also note
    the <literal>proxyCallbackUrl</literal> is set so the service can
    receive a proxy-granting ticket. As mentioned above, this is optional
    and unnecessary if you do not require proxy-granting tickets. If you
    do use this feature, you will need to configure a suitable servlet to
    receive the proxy-granting tickets. We suggest you use CAS'
    <literal>ProxyTicketReceptor</literal> by adding the following to your
    web application's <literal>web.xml</literal>:</para>

    <para><programlisting>
&lt;servlet&gt;
&lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
&lt;servlet-class&gt;edu.yale.its.tp.cas.proxy.ProxyTicketReceptor&lt;/servlet-class&gt;
&lt;/servlet&gt;

&lt;servlet-mapping&gt;
&lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
&lt;url-pattern&gt;/casProxy/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;

    </programlisting></para>

    <para>This completes the configuration of CAS. If you haven't made any
    mistakes, your web application should happily work within the
    framework of CAS single sign on. No other parts of Spring Security
    need to be concerned about the fact CAS handled authentication.</para>

    <para>There is also a <literal>contacts-cas.war</literal> file in the
    sample applications directory. This sample application uses the above
    settings and can be deployed to see CAS in operation</para>
  </section>

  <section xml:id="cas-advanced">
    <info><title>Advanced Issues</title></info>

    <para>The <literal>CasAuthenticationProvider</literal> distinguishes
    between stateful and stateless clients. A stateful client is
    considered any that originates via the
    <literal>CasProcessingFilter</literal>. A stateless client is any that
    presents an authentication request via the
    <literal>UsernamePasswordAuthenticationToken</literal> with a
    principal equal to
    <literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>.</para>

    <para>Stateless clients are likely to be via remoting protocols such
    as Hessian and Burlap. The <literal>BasicProcessingFilter</literal> is
    still used in this case, but the remoting protocol client is expected
    to present a username equal to the static string above, and a password
    equal to a CAS service ticket. Clients should acquire a CAS service
    ticket directly from the CAS server.</para>

    <para>Because remoting protocols have no way of presenting themselves
    within the context of an <literal>HttpSession</literal>, it isn't
    possible to rely on the <literal>HttpSession</literal>'s
    <literal>HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY</literal>
    attribute to locate the <literal>CasAuthenticationToken</literal>.
    Furthermore, because the CAS server invalidates a service ticket after
    it has been validated by the <literal>TicketValidator</literal>,
    presenting the same service ticket on subsequent requests will not
    work. It is similarly very difficult to obtain a proxy-granting ticket
    for a remoting protocol client, as they are often deployed on client
    machines which rarely have HTTPS URLs that would be accessible to the
    CAS server.</para>

    <para>One obvious option is to not use CAS at all for remoting
    protocol clients. However, this would eliminate many of the desirable
    features of CAS.</para>

    <para>As a middle-ground, the
    <literal>CasAuthenticationProvider</literal> uses a
    <literal>StatelessTicketCache</literal>. This is used solely for
    requests with a principal equal to
    <literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>. What
    happens is the <literal>CasAuthenticationProvider</literal> will store
    the resulting <literal>CasAuthenticationToken</literal> in the
    <literal>StatelessTicketCache</literal>, keyed on the service ticket.
    Accordingly, remoting protocol clients can present the same service
    ticket and the <literal>CasAuthenticationProvider</literal> will not
    need to contact the CAS server for validation (aside from the first
    request).</para>

    <para>The other aspect of advanced CAS usage involves creating proxy
    tickets from the proxy-granting ticket. As indicated above, we
    recommend you use CAS' <literal>ProxyTicketReceptor</literal> to
    receive these tickets. The <literal>ProxyTicketReceptor</literal>
    provides a static method that enables you to obtain a proxy ticket by
    presenting the proxy-granting IOU ticket. You can obtain the
    proxy-granting IOU ticket by calling
    <literal>CasAuthenticationToken.getProxyGrantingTicketIou()</literal>.</para>

    <para>It is hoped you find CAS integration easy and useful with Spring
    Security classes. Welcome to enterprise-wide single sign on!</para>

  </section>
-->
</chapter>
