22.3.3 Authenticating to a Stateless Service with CAS
Thissection describes how to authenticate to a service using CAS. In other words,this section discusses how to setup a client that uses a service thatauthenticates with CAS. The next section describes how to setup a statelessservice to Authenticate using CAS.
Configuring CAS toObtain Proxy Granting Tickets
In orderto authenticate to a stateless service, the application needs to obtain a proxygranting ticket (PGT). This section describes how to configure Spring Securityto obtain a PGT building upon then Service Ticket Authentication configuration.
The firststep is to include a ProxyGrantingTicketStorage
in your Spring Securityconfiguration. This is used to store PGT's that are obtained by the CasAuthenticationFilter
so that they can be used toobtain proxy tickets. An example configuration is shown below
<!--
NOTE: In a real application you should not use an in memory implementation. You will also want
to ensure to clean up expired tickets by calling ProxyGrantingTicketStorage.cleanup()
-->
<bean id="pgtStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>
The nextstep is to update the CasAuthenticationProvider
to be able to obtain proxytickets. To do this replace the Cas20ServiceTicketValidator
with a Cas20ProxyTicketValidator
. TheproxyCallbackUrl
should be set to a URL that theapplication will receive PGT's at. Last, the configuration should alsoreference the ProxyGrantingTicketStorage
so it can use a PGT to obtainproxy tickets. You can find an example of the configuration changes that shouldbe made below.
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
...
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator">
<constructor-arg value="https://localhost:9443/cas"/>
<property name="proxyCallbackUrl"
value="https://localhost:8443/cas-sample/j_spring_cas_security_proxyreceptor"/>
<property name="proxyGrantingTicketStorage" ref="pgtStorage"/>
</bean>
</property>
</bean>
The laststep is to update the CasAuthenticationFilter
to accept PGT and to store themin the ProxyGrantingTicketStorage
.It is important the the proxyReceptorUrl
matches theproxyCallbackUrl
of the Cas20ProxyTicketValidator
. Anexample configuration is shown below.
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
...
<property name="proxyGrantingTicketStorage" ref="pgtStorage"/>
<property name="proxyReceptorUrl" value="/j_spring_cas_security_proxyreceptor"/>
</bean>
Calling a StatelessService Using a Proxy Ticket
Now thatSpring Security obtains PGTs, you can use them to create proxy tickets whichcan be used to authenticate to a stateless service. The CAS sampleapplication containsa working example in the ProxyTicketSampleServlet
.Example code can be found below:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// NOTE: The CasAuthenticationToken can also be obtained using
// SecurityContextHolder.getContext().getAuthentication()
final CasAuthenticationToken token = (CasAuthenticationToken) request.getUserPrincipal();
// proxyTicket could be reused to make calls to the CAS service even if the
// target url differs
final String proxyTicket = token.getAssertion().getPrincipal().getProxyTicketFor(targetUrl);
// Make a remote call using the proxy ticket
final String serviceUrl = targetUrl+"?ticket="+URLEncoder.encode(proxyTicket, "UTF-8");
String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8");
...
}
22.3.4 Proxy TicketAuthentication
The CasAuthenticationProvider
distinguishes between statefuland stateless clients. A stateful client is considered any that submits to the filterProcessUrl
ofthe CasAuthenticationFilter
.A stateless client is any that presents an authentication request to CasAuthenticationFilter
on a URL other than the filterProcessUrl
.
Becauseremoting protocols have no way of presenting themselves within the context ofan HttpSession
, itisn't possible to rely on the default practice of storing the security contextin the session between requests. Furthermore, because the CAS serverinvalidates a ticket after it has been validated by the TicketValidator
, presenting the sameproxy ticket on subsequent requests will not work.
Oneobvious option is to not use CAS at all for remoting protocol clients. However,this would eliminate many of the desirable features of CAS. As a middle-ground,theCasAuthenticationProvider
uses a StatelessTicketCache
. This isused solely for stateless clients which use a principal equal to CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER
.What happens is the CasAuthenticationProvider
will store the resulting CasAuthenticationToken
in the StatelessTicketCache
, keyedon the proxy ticket. Accordingly, remoting protocol clients can present thesame proxy ticket and the CasAuthenticationProvider
will not need to contact the CASserver for validation (aside from the first request). Once authenticated, theproxy ticket could be used for URLs other than the original target service.
Thissection builds upon the previous sections to accomodate proxy ticketauthentication. The first step is to specify to authenticate all artifacts asshown below.
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
...
<property name="authenticateAllArtifacts" value="true"/>
</bean>
The nextstep is to specify serviceProperties
and the authenticationDetailsSource
for the CasAuthenticationFilter
. The serviceProperties
propertyinstructs the CasAuthenticationFilter
to attempt to authenticate allartifacts instead of only ones present on the filterProcessUrl
. The ServiceAuthenticationDetailsSource
creates a ServiceAuthenticationDetails
that ensures the current URL,based upon the HttpServletRequest
,is used as the service URL when validating the ticket. The method forgenerating the service URL can be customized by injecting a custom AuthenticationDetailsSource
that returns a custom ServiceAuthenticationDetails
.
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
...
<property name="serviceProperties" ref="serviceProperties"/>
<property name="authenticationDetailsSource">
<bean class=
"org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<constructor-arg ref="serviceProperties"/>
</bean>
</property>
</bean>
You willalso need to update the CasAuthenticationProvider
to handle proxy tickets. To dothis replace the Cas20ServiceTicketValidator
with a Cas20ProxyTicketValidator
. Youwill need to configure the statelessTicketCache
and which proxies you want toaccept. You can find an example of the updates required to accept all proxiesbelow.
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
...
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator">
<constructor-arg value="https://localhost:9443/cas"/>
<property name="acceptAnyProxy" value="true"/>
</bean>
</property>
<property name="statelessTicketCache">
<bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
<property name="cache">
<bean class="net.sf.ehcache.Cache"
init-method="initialise" destroy-method="dispose">
<constructor-arg value="casTickets"/>
<constructor-arg value="50"/>
<constructor-arg value="true"/>
<constructor-arg value="false"/>
<constructor-arg value="3600"/>
<constructor-arg value="900"/>
</bean>
</property>
</bean>
</property>
</bean>