|
|
@@ -0,0 +1,744 @@
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
|
+ "http://www.docbook.org/xml/4.4/docbookx.dtd">
|
|
|
+
|
|
|
+<chapter id="cas">
|
|
|
+ <title>CAS Authentication</title>
|
|
|
+
|
|
|
+ <sect1 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 need
|
|
|
+ to visit this URL to download the CAS Server files. Whilst Spring
|
|
|
+ Security includes two CAS libraries in the "-with-dependencies" ZIP
|
|
|
+ file, you will still need the CAS Java Server Pages and
|
|
|
+ <literal>web.xml</literal> to customise and deploy your CAS
|
|
|
+ server.</para>
|
|
|
+ </sect1>
|
|
|
+
|
|
|
+ <sect1 id="cas-how-it-works">
|
|
|
+ <title>How CAS Works</title>
|
|
|
+
|
|
|
+ <para>Whilst the CAS web site above contains two documents that detail
|
|
|
+ the architecture of CAS, we present the general overview again here
|
|
|
+ within the context of Spring Security. The following refers to both
|
|
|
+ CAS 2.0 (produced by Yale) and CAS 3.0 (produced by JA-SIG), being the
|
|
|
+ versions of CAS that Spring Security supports.</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>If you are deploying CAS 2.0, you will also need to specify in
|
|
|
+ the web.xml a <literal>PasswordHandler</literal>. The
|
|
|
+ <literal>PasswordHandler</literal> has a simple method that returns a
|
|
|
+ boolean as to whether a given username and password is valid. Your
|
|
|
+ <literal>PasswordHandler</literal> implementation will need to link
|
|
|
+ into some type of backend authentication repository, such as an LDAP
|
|
|
+ server or database.</para>
|
|
|
+
|
|
|
+ <para>If you are already running an existing CAS 2.0 server instance,
|
|
|
+ you will have already established a
|
|
|
+ <literal>PasswordHandler</literal>. If you do not already have a
|
|
|
+ <literal>PasswordHandler</literal>, you might prefer to use Spring
|
|
|
+ Security's <literal>CasPasswordHandler</literal> class. This class
|
|
|
+ delegates through to the standard Spring Security
|
|
|
+ <literal>AuthenticationManager</literal>, enabling you to use a
|
|
|
+ security configuration you might already have in place. You do not
|
|
|
+ need to use the <literal>CasPasswordHandler</literal> class on your
|
|
|
+ CAS server if you do not wish. Spring Security will function as a CAS
|
|
|
+ client successfully irrespective of the
|
|
|
+ <literal>PasswordHandler</literal> you've chosen for your CAS
|
|
|
+ server.</para>
|
|
|
+
|
|
|
+ <para>If you are deploying CAS 3.0, you will also need to specify an
|
|
|
+ <literal>AuthenticationHandler</literal> in the
|
|
|
+ deployerConfigContext.xml 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.</para>
|
|
|
+
|
|
|
+ <para>If you are already running an existing CAS 3.0 server instance,
|
|
|
+ you will have already established an
|
|
|
+ <literal>AuthenticationHandler</literal>. If you do not already have
|
|
|
+ an <literal>AuthenticationHandler</literal>, you might prefer to use
|
|
|
+ Spring Security <literal>CasAuthenticationHandler</literal> class.
|
|
|
+ This class delegates through to the standard Spring Security
|
|
|
+ <literal>AuthenticationManager</literal>, enabling you to use a
|
|
|
+ security configuration you might already have in place. You do not
|
|
|
+ need to use the <literal>CasAuthenticationHandler</literal> class on
|
|
|
+ your CAS server if you do not wish. Spring Security will function as a
|
|
|
+ CAS client successfully irrespective of the
|
|
|
+ <literal>AuthenticationHandler</literal> you've chosen for your CAS
|
|
|
+ server.</para>
|
|
|
+
|
|
|
+ <para>Apart from the CAS server itself, the other key player is 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>
|
|
|
+
|
|
|
+ <para>Services can be developed in a large variety of languages, due
|
|
|
+ to CAS 2.0's very light XML-based protocol. The JA-SIG CAS home page
|
|
|
+ contains a clients archive which demonstrates CAS clients in Java,
|
|
|
+ Active Server Pages, Perl, Python and others. Naturally, Java support
|
|
|
+ is very strong given the CAS server is written in Java. You do not
|
|
|
+ need to use any of CAS' client classes in applications secured by
|
|
|
+ Spring Security. This is handled transparently for you.</para>
|
|
|
+
|
|
|
+ <para>The basic interaction between a web browser, CAS server and n
|
|
|
+ Spring Security-secured service is as follows:</para>
|
|
|
+
|
|
|
+ <orderedlist>
|
|
|
+ <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
|
|
|
+ <literal>ExceptionTranslationFilter</literal> will detect the
|
|
|
+ <literal>AuthenticationException</literal>.</para>
|
|
|
+ </listitem>
|
|
|
+
|
|
|
+ <listitem>
|
|
|
+ <para>Because the user's <literal>Authentication</literal> object
|
|
|
+ (or lack thereof) caused an
|
|
|
+ <literal>AuthenticationException</literal>, the
|
|
|
+ <literal>ExceptionTranslationFilter</literal> will call the
|
|
|
+ configured <literal>AuthenticationEntryPoint</literal>. 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
|
|
|
+ <literal>AuthenticationManager</literal>.</para>
|
|
|
+ </listitem>
|
|
|
+
|
|
|
+ <listitem>
|
|
|
+ <para>The <literal>AuthenticationManager</literal> 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
|
|
|
+ <literal>GrantedAuthority</literal> objects that apply to the user
|
|
|
+ contained in the <literal>TicketResponse</literal>. Spring
|
|
|
+ Security includes a <literal>DaoCasAuthoritiesPopulator</literal>
|
|
|
+ which simply uses the <literal>UserDetailsService</literal>
|
|
|
+ infrastructure to find the <literal>UserDetails</literal> and
|
|
|
+ their associated <literal>GrantedAuthority</literal>s. Note that
|
|
|
+ the password and enabled/disabled status of
|
|
|
+ <literal>UserDetails</literal> returned by the
|
|
|
+ <literal>UserDetailsService</literal> are ignored, as the CAS
|
|
|
+ server is responsible for authentication decisions.
|
|
|
+ <literal>DaoCasAuthoritiesPopulator</literal> is only concerned
|
|
|
+ with retrieving the <literal>GrantedAuthority</literal>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
|
|
|
+ <literal>GrantedAuthority</literal>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 <literal>Authentication</literal> object is now in
|
|
|
+ the well-known location, it is handled like any other
|
|
|
+ authentication approach. Usually the
|
|
|
+ <literal>HttpSessionContextIntegrationFilter</literal> will be
|
|
|
+ used to associate the <literal>Authentication</literal> object
|
|
|
+ with the <literal>SecurityContextHolder</literal> 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>
|
|
|
+ </sect1>
|
|
|
+
|
|
|
+ <sect1 id="cas-server">
|
|
|
+ <title>Optional CAS Server Setup</title>
|
|
|
+
|
|
|
+ <para>Spring Security can even act as the backend which a CAS version
|
|
|
+ 2.0 or 3.0 server utilises. The configuration approach is described
|
|
|
+ below. Of course, if you have an existing CAS environment you might
|
|
|
+ just like to use it instead.</para>
|
|
|
+
|
|
|
+ <sect2 id="cas-server-2">
|
|
|
+ <title>CAS Version 2.0</title>
|
|
|
+
|
|
|
+ <para>As mentioned above, Spring Security includes a
|
|
|
+ <literal>PasswordHandler</literal> that bridges your existing
|
|
|
+ <literal>AuthenticationManager</literal> into CAS 2.0. You do not
|
|
|
+ need to use this <literal>PasswordHandler</literal> to use Spring
|
|
|
+ Security on the client side (any CAS
|
|
|
+ <literal>PasswordHandler</literal> will do).</para>
|
|
|
+
|
|
|
+ <para>To install, you will need to download and extract the CAS
|
|
|
+ server archive. We used version 2.0.12. There will be a
|
|
|
+ <literal>/web</literal> directory in the root of the deployment.
|
|
|
+ Copy an <literal>applicationContext.xml</literal> containing your
|
|
|
+ <literal>AuthenticationManager</literal> as well as the
|
|
|
+ <literal>CasPasswordHandler</literal> into the
|
|
|
+ <literal>/web/WEB-INF</literal> directory. A sample
|
|
|
+ <literal>applicationContext.xml</literal> is included below:</para>
|
|
|
+
|
|
|
+ <programlisting>
|
|
|
+<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
|
|
+<property name="userMap">
|
|
|
+<value>
|
|
|
+ rod=koala,ROLES_IGNORED_BY_CAS
|
|
|
+ dianne=emu,ROLES_IGNORED_BY_CAS
|
|
|
+ scott=wombat,ROLES_IGNORED_BY_CAS
|
|
|
+ peter=opal,disabled,ROLES_IGNORED_BY_CAS
|
|
|
+</value>
|
|
|
+</property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="daoAuthenticationProvider"
|
|
|
+ class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
|
|
+<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
|
|
+<property name="providers">
|
|
|
+<list>
|
|
|
+ <ref bean="daoAuthenticationProvider"/>
|
|
|
+</list>
|
|
|
+</property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="casPasswordHandler" class="org.springframework.security.adapters.cas.CasPasswordHandler">
|
|
|
+<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+ </programlisting>
|
|
|
+
|
|
|
+ <para>Note the granted authorities are ignored by CAS because it has
|
|
|
+ no way of communicating the granted authorities to calling
|
|
|
+ applications. CAS is only concerned with username and passwords (and
|
|
|
+ the enabled/disabled status).</para>
|
|
|
+
|
|
|
+ <para>Next you will need to edit the existing
|
|
|
+ <literal>/web/WEB-INF/web.xml</literal> file. Add (or edit in the
|
|
|
+ case of the <literal>authHandler</literal> property) the following
|
|
|
+ lines:</para>
|
|
|
+
|
|
|
+ <para><programlisting>
|
|
|
+
|
|
|
+<context-param>
|
|
|
+<param-name>edu.yale.its.tp.cas.authHandler</param-name>
|
|
|
+<param-value>org.springframework.security.adapters.cas.CasPasswordHandlerProxy</param-value>
|
|
|
+</context-param>
|
|
|
+
|
|
|
+<context-param>
|
|
|
+<param-name>contextConfigLocation</param-name>
|
|
|
+<param-value>/WEB-INF/applicationContext.xml</param-value>
|
|
|
+</context-param>
|
|
|
+
|
|
|
+<listener>
|
|
|
+<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
|
|
+</listener>
|
|
|
+
|
|
|
+ </programlisting></para>
|
|
|
+
|
|
|
+ <para>Copy the <literal>spring.jar</literal> and
|
|
|
+ <literal>acegi-security.jar</literal> files into
|
|
|
+ <literal>/web/WEB-INF/lib</literal>. Now use the <literal>ant
|
|
|
+ dist</literal> task in the <literal>build.xml</literal> in the root
|
|
|
+ of the directory structure. This will create
|
|
|
+ <literal>/lib/cas.war</literal>, which is ready for deployment to
|
|
|
+ your servlet container.</para>
|
|
|
+
|
|
|
+ <para>Note CAS heavily relies on HTTPS. You can't even test the
|
|
|
+ system without an HTTPS certificate. Whilst you should refer to your
|
|
|
+ web container's documentation on setting up HTTPS, if you need some
|
|
|
+ additional help or a test certificate you might like to check the
|
|
|
+ <literal>samples/contacts/etc/ssl</literal> directory</para>
|
|
|
+ </sect2>
|
|
|
+
|
|
|
+ <sect2 id="cas-server-3">
|
|
|
+ <title>CAS Version 3.0</title>
|
|
|
+
|
|
|
+ <para>As mentioned above, Spring Security includes an
|
|
|
+ <literal>AuthenticationHandler</literal> that bridges your existing
|
|
|
+ <literal>AuthenticationManager</literal> into CAS 3.0. You do not
|
|
|
+ need to use this <literal>AuthenticationHandler</literal> to use
|
|
|
+ Spring Security on the client side (any CAS
|
|
|
+ <literal>AuthenticationHandler</literal> will do).</para>
|
|
|
+
|
|
|
+ <para>To install, you will need to download and extract the CAS
|
|
|
+ server archive. We used version 3.0.4. There will be a
|
|
|
+ <literal>/webapp</literal> directory in the root of the deployment.
|
|
|
+ Edit the an <literal>deployerConfigContext.xml</literal> so that it
|
|
|
+ contains your <literal>AuthenticationManager</literal> as well as
|
|
|
+ the <literal>CasAuthenticationHandler</literal>. A sample
|
|
|
+ <literal>applicationContext.xml</literal> is included below:</para>
|
|
|
+
|
|
|
+ <programlisting>
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
|
|
+<beans>
|
|
|
+ <bean
|
|
|
+ id="authenticationManager"
|
|
|
+ class="org.jasig.cas.authentication.AuthenticationManagerImpl">
|
|
|
+ <property name="credentialsToPrincipalResolvers">
|
|
|
+ <list>
|
|
|
+ <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" />
|
|
|
+ <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
|
|
|
+ </list>
|
|
|
+ </property>
|
|
|
+
|
|
|
+ <property name="authenticationHandlers">
|
|
|
+ <list>
|
|
|
+ <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" />
|
|
|
+ <bean class="org.springframework.security.adapters.cas3.CasAuthenticationHandler">
|
|
|
+ <property name="authenticationManager" ref="authenticationManager" />
|
|
|
+ </bean>
|
|
|
+ </list>
|
|
|
+ </property>
|
|
|
+ </bean>
|
|
|
+
|
|
|
+
|
|
|
+ <bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
|
|
+ <property name="userMap">
|
|
|
+ <value>
|
|
|
+ rod=koala,ROLES_IGNORED_BY_CAS
|
|
|
+ dianne=emu,ROLES_IGNORED_BY_CAS
|
|
|
+ scott=wombat,ROLES_IGNORED_BY_CAS
|
|
|
+ peter=opal,disabled,ROLES_IGNORED_BY_CAS
|
|
|
+ </value>
|
|
|
+ </property>
|
|
|
+ </bean>
|
|
|
+
|
|
|
+ <bean id="daoAuthenticationProvider"
|
|
|
+ class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
|
|
+ <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
|
|
+ </bean>
|
|
|
+
|
|
|
+ <bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
|
|
+ <property name="providers">
|
|
|
+ <list>
|
|
|
+ <ref bean="daoAuthenticationProvider"/>
|
|
|
+ </list>
|
|
|
+ </property>
|
|
|
+ </bean>
|
|
|
+</beans>
|
|
|
+
|
|
|
+ </programlisting>
|
|
|
+
|
|
|
+ <para>Note the granted authorities are ignored by CAS because it has
|
|
|
+ no way of communicating the granted authorities to calling
|
|
|
+ applications. CAS is only concerned with username and passwords (and
|
|
|
+ the enabled/disabled status).</para>
|
|
|
+
|
|
|
+ <para>Copy <literal>acegi-security.jar</literal> and
|
|
|
+ <literal>acegi-security-cas.jar</literal> files into
|
|
|
+ <literal>/localPlugins/lib</literal>. Now use the <literal>ant
|
|
|
+ war</literal> task in the <literal>build.xml</literal> in the
|
|
|
+ /localPlugins directory. This will create
|
|
|
+ <literal>/localPlugins/target/cas.war</literal>, which is ready for
|
|
|
+ deployment to your servlet container.</para>
|
|
|
+
|
|
|
+ <para>Note CAS heavily relies on HTTPS. You can't even test the
|
|
|
+ system without an HTTPS certificate. Whilst you should refer to your
|
|
|
+ web container's documentation on setting up HTTPS, if you need some
|
|
|
+ additional help or a test certificate you might like to check the
|
|
|
+ CAS documentation on setting up SSL:
|
|
|
+ <literal>http://www.ja-sig.org/products/cas/server/ssl/index.html</literal></para>
|
|
|
+ </sect2>
|
|
|
+ </sect1>
|
|
|
+
|
|
|
+ <sect1 id="cas-client">
|
|
|
+ <title>Configuration of CAS Client</title>
|
|
|
+
|
|
|
+ <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. Only the CAS-specific
|
|
|
+ beans are mentioned.</para>
|
|
|
+
|
|
|
+ <para>You will need to add a <literal>ServiceProperties</literal> bean
|
|
|
+ to your application context. This represents your service:</para>
|
|
|
+
|
|
|
+ <para><programlisting>
|
|
|
+
|
|
|
+<bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties">
|
|
|
+<property name="service"><value>https://localhost:8443/contacts-cas/j_spring_cas_security_check</value></property>
|
|
|
+<property name="sendRenew"><value>false</value></property>
|
|
|
+</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>
|
|
|
+<bean id="casProcessingFilter" class="org.springframework.security.ui.cas.CasProcessingFilter">
|
|
|
+<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
|
|
+<property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property>
|
|
|
+<property name="defaultTargetUrl"><value>/</value></property>
|
|
|
+<property name="filterProcessesUrl"><value>/j_spring_cas_security_check</value></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="exceptionTranslationFilter" class="org.springframework.security.ui.ExceptionTranslationFilter">
|
|
|
+<property name="authenticationEntryPoint"><ref local="casProcessingFilterEntryPoint"/></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="casProcessingFilterEntryPoint"
|
|
|
+ class="org.springframework.security.ui.cas.CasProcessingFilterEntryPoint">
|
|
|
+<property name="loginUrl"><value>https://localhost:8443/cas/login</value></property>
|
|
|
+<property name="serviceProperties"><ref bean="serviceProperties"/></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+ </programlisting></para>
|
|
|
+
|
|
|
+ <para>You will also need to add the
|
|
|
+ <literal>CasProcessingFilter</literal> to web.xml:</para>
|
|
|
+
|
|
|
+ <para><programlisting>
|
|
|
+<filter>
|
|
|
+<filter-name>Spring Security CAS Processing Filter</filter-name>
|
|
|
+<filter-class>org.springframework.security.util.FilterToBeanProxy</filter-class>
|
|
|
+<init-param>
|
|
|
+<param-name>targetClass</param-name>
|
|
|
+<param-value>org.springframework.security.ui.cas.CasProcessingFilter</param-value>
|
|
|
+</init-param>
|
|
|
+</filter>
|
|
|
+
|
|
|
+<filter-mapping>
|
|
|
+<filter-name>Spring Security CAS Processing Filter</filter-name>
|
|
|
+<url-pattern>/*</url-pattern>
|
|
|
+</filter-mapping>
|
|
|
+
|
|
|
+ </programlisting></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.</para>
|
|
|
+
|
|
|
+ <para>For CAS to operate, the
|
|
|
+ <literal>ExceptionTranslationFilter</literal> 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 an <literal>AuthenticationManager</literal>
|
|
|
+ that uses <literal>CasAuthenticationProvider</literal> and its
|
|
|
+ collaborators:</para>
|
|
|
+
|
|
|
+ <para><programlisting>
|
|
|
+<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
|
|
+<property name="providers">
|
|
|
+<list>
|
|
|
+ <ref bean="casAuthenticationProvider"/>
|
|
|
+</list>
|
|
|
+</property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="casAuthenticationProvider"
|
|
|
+ class="org.springframework.security.providers.cas.CasAuthenticationProvider">
|
|
|
+<property name="casAuthoritiesPopulator"><ref bean="casAuthoritiesPopulator"/></property>
|
|
|
+<property name="casProxyDecider"><ref bean="casProxyDecider"/></property>
|
|
|
+<property name="ticketValidator"><ref bean="casProxyTicketValidator"/></property>
|
|
|
+<property name="statelessTicketCache"><ref bean="statelessTicketCache"/></property>
|
|
|
+<property name="key"><value>my_password_for_this_auth_provider_only</value></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="casProxyTicketValidator"
|
|
|
+ class="org.springframework.security.providers.cas.ticketvalidator.CasProxyTicketValidator">
|
|
|
+<property name="casValidate"><value>https://localhost:8443/cas/proxyValidate</value></property>
|
|
|
+<property name="proxyCallbackUrl"><value>https://localhost:8443/contacts-cas/casProxy/receptor</value></property>
|
|
|
+<property name="serviceProperties"><ref bean="serviceProperties"/></property>
|
|
|
+<!-- <property name="trustStore"><value>/some/path/to/your/lib/security/cacerts</value></property> -->
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
|
|
|
+<property name="configLocation">
|
|
|
+<value>classpath:/ehcache-failsafe.xml</value>
|
|
|
+</property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="ticketCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
|
|
+<property name="cacheManager">
|
|
|
+<ref local="cacheManager"/>
|
|
|
+</property>
|
|
|
+<property name="cacheName">
|
|
|
+<value>ticketCache</value>
|
|
|
+</property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="statelessTicketCache" class="org.springframework.security.providers.cas.cache.EhCacheBasedTicketCache">
|
|
|
+<property name="cache"><ref local="ticketCacheBackend"/></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="casAuthoritiesPopulator"
|
|
|
+ class="org.springframework.security.providers.cas.populator.DaoCasAuthoritiesPopulator">
|
|
|
+<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
|
|
+</bean>
|
|
|
+
|
|
|
+<bean id="casProxyDecider" class="org.springframework.security.providers.cas.proxy.RejectProxyTickets"/>
|
|
|
+
|
|
|
+ </programlisting></para>
|
|
|
+
|
|
|
+ <para>The beans are all reasonable self-explanatory if you refer back
|
|
|
+ to the "How CAS Works" section. Careful readers might notice one
|
|
|
+ surprise: the <literal>statelessTicketCache</literal> property of the
|
|
|
+ <literal>CasAuthenticationProvider</literal>. This is discussed in
|
|
|
+ detail in the "Advanced CAS Usage" section.</para>
|
|
|
+
|
|
|
+ <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>
|
|
|
+ </sect1>
|
|
|
+
|
|
|
+ <sect1 id="cas-advanced">
|
|
|
+ <title>Advanced Issues</title>
|
|
|
+
|
|
|
+ <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>
|
|
|
+ </sect1>
|
|
|
+</chapter>
|