1 17 18 19 package org.apache.catalina.authenticator; 20 21 22 import java.io.IOException ; 23 import java.security.MessageDigest ; 24 import java.security.NoSuchAlgorithmException ; 25 import java.security.Principal ; 26 import java.util.StringTokenizer ; 27 28 import javax.servlet.http.HttpServletResponse ; 29 30 31 import org.apache.catalina.Realm; 32 import org.apache.catalina.connector.Request; 33 import org.apache.catalina.connector.Response; 34 import org.apache.catalina.deploy.LoginConfig; 35 import org.apache.catalina.util.MD5Encoder; 36 import org.apache.commons.logging.Log; 37 import org.apache.commons.logging.LogFactory; 38 39 40 41 49 50 public class DigestAuthenticator 51 extends AuthenticatorBase { 52 private static Log log = LogFactory.getLog(DigestAuthenticator.class); 53 54 55 57 60 protected static final MD5Encoder md5Encoder = new MD5Encoder(); 61 62 63 66 protected static final String info = 67 "org.apache.catalina.authenticator.DigestAuthenticator/1.0"; 68 69 70 72 73 public DigestAuthenticator() { 74 super(); 75 try { 76 if (md5Helper == null) 77 md5Helper = MessageDigest.getInstance("MD5"); 78 } catch (NoSuchAlgorithmException e) { 79 e.printStackTrace(); 80 throw new IllegalStateException (); 81 } 82 } 83 84 85 87 88 91 protected static MessageDigest md5Helper; 92 93 94 97 protected String key = "Catalina"; 98 99 100 102 103 106 public String getInfo() { 107 108 return (info); 109 110 } 111 112 113 115 116 129 public boolean authenticate(Request request, 130 Response response, 131 LoginConfig config) 132 throws IOException { 133 134 Principal principal = request.getUserPrincipal(); 136 if (principal != null) { 138 if (log.isDebugEnabled()) 139 log.debug("Already authenticated '" + principal.getName() + "'"); 140 String ssoId = (String ) request.getNote(Constants.REQ_SSOID_NOTE); 143 if (ssoId != null) 144 associate(ssoId, request.getSessionInternal(true)); 145 return (true); 146 } 147 148 172 173 String authorization = request.getHeader("authorization"); 175 if (authorization != null) { 176 principal = findPrincipal(request, authorization, context.getRealm()); 177 if (principal != null) { 178 String username = parseUsername(authorization); 179 register(request, response, principal, 180 Constants.DIGEST_METHOD, 181 username, null); 182 return (true); 183 } 184 } 185 186 188 String nOnce = generateNOnce(request); 191 192 setAuthenticateHeader(request, response, config, nOnce); 193 response.sendError(HttpServletResponse.SC_UNAUTHORIZED); 194 return (false); 196 197 } 198 199 200 202 203 213 protected static Principal findPrincipal(Request request, 214 String authorization, 215 Realm realm) { 216 217 if (authorization == null) 220 return (null); 221 if (!authorization.startsWith("Digest ")) 222 return (null); 223 authorization = authorization.substring(7).trim(); 224 225 String [] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)"); 227 228 String userName = null; 229 String realmName = null; 230 String nOnce = null; 231 String nc = null; 232 String cnonce = null; 233 String qop = null; 234 String uri = null; 235 String response = null; 236 String method = request.getMethod(); 237 238 for (int i = 0; i < tokens.length; i++) { 239 String currentToken = tokens[i]; 240 if (currentToken.length() == 0) 241 continue; 242 243 int equalSign = currentToken.indexOf('='); 244 if (equalSign < 0) 245 return null; 246 String currentTokenName = 247 currentToken.substring(0, equalSign).trim(); 248 String currentTokenValue = 249 currentToken.substring(equalSign + 1).trim(); 250 if ("username".equals(currentTokenName)) 251 userName = removeQuotes(currentTokenValue); 252 if ("realm".equals(currentTokenName)) 253 realmName = removeQuotes(currentTokenValue, true); 254 if ("nonce".equals(currentTokenName)) 255 nOnce = removeQuotes(currentTokenValue); 256 if ("nc".equals(currentTokenName)) 257 nc = removeQuotes(currentTokenValue); 258 if ("cnonce".equals(currentTokenName)) 259 cnonce = removeQuotes(currentTokenValue); 260 if ("qop".equals(currentTokenName)) 261 qop = removeQuotes(currentTokenValue); 262 if ("uri".equals(currentTokenName)) 263 uri = removeQuotes(currentTokenValue); 264 if ("response".equals(currentTokenName)) 265 response = removeQuotes(currentTokenValue); 266 } 267 268 if ( (userName == null) || (realmName == null) || (nOnce == null) 269 || (uri == null) || (response == null) ) 270 return null; 271 272 String a2 = method + ":" + uri; 275 277 byte[] buffer = null; 278 synchronized (md5Helper) { 279 buffer = md5Helper.digest(a2.getBytes()); 280 } 281 String md5a2 = md5Encoder.encode(buffer); 282 283 return (realm.authenticate(userName, response, nOnce, nc, cnonce, qop, 284 realmName, md5a2)); 285 286 } 287 288 289 295 protected String parseUsername(String authorization) { 296 297 if (authorization == null) 300 return (null); 301 if (!authorization.startsWith("Digest ")) 302 return (null); 303 authorization = authorization.substring(7).trim(); 304 305 StringTokenizer commaTokenizer = 306 new StringTokenizer (authorization, ","); 307 308 while (commaTokenizer.hasMoreTokens()) { 309 String currentToken = commaTokenizer.nextToken(); 310 int equalSign = currentToken.indexOf('='); 311 if (equalSign < 0) 312 return null; 313 String currentTokenName = 314 currentToken.substring(0, equalSign).trim(); 315 String currentTokenValue = 316 currentToken.substring(equalSign + 1).trim(); 317 if ("username".equals(currentTokenName)) 318 return (removeQuotes(currentTokenValue)); 319 } 320 321 return (null); 322 323 } 324 325 326 330 protected static String removeQuotes(String quotedString, 331 boolean quotesRequired) { 332 if (quotedString.length() > 0 && quotedString.charAt(0) != '"' && 334 !quotesRequired) { 335 return quotedString; 336 } else if (quotedString.length() > 2) { 337 return quotedString.substring(1, quotedString.length() - 1); 338 } else { 339 return new String (); 340 } 341 } 342 343 346 protected static String removeQuotes(String quotedString) { 347 return removeQuotes(quotedString, false); 348 } 349 350 357 protected String generateNOnce(Request request) { 358 359 long currentTime = System.currentTimeMillis(); 360 361 String nOnceValue = request.getRemoteAddr() + ":" + 362 currentTime + ":" + key; 363 364 byte[] buffer = null; 365 synchronized (md5Helper) { 366 buffer = md5Helper.digest(nOnceValue.getBytes()); 367 } 368 nOnceValue = md5Encoder.encode(buffer); 369 370 return nOnceValue; 371 } 372 373 374 401 protected void setAuthenticateHeader(Request request, 402 Response response, 403 LoginConfig config, 404 String nOnce) { 405 406 String realmName = config.getRealmName(); 408 if (realmName == null) 409 realmName = request.getServerName() + ":" 410 + request.getServerPort(); 411 412 byte[] buffer = null; 413 synchronized (md5Helper) { 414 buffer = md5Helper.digest(nOnce.getBytes()); 415 } 416 417 String authenticateHeader = "Digest realm=\"" + realmName + "\", " 418 + "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\"" 419 + md5Encoder.encode(buffer) + "\""; 420 response.setHeader("WWW-Authenticate", authenticateHeader); 421 422 } 423 424 425 } 426 | Popular Tags |