| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- <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/products/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 2.0 supports
- CAS 3. At the time of writing, the CAS server was at version 3.2.</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.2 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&ticket=ST-0-ER94xMJmn6pha35CQRoZ&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&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 <literal>ServiceProperties</literal> bean
- to your application context. This represents your 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>CasProcessingFilter</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:</para>
- <para><programlisting><![CDATA[
- <security:authentication-manager alias="authenticationManager"/>
-
- <bean id="casProcessingFilter" class="org.springframework.security.cas.web.CasProcessingFilter">
- <security:custom-filter after="CAS_PROCESSING_FILTER"/>
- <property name="authenticationManager" ref="authenticationManager"/>
- <property name="authenticationFailureUrl" value="/casfailed.jsp"/>
- <property name="defaultTargetUrl" value="/"/>
- </bean>
- <bean id="casProcessingFilterEntryPoint"
- class="org.springframework.security.cas.web.CasProcessingFilterEntryPoint">
- <property name="loginUrl" value="https://localhost:9443/cas/login"/>
- <property name="serviceProperties" ref="serviceProperties"/>
- </bean>
- ]]>
-
- </programlisting></para>
-
- <para>
- The <classname>CasProcessingFilterEntryPoint</classname> should be selected to
- drive authentication using <link xlink:href="ns-entry-point-ref"><literal>entry-point-ref</literal></link>.
- </para>
- <para>The <literal>CasProcessingFilter</literal> has very similar
- properties to the <literal>AuthenticationProcessingFilter</literal>
- (used for form-based logins). Each property is
- self-explanatory. Note that we've also used the namespace syntax
- for setting up an alias to the authentication mnager, since the
- <literal>CasProcessingFilter</literal> needs a reference to it.</para>
- <para>For CAS to operate, the
- <classname>ExceptionTranslationFilter</classname> must have its
- <literal>authenticationEntryPoint</literal> property set to the
- <literal>CasProcessingFilterEntryPoint</literal> bean.</para>
- <para>The <literal>CasProcessingFilterEntryPoint</literal> must refer
- to the <literal>ServiceProperties</literal> 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[
- <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
- <security:custom-authentication-provider />
- <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>
- <servlet>
- <servlet-name>casproxy</servlet-name>
- <servlet-class>edu.yale.its.tp.cas.proxy.ProxyTicketReceptor</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>casproxy</servlet-name>
- <url-pattern>/casProxy/*</url-pattern>
- </servlet-mapping>
- </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>
|