Coverage Report - org.acegisecurity.ui.x509.X509ProcessingFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
X509ProcessingFilter
80% 
100% 
2.3
 
 1  
 /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 2  
  *
 3  
  * Licensed under the Apache License, Version 2.0 (the "License");
 4  
  * you may not use this file except in compliance with the License.
 5  
  * You may obtain a copy of the License at
 6  
  *
 7  
  *     http://www.apache.org/licenses/LICENSE-2.0
 8  
  *
 9  
  * Unless required by applicable law or agreed to in writing, software
 10  
  * distributed under the License is distributed on an "AS IS" BASIS,
 11  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
  * See the License for the specific language governing permissions and
 13  
  * limitations under the License.
 14  
  */
 15  
 
 16  
 package org.acegisecurity.ui.x509;
 17  
 
 18  
 import org.acegisecurity.Authentication;
 19  
 import org.acegisecurity.AuthenticationException;
 20  
 import org.acegisecurity.AuthenticationManager;
 21  
 
 22  
 import org.acegisecurity.context.SecurityContextHolder;
 23  
 
 24  
 import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
 25  
 
 26  
 import org.acegisecurity.providers.x509.X509AuthenticationToken;
 27  
 
 28  
 import org.acegisecurity.ui.AbstractProcessingFilter;
 29  
 import org.acegisecurity.ui.AuthenticationDetailsSource;
 30  
 import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 
 35  
 import org.springframework.beans.factory.InitializingBean;
 36  
 
 37  
 import org.springframework.context.ApplicationEventPublisher;
 38  
 import org.springframework.context.ApplicationEventPublisherAware;
 39  
 
 40  
 import org.springframework.util.Assert;
 41  
 
 42  
 import java.io.IOException;
 43  
 
 44  
 import java.security.cert.X509Certificate;
 45  
 
 46  
 import javax.servlet.http.HttpServletRequest;
 47  
 import javax.servlet.http.HttpServletResponse;
 48  
 import javax.servlet.Filter;
 49  
 import javax.servlet.ServletRequest;
 50  
 import javax.servlet.ServletException;
 51  
 import javax.servlet.FilterChain;
 52  
 import javax.servlet.ServletResponse;
 53  
 import javax.servlet.FilterConfig;
 54  
 
 55  
 
 56  
 /**
 57  
  * Processes the X.509 certificate submitted by a client browser when HTTPS is used with client-authentication
 58  
  * enabled.<p>An {@link X509AuthenticationToken} is created with the certificate as the credentials.</p>
 59  
  *  <p>The configured authentication manager is expected to supply a provider which can handle this token (usually
 60  
  * an instance of {@link org.acegisecurity.providers.x509.X509AuthenticationProvider}).</p>
 61  
  *  <p>If authentication is successful, an {@link
 62  
  * org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} will be published to the application
 63  
  * context. No events will be published if authentication was unsuccessful, because this would generally be recorded
 64  
  * via an <code>AuthenticationManager</code>-specific application event.</p>
 65  
  *  <p><b>Do not use this class directly.</b> Instead configure <code>web.xml</code> to use the {@link
 66  
  * org.acegisecurity.util.FilterToBeanProxy}.</p>
 67  
  *
 68  
  * @author Luke Taylor
 69  
  * @version $Id: X509ProcessingFilter.java 1784 2007-02-24 21:00:24Z luke_t $
 70  
  */
 71  6
 public class X509ProcessingFilter implements Filter, InitializingBean, ApplicationEventPublisherAware {
 72  
     //~ Static fields/initializers =====================================================================================
 73  
 
 74  2
     private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class);
 75  
 
 76  
     //~ Instance fields ================================================================================================
 77  
 
 78  
     private ApplicationEventPublisher eventPublisher;
 79  6
     private AuthenticationDetailsSource authenticationDetailsSource = new AuthenticationDetailsSourceImpl();
 80  
     private AuthenticationManager authenticationManager;
 81  
 
 82  
     //~ Methods ========================================================================================================
 83  
 
 84  
     public void afterPropertiesSet() throws Exception {
 85  3
         Assert.notNull(authenticationManager, "An AuthenticationManager must be set");
 86  2
     }
 87  
 
 88  2
     public void destroy() {}
 89  
 
 90  
     /**
 91  
      * This method first checks for an existing, non-null authentication in the secure context. If one is found
 92  
      * it does nothing.<p>If no authentication object exists, it attempts to obtain the client authentication
 93  
      * certificate from the request. If there is no certificate present then authentication is skipped. Otherwise a
 94  
      * new authentication request containing the certificate will be passed to the configured {@link
 95  
      * AuthenticationManager}.</p>
 96  
      *  <p>If authentication is successful the returned token will be stored in the secure context. Otherwise
 97  
      * it will be set to null. In either case, the request proceeds through the filter chain.</p>
 98  
      *
 99  
      * @param request DOCUMENT ME!
 100  
      * @param response DOCUMENT ME!
 101  
      * @param filterChain DOCUMENT ME!
 102  
      *
 103  
      * @throws IOException DOCUMENT ME!
 104  
      * @throws javax.servlet.ServletException DOCUMENT ME!
 105  
      */
 106  
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
 107  
         throws IOException, ServletException {
 108  5
         if (!(request instanceof HttpServletRequest)) {
 109  1
             throw new ServletException("Can only process HttpServletRequest");
 110  
         }
 111  
 
 112  4
         if (!(response instanceof HttpServletResponse)) {
 113  1
             throw new ServletException("Can only process HttpServletResponse");
 114  
         }
 115  
 
 116  3
         HttpServletRequest httpRequest = (HttpServletRequest) request;
 117  3
         HttpServletResponse httpResponse = (HttpServletResponse) response;
 118  
 
 119  3
         if (logger.isDebugEnabled()) {
 120  0
             logger.debug("Checking secure context token: " + SecurityContextHolder.getContext().getAuthentication());
 121  
         }
 122  
 
 123  3
         if (SecurityContextHolder.getContext().getAuthentication() == null) {
 124  3
             Authentication authResult = null;
 125  3
             X509Certificate clientCertificate = extractClientCertificate(httpRequest);
 126  
 
 127  
             try {
 128  3
                 X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
 129  
 
 130  3
                 authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
 131  3
                 authResult = authenticationManager.authenticate(authRequest);
 132  1
                 successfulAuthentication(httpRequest, httpResponse, authResult);
 133  2
             } catch (AuthenticationException failed) {
 134  2
                 unsuccessfulAuthentication(httpRequest, httpResponse, failed);
 135  1
             }
 136  
         }
 137  
 
 138  3
         filterChain.doFilter(request, response);
 139  3
     }
 140  
 
 141  
     private X509Certificate extractClientCertificate(HttpServletRequest request) {
 142  3
         X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
 143  
 
 144  3
         if ((certs != null) && (certs.length > 0)) {
 145  2
             return certs[0];
 146  
         }
 147  
 
 148  1
         if (logger.isDebugEnabled()) {
 149  0
             logger.debug("No client certificate found in request.");
 150  
         }
 151  
 
 152  1
         return null;
 153  
     }
 154  
 
 155  2
     public void init(FilterConfig ignored) throws ServletException {}
 156  
 
 157  
     public void setApplicationEventPublisher(ApplicationEventPublisher context) {
 158  0
         this.eventPublisher = context;
 159  0
     }
 160  
 
 161  
     public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
 162  0
         Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required");
 163  0
         this.authenticationDetailsSource = authenticationDetailsSource;
 164  0
     }
 165  
 
 166  
     public void setAuthenticationManager(AuthenticationManager authenticationManager) {
 167  3
         this.authenticationManager = authenticationManager;
 168  3
     }
 169  
 
 170  
     /**
 171  
      * Puts the <code>Authentication</code> instance returned by the authentication manager into the secure
 172  
      * context.
 173  
      *
 174  
      * @param request DOCUMENT ME!
 175  
      * @param response DOCUMENT ME!
 176  
      * @param authResult DOCUMENT ME!
 177  
      *
 178  
      * @throws IOException DOCUMENT ME!
 179  
      */
 180  
     protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
 181  
         Authentication authResult) throws IOException {
 182  1
         if (logger.isDebugEnabled()) {
 183  0
             logger.debug("Authentication success: " + authResult);
 184  
         }
 185  
 
 186  1
         SecurityContextHolder.getContext().setAuthentication(authResult);
 187  
 
 188  
         // Fire event
 189  1
         if (this.eventPublisher != null) {
 190  0
             eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
 191  
         }
 192  1
     }
 193  
 
 194  
     /**
 195  
      * Ensures the authentication object in the secure context is set to null when authentication fails.
 196  
      *
 197  
      * @param request DOCUMENT ME!
 198  
      * @param response DOCUMENT ME!
 199  
      * @param failed DOCUMENT ME!
 200  
      */
 201  
     protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
 202  
         AuthenticationException failed) {
 203  2
         SecurityContextHolder.getContext().setAuthentication(null);
 204  
 
 205  2
         if (logger.isDebugEnabled()) {
 206  0
             logger.debug("Updated SecurityContextHolder to contain null Authentication");
 207  
         }
 208  
 
 209  2
         request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed);
 210  2
     }
 211  
 }