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(); StringBuilder rb = new StringBuilder(DIGEST_PREFIX); rb.append(Headers.REALM.toString()).append("=\"").append(realmName).append("\","); rb.append(Headers.DOMAIN.toString()).append("=\"").append(domain).append("\","); // based on security constraints. rb.append(Headers.NONCE.toString()) .append("=\"") .append(nonceManager.nextNonce(null, exchange)) .append("\","); // Not currently using OPAQUE as it offers no integrity, used for session data leaves it // vulnerable to // session fixation type issues as well. rb.append(Headers.OPAQUE.toString()).append("=\"00000000000000000000000000000000\""); if (stale) { rb.append(",stale=true"); } if (supportedAlgorithms.size() > 0) { // This header will need to be repeated once for each algorithm. rb.append(",").append(Headers.ALGORITHM.toString()).append("=%s"); } if (qopString != null) { rb.append(",").append(Headers.QOP.toString()).append("=\"").append(qopString).append("\""); } String theChallenge = rb.toString(); HeaderMap responseHeader = exchange.getResponseHeaders(); if (supportedAlgorithms.isEmpty()) { responseHeader.add(WWW_AUTHENTICATE, theChallenge); } else { for (DigestAlgorithm current : supportedAlgorithms) { responseHeader.add(WWW_AUTHENTICATE, String.format(theChallenge, current.getToken())); } } return new ChallengeResult(true, UNAUTHORIZED); }