Coverage Report - org.acegisecurity.ui.digestauth.DigestProcessingFilterEntryPoint
 
Classes in this File Line Coverage Branch Coverage Complexity
DigestProcessingFilterEntryPoint
88% 
100% 
1.6
 
 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.digestauth;
 17  
 
 18  
 import java.io.IOException;
 19  
 
 20  
 import javax.servlet.ServletException;
 21  
 import javax.servlet.ServletRequest;
 22  
 import javax.servlet.ServletResponse;
 23  
 import javax.servlet.http.HttpServletResponse;
 24  
 
 25  
 import org.acegisecurity.AuthenticationException;
 26  
 import org.acegisecurity.ui.AuthenticationEntryPoint;
 27  
 import org.apache.commons.codec.binary.Base64;
 28  
 import org.apache.commons.codec.digest.DigestUtils;
 29  
 import org.apache.commons.logging.Log;
 30  
 import org.apache.commons.logging.LogFactory;
 31  
 import org.springframework.beans.factory.InitializingBean;
 32  
 import org.springframework.core.Ordered;
 33  
 
 34  
 
 35  
 /**
 36  
  * Used by the <code>SecurityEnforcementFilter</code> to commence authentication via the {@link
 37  
  * DigestProcessingFilter}.<p>The nonce sent back to the user agent will be valid for the period indicated by
 38  
  * {@link #setNonceValiditySeconds(int)}. By default this is 300 seconds. Shorter times should be used if replay
 39  
  * attacks are a major concern. Larger values can be used if performance is a greater concern. This class correctly
 40  
  * presents the <code>stale=true</code> header when the nonce has expierd, so properly implemented user agents will
 41  
  * automatically renegotiate with a new nonce value (ie without presenting a new password dialog box to the user).</p>
 42  
  *
 43  
  * @author Ben Alex
 44  
  * @version $Id: DigestProcessingFilterEntryPoint.java 1822 2007-05-17 12:20:16Z vishalpuri $
 45  
  */
 46  28
 public class DigestProcessingFilterEntryPoint implements AuthenticationEntryPoint, InitializingBean, Ordered {
 47  
     //~ Static fields/initializers =====================================================================================
 48  
 
 49  2
     private static final Log logger = LogFactory.getLog(DigestProcessingFilterEntryPoint.class);
 50  
 
 51  
     //~ Instance fields ================================================================================================
 52  
 
 53  
     private String key;
 54  
     private String realmName;
 55  28
     private int nonceValiditySeconds = 300;
 56  28
     private int order = Integer.MAX_VALUE; // ~ default
 57  
 
 58  
     //~ Methods ========================================================================================================
 59  
 
 60  
     public int getOrder() {
 61  0
                 return order;
 62  
         }
 63  
 
 64  
         public void setOrder(int order) {
 65  0
                 this.order = order;
 66  0
         }
 67  
 
 68  
         public void afterPropertiesSet() throws Exception {
 69  4
         if ((realmName == null) || "".equals(realmName)) {
 70  1
             throw new IllegalArgumentException("realmName must be specified");
 71  
         }
 72  
 
 73  3
         if ((key == null) || "".equals(key)) {
 74  1
             throw new IllegalArgumentException("key must be specified");
 75  
         }
 76  2
     }
 77  
 
 78  
     public void commence(ServletRequest request, ServletResponse response, AuthenticationException authException)
 79  
         throws IOException, ServletException {
 80  14
         HttpServletResponse httpResponse = (HttpServletResponse) response;
 81  
 
 82  
         // compute a nonce (do not use remote IP address due to proxy farms)
 83  
         // format of nonce is:  
 84  
         //   base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
 85  14
         long expiryTime = System.currentTimeMillis() + (nonceValiditySeconds * 1000);
 86  14
         String signatureValue = new String(DigestUtils.md5Hex(expiryTime + ":" + key));
 87  14
         String nonceValue = expiryTime + ":" + signatureValue;
 88  14
         String nonceValueBase64 = new String(Base64.encodeBase64(nonceValue.getBytes()));
 89  
 
 90  
         // qop is quality of protection, as defined by RFC 2617.
 91  
         // we do not use opaque due to IE violation of RFC 2617 in not
 92  
         // representing opaque on subsequent requests in same session.
 93  14
         String authenticateHeader = "Digest realm=\"" + realmName + "\", " + "qop=\"auth\", nonce=\""
 94  
             + nonceValueBase64 + "\"";
 95  
 
 96  14
         if (authException instanceof NonceExpiredException) {
 97  2
             authenticateHeader = authenticateHeader + ", stale=\"true\"";
 98  
         }
 99  
 
 100  14
         if (logger.isDebugEnabled()) {
 101  0
             logger.debug("WWW-Authenticate header sent to user agent: " + authenticateHeader);
 102  
         }
 103  
 
 104  14
         httpResponse.addHeader("WWW-Authenticate", authenticateHeader);
 105  14
         httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
 106  14
     }
 107  
 
 108  
     public String getKey() {
 109  10
         return key;
 110  
     }
 111  
 
 112  
     public int getNonceValiditySeconds() {
 113  2
         return nonceValiditySeconds;
 114  
     }
 115  
 
 116  
     public String getRealmName() {
 117  15
         return realmName;
 118  
     }
 119  
 
 120  
     public void setKey(String key) {
 121  25
         this.key = key;
 122  25
     }
 123  
 
 124  
     public void setNonceValiditySeconds(int nonceValiditySeconds) {
 125  2
         this.nonceValiditySeconds = nonceValiditySeconds;
 126  2
     }
 127  
 
 128  
     public void setRealmName(String realmName) {
 129  25
         this.realmName = realmName;
 130  25
     }
 131  
 }