org.codehaus.httpcache4j.auth.digest.RequestDigest Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2010. The Codehaus. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.httpcache4j.auth.digest;
import org.codehaus.httpcache4j.*;
import org.codehaus.httpcache4j.util.Digester;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author Erlend Hamnaberg
* @version $Revision: $
*/
//TODO: handle auth-int
public class RequestDigest {
private static final String CNONCE_COUNT = "00000001";
private final Map directives = new LinkedHashMap();
private final UsernamePasswordChallenge challenge;
private final HTTPMethod method;
private final URI requestURI;
private final Digest serverDigest;
private final Algorithm algorithm;
RequestDigest(UsernamePasswordChallenge challenge, HTTPMethod method, URI requestURI, Digest serverDigest) {
this.challenge = challenge;
this.method = method;
this.requestURI = requestURI;
this.serverDigest = serverDigest;
addDirective("username", challenge.getIdentifier(), true);
addDirective("realm", serverDigest.getScheme().getRealm(), true);
addDirective("nonce", serverDigest.getNonce(), true);
addDirective("uri", requestURI.toString(), true);
if (serverDigest.getAlgorithm() != null) {
addDirective("algorithm", serverDigest.getAlgorithm().getValue(), true);
algorithm = serverDigest.getAlgorithm();
}
else {
algorithm = Algorithm.MD5;
}
if (!Objects.toString(serverDigest.getQop(), "").isEmpty()) {
addDirective("qop", serverDigest.getQop(), false);
addDirective("nc", CNONCE_COUNT, false);
addDirective("cnonce", calculateCNonce(), true);
}
addDirective("response", calculateResponse(), true);
if (!Objects.toString(serverDigest.getOpaque(), "").isEmpty()) {
addDirective("opaque", serverDigest.getOpaque(), true);
}
}
String calculateResponse() {
String ha1 = calculateHashA1();
Directive qopDirective = directives.get("qop");
Directive nonce = directives.get("nonce");
String response;
String ha2 = calculateHashA2();
if (qopDirective != null) {
if (isAuthIntQualityOfProtection(qopDirective)) {
throw new IllegalArgumentException("Auth-int not supported yet");
}
else if (isAuthQualityOfProtection(qopDirective)) {
Directive clientNonce = directives.get("cnonce");
StringBuilder builder = new StringBuilder();
builder.append(ha1);
builder.append(':');
builder.append(nonce.getValue());
builder.append(':');
builder.append(CNONCE_COUNT);
builder.append(':');
builder.append(clientNonce.getValue());
builder.append(':');
builder.append(qopDirective.getValue());
builder.append(':');
builder.append(ha2);
response = hash(algorithm, builder.toString(), "ISO-8859-1");
}
else {
throw new IllegalArgumentException("Unknown QOP: " + qopDirective.getValue());
}
}
else {
response = hash(algorithm, String.format("%s:%s:%s", ha1, nonce.getValue(), ha2), "US-ASCII");
}
return response;
}
String calculateHashA2() {
return hash(algorithm, String.format("%s:%s", method, requestURI), "ISO-8859-1");
}
String calculateHashA1() {
StringBuilder a1 = new StringBuilder();
a1.append(challenge.getIdentifier());
a1.append(':');
a1.append(serverDigest.getScheme().getRealm());
a1.append(':');
a1.append(challenge.getPassword());
return hash(algorithm, a1.toString(), "US-ASCII");
}
private boolean isAuthQualityOfProtection(Directive directive) {
return "auth".equals(directive.getValue());
}
private boolean isAuthIntQualityOfProtection(Directive directive) {
return "auth-int".equals(directive.getValue());
}
private String hash(Algorithm algorithm, String input, final String charset) {
switch (algorithm) {
case MD5:
case MD5_SESSION:
return Digester.md5(input, Charset.forName(charset));
case TOKEN:
default:
throw new IllegalArgumentException("No such algorithm");
}
}
String calculateCNonce() {
return hash(Algorithm.MD5, Long.toString(System.currentTimeMillis()), "US-ASCII");
}
public String toHeaderValue() {
StringBuilder builder = new StringBuilder();
builder.append("Digest ");
for (Directive directive : directives.values()) {
if (builder.length() > "Digest ".length()) {
builder.append(", ");
}
builder.append(directive);
}
return builder.toString();
}
public static RequestDigest newInstance(UsernamePasswordChallenge challenge, HTTPRequest request, Digest digest) {
return new RequestDigest(challenge, request.getMethod(), URI.create(request.getRequestURI().getRawPath()), digest);
}
private void addDirective(String name, String value, boolean quoted) {
if (quoted) {
directives.put(name, new QuotedDirective(name, value));
}
else {
directives.put(name, new Directive(name, value));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy