1 7 package winstone.auth; 8 9 import java.io.IOException ; 10 import java.io.UnsupportedEncodingException ; 11 import java.security.MessageDigest ; 12 import java.security.NoSuchAlgorithmException ; 13 import java.util.List ; 14 import java.util.Random ; 15 import java.util.Set ; 16 import java.util.StringTokenizer ; 17 18 import javax.servlet.http.HttpServletRequest ; 19 import javax.servlet.http.HttpServletRequestWrapper ; 20 import javax.servlet.http.HttpServletResponse ; 21 22 import org.w3c.dom.Node ; 23 24 import winstone.AuthenticationPrincipal; 25 import winstone.AuthenticationRealm; 26 import winstone.Logger; 27 import winstone.WinstoneRequest; 28 import winstone.WinstoneResourceBundle; 29 30 37 public class DigestAuthenticationHandler extends BaseAuthenticationHandler { 38 private MessageDigest md5Digester; 39 40 public DigestAuthenticationHandler(Node loginConfigNode, 41 List constraintNodes, Set rolesAllowed, 42 AuthenticationRealm realm) throws NoSuchAlgorithmException { 43 super(loginConfigNode, constraintNodes, rolesAllowed, realm); 44 this.md5Digester = MessageDigest.getInstance("MD5"); 45 Logger.log(Logger.DEBUG, AUTH_RESOURCES, 46 "DigestAuthenticationHandler.Initialised", realmName); 47 } 48 49 52 protected void requestAuthentication(HttpServletRequest request, 53 HttpServletResponse response, String pathRequested) 54 throws IOException { 55 String oneTimeToken = "WinstoneToken:" 57 + (new Random ().nextDouble() * System.currentTimeMillis()); 58 59 String authHeader = "Digest realm=\"" + this.realmName 61 + "\", qop=\"auth\", " + "nonce=\"" + oneTimeToken 62 + "\", opaque=\"" + md5Encode(oneTimeToken) + "\""; 63 response.setHeader("WWW-Authenticate", authHeader); 64 65 response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_RESOURCES 67 .getString("DigestAuthenticationHandler.UnauthorizedMessage")); 68 } 69 70 76 protected boolean validatePossibleAuthenticationResponse( 77 HttpServletRequest request, HttpServletResponse response, 78 String pathRequested) throws IOException { 79 String authorization = request.getHeader("Authorization"); 80 if (authorization == null) 81 return true; 82 83 if (!authorization.startsWith("Digest")) 85 return true; 86 87 String userName = null; 89 String realm = null; 90 String qop = null; 91 String algorithm = null; 92 String uri = null; 93 String nOnce = null; 94 String nc = null; 95 String cnOnce = null; 96 String clientResponseDigest = null; 97 98 StringTokenizer st = new StringTokenizer (authorization.substring(6) 99 .trim(), ","); 100 while (st.hasMoreTokens()) { 101 String token = st.nextToken().trim(); 102 int equalPos = token.indexOf('='); 103 String paramName = token.substring(0, equalPos); 104 if (paramName.equals("username")) 105 userName = WinstoneResourceBundle.globalReplace(token 106 .substring(equalPos + 1).trim(), "\"", ""); 107 else if (paramName.equals("realm")) 108 realm = WinstoneResourceBundle.globalReplace(token.substring( 109 equalPos + 1).trim(), "\"", ""); 110 else if (paramName.equals("qop")) 111 qop = WinstoneResourceBundle.globalReplace(token.substring( 112 equalPos + 1).trim(), "\"", ""); 113 else if (paramName.equals("algorithm")) 114 algorithm = WinstoneResourceBundle.globalReplace(token 115 .substring(equalPos + 1).trim(), "\"", ""); 116 else if (paramName.equals("uri")) 117 uri = WinstoneResourceBundle.globalReplace(token.substring( 118 equalPos + 1).trim(), "\"", ""); 119 else if (paramName.equals("nonce")) 120 nOnce = WinstoneResourceBundle.globalReplace(token.substring( 121 equalPos + 1).trim(), "\"", ""); 122 else if (paramName.equals("nc")) 123 nc = WinstoneResourceBundle.globalReplace(token.substring( 124 equalPos + 1).trim(), "\"", ""); 125 else if (paramName.equals("cnonce")) 126 cnOnce = WinstoneResourceBundle.globalReplace(token.substring( 127 equalPos + 1).trim(), "\"", ""); 128 else if (paramName.equals("response")) 129 clientResponseDigest = WinstoneResourceBundle.globalReplace( 130 token.substring(equalPos + 1).trim(), "\"", ""); 131 } 132 133 if ((userName == null) || (realm == null) || (qop == null) 135 || (uri == null) || (nOnce == null) || (nc == null) 136 || (cnOnce == null) || (clientResponseDigest == null)) 137 return true; 138 else if ((algorithm != null) && !algorithm.equals("MD5")) 139 return true; 140 141 AuthenticationPrincipal principal = this.realm.retrieveUser(userName); 143 if (principal == null) 144 return true; 145 146 String userRealmPasswordDigest = md5Encode(userName + ":" + realm + ":" 148 + principal.getPassword()); 149 String methodURIDigest = md5Encode(request.getMethod() + ":" + uri); 150 String serverResponseDigest = md5Encode(userRealmPasswordDigest + ":" 151 + nOnce + ":" + nc + ":" + cnOnce + ":" + qop + ":" 152 + methodURIDigest); 153 if (serverResponseDigest.equals(clientResponseDigest)) { 154 principal.setAuthType(HttpServletRequest.DIGEST_AUTH); 155 if (request instanceof WinstoneRequest) 156 ((WinstoneRequest) request).setRemoteUser(principal); 157 else if (request instanceof HttpServletRequestWrapper ) { 158 HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper ) request; 159 if (wrapper.getRequest() instanceof WinstoneRequest) 160 ((WinstoneRequest) wrapper.getRequest()) 161 .setRemoteUser(principal); 162 else 163 Logger.log(Logger.WARNING, AUTH_RESOURCES, 164 "DigestAuthenticationHandler.CantSetUser", wrapper 165 .getRequest().getClass().getName()); 166 } else 167 Logger.log(Logger.WARNING, AUTH_RESOURCES, 168 "DigestAuthenticationHandler.CantSetUser", request 169 .getClass().getName()); 170 } 171 return true; 172 } 173 174 179 public String md5Encode(String input) throws UnsupportedEncodingException { 180 byte digestBytes[] = this.md5Digester.digest(input.getBytes("8859_1")); 182 183 char outArray[] = new char[32]; 185 for (int n = 0; n < digestBytes.length; n++) { 186 int hiNibble = (digestBytes[n] & 0xFF) >> 4; 187 int loNibble = (digestBytes[n] & 0xF); 188 outArray[2 * n] = (hiNibble > 9 ? (char) (hiNibble + 87) 189 : (char) (hiNibble + 48)); 190 outArray[2 * n + 1] = (loNibble > 9 ? (char) (loNibble + 87) 191 : (char) (loNibble + 48)); 192 } 193 return new String (outArray); 194 } 195 } 196 | Popular Tags |