Coverage Report - org.acegisecurity.ui.ExceptionTranslationFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
ExceptionTranslationFilter
79% 
100% 
2.333
 
 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;
 17  
 
 18  
 import org.acegisecurity.AccessDeniedException;
 19  
 import org.acegisecurity.AcegiSecurityException;
 20  
 import org.acegisecurity.AuthenticationException;
 21  
 import org.acegisecurity.AuthenticationTrustResolver;
 22  
 import org.acegisecurity.AuthenticationTrustResolverImpl;
 23  
 import org.acegisecurity.InsufficientAuthenticationException;
 24  
 
 25  
 import org.acegisecurity.context.SecurityContextHolder;
 26  
 
 27  
 import org.acegisecurity.ui.savedrequest.SavedRequest;
 28  
 
 29  
 import org.acegisecurity.util.PortResolver;
 30  
 import org.acegisecurity.util.PortResolverImpl;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 
 35  
 import org.springframework.beans.factory.InitializingBean;
 36  
 import org.springframework.context.ApplicationContext;
 37  
 
 38  
 import org.springframework.util.Assert;
 39  
 
 40  
 import java.io.IOException;
 41  
 import java.util.Map;
 42  
 
 43  
 import javax.servlet.Filter;
 44  
 import javax.servlet.FilterChain;
 45  
 import javax.servlet.FilterConfig;
 46  
 import javax.servlet.ServletException;
 47  
 import javax.servlet.ServletRequest;
 48  
 import javax.servlet.ServletResponse;
 49  
 import javax.servlet.http.HttpServletRequest;
 50  
 import javax.servlet.http.HttpServletResponse;
 51  
 
 52  
 /**
 53  
  * Handles any <code>AccessDeniedException</code> and <code>AuthenticationException</code> thrown within the
 54  
  * filter chain.
 55  
  * <p>
 56  
  * This filter is necessary because it provides the bridge between Java exceptions and HTTP responses.
 57  
  * It is solely concerned with maintaining the user interface. This filter does not do any actual security enforcement.
 58  
  * </p>
 59  
  * <p>
 60  
  * If an {@link AuthenticationException} is detected, the filter will launch the <code>authenticationEntryPoint</code>.
 61  
  * This allows common handling of authentication failures originating from any subclass of
 62  
  * {@link org.acegisecurity.intercept.AbstractSecurityInterceptor}.
 63  
  * </p>
 64  
  * <p>
 65  
  * If an {@link AccessDeniedException} is detected, the filter will determine whether or not the user is an anonymous
 66  
  * user. If they are an anonymous user, the <code>authenticationEntryPoint</code> will be launched. If they are not
 67  
  * an anonymous user, the filter will delegate to the {@link org.acegisecurity.ui.AccessDeniedHandler}.
 68  
  * By default the filter will use {@link org.acegisecurity.ui.AccessDeniedHandlerImpl}.
 69  
  * </p>
 70  
  * <p>
 71  
  * To use this filter, it is necessary to specify the following properties:
 72  
  * </p>
 73  
  * <ul>
 74  
  * <li><code>authenticationEntryPoint</code> indicates the handler that
 75  
  * should commence the authentication process if an
 76  
  * <code>AuthenticationException</code> is detected. Note that this may also
 77  
  * switch the current protocol from http to https for an SSL login.</li>
 78  
  * <li><code>portResolver</code> is used to determine the "real" port that a
 79  
  * request was received on.</li>
 80  
  * </ul>
 81  
  * <P>
 82  
  * <B>Do not use this class directly.</B> Instead configure
 83  
  * <code>web.xml</code> to use the {@link
 84  
  * org.acegisecurity.util.FilterToBeanProxy}.
 85  
  * </p>
 86  
  *
 87  
  * @author Ben Alex
 88  
  * @author colin sampaleanu
 89  
  * @version $Id: ExceptionTranslationFilter.java 2134 2007-09-19 16:41:06Z luke_t $
 90  
  */
 91  13
 public class ExceptionTranslationFilter implements Filter, InitializingBean {
 92  
 
 93  
     //~ Static fields/initializers =====================================================================================
 94  
 
 95  2
         private static final Log logger = LogFactory.getLog(ExceptionTranslationFilter.class);
 96  
 
 97  
         //~ Instance fields ================================================================================================
 98  
 
 99  13
     private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
 100  
         private AuthenticationEntryPoint authenticationEntryPoint;
 101  13
         private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
 102  13
         private PortResolver portResolver = new PortResolverImpl();
 103  13
         private boolean createSessionAllowed = true;
 104  
 
 105  
         //~ Methods ========================================================================================================
 106  
 
 107  
         public void afterPropertiesSet() throws Exception {
 108  2
                 Assert.notNull(authenticationEntryPoint, "authenticationEntryPoint must be specified");
 109  1
                 Assert.notNull(portResolver, "portResolver must be specified");
 110  0
                 Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver must be specified");
 111  0
         }
 112  
 
 113  
         public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
 114  
                         ServletException {
 115  9
                 if (!(request instanceof HttpServletRequest)) {
 116  1
                         throw new ServletException("HttpServletRequest required");
 117  
                 }
 118  
 
 119  8
                 if (!(response instanceof HttpServletResponse)) {
 120  1
                         throw new ServletException("HttpServletResponse required");
 121  
                 }
 122  
 
 123  
                 try {
 124  7
                         chain.doFilter(request, response);
 125  
 
 126  1
                         if (logger.isDebugEnabled()) {
 127  0
                                 logger.debug("Chain processed normally");
 128  
                         }
 129  
                 }
 130  2
                 catch (AuthenticationException ex) {
 131  2
                         handleException(request, response, chain, ex);
 132  
                 }
 133  2
                 catch (AccessDeniedException ex) {
 134  2
                         handleException(request, response, chain, ex);
 135  
                 }
 136  1
                 catch (ServletException ex) {
 137  1
                         if (ex.getRootCause() instanceof AuthenticationException
 138  
                                         || ex.getRootCause() instanceof AccessDeniedException) {
 139  0
                                 handleException(request, response, chain, (AcegiSecurityException) ex.getRootCause());
 140  
                         }
 141  
                         else {
 142  1
                                 throw ex;
 143  
                         }
 144  
                 }
 145  1
                 catch (IOException ex) {
 146  1
                         throw ex;
 147  5
                 }
 148  5
         }
 149  
 
 150  
         public AuthenticationEntryPoint getAuthenticationEntryPoint() {
 151  1
                 return authenticationEntryPoint;
 152  
         }
 153  
 
 154  
         public AuthenticationTrustResolver getAuthenticationTrustResolver() {
 155  0
                 return authenticationTrustResolver;
 156  
         }
 157  
 
 158  
         public PortResolver getPortResolver() {
 159  1
                 return portResolver;
 160  
         }
 161  
 
 162  
         private void handleException(ServletRequest request, ServletResponse response, FilterChain chain,
 163  
                         AcegiSecurityException exception) throws IOException, ServletException {
 164  4
                 if (exception instanceof AuthenticationException) {
 165  2
                         if (logger.isDebugEnabled()) {
 166  0
                                 logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);
 167  
                         }
 168  
 
 169  2
                         sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
 170  
                 }
 171  2
                 else if (exception instanceof AccessDeniedException) {
 172  2
                         if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
 173  1
                                 if (logger.isDebugEnabled()) {
 174  0
                                         logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
 175  
                                                         exception);
 176  
                                 }
 177  
 
 178  1
                                 sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException(
 179  
                                                 "Full authentication is required to access this resource"));
 180  
                         }
 181  
                         else {
 182  1
                                 if (logger.isDebugEnabled()) {
 183  0
                                         logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler",
 184  
                                                         exception);
 185  
                                 }
 186  
 
 187  1
                                 accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
 188  
                         }
 189  
                 }
 190  4
         }
 191  
 
 192  
         /**
 193  
          * If <code>true</code>, indicates that <code>SecurityEnforcementFilter</code> is permitted to store the target
 194  
          * URL and exception information in the <code>HttpSession</code> (the default).
 195  
      * In situations where you do not wish to unnecessarily create <code>HttpSession</code>s - because the user agent
 196  
      * will know the failed URL, such as with BASIC or Digest authentication - you may wish to
 197  
          * set this property to <code>false</code>. Remember to also set the
 198  
          * {@link org.acegisecurity.context.HttpSessionContextIntegrationFilter#allowSessionCreation}
 199  
          * to <code>false</code> if you set this property to <code>false</code>.
 200  
          *
 201  
          * @return <code>true</code> if the <code>HttpSession</code> will be
 202  
          * used to store information about the failed request, <code>false</code>
 203  
          * if the <code>HttpSession</code> will not be used
 204  
          */
 205  
         public boolean isCreateSessionAllowed() {
 206  0
                 return createSessionAllowed;
 207  
         }
 208  
 
 209  
         protected void sendStartAuthentication(ServletRequest request, ServletResponse response, FilterChain chain,
 210  
                         AuthenticationException reason) throws ServletException, IOException {
 211  3
                 HttpServletRequest httpRequest = (HttpServletRequest) request;
 212  
 
 213  3
                 SavedRequest savedRequest = new SavedRequest(httpRequest, portResolver);
 214  
 
 215  3
                 if (logger.isDebugEnabled()) {
 216  0
                         logger.debug("Authentication entry point being called; SavedRequest added to Session: " + savedRequest);
 217  
                 }
 218  
 
 219  3
                 if (createSessionAllowed) {
 220  
                         // Store the HTTP request itself. Used by AbstractProcessingFilter
 221  
                         // for redirection after successful authentication (SEC-29)
 222  3
                         httpRequest.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY, savedRequest);
 223  
                 }
 224  
 
 225  
                 // SEC-112: Clear the SecurityContextHolder's Authentication, as the
 226  
                 // existing Authentication is no longer considered valid
 227  3
                 SecurityContextHolder.getContext().setAuthentication(null);
 228  
 
 229  3
                 authenticationEntryPoint.commence(httpRequest, (HttpServletResponse) response, reason);
 230  3
         }
 231  
 
 232  
         public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
 233  1
                 Assert.notNull(accessDeniedHandler, "AccessDeniedHandler required");
 234  1
                 this.accessDeniedHandler = accessDeniedHandler;
 235  1
         }
 236  
 
 237  
         public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
 238  9
                 this.authenticationEntryPoint = authenticationEntryPoint;
 239  9
         }
 240  
 
 241  
         public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
 242  0
                 this.authenticationTrustResolver = authenticationTrustResolver;
 243  0
         }
 244  
 
 245  
         public void setCreateSessionAllowed(boolean createSessionAllowed) {
 246  0
                 this.createSessionAllowed = createSessionAllowed;
 247  0
         }
 248  
 
 249  
         public void setPortResolver(PortResolver portResolver) {
 250  4
                 this.portResolver = portResolver;
 251  4
         }
 252  
 
 253  
     public void init(FilterConfig filterConfig) throws ServletException {
 254  1
     }
 255  
 
 256  
     public void destroy() {
 257  1
     }    
 258  
 }