/** * Generate a unique token. The token is generated according to the following pattern. NOnceToken * = Base64 ( MD5 ( client-IP ":" time-stamp ":" private-key ) ). * * @param request HTTP Servlet request */ protected String generateNonce(Request request) { long currentTime = System.currentTimeMillis(); synchronized (lastTimestampLock) { if (currentTime > lastTimestamp) { lastTimestamp = currentTime; } else { currentTime = ++lastTimestamp; } } String ipTimeKey = request.getRemoteAddr() + ":" + currentTime + ":" + getKey(); byte[] buffer = ConcurrentMessageDigest.digestMD5(ipTimeKey.getBytes(StandardCharsets.ISO_8859_1)); String nonce = currentTime + ":" + MD5Encoder.encode(buffer); NonceInfo info = new NonceInfo(currentTime, getNonceCountWindowSize()); synchronized (nonces) { nonces.put(nonce, info); } return nonce; }
public Principal authenticate(Realm realm) { // Second MD5 digest used to calculate the digest : // MD5(Method + ":" + uri) String a2 = method + ":" + uri; byte[] buffer = ConcurrentMessageDigest.digestMD5(a2.getBytes(StandardCharsets.ISO_8859_1)); String md5a2 = MD5Encoder.encode(buffer); return realm.authenticate(userName, response, nonce, nc, cnonce, qop, realmName, md5a2); }
public boolean validate(Request request) { if ((userName == null) || (realmName == null) || (nonce == null) || (uri == null) || (response == null)) { return false; } // Validate the URI - should match the request line sent by client if (validateUri) { String uriQuery; String query = request.getQueryString(); if (query == null) { uriQuery = request.getRequestURI(); } else { uriQuery = request.getRequestURI() + "?" + query; } if (!uri.equals(uriQuery)) { // Some clients (older Android) use an absolute URI for // DIGEST but a relative URI in the request line. // request. 2.3.5 < fixed Android version <= 4.0.3 String host = request.getHeader("host"); String scheme = request.getScheme(); if (host != null && !uriQuery.startsWith(scheme)) { StringBuilder absolute = new StringBuilder(); absolute.append(scheme); absolute.append("://"); absolute.append(host); absolute.append(uriQuery); if (!uri.equals(absolute.toString())) { return false; } } else { return false; } } } // Validate the Realm name String lcRealm = getRealmName(request.getContext()); if (!lcRealm.equals(realmName)) { return false; } // Validate the opaque string if (!opaque.equals(opaqueReceived)) { return false; } // Validate nonce int i = nonce.indexOf(":"); if (i < 0 || (i + 1) == nonce.length()) { return false; } long nonceTime; try { nonceTime = Long.parseLong(nonce.substring(0, i)); } catch (NumberFormatException nfe) { return false; } String md5clientIpTimeKey = nonce.substring(i + 1); long currentTime = System.currentTimeMillis(); if ((currentTime - nonceTime) > nonceValidity) { nonceStale = true; synchronized (nonces) { nonces.remove(nonce); } } String serverIpTimeKey = request.getRemoteAddr() + ":" + nonceTime + ":" + key; byte[] buffer = ConcurrentMessageDigest.digestMD5(serverIpTimeKey.getBytes(StandardCharsets.ISO_8859_1)); String md5ServerIpTimeKey = MD5Encoder.encode(buffer); if (!md5ServerIpTimeKey.equals(md5clientIpTimeKey)) { return false; } // Validate qop if (qop != null && !QOP.equals(qop)) { return false; } // Validate cnonce and nc // Check if presence of nc and Cnonce is consistent with presence of qop if (qop == null) { if (cnonce != null || nc != null) { return false; } } else { if (cnonce == null || nc == null) { return false; } // RFC 2617 says nc must be 8 digits long. Older Android clients // use 6. 2.3.5 < fixed Android version <= 4.0.3 if (nc.length() < 6 || nc.length() > 8) { return false; } long count; try { count = Long.parseLong(nc, 16); } catch (NumberFormatException nfe) { return false; } NonceInfo info; synchronized (nonces) { info = nonces.get(nonce); } if (info == null) { // Nonce is valid but not in cache. It must have dropped out // of the cache - force a re-authentication nonceStale = true; } else { if (!info.nonceCountValid(count)) { return false; } } } return true; }