
io.femo.http.auth.DefaultDigestStrategy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http-jdk7 Show documentation
Show all versions of http-jdk7 Show documentation
An easy to use HTTP API, that supports synchronous and asynchronous execution of HTTP request.
On android only asynchronous driver is supported.
This library has been backported to jdk 7 to retain compatibility with android!
The newest version!
package io.femo.http.auth;
import io.femo.http.Authentication;
import io.femo.http.HttpException;
import io.femo.http.HttpRequest;
import io.femo.http.HttpResponse;
import io.femo.support.jdk7.Supplier;
import io.femo.support.jdk7.ValueSupplier;
import org.jetbrains.annotations.NotNull;
import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by felix on 6/21/16.
*/
public class DefaultDigestStrategy extends Authentication {
private Supplier username;
private Supplier password;
public DefaultDigestStrategy(Supplier username, Supplier password) {
this.username = username;
this.password = password;
this.nc = new AtomicInteger(1);
}
public DefaultDigestStrategy(String username, String password) {
this(new ValueSupplier<>(username), new ValueSupplier<>(password));
}
private ThreadLocal digest = new ThreadLocal() {
@Override
protected MessageDigest initialValue() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
};
private String nonce;
private AtomicInteger nc;
private String realm;
private String opaque;
private String basePath;
private String host;
@Override
public boolean isInitialized() {
return nonce != null && realm != null && opaque != null && nc != null;
}
@Override
public boolean matches(HttpRequest request) {
return host.equalsIgnoreCase(request.header("Host").value()) && request.path().startsWith(basePath);
}
@Override
public boolean supportsMulti() {
return false;
}
@Override
public boolean supportsDirect() {
return false;
}
@Override
public void init(HttpResponse response) {
Properties data = readData(response.header("WWW-Authenticate").value().substring("Digest".length()));
if(!data.containsKey("nonce") && !data.containsKey("opaque") && !data.containsKey("realm")) {
throw new HttpException(response.request(), "Not all required fields for HTTP Digest Authentication are present.");
}
this.nonce = removeQuotes(data.getProperty("nonce"));
this.realm = removeQuotes(data.getProperty("realm"));
this.opaque = removeQuotes(data.getProperty("opaque"));
this.host = response.request().header("Host").value();
this.basePath = response.request().path();
}
@Override
public String strategy() {
return "Digest";
}
@Override
public void authenticate(HttpRequest request) {
StringBuilder stringBuilder = new StringBuilder();
int nc = this.nc.getAndIncrement();
String cnonce = "0a4f113b"; //UUID.randomUUID().toString();
stringBuilder.append("Digest username=\"")
.append(username.get())
.append("\", realm=\"")
.append(realm)
.append("\", nonce=\"")
.append(nonce)
.append("\", uri=\"")
.append(request.path())
.append("\", qop=auth, nc=")
.append(String.format("%08x", nc))
.append(", cnonce=\"")
.append(cnonce)
.append("\", response=\"");
String ha1 = md5(username.get() + ":" + realm + ":" + password.get());
String ha2 = md5(request.method() + ":" + request.path());
String response = md5(ha1 + ":" + nonce
+ ":" + String.format("%08x", nc) + ":" + cnonce +
":auth:" + ha2);
stringBuilder.append(response)
.append("\", opaque=\"")
.append(opaque)
.append("\"");
request.header("Authorization", stringBuilder.toString());
}
private Properties readData(String authData) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(authData.replace(",", "\n").getBytes());
Properties properties = new Properties();
try {
properties.load(byteArrayInputStream);
} catch (IOException ignored) {
}
return properties;
}
@NotNull
private String md5(String data) {
MessageDigest digest = this.digest.get();
digest.reset();
byte[] res = digest.digest(data.getBytes());
return DatatypeConverter.printHexBinary(res).toLowerCase();
}
private String removeQuotes(String string) {
while (string.startsWith("\"")) {
string = string.substring(1);
}
while (string.endsWith("\"")) {
string = string.substring(0, string.length() - 1);
}
return string;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy