Initial CAS support.
This commit is contained in:
+606
-13
@@ -294,7 +294,7 @@
|
||||
handling each request. Handling involves a number of
|
||||
operations:</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Store the configuration attributes that are associated with
|
||||
each secure request.</para>
|
||||
@@ -354,7 +354,7 @@
|
||||
<para>Return any result received from the
|
||||
<literal>SecurityInterceptorCallback</literal>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</orderedlist>
|
||||
|
||||
<para>Whilst this may seem quite involved, don't worry. Developers
|
||||
interact with the security process by simply implementing basic
|
||||
@@ -854,6 +854,13 @@
|
||||
<literal>AuthenticationProvider</literal> if you were not using
|
||||
container adapters.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>CasAuthenticationProvider</literal> is able to
|
||||
authenticate Yale Central Authentication Service (CAS) tickets.
|
||||
This is discussed further in the CAS Single Sign On
|
||||
section.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</sect2>
|
||||
|
||||
@@ -870,8 +877,26 @@
|
||||
|
||||
<para><programlisting><bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="saltSource"><ref bean="saltSource"/></property>
|
||||
<property name="passwordEncoder"><ref bean="passwordEncoder"/></property>
|
||||
</bean></programlisting></para>
|
||||
|
||||
<para>The <literal>PasswordEncoder</literal> and
|
||||
<literal>SaltSource</literal> are optional. A
|
||||
<literal>PasswordEncoder</literal> provides encoding and decoding of
|
||||
passwords obtained from the authentication repository. A
|
||||
<literal>SaltSource</literal> enables the passwords to be populated
|
||||
with a "salt", which enhances the security of the passwords in the
|
||||
authentication repository. <literal>PasswordEncoder</literal>
|
||||
implementations are provided with the Acegi Security System for Spring
|
||||
covering MD5, SHA and cleartext encodings. Two
|
||||
<literal>SaltSource</literal> implementations are also provided:
|
||||
<literal>SystemWideSaltSource</literal> which encodes all passwords
|
||||
with the same salt, and <literal>ReflectionSaltSource</literal>, which
|
||||
inspects a given property of the returned User object to obtain the
|
||||
salt. Please refer to the JavaDocs for further details on these
|
||||
optional features.</para>
|
||||
|
||||
<para>For a class to be able to provide the
|
||||
<literal>DaoAuthenticationProvider</literal> with access to an
|
||||
authentication repository, it must implement the
|
||||
@@ -957,10 +982,13 @@
|
||||
<para>You can use different relational database management systems by
|
||||
modifying the <literal>DriverManagerDataSource</literal> shown above.
|
||||
Irrespective of the database used, a standard schema must be used as
|
||||
indicated in <literal>dbinit.txt</literal>. Of particular note is the
|
||||
database must return responses that treat the username as case
|
||||
insensitive, in order to comply with the
|
||||
<literal>AuthenticationDao</literal> contract.</para>
|
||||
indicated in <literal>dbinit.txt</literal>.</para>
|
||||
|
||||
<para>If you default schema is unsuitable for your needs,
|
||||
<literal>JdbcDaoImpl</literal> provides two properties that allow
|
||||
customisation of the SQL statements. You may also subclass the
|
||||
<literal>JdbcDaoImpl</literal> if further customisation is necessary.
|
||||
Please refer to the JavaDocs for details.</para>
|
||||
|
||||
<para>The Acegi Security System for Spring ships with a Hypersonic SQL
|
||||
instance that has the required authentication information and sample
|
||||
@@ -1487,11 +1515,13 @@ public boolean supports(Class clazz);</programlisting></para>
|
||||
<literal>HttpSession</literal> object and filters to authenticate the
|
||||
user. Another approach is HTTP Basic Authentication, which allows
|
||||
clients to use HTTP headers to present authentication information to
|
||||
the Acegi Security System for Spring. The final approach is via
|
||||
Container Adapters, which allow supported web containers to perform
|
||||
the authentication themselves. HTTP Session Authentication is
|
||||
discussed below, whilst Container Adapters are discussed in a separate
|
||||
section.</para>
|
||||
the Acegi Security System for Spring. Alternatively, you can also use
|
||||
Yale Central Authentication Service (CAS) for enterprise-wide single
|
||||
sign on. The final approach is via Container Adapters, which allow
|
||||
supported web containers to perform the authentication themselves.
|
||||
HTTP Session and Basic Authentication is discussed below, whilst CAS
|
||||
and Container Adapters are discussed in separate sections of this
|
||||
document.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="security-ui-http-session">
|
||||
@@ -1538,7 +1568,7 @@ public boolean supports(Class clazz);</programlisting></para>
|
||||
<literal>authenticationFailureUrl</literal>. The
|
||||
<literal>AuthenticationException</literal> will be placed into the
|
||||
<literal>HttpSession</literal> attribute indicated by
|
||||
<literal>AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY</literal>,
|
||||
<literal>AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY</literal>,
|
||||
enabling a reason to be provided to the user on the error page.</para>
|
||||
|
||||
<para>If authentication is successful, the resulting
|
||||
@@ -1552,7 +1582,7 @@ public boolean supports(Class clazz);</programlisting></para>
|
||||
browser will need to be redirected to the target URL. The target URL
|
||||
is usually indicated by the <literal>HttpSession</literal> attribute
|
||||
specified by
|
||||
<literal>AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY</literal>.
|
||||
<literal>AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY</literal>.
|
||||
This attribute is automatically set by the
|
||||
<literal>SecurityEnforcementFilter</literal> when an
|
||||
<literal>AuthenticationException</literal> occurs, so that after login
|
||||
@@ -2100,6 +2130,569 @@ $CATALINA_HOME/bin/startup.sh</programlisting></para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="security-cas">
|
||||
<title>Yale Central Authentication Service (CAS) Single Sign On</title>
|
||||
|
||||
<sect2 id="security-cas-overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>Yale University produces an enterprise-wide single sign on
|
||||
system known as CAS. Unlike other initiatives, Yale's Central
|
||||
Authentication Service is open source, widely used, simple to
|
||||
understand, platform independent, and supports proxy capabilities. The
|
||||
Acegi Security System for Spring fully supports CAS, and provides an
|
||||
easy migration path from single-application deployments of Acegi
|
||||
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.yale.edu/tp/auth/</literal>. You will need to
|
||||
visit this URL to download the CAS Server files. Whilst the Acegi
|
||||
Security System for Spring 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>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="security-cas-how-cas-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 the Acegi Security System for Spring. The
|
||||
following refers to CAS 2.0, being the version of CAS that Acegi
|
||||
Security for Spring 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. 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're running an existing CAS server, you will have already
|
||||
established a <literal>PasswordHandler</literal>. If you have not,
|
||||
might prefer to use the Acegi Security System for Spring
|
||||
<literal>CasPasswordHandler</literal> class. This class delegates
|
||||
through to the standard Acegi 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 unless you do not wish. The Acegi Security System for
|
||||
Spring will function as a CAS client successfully irrespective of the
|
||||
<literal>PasswordHandler</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 Yale 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 one of CAS' clients to interact with the CAS server from
|
||||
Acegi Security System for Spring secured applications. This is handled
|
||||
transparently for you.</para>
|
||||
|
||||
<para>The basic interaction between a web browser, CAS server and an
|
||||
Acegi Security for System Spring secured service is as follows:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>The web user is browsing the service's public pages. CAS or
|
||||
Acegi 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. Acegi Security's
|
||||
SecurityEnforcementFilter will detect the
|
||||
AuthenticationException.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Because the user has no <literal>Authentication</literal>
|
||||
object in
|
||||
<literal>HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY</literal>,
|
||||
the SecurityEnforcementFilter will call the configured
|
||||
<literal>AuthenticationEntryPoint</literal>. If using CAS, this
|
||||
will be the <literal>CasProcessingFilterEntryPoint</literal>
|
||||
class.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The CasProcessingFilterEntry 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 the Acegi Security service. For example, the URL the browser
|
||||
is redirected to might be
|
||||
<literal>https://my.company.com/cas/login?service=https://server3.company.com/webapp/j_acegi_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
|
||||
PasswordHandler 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_acegi_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_acegi_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 AuthenticationManager 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. Acegi Security includes one implementation, the
|
||||
<literal>CasProxyTicketValidator</literal>. This implementation
|
||||
uses a CAS-supplied ticket validator. The
|
||||
<literal>CasProxyTicketValidator</literal> makes a HTTPS request
|
||||
to the CAS server in order to validate the service ticket. The
|
||||
<literal>CasProxyTicketValidator</literal> may also include a
|
||||
proxy callback parameter, which is included in this example:
|
||||
<literal>https://my.company.com/cas/proxyValidate?service=https://server3.company.com/webapp/j_acegi_cas_security_check&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/casProxy/receptor</literal>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Back of the CAS server, the proxy validation request will be
|
||||
received. If the presented service ticket matches the service URL
|
||||
requested initially, 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 <literal>pgtUrl</literal>, 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. 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 the Acegi
|
||||
Security System: <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>. Acegi Security
|
||||
includes a <literal>DaoCasAuthoritiesPopulator</literal> which
|
||||
simply uses the <literal>AuthenticationDao</literal>
|
||||
infrastructure to find the <literal>User</literal> and their
|
||||
associated <literal>GrantedAuthority</literal>s. Note that the
|
||||
password and enabled/disabled status of <literal>User</literal>s
|
||||
returned by the <literal>AuthenticationDao</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>HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_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>AutoIntegrationFilter</literal> will be used to associate
|
||||
the <literal>Authentication</literal> object with the
|
||||
<literal>ContextHolder</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 the Acegi Security System for Spring classes hide
|
||||
much of the complexity. Let's now look at how this is
|
||||
configured.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="security-cas-install-server">
|
||||
<title>CAS Server Installation (Optional)</title>
|
||||
|
||||
<para>As mentioned above, the Acegi Security System for Spring
|
||||
includes a <literal>PasswordHandler</literal> that bridges your
|
||||
existing <literal>AuthenticationManager</literal> into CAS. You do not
|
||||
need to use this <literal>PasswordHandler</literal> to use Acegi
|
||||
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 Beta 3. 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="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
marissa=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="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="casPasswordHandler" class="net.sf.acegisecurity.adapters.cas.CasPasswordHandler">
|
||||
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>Note the granted authorities are ignored by CAS. It has no way
|
||||
of communciating the granted authorities to calling applications. CAS
|
||||
is only concerned with username and passwords.</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>net.sf.acegisecurity.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>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="security-cas-install-client">
|
||||
<title>CAS Acegi Security System Client Installation</title>
|
||||
|
||||
<para>The web application side of CAS is made easy due to the Acegi
|
||||
Security System for Spring. It is assumed you already know the basics
|
||||
of using the Acegi Security System for Spring, 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="net.sf.acegisecurity.ui.cas.ServiceProperties">
|
||||
<property name="service"><value>https://localhost:8443/contacts-cas/j_acegi_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="net.sf.acegisecurity.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_acegi_cas_security_check</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
|
||||
<property name="filterSecurityInterceptor"><ref bean="filterInvocationInterceptor"/></property>
|
||||
<property name="authenticationEntryPoint"><ref bean="casProcessingFilterEntryPoint"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="casProcessingFilterEntryPoint" class="net.sf.acegisecurity.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>Acegi CAS Processing Filter</filter-name>
|
||||
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
|
||||
<init-param>
|
||||
<param-name>targetClass</param-name>
|
||||
<param-value>net.sf.acegisecurity.ui.cas.CasProcessingFilter</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>Acegi 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>SecurityEnforcementFilter</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) and
|
||||
provide 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="net.sf.acegisecurity.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="casAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="casAuthenticationProvider" class="net.sf.acegisecurity.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="net.sf.acegisecurity.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="statelessTicketCache" class="net.sf.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache">
|
||||
<property name="minutesToIdle"><value>20</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="casAuthoritiesPopulator" class="net.sf.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="casProxyDecider" class="net.sf.acegisecurity.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 the Acegi Security
|
||||
System for Spring 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>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="security-cas-advanced-usage">
|
||||
<title>Advanced CAS Usage</title>
|
||||
|
||||
<para>[DRAFT - COMMENTS WELCOME]</para>
|
||||
|
||||
<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 a <literal>HttpSession</literal>, it isn't
|
||||
possible to rely on the <literal>HttpSession</literal>'s
|
||||
<literal>HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY</literal>
|
||||
attribute to locate the CasAuthenticationToken. Furthermore, because
|
||||
the CAS server invalidates a service ticket after it has been
|
||||
validated by the TicketValidator, 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 operational on client machines which do not have HTTPS
|
||||
certificates that would be trusted by 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 CasAuthenticationProvider uses a
|
||||
StatelessTicketCache. This is used solely for requests with a
|
||||
principal equal to
|
||||
<literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>. What
|
||||
happens is the CasAuthenticationProvider will store the resulting
|
||||
CasAuthenticationToken in the StatelessTicketCache, keyed on the
|
||||
service ticket. Accordingly, remoting protocol clients can present the
|
||||
same service ticket and the CasAuthenticationProvider will not need to
|
||||
contact the CAS server for validation.</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 the
|
||||
Acegi Security System for Spring classes. Welcome to enterprise-wide
|
||||
single sign on!</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="security-sample">
|
||||
<title>Contacts Sample Application</title>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user