|  | @@ -17,41 +17,139 @@ package org.springframework.security.cas.web;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.io.IOException;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +import javax.servlet.FilterChain;
 | 
	
		
			
				|  |  | +import javax.servlet.ServletException;
 | 
	
		
			
				|  |  |  import javax.servlet.http.HttpServletRequest;
 | 
	
		
			
				|  |  |  import javax.servlet.http.HttpServletResponse;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
 | 
	
		
			
				|  |  |  import org.jasig.cas.client.util.CommonUtils;
 | 
	
		
			
				|  |  |  import org.jasig.cas.client.validation.TicketValidator;
 | 
	
		
			
				|  |  | +import org.springframework.security.authentication.AnonymousAuthenticationToken;
 | 
	
		
			
				|  |  | +import org.springframework.security.authentication.AuthenticationDetailsSource;
 | 
	
		
			
				|  |  |  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 | 
	
		
			
				|  |  | +import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
 | 
	
		
			
				|  |  |  import org.springframework.security.cas.ServiceProperties;
 | 
	
		
			
				|  |  | +import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
 | 
	
		
			
				|  |  | +import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
 | 
	
		
			
				|  |  |  import org.springframework.security.core.Authentication;
 | 
	
		
			
				|  |  |  import org.springframework.security.core.AuthenticationException;
 | 
	
		
			
				|  |  | +import org.springframework.security.core.context.SecurityContextHolder;
 | 
	
		
			
				|  |  |  import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 | 
	
		
			
				|  |  | +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
 | 
	
		
			
				|  |  | +import org.springframework.util.Assert;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | - * Processes a CAS service ticket.
 | 
	
		
			
				|  |  | + * Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy tickets.
 | 
	
		
			
				|  |  | + * <h2>Service Tickets</h2>
 | 
	
		
			
				|  |  |   * <p>
 | 
	
		
			
				|  |  |   * A service ticket consists of an opaque ticket string. It arrives at this filter by the user's browser successfully
 | 
	
		
			
				|  |  |   * authenticating using CAS, and then receiving a HTTP redirect to a <code>service</code>. The opaque ticket string is
 | 
	
		
			
				|  |  | - * presented in the <code>ticket</code> request parameter. This filter monitors the <code>service</code> URL so it can
 | 
	
		
			
				|  |  | - * receive the service ticket and process it. The CAS server knows which <code>service</code> URL to use via the
 | 
	
		
			
				|  |  | - * {@link ServiceProperties#getService()} method.
 | 
	
		
			
				|  |  | + * presented in the <code>ticket</code> request parameter.
 | 
	
		
			
				|  |  | + * <p>
 | 
	
		
			
				|  |  | + * This filter monitors the <code>service</code> URL so it can
 | 
	
		
			
				|  |  | + * receive the service ticket and process it. By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
 | 
	
		
			
				|  |  | + * When processing this URL, the value of {@link ServiceProperties#getService()} is used as the <tt>service</tt> when validating
 | 
	
		
			
				|  |  | + * the <code>ticket</code>. This means that it is important that {@link ServiceProperties#getService()} specifies the same value
 | 
	
		
			
				|  |  | + * as the <tt>filterProcessesUrl</tt>.
 | 
	
		
			
				|  |  |   * <p>
 | 
	
		
			
				|  |  |   * Processing the service ticket involves creating a <code>UsernamePasswordAuthenticationToken</code> which
 | 
	
		
			
				|  |  |   * uses {@link #CAS_STATEFUL_IDENTIFIER} for the <code>principal</code> and the opaque ticket string as the
 | 
	
		
			
				|  |  |   * <code>credentials</code>.
 | 
	
		
			
				|  |  | + * <h2>Obtaining Proxy Granting Tickets</h2>
 | 
	
		
			
				|  |  | + * <p>
 | 
	
		
			
				|  |  | + * If specified, the filter can also monitor the <code>proxyReceptorUrl</code>. The filter will respond to requests matching
 | 
	
		
			
				|  |  | + * this url so that the CAS Server can provide a PGT to the filter. Note that in addition to the <code>proxyReceptorUrl</code> a non-null
 | 
	
		
			
				|  |  | + * <code>proxyGrantingTicketStorage</code> must be provided in order for the filter to respond to proxy receptor requests. By configuring
 | 
	
		
			
				|  |  | + * a shared {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the CasAuthenticationFilter one can have the
 | 
	
		
			
				|  |  | + * CasAuthenticationFilter handle the proxying requirements for CAS.
 | 
	
		
			
				|  |  | + * <h2>Proxy Tickets</h2>
 | 
	
		
			
				|  |  | + * <p>
 | 
	
		
			
				|  |  | + * The filter can process tickets present on any url. This is useful when wanting to process proxy tickets. In order for proxy
 | 
	
		
			
				|  |  | + * tickets to get processed {@link ServiceProperties#isAuthenticateAllArtifacts()} must return <code>true</code>. Additionally,
 | 
	
		
			
				|  |  | + * if the request is already authenticated, authentication will <b>not</b> occur. Last, {@link AuthenticationDetailsSource#buildDetails(Object)}
 | 
	
		
			
				|  |  | + * must return a {@link ServiceAuthenticationDetails}. This can be accomplished using the {@link ServiceAuthenticationDetailsSource}.
 | 
	
		
			
				|  |  | + * In this case {@link ServiceAuthenticationDetails#getServiceUrl()} will be used for the service url.
 | 
	
		
			
				|  |  | + * <p>
 | 
	
		
			
				|  |  | + * Processing the proxy ticket involves creating a <code>UsernamePasswordAuthenticationToken</code> which
 | 
	
		
			
				|  |  | + * uses {@link #CAS_STATELESS_IDENTIFIER} for the <code>principal</code> and the opaque ticket string as the
 | 
	
		
			
				|  |  | + * <code>credentials</code>. When a proxy ticket is successfully authenticated, the FilterChain continues and the
 | 
	
		
			
				|  |  | + * <code>authenticationSuccessHandler</code> is not used.
 | 
	
		
			
				|  |  | + * <h2>Notes about the <code>AuthenticationManager</code></h2>
 | 
	
		
			
				|  |  |   * <p>
 | 
	
		
			
				|  |  |   * The configured <code>AuthenticationManager</code> is expected to provide a provider that can recognise
 | 
	
		
			
				|  |  |   * <code>UsernamePasswordAuthenticationToken</code>s containing this special <code>principal</code> name, and process
 | 
	
		
			
				|  |  | - * them accordingly by validation with the CAS server.
 | 
	
		
			
				|  |  | - * <p>
 | 
	
		
			
				|  |  | - * By configuring a shared {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the
 | 
	
		
			
				|  |  | - * CasAuthenticationFilter one can have the CasAuthenticationFilter handle the proxying requirements for CAS. In addition, the
 | 
	
		
			
				|  |  | - * URI endpoint for the proxying would also need to be configured (i.e. the part after protocol, hostname, and port).
 | 
	
		
			
				|  |  | + * them accordingly by validation with the CAS server. Additionally, it should be capable of using the result of
 | 
	
		
			
				|  |  | + * {@link ServiceAuthenticationDetails#getServiceUrl()} as the service when validating the ticket.
 | 
	
		
			
				|  |  | + * <h2>Example Configuration</h2>
 | 
	
		
			
				|  |  |   * <p>
 | 
	
		
			
				|  |  | - * By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
 | 
	
		
			
				|  |  | + * An example configuration that supports service tickets, obtaining proxy granting tickets, and proxy tickets is
 | 
	
		
			
				|  |  | + * illustrated below:
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * <pre>
 | 
	
		
			
				|  |  | + * <b:bean id="serviceProperties"
 | 
	
		
			
				|  |  | + *     class="org.springframework.security.cas.ServiceProperties"
 | 
	
		
			
				|  |  | + *     p:service="https://service.example.com/cas-sample/j_spring_cas_security_check"
 | 
	
		
			
				|  |  | + *     p:authenticateAllArtifacts="true"/>
 | 
	
		
			
				|  |  | + * <b:bean id="casEntryPoint"
 | 
	
		
			
				|  |  | + *     class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
 | 
	
		
			
				|  |  | + *     p:serviceProperties-ref="serviceProperties" p:loginUrl="https://login.example.org/cas/login" />
 | 
	
		
			
				|  |  | + * <b:bean id="casFilter"
 | 
	
		
			
				|  |  | + *     class="org.springframework.security.cas.web.CasAuthenticationFilter"
 | 
	
		
			
				|  |  | + *     p:authenticationManager-ref="authManager"
 | 
	
		
			
				|  |  | + *     p:serviceProperties-ref="serviceProperties"
 | 
	
		
			
				|  |  | + *     p:proxyGrantingTicketStorage-ref="pgtStorage"
 | 
	
		
			
				|  |  | + *     p:proxyReceptorUrl="/j_spring_cas_security_proxyreceptor">
 | 
	
		
			
				|  |  | + *     <b:property name="authenticationDetailsSource">
 | 
	
		
			
				|  |  | + *         <b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
 | 
	
		
			
				|  |  | + *     </b:property>
 | 
	
		
			
				|  |  | + *     <b:property name="authenticationFailureHandler">
 | 
	
		
			
				|  |  | + *         <b:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
 | 
	
		
			
				|  |  | + *             p:defaultFailureUrl="/casfailed.jsp"/>
 | 
	
		
			
				|  |  | + *     </b:property>
 | 
	
		
			
				|  |  | + * </b:bean>
 | 
	
		
			
				|  |  | + * <!--
 | 
	
		
			
				|  |  | + *     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()
 | 
	
		
			
				|  |  | + *  -->
 | 
	
		
			
				|  |  | + * <b:bean id="pgtStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>
 | 
	
		
			
				|  |  | + * <b:bean id="casAuthProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"
 | 
	
		
			
				|  |  | + *     p:serviceProperties-ref="serviceProperties"
 | 
	
		
			
				|  |  | + *     p:key="casAuthProviderKey">
 | 
	
		
			
				|  |  | + *     <b:property name="authenticationUserDetailsService">
 | 
	
		
			
				|  |  | + *         <b:bean
 | 
	
		
			
				|  |  | + *             class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
 | 
	
		
			
				|  |  | + *             <b:constructor-arg ref="userService" />
 | 
	
		
			
				|  |  | + *         </b:bean>
 | 
	
		
			
				|  |  | + *     </b:property>
 | 
	
		
			
				|  |  | + *     <b:property name="ticketValidator">
 | 
	
		
			
				|  |  | + *         <b:bean
 | 
	
		
			
				|  |  | + *             class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"
 | 
	
		
			
				|  |  | + *             p:acceptAnyProxy="true"
 | 
	
		
			
				|  |  | + *             p:proxyCallbackUrl="https://service.example.com/cas-sample/j_spring_cas_security_proxyreceptor"
 | 
	
		
			
				|  |  | + *             p:proxyGrantingTicketStorage-ref="pgtStorage">
 | 
	
		
			
				|  |  | + *             <b:constructor-arg value="https://login.example.org/cas" />
 | 
	
		
			
				|  |  | + *         </b:bean>
 | 
	
		
			
				|  |  | + *     </b:property>
 | 
	
		
			
				|  |  | + *     <b:property name="statelessTicketCache">
 | 
	
		
			
				|  |  | + *         <b:bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
 | 
	
		
			
				|  |  | + *             <b:property name="cache">
 | 
	
		
			
				|  |  | + *                 <b:bean class="net.sf.ehcache.Cache"
 | 
	
		
			
				|  |  | + *                   init-method="initialise"
 | 
	
		
			
				|  |  | + *                   destroy-method="dispose">
 | 
	
		
			
				|  |  | + *                     <b:constructor-arg value="casTickets"/>
 | 
	
		
			
				|  |  | + *                     <b:constructor-arg value="50"/>
 | 
	
		
			
				|  |  | + *                     <b:constructor-arg value="true"/>
 | 
	
		
			
				|  |  | + *                     <b:constructor-arg value="false"/>
 | 
	
		
			
				|  |  | + *                     <b:constructor-arg value="3600"/>
 | 
	
		
			
				|  |  | + *                     <b:constructor-arg value="900"/>
 | 
	
		
			
				|  |  | + *                 </b:bean>
 | 
	
		
			
				|  |  | + *             </b:property>
 | 
	
		
			
				|  |  | + *         </b:bean>
 | 
	
		
			
				|  |  | + *     </b:property>
 | 
	
		
			
				|  |  | + * </b:bean>
 | 
	
		
			
				|  |  | + * </pre>
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * @author Ben Alex
 | 
	
		
			
				|  |  |   * @author Rob Winch
 | 
	
	
		
			
				|  | @@ -81,26 +179,59 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      private String artifactParameter = ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    private boolean authenticateAllArtifacts;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      //~ Constructors ===================================================================================================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public CasAuthenticationFilter() {
 | 
	
		
			
				|  |  |          super("/j_spring_cas_security_check");
 | 
	
		
			
				|  |  | +        setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      //~ Methods ========================================================================================================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  | +    protected final void successfulAuthentication(HttpServletRequest request,
 | 
	
		
			
				|  |  | +            HttpServletResponse response, FilterChain chain, Authentication authResult)
 | 
	
		
			
				|  |  | +            throws IOException, ServletException {
 | 
	
		
			
				|  |  | +        boolean continueFilterChain = proxyTicketRequest(serviceTicketRequest(request, response),request);
 | 
	
		
			
				|  |  | +        if(!continueFilterChain) {
 | 
	
		
			
				|  |  | +            super.successfulAuthentication(request, response, chain, authResult);
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (logger.isDebugEnabled()) {
 | 
	
		
			
				|  |  | +            logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        SecurityContextHolder.getContext().setAuthentication(authResult);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Fire event
 | 
	
		
			
				|  |  | +        if (this.eventPublisher != null) {
 | 
	
		
			
				|  |  | +            eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        chain.doFilter(request, response);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  |      public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
 | 
	
		
			
				|  |  |              throws AuthenticationException, IOException {
 | 
	
		
			
				|  |  |          // if the request is a proxy request process it and return null to indicate the request has been processed
 | 
	
		
			
				|  |  | -        if(isProxyRequest(request)) {
 | 
	
		
			
				|  |  | +        if(proxyReceptorRequest(request)) {
 | 
	
		
			
				|  |  | +            logger.debug("Responding to proxy receptor request");
 | 
	
		
			
				|  |  |              CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
 | 
	
		
			
				|  |  |              return null;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        final String username = CAS_STATEFUL_IDENTIFIER;
 | 
	
		
			
				|  |  | -        String password = request.getParameter(this.artifactParameter);
 | 
	
		
			
				|  |  | +        final boolean serviceTicketRequest = serviceTicketRequest(request, response);
 | 
	
		
			
				|  |  | +        final String username = serviceTicketRequest ? CAS_STATEFUL_IDENTIFIER : CAS_STATELESS_IDENTIFIER;
 | 
	
		
			
				|  |  | +        String password = obtainArtifact(request);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if (password == null) {
 | 
	
		
			
				|  |  | +            logger.debug("Failed to obtain an artifact (cas ticket)");
 | 
	
		
			
				|  |  |              password = "";
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -111,11 +242,47 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
 | 
	
		
			
				|  |  |          return this.getAuthenticationManager().authenticate(authRequest);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * If present, gets the artifact (CAS ticket) from the {@link HttpServletRequest}.
 | 
	
		
			
				|  |  | +     * @param request
 | 
	
		
			
				|  |  | +     * @return if present the artifact from the {@link HttpServletRequest}, else null
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    protected String obtainArtifact(HttpServletRequest request) {
 | 
	
		
			
				|  |  | +        return request.getParameter(artifactParameter);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * Overridden to provide proxying capabilities.
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  |      protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
 | 
	
		
			
				|  |  | -        return isProxyRequest(request) || super.requiresAuthentication(request, response);
 | 
	
		
			
				|  |  | +        final boolean serviceTicketRequest = serviceTicketRequest(request, response);
 | 
	
		
			
				|  |  | +        final boolean result = serviceTicketRequest || proxyReceptorRequest(request) || (proxyTicketRequest(serviceTicketRequest, request));
 | 
	
		
			
				|  |  | +        if(logger.isDebugEnabled()) {
 | 
	
		
			
				|  |  | +            logger.debug("requiresAuthentication = "+result);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return result;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * Sets the {@link AuthenticationFailureHandler} for proxy requests.
 | 
	
		
			
				|  |  | +     * @param proxyFailureHandler
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    public final void setProxyAuthenticationFailureHandler(
 | 
	
		
			
				|  |  | +            AuthenticationFailureHandler proxyFailureHandler) {
 | 
	
		
			
				|  |  | +        Assert.notNull(proxyFailureHandler,"proxyFailureHandler cannot be null");
 | 
	
		
			
				|  |  | +        this.proxyFailureHandler = proxyFailureHandler;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * Wraps the {@link AuthenticationFailureHandler} to distinguish between
 | 
	
		
			
				|  |  | +     * handling proxy ticket authentication failures and service ticket
 | 
	
		
			
				|  |  | +     * failures.
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  | +    public final void setAuthenticationFailureHandler(
 | 
	
		
			
				|  |  | +            AuthenticationFailureHandler failureHandler) {
 | 
	
		
			
				|  |  | +        super.setAuthenticationFailureHandler(new CasAuthenticationFailureHandler(failureHandler));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
 | 
	
	
		
			
				|  | @@ -129,15 +296,97 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public final void setServiceProperties(final ServiceProperties serviceProperties) {
 | 
	
		
			
				|  |  |          this.artifactParameter = serviceProperties.getArtifactParameter();
 | 
	
		
			
				|  |  | +        this.authenticateAllArtifacts = serviceProperties.isAuthenticateAllArtifacts();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  | -     * Indicates if the request is eligible to be processed as a proxy request.
 | 
	
		
			
				|  |  | +     * Indicates if the request is elgible to process a service ticket. This method exists for readability.
 | 
	
		
			
				|  |  |       * @param request
 | 
	
		
			
				|  |  | +     * @param response
 | 
	
		
			
				|  |  |       * @return
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    private boolean isProxyRequest(final HttpServletRequest request) {
 | 
	
		
			
				|  |  | +    private boolean serviceTicketRequest(final HttpServletRequest request, final HttpServletResponse response) {
 | 
	
		
			
				|  |  | +        boolean result = super.requiresAuthentication(request, response);
 | 
	
		
			
				|  |  | +        if(logger.isDebugEnabled()) {
 | 
	
		
			
				|  |  | +            logger.debug("serviceTicketRequest = "+result);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return result;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * Indicates if the request is elgible to process a proxy ticket.
 | 
	
		
			
				|  |  | +     * @param request
 | 
	
		
			
				|  |  | +     * @return
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    private boolean proxyTicketRequest(final boolean serviceTicketRequest, final HttpServletRequest request) {
 | 
	
		
			
				|  |  | +        if(serviceTicketRequest) {
 | 
	
		
			
				|  |  | +            return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        final boolean result = authenticateAllArtifacts && obtainArtifact(request) != null && !authenticated();
 | 
	
		
			
				|  |  | +        if(logger.isDebugEnabled()) {
 | 
	
		
			
				|  |  | +            logger.debug("proxyTicketRequest = "+result);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return result;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * Determines if a user is already authenticated.
 | 
	
		
			
				|  |  | +     * @return
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    private boolean authenticated() {
 | 
	
		
			
				|  |  | +        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
 | 
	
		
			
				|  |  | +        return authentication != null && authentication.isAuthenticated() && !(authentication instanceof AnonymousAuthenticationToken);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * Indicates if the request is elgible to be processed as the proxy receptor.
 | 
	
		
			
				|  |  | +     * @param request
 | 
	
		
			
				|  |  | +     * @return
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    private boolean proxyReceptorRequest(final HttpServletRequest request) {
 | 
	
		
			
				|  |  |          final String requestUri = request.getRequestURI();
 | 
	
		
			
				|  |  | -        return this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl) && requestUri.endsWith(this.proxyReceptorUrl);
 | 
	
		
			
				|  |  | +        final boolean result = proxyReceptorConfigured() && requestUri.endsWith(this.proxyReceptorUrl);
 | 
	
		
			
				|  |  | +        if(logger.isDebugEnabled()) {
 | 
	
		
			
				|  |  | +            logger.debug("proxyReceptorRequest = "+result);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return result;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * Determines if the {@link CasAuthenticationFilter} is configured to handle the proxy receptor requests.
 | 
	
		
			
				|  |  | +     *
 | 
	
		
			
				|  |  | +     * @return
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    private boolean proxyReceptorConfigured() {
 | 
	
		
			
				|  |  | +        final boolean result = this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl);
 | 
	
		
			
				|  |  | +        if(logger.isDebugEnabled()) {
 | 
	
		
			
				|  |  | +            logger.debug("proxyReceptorConfigured = "+result);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return result;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * A wrapper for the AuthenticationFailureHandler that will flex the {@link AuthenticationFailureHandler} that is used. The value
 | 
	
		
			
				|  |  | +     * {@link CasAuthenticationFilter#setProxyAuthenticationFailureHandler(AuthenticationFailureHandler) will be used for proxy requests
 | 
	
		
			
				|  |  | +     * that fail. The value {@link CasAuthenticationFilter#setAuthenticationFailureHandler(AuthenticationFailureHandler)} will be used for
 | 
	
		
			
				|  |  | +     * service tickets that fail.
 | 
	
		
			
				|  |  | +     *
 | 
	
		
			
				|  |  | +     * @author Rob Winch
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    private class CasAuthenticationFailureHandler implements AuthenticationFailureHandler {
 | 
	
		
			
				|  |  | +        private final AuthenticationFailureHandler serviceTicketFailureHandler;
 | 
	
		
			
				|  |  | +        public CasAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
 | 
	
		
			
				|  |  | +            Assert.notNull(failureHandler,"failureHandler");
 | 
	
		
			
				|  |  | +            this.serviceTicketFailureHandler = failureHandler;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        public void onAuthenticationFailure(HttpServletRequest request,
 | 
	
		
			
				|  |  | +                HttpServletResponse response,
 | 
	
		
			
				|  |  | +                AuthenticationException exception) throws IOException,
 | 
	
		
			
				|  |  | +                ServletException {
 | 
	
		
			
				|  |  | +            if(serviceTicketRequest(request, response)) {
 | 
	
		
			
				|  |  | +                serviceTicketFailureHandler.onAuthenticationFailure(request, response, exception);
 | 
	
		
			
				|  |  | +            }else {
 | 
	
		
			
				|  |  | +                proxyFailureHandler.onAuthenticationFailure(request, response, exception);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +}
 |