public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) { List<String> authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION); if (authHeaders != null) { for (String current : authHeaders) { if (current.startsWith(DIGEST_PREFIX)) { String digestChallenge = current.substring(PREFIX_LENGTH); try { DigestContext context = new DigestContext(); Map<DigestAuthorizationToken, String> parsedHeader = parseHeader(digestChallenge); context.setMethod(exchange.getRequestMethod().toString()); context.setParsedHeader(parsedHeader); // Some form of Digest authentication is going to occur so get the DigestContext set on the exchange. exchange.putAttachment(DigestContext.ATTACHMENT_KEY, context); UndertowLogger.SECURITY_LOGGER.debugf("Found digest header %s in %s", current, exchange); return handleDigestHeader(exchange, securityContext); } catch (Exception e) { e.printStackTrace(); } } // By this point we had a header we should have been able to verify but for some reason // it was not correctly structured. return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; } } // No suitable header has been found in this request, return AuthenticationMechanismOutcome.NOT_ATTEMPTED; }
@Override public byte[] getSessionData() { if (!context.getAlgorithm().isSession()) { throw MESSAGES.noSessionData(); } byte[] nonce = context.getParsedHeader().get(DigestAuthorizationToken.NONCE).getBytes(StandardCharsets.UTF_8); byte[] cnonce = context.getParsedHeader().get(DigestAuthorizationToken.CNONCE).getBytes(StandardCharsets.UTF_8); byte[] response = new byte[nonce.length + cnonce.length + 1]; System.arraycopy(nonce, 0, response, 0, nonce.length); response[nonce.length] = ':'; System.arraycopy(cnonce, 0, response, nonce.length + 1, cnonce.length); return response; }
private byte[] createRFC2617RequestDigest(final byte[] ha1, final byte[] ha2, final DigestContext context) { final MessageDigest digest = context.getDigest(); final Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); byte[] nonce = parsedHeader.get(DigestAuthorizationToken.NONCE).getBytes(StandardCharsets.UTF_8); byte[] nonceCount = parsedHeader.get(DigestAuthorizationToken.NONCE_COUNT).getBytes(StandardCharsets.UTF_8); byte[] cnonce = parsedHeader.get(DigestAuthorizationToken.CNONCE).getBytes(StandardCharsets.UTF_8); byte[] qop = parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP).getBytes(StandardCharsets.UTF_8); try { digest.update(ha1); digest.update(COLON); digest.update(nonce); digest.update(COLON); digest.update(nonceCount); digest.update(COLON); digest.update(cnonce); digest.update(COLON); digest.update(qop); digest.update(COLON); digest.update(ha2); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }
private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); context.setQop(qop); mandatoryTokens.add(DigestAuthorizationToken.CNONCE); mandatoryTokens.add(DigestAuthorizationToken.NONCE_COUNT); context.setAlgorithm(algorithm); } catch (NoSuchAlgorithmException e) { context.markStale();
private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); context.setQop(qop); mandatoryTokens.add(DigestAuthorizationToken.CNONCE); mandatoryTokens.add(DigestAuthorizationToken.NONCE_COUNT); context.setAlgorithm(algorithm); } catch (NoSuchAlgorithmException e) { context.markStale();
@Override public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); boolean stale = context == null ? false : context.isStale();
public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) { List<String> authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION); if (authHeaders != null) { for (String current : authHeaders) { if (current.startsWith(DIGEST_PREFIX)) { String digestChallenge = current.substring(PREFIX_LENGTH); try { DigestContext context = new DigestContext(); Map<DigestAuthorizationToken, String> parsedHeader = parseHeader(digestChallenge); context.setMethod(exchange.getRequestMethod().toString()); context.setParsedHeader(parsedHeader); // Some form of Digest authentication is going to occur so get the DigestContext set on the exchange. exchange.putAttachment(DigestContext.ATTACHMENT_KEY, context); UndertowLogger.SECURITY_LOGGER.debugf("Found digest header %s in %s", current, exchange); return handleDigestHeader(exchange, securityContext); } catch (Exception e) { e.printStackTrace(); } } // By this point we had a header we should have been able to verify but for some reason // it was not correctly structured. return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; } } // No suitable header has been found in this request, return AuthenticationMechanismOutcome.NOT_ATTEMPTED; }
private byte[] createRFC2617RequestDigest(final byte[] ha1, final byte[] ha2, final DigestContext context) { final MessageDigest digest = context.getDigest(); final Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); byte[] nonce = parsedHeader.get(DigestAuthorizationToken.NONCE).getBytes(StandardCharsets.UTF_8); byte[] nonceCount = parsedHeader.get(DigestAuthorizationToken.NONCE_COUNT).getBytes(StandardCharsets.UTF_8); byte[] cnonce = parsedHeader.get(DigestAuthorizationToken.CNONCE).getBytes(StandardCharsets.UTF_8); byte[] qop = parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP).getBytes(StandardCharsets.UTF_8); try { digest.update(ha1); digest.update(COLON); digest.update(nonce); digest.update(COLON); digest.update(nonceCount); digest.update(COLON); digest.update(cnonce); digest.update(COLON); digest.update(qop); digest.update(COLON); digest.update(ha2); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }
public void sendAuthenticationInfoHeader(final HttpServerExchange exchange) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); DigestQop qop = context.getQop(); String currentNonce = context.getNonce(); String nextNonce = nonceManager.nextNonce(currentNonce, exchange); if (qop != null || !nextNonce.equals(currentNonce)) { StringBuilder sb = new StringBuilder(); sb.append(NEXT_NONCE).append("=\"").append(nextNonce).append("\""); if (qop != null) { Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); sb.append(",").append(Headers.QOP.toString()).append("=\"").append(qop.getToken()).append("\""); byte[] ha1 = context.getHa1(); byte[] ha2; if (qop == DigestQop.AUTH) { ha2 = createHA2Auth(context); } else { ha2 = createHA2AuthInt(); } String rspauth = new String(createRFC2617RequestDigest(ha1, ha2, context), StandardCharsets.UTF_8); sb.append(",").append(Headers.RESPONSE_AUTH.toString()).append("=\"").append(rspauth).append("\""); sb.append(",").append(Headers.CNONCE.toString()).append("=\"").append(parsedHeader.get(DigestAuthorizationToken.CNONCE)).append("\""); sb.append(",").append(Headers.NONCE_COUNT.toString()).append("=").append(parsedHeader.get(DigestAuthorizationToken.NONCE_COUNT)); } HeaderMap responseHeader = exchange.getResponseHeaders(); responseHeader.add(AUTHENTICATION_INFO, sb.toString()); } exchange.removeAttachment(DigestContext.ATTACHMENT_KEY); }
@Override public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); boolean stale = context == null ? false : context.isStale();
public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) { List<String> authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION); if (authHeaders != null) { for (String current : authHeaders) { if (current.startsWith(DIGEST_PREFIX)) { String digestChallenge = current.substring(PREFIX_LENGTH); try { DigestContext context = new DigestContext(); Map<DigestAuthorizationToken, String> parsedHeader = parseHeader(digestChallenge); context.setMethod(exchange.getRequestMethod().toString()); context.setParsedHeader(parsedHeader); // Some form of Digest authentication is going to occur so get the DigestContext set on the exchange. exchange.putAttachment(DigestContext.ATTACHMENT_KEY, context); UndertowLogger.SECURITY_LOGGER.debugf("Found digest header %s in %s", current, exchange); return handleDigestHeader(exchange, securityContext); } catch (Exception e) { e.printStackTrace(); } } // By this point we had a header we should have been able to verify but for some reason // it was not correctly structured. return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; } } // No suitable header has been found in this request, return AuthenticationMechanismOutcome.NOT_ATTEMPTED; }
public void sendAuthenticationInfoHeader(final HttpServerExchange exchange) { DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); DigestQop qop = context.getQop(); String currentNonce = context.getNonce(); String nextNonce = nonceManager.nextNonce(currentNonce, exchange); if (qop != null || !nextNonce.equals(currentNonce)) { StringBuilder sb = new StringBuilder(); sb.append(NEXT_NONCE).append("=\"").append(nextNonce).append("\""); if (qop != null) { Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); sb.append(",").append(Headers.QOP.toString()).append("=\"").append(qop.getToken()).append("\""); byte[] ha1 = context.getHa1(); byte[] ha2; if (qop == DigestQop.AUTH) { ha2 = createHA2Auth(context); } else { ha2 = createHA2AuthInt(); } String rspauth = new String(createRFC2617RequestDigest(ha1, ha2, context), StandardCharsets.UTF_8); sb.append(",").append(Headers.RESPONSE_AUTH.toString()).append("=\"").append(rspauth).append("\""); sb.append(",").append(Headers.CNONCE.toString()).append("=\"").append(parsedHeader.get(DigestAuthorizationToken.CNONCE)).append("\""); sb.append(",").append(Headers.NONCE_COUNT.toString()).append("=").append(parsedHeader.get(DigestAuthorizationToken.NONCE_COUNT)); } HeaderMap responseHeader = exchange.getResponseHeaders(); responseHeader.add(AUTHENTICATION_INFO, sb.toString()); } exchange.removeAttachment(DigestContext.ATTACHMENT_KEY); }
private byte[] createRFC2617RequestDigest(final byte[] ha1, final byte[] ha2, final DigestContext context) { final MessageDigest digest = context.getDigest(); final Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); byte[] nonce = parsedHeader.get(DigestAuthorizationToken.NONCE).getBytes(StandardCharsets.UTF_8); byte[] nonceCount = parsedHeader.get(DigestAuthorizationToken.NONCE_COUNT).getBytes(StandardCharsets.UTF_8); byte[] cnonce = parsedHeader.get(DigestAuthorizationToken.CNONCE).getBytes(StandardCharsets.UTF_8); byte[] qop = parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP).getBytes(StandardCharsets.UTF_8); try { digest.update(ha1); digest.update(COLON); digest.update(nonce); digest.update(COLON); digest.update(nonceCount); digest.update(COLON); digest.update(cnonce); digest.update(COLON); digest.update(qop); digest.update(COLON); digest.update(ha2); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }
private boolean validateRequest(final DigestContext context, final byte[] ha1) { byte[] ha2; DigestQop qop = context.getQop(); // Step 2.2 Calculate H(A2) if (qop == null || qop.equals(DigestQop.AUTH)) { ha2 = createHA2Auth(context, context.getParsedHeader()); } else { ha2 = createHA2AuthInt(); } byte[] requestDigest; if (qop == null) { requestDigest = createRFC2069RequestDigest(ha1, ha2, context); } else { requestDigest = createRFC2617RequestDigest(ha1, ha2, context); } byte[] providedResponse = context.getParsedHeader().get(DigestAuthorizationToken.RESPONSE).getBytes(StandardCharsets.UTF_8); return MessageDigest.isEqual(requestDigest, providedResponse); }
private byte[] createRFC2069RequestDigest(final byte[] ha1, final byte[] ha2, final DigestContext context) { final MessageDigest digest = context.getDigest(); final Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); byte[] nonce = parsedHeader.get(DigestAuthorizationToken.NONCE).getBytes(StandardCharsets.UTF_8); try { digest.update(ha1); digest.update(COLON); digest.update(nonce); digest.update(COLON); digest.update(ha2); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }
private boolean validateRequest(final DigestContext context, final byte[] ha1) { byte[] ha2; DigestQop qop = context.getQop(); // Step 2.2 Calculate H(A2) if (qop == null || qop.equals(DigestQop.AUTH)) { ha2 = createHA2Auth(context, context.getParsedHeader()); } else { ha2 = createHA2AuthInt(); } byte[] requestDigest; if (qop == null) { requestDigest = createRFC2069RequestDigest(ha1, ha2, context); } else { requestDigest = createRFC2617RequestDigest(ha1, ha2, context); } byte[] providedResponse = context.getParsedHeader().get(DigestAuthorizationToken.RESPONSE).getBytes(StandardCharsets.UTF_8); return MessageDigest.isEqual(requestDigest, providedResponse); }
private byte[] createRFC2069RequestDigest(final byte[] ha1, final byte[] ha2, final DigestContext context) { final MessageDigest digest = context.getDigest(); final Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader(); byte[] nonce = parsedHeader.get(DigestAuthorizationToken.NONCE).getBytes(StandardCharsets.UTF_8); try { digest.update(ha1); digest.update(COLON); digest.update(nonce); digest.update(COLON); digest.update(ha2); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }
private byte[] createHA2Auth(final DigestContext context, Map<DigestAuthorizationToken, String> parsedHeader) { byte[] method = context.getMethod().getBytes(StandardCharsets.UTF_8); byte[] digestUri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI).getBytes(StandardCharsets.UTF_8); MessageDigest digest = context.getDigest(); try { digest.update(method); digest.update(COLON); digest.update(digestUri); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }
@Override public DigestAlgorithm getAlgorithm() { return context.getAlgorithm(); }
private byte[] createHA2Auth(final DigestContext context, Map<DigestAuthorizationToken, String> parsedHeader) { byte[] method = context.getMethod().getBytes(StandardCharsets.UTF_8); byte[] digestUri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI).getBytes(StandardCharsets.UTF_8); MessageDigest digest = context.getDigest(); try { digest.update(method); digest.update(COLON); digest.update(digestUri); return HexConverter.convertToHexBytes(digest.digest()); } finally { digest.reset(); } }