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: 218   Methods: 8
NCLOC: 103   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
BasicProcessingFilter.java 75% 92.3% 100% 88.9%
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.basicauth;
 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.intercept.web.AuthenticationEntryPoint;
 23    import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 24    import org.acegisecurity.ui.WebAuthenticationDetails;
 25   
 26    import org.apache.commons.codec.binary.Base64;
 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.util.Assert;
 33   
 34    import java.io.IOException;
 35   
 36    import javax.servlet.Filter;
 37    import javax.servlet.FilterChain;
 38    import javax.servlet.FilterConfig;
 39    import javax.servlet.ServletException;
 40    import javax.servlet.ServletRequest;
 41    import javax.servlet.ServletResponse;
 42    import javax.servlet.http.HttpServletRequest;
 43    import javax.servlet.http.HttpServletResponse;
 44   
 45   
 46    /**
 47    * Processes a HTTP request's BASIC authorization headers, putting the result
 48    * into the <code>SecurityContextHolder</code>.
 49    *
 50    * <p>
 51    * For a detailed background on what this filter is designed to process, refer
 52    * to <A HREF="http://www.faqs.org/rfcs/rfc1945.html">RFC 1945, Section
 53    * 11.1</A>. Any realm name presented in the HTTP request is ignored.
 54    * </p>
 55    *
 56    * <p>
 57    * In summary, this filter is responsible for processing any request that has a
 58    * HTTP request header of <code>Authorization</code> with an authentication
 59    * scheme of <code>Basic</code> and a Base64-encoded
 60    * <code>username:password</code> token. For example, to authenticate user
 61    * "Aladdin" with password "open sesame" the following header would be
 62    * presented:
 63    * </p>
 64    *
 65    * <p>
 66    * <code>Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==</code>.
 67    * </p>
 68    *
 69    * <p>
 70    * This filter can be used to provide BASIC authentication services to both
 71    * remoting protocol clients (such as Hessian and SOAP) as well as standard
 72    * user agents (such as Internet Explorer and Netscape).
 73    * </p>
 74    *
 75    * <P>
 76    * If authentication is successful, the resulting {@link Authentication} object
 77    * will be placed into the <code>SecurityContextHolder</code>.
 78    * </p>
 79    *
 80    * <p>
 81    * If authentication fails, an {@link AuthenticationEntryPoint} implementation
 82    * is called. Usually this should be {@link BasicProcessingFilterEntryPoint},
 83    * which will prompt the user to authenticate again via BASIC authentication.
 84    * </p>
 85    *
 86    * <p>
 87    * Basic authentication is an attractive protocol because it is simple and
 88    * widely deployed. However, it still transmits a password in clear text and
 89    * as such is undesirable in many situations. Digest authentication is also
 90    * provided by Acegi Security and should be used instead of Basic
 91    * authentication wherever possible. See {@link
 92    * org.acegisecurity.ui.digestauth.DigestProcessingFilter}.
 93    * </p>
 94    *
 95    * <p>
 96    * <b>Do not use this class directly.</b> Instead configure
 97    * <code>web.xml</code> to use the {@link
 98    * org.acegisecurity.util.FilterToBeanProxy}.
 99    * </p>
 100    *
 101    * @author Ben Alex
 102    * @version $Id: BasicProcessingFilter.java,v 1.16 2005/11/17 00:56:48 benalex Exp $
 103    */
 104    public class BasicProcessingFilter implements Filter, InitializingBean {
 105    //~ Static fields/initializers =============================================
 106   
 107    private static final Log logger = LogFactory.getLog(BasicProcessingFilter.class);
 108   
 109    //~ Instance fields ========================================================
 110   
 111    private AuthenticationEntryPoint authenticationEntryPoint;
 112    private AuthenticationManager authenticationManager;
 113   
 114    //~ Methods ================================================================
 115   
 116  8 public void setAuthenticationEntryPoint(
 117    AuthenticationEntryPoint authenticationEntryPoint) {
 118  8 this.authenticationEntryPoint = authenticationEntryPoint;
 119    }
 120   
 121  1 public AuthenticationEntryPoint getAuthenticationEntryPoint() {
 122  1 return authenticationEntryPoint;
 123    }
 124   
 125  8 public void setAuthenticationManager(
 126    AuthenticationManager authenticationManager) {
 127  8 this.authenticationManager = authenticationManager;
 128    }
 129   
 130  1 public AuthenticationManager getAuthenticationManager() {
 131  1 return authenticationManager;
 132    }
 133   
 134  8 public void afterPropertiesSet() throws Exception {
 135  8 Assert.notNull(this.authenticationManager,
 136    "An AuthenticationManager is required");
 137  7 Assert.notNull(this.authenticationEntryPoint,
 138    "An AuthenticationEntryPoint is required");
 139    }
 140   
 141  7 public void destroy() {}
 142   
 143  9 public void doFilter(ServletRequest request, ServletResponse response,
 144    FilterChain chain) throws IOException, ServletException {
 145  9 if (!(request instanceof HttpServletRequest)) {
 146  1 throw new ServletException("Can only process HttpServletRequest");
 147    }
 148   
 149  8 if (!(response instanceof HttpServletResponse)) {
 150  1 throw new ServletException("Can only process HttpServletResponse");
 151    }
 152   
 153  7 HttpServletRequest httpRequest = (HttpServletRequest) request;
 154   
 155  7 String header = httpRequest.getHeader("Authorization");
 156   
 157  7 if (logger.isDebugEnabled()) {
 158  0 logger.debug("Authorization header: " + header);
 159    }
 160   
 161  7 if ((header != null) && header.startsWith("Basic ")) {
 162  5 String base64Token = header.substring(6);
 163  5 String token = new String(Base64.decodeBase64(
 164    base64Token.getBytes()));
 165   
 166  5 String username = "";
 167  5 String password = "";
 168  5 int delim = token.indexOf(":");
 169   
 170  5 if (delim != -1) {
 171  4 username = token.substring(0, delim);
 172  4 password = token.substring(delim + 1);
 173    }
 174   
 175    // Only reauthenticate if username doesn't match SecurityContextHolder and user isn't authenticated (see SEC-53)
 176  5 Authentication existingAuth = SecurityContextHolder.getContext()
 177    .getAuthentication();
 178   
 179  5 if ((existingAuth == null)
 180    || !existingAuth.getName().equals(username)
 181    || !existingAuth.isAuthenticated()) {
 182  5 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
 183    password);
 184  5 authRequest.setDetails(new WebAuthenticationDetails(
 185    httpRequest, false));
 186   
 187  5 Authentication authResult;
 188   
 189  5 try {
 190  5 authResult = authenticationManager.authenticate(authRequest);
 191    } catch (AuthenticationException failed) {
 192    // Authentication failed
 193  3 if (logger.isDebugEnabled()) {
 194  0 logger.debug("Authentication request for user: "
 195    + username + " failed: " + failed.toString());
 196    }
 197   
 198  3 SecurityContextHolder.getContext().setAuthentication(null);
 199  3 authenticationEntryPoint.commence(request, response, failed);
 200   
 201  3 return;
 202    }
 203   
 204    // Authentication success
 205  2 if (logger.isDebugEnabled()) {
 206  0 logger.debug("Authentication success: "
 207    + authResult.toString());
 208    }
 209   
 210  2 SecurityContextHolder.getContext().setAuthentication(authResult);
 211    }
 212    }
 213   
 214  4 chain.doFilter(request, response);
 215    }
 216   
 217  7 public void init(FilterConfig arg0) throws ServletException {}
 218    }