Clover coverage report - Acegi Security System for Spring - 1.0.0-RC1
Coverage timestamp: Mon Dec 5 2005 09:05:15 EST
file stats: LOC: 230   Methods: 9
NCLOC: 99   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
X509ProcessingFilter.java 66.7% 83.3% 88.9% 79.4%
coverage coverage
 1    /* Copyright 2004, 2005 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    import org.acegisecurity.context.SecurityContextHolder;
 22    import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
 23    import org.acegisecurity.providers.x509.X509AuthenticationToken;
 24    import org.acegisecurity.ui.AbstractProcessingFilter;
 25    import org.acegisecurity.ui.WebAuthenticationDetails;
 26   
 27    import org.apache.commons.logging.Log;
 28    import org.apache.commons.logging.LogFactory;
 29   
 30    import org.springframework.beans.factory.InitializingBean;
 31   
 32    import org.springframework.context.ApplicationEventPublisherAware;
 33    import org.springframework.context.ApplicationEventPublisher;
 34   
 35    import org.springframework.util.Assert;
 36   
 37    import java.io.IOException;
 38   
 39    import java.security.cert.X509Certificate;
 40   
 41    import javax.servlet.*;
 42    import javax.servlet.http.HttpServletRequest;
 43    import javax.servlet.http.HttpServletResponse;
 44   
 45   
 46    /**
 47    * Processes the X.509 certificate submitted by a client browser when HTTPS is
 48    * used with client-authentication enabled.
 49    *
 50    * <p>
 51    * An {@link X509AuthenticationToken} is created with the certificate as the
 52    * credentials.
 53    * </p>
 54    *
 55    * <p>
 56    * The configured authentication manager is expected to supply a provider which
 57    * can handle this token (usually an instance of {@link
 58    * org.acegisecurity.providers.x509.X509AuthenticationProvider}).
 59    * </p>
 60    *
 61    * <p>
 62    * If authentication is successful, an {@link
 63    * org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} will be
 64    * published to the application context. No events will be published if
 65    * authentication was unsuccessful, because this would generally be recorded
 66    * via an <code>AuthenticationManager</code>-specific application event.
 67    * </p>
 68    *
 69    * <p>
 70    * <b>Do not use this class directly.</b> Instead configure
 71    * <code>web.xml</code> to use the {@link
 72    * org.acegisecurity.util.FilterToBeanProxy}.
 73    * </p>
 74    *
 75    * @author Luke Taylor
 76    * @version $Id: X509ProcessingFilter.java,v 1.13 2005/11/17 00:56:28 benalex Exp $
 77    */
 78    public class X509ProcessingFilter implements Filter, InitializingBean,
 79    ApplicationEventPublisherAware {
 80    //~ Static fields/initializers =============================================
 81   
 82    private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class);
 83   
 84    //~ Instance fields ========================================================
 85   
 86    private ApplicationEventPublisher eventPublisher;
 87    private AuthenticationManager authenticationManager;
 88   
 89    //~ Methods ================================================================
 90   
 91  0 public void setApplicationEventPublisher(ApplicationEventPublisher context) {
 92  0 this.eventPublisher = context;
 93    }
 94   
 95  3 public void setAuthenticationManager(
 96    AuthenticationManager authenticationManager) {
 97  3 this.authenticationManager = authenticationManager;
 98    }
 99   
 100  3 public void afterPropertiesSet() throws Exception {
 101  3 Assert.notNull(authenticationManager,
 102    "An AuthenticationManager must be set");
 103    }
 104   
 105  2 public void destroy() {}
 106   
 107    /**
 108    * This method first checks for an existing, non-null authentication in the
 109    * secure context. If one is found it does nothing.
 110    *
 111    * <p>
 112    * If no authentication object exists, it attempts to obtain the client
 113    * authentication certificate from the request. If there is no certificate
 114    * present then authentication is skipped. Otherwise a new authentication
 115    * request containing the certificate will be passed to the configured
 116    * {@link AuthenticationManager}.
 117    * </p>
 118    *
 119    * <p>
 120    * If authentication is successful the returned token will be stored in the
 121    * secure context. Otherwise it will be set to null. In either case, the
 122    * request proceeds through the filter chain.
 123    * </p>
 124    *
 125    * @param request DOCUMENT ME!
 126    * @param response DOCUMENT ME!
 127    * @param filterChain DOCUMENT ME!
 128    *
 129    * @throws IOException DOCUMENT ME!
 130    * @throws ServletException DOCUMENT ME!
 131    */
 132  5 public void doFilter(ServletRequest request, ServletResponse response,
 133    FilterChain filterChain) throws IOException, ServletException {
 134  5 if (!(request instanceof HttpServletRequest)) {
 135  1 throw new ServletException("Can only process HttpServletRequest");
 136    }
 137   
 138  4 if (!(response instanceof HttpServletResponse)) {
 139  1 throw new ServletException("Can only process HttpServletResponse");
 140    }
 141   
 142  3 HttpServletRequest httpRequest = (HttpServletRequest) request;
 143  3 HttpServletResponse httpResponse = (HttpServletResponse) response;
 144   
 145  3 if (logger.isDebugEnabled()) {
 146  0 logger.debug("Checking secure context token: "
 147    + SecurityContextHolder.getContext().getAuthentication());
 148    }
 149   
 150  3 if (SecurityContextHolder.getContext().getAuthentication() == null) {
 151  3 Authentication authResult = null;
 152  3 X509Certificate clientCertificate = extractClientCertificate(httpRequest);
 153   
 154  3 try {
 155  3 X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
 156   
 157  3 authRequest.setDetails(new WebAuthenticationDetails(httpRequest));
 158  3 authResult = authenticationManager.authenticate(authRequest);
 159  1 successfulAuthentication(httpRequest, httpResponse, authResult);
 160    } catch (AuthenticationException failed) {
 161  2 unsuccessfulAuthentication(httpRequest, httpResponse, failed);
 162    }
 163    }
 164   
 165  3 filterChain.doFilter(request, response);
 166    }
 167   
 168  2 public void init(FilterConfig ignored) throws ServletException {}
 169   
 170    /**
 171    * Puts the <code>Authentication</code> instance returned by the
 172    * authentication manager into the secure 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  1 protected void successfulAuthentication(HttpServletRequest request,
 181    HttpServletResponse response, Authentication authResult)
 182    throws IOException {
 183  1 if (logger.isDebugEnabled()) {
 184  0 logger.debug("Authentication success: " + authResult);
 185    }
 186   
 187  1 SecurityContextHolder.getContext().setAuthentication(authResult);
 188   
 189    // Fire event
 190  1 if (this.eventPublisher != null) {
 191  0 eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
 192    authResult, this.getClass()));
 193    }
 194    }
 195   
 196    /**
 197    * Ensures the authentication object in the secure context is set to null
 198    * when authentication fails.
 199    *
 200    * @param request DOCUMENT ME!
 201    * @param response DOCUMENT ME!
 202    * @param failed DOCUMENT ME!
 203    */
 204  2 protected void unsuccessfulAuthentication(HttpServletRequest request,
 205    HttpServletResponse response, AuthenticationException failed) {
 206  2 SecurityContextHolder.getContext().setAuthentication(null);
 207   
 208  2 if (logger.isDebugEnabled()) {
 209  0 logger.debug("Updated SecurityContextHolder to contain null Authentication");
 210    }
 211   
 212  2 request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
 213    failed);
 214    }
 215   
 216  3 private X509Certificate extractClientCertificate(HttpServletRequest request) {
 217  3 X509Certificate[] certs = (X509Certificate[]) request.getAttribute(
 218    "javax.servlet.request.X509Certificate");
 219   
 220  3 if ((certs != null) && (certs.length > 0)) {
 221  2 return certs[0];
 222    }
 223   
 224  1 if (logger.isDebugEnabled()) {
 225  0 logger.debug("No client certificate found in request.");
 226    }
 227   
 228  1 return null;
 229    }
 230    }