com.identityx.auth.impl.DigestResponseAuthenticator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of daon-http-digest-auth Show documentation
Show all versions of daon-http-digest-auth Show documentation
Client library used for adding authentication to http messages as required by IdentityX Rest Services
/*
* Copyright Daon.
*
* 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 com.identityx.auth.impl;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.SimpleTimeZone;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.identityx.auth.def.ITokenKey;
import com.identityx.auth.def.IResponse;
import com.identityx.auth.def.IResponseAuthenticator;
import com.identityx.auth.support.ResponseAuthenticationException;
import com.identityx.auth.util.Base64;
import com.identityx.auth.util.StringInputStream;
public class DigestResponseAuthenticator extends DigestAuthenticator implements IResponseAuthenticator {
private static final Log log = LogFactory.getLog(DigestResponseAuthenticator.class);
public DigestResponseAuthenticator() {
}
@Override
public void authenticate(IResponse response, final ITokenKey apiKey, final Date date, final String nonce) throws UnsupportedEncodingException {
String authorizationHeader = buildAuthorizationHeader(response, apiKey, date, nonce);
response.getHeaders().set(AuthSettings.AUTHORIZATION_HEADER, authorizationHeader);
}
@Override
public String buildAuthorizationHeader(IResponse response, final ITokenKey apiKey, Date date, final String nonce) throws UnsupportedEncodingException {
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
dateFormat.setTimeZone(new SimpleTimeZone(0, TIME_ZONE));
SimpleDateFormat timestampFormat = new SimpleDateFormat(TIMESTAMP_FORMAT);
timestampFormat.setTimeZone(new SimpleTimeZone(0, TIME_ZONE));
String timeStamp = timestampFormat.format(date);
String dateStamp = dateFormat.format(date);
setCustomHeaders(response, timeStamp);
return buildAuthorizationHeader(response, apiKey, nonce, dateStamp, timeStamp);
}
public void setCustomHeaders(IResponse response, final String timeStamp) {
response.getHeaders().set(DATE_HEADER, timeStamp);
//response.getHeaders().set("Content-Type", "application/json");
}
public String buildCanonicalResponse(final IResponse response) {
//String canonicalResourcePath = this.canonicalizeResourcePath(response.getUri().getPath());
String httpStatusString = Integer.toString(response.getHttpStatus());
String canonicalHeadersString = canonicalizeHeadersString(response);
String signedHeadersString = getSignedHeadersString(response);
String responsePayload = getResponsePayload(response);
String ResponsePayloadHashHex = toHex(hash(responsePayload));
String canonicalResponse =
//response.getMethod() + NL +
httpStatusString + NL +
//canonicalResourcePath + NL +
canonicalHeadersString + NL +
signedHeadersString + NL +
ResponsePayloadHashHex;
log.debug("Canonical response was: " + canonicalResponse.replace(NL, " - "));
return canonicalResponse;
}
public String buildAuthorizationHeader(IResponse response, final ITokenKey apiKey, final String nonce, String dateStamp, String timeStamp) throws UnsupportedEncodingException {
String canonicalResponse = buildCanonicalResponse(response);
log.debug("Canonical Response:" + canonicalResponse);
log.debug("canonicalResponse(b64):" + Base64.encodeBase64String(canonicalResponse.getBytes()));
String id = apiKey.getId() + "/" + dateStamp + "/" + nonce + "/" + ID_TERMINATOR;
log.debug("Response id: " + id);
String canonicalResponseHashHex = toHex(hash(canonicalResponse));
log.debug("canonicalResponseHashHex:" + canonicalResponseHashHex);
String stringToSign =
ALGORITHM + NL +
timeStamp + NL +
id + NL +
canonicalResponseHashHex;
log.debug("String to Sign: " + stringToSign);
byte[] kDate = apiKey.applySignature((dateStamp + AUTHENTICATION_SCHEME).getBytes(DEFAULT_ENCODING));
byte[] kNonce = sign(nonce, kDate, MacAlgorithm.HmacSHA256);
log.debug("The nonce was: " + nonce);
byte[] kSigning = sign(ID_TERMINATOR, kNonce, MacAlgorithm.HmacSHA256);
byte[] signature = sign(toUtf8Bytes(stringToSign), kSigning, MacAlgorithm.HmacSHA256);
String signatureHex = toHex(signature);
String signedHeadersString = getSignedHeadersString(response);
log.debug("signedHeadersString: " + signedHeadersString);
String authorizationHeader =
AUTHENTICATION_SCHEME + " " +
createNameValuePair(DIGEST_ID, id) + ", " +
createNameValuePair(DIGEST_SIGNED_HEADERS, signedHeadersString) + ", " +
createNameValuePair(DIGEST_SIGNATURE, signatureHex);
log.debug("Authorization Header: " + authorizationHeader);
return authorizationHeader;
}
protected String getResponsePayload(IResponse response) {
try {
InputStream content = response.getBody();
if (content == null) return "";
if (content instanceof StringInputStream) {
return content.toString();
}
if (!content.markSupported()) {
throw new ResponseAuthenticationException("Unable to read Response payload to authenticate Response (mark not supported).");
}
content.mark(-1);
//convert InputStream into a String in one shot:
String string;
try {
string = new Scanner(content, "UTF-8").useDelimiter("\\A").next();
} catch (NoSuchElementException nsee) {
string = "";
}
//BAM! That just happened.
content.reset();
return string;
} catch (Exception e) {
throw new ResponseAuthenticationException("Unable to read Response payload to authenticate Response: " + e.getMessage(), e);
}
}
private String canonicalizeHeadersString(IResponse response) {
List sortedHeaders = new ArrayList();
List signedHeaderNames = getSignedHeaderNames(response);
if (signedHeaderNames != null) {
for (String key : response.getHeaders().keySet()) {
if (signedHeaderNames.contains(key.toLowerCase())) {
sortedHeaders.add(key);
}
}
}
else {
sortedHeaders.addAll(response.getHeaders().keySet());
}
Collections.sort(sortedHeaders, String.CASE_INSENSITIVE_ORDER);
StringBuilder buffer = new StringBuilder();
for (String header : sortedHeaders) {
buffer.append(header.toLowerCase()).append(":");
Collection values = response.getHeaders().get(header);
boolean first = true;
if (values != null) {
for(String value : values) {
if (!first) {
buffer.append(",");
}
buffer.append(value);
first = false;
}
}
buffer.append(NL);
}
return buffer.toString();
}
protected List getSignedHeaderNames(IResponse response) {
ArrayList result = new ArrayList();
if (response.getHeaders().containsKey(AuthSettings.AUTHORIZATION_HEADER)) {
String authHeader = response.getHeaders().get(AuthSettings.AUTHORIZATION_HEADER).get(0);
String[] splits = authHeader.split(",");
for (String split : splits) {
String[] splitParts = split.split("=");
if (splitParts != null && splitParts.length > 0 && splitParts[0].replaceAll("\\s", "").equals(DigestAuthenticator.DIGEST_SIGNED_HEADERS)) {
for (String headerName : splitParts[1].split(";")) {
result.add(headerName.toLowerCase().replaceAll("\\s", ""));
}
return result;
}
}
}
return null;
}
protected String getSignedHeadersString(IResponse response) {
List sortedHeaders = new ArrayList();
List signedHeaderNames = getSignedHeaderNames(response);
if (signedHeaderNames != null) {
for (String key : response.getHeaders().keySet()) {
if (signedHeaderNames.contains(key.toLowerCase())) {
sortedHeaders.add(key);
}
}
}
else {
sortedHeaders.addAll(response.getHeaders().keySet());
}
Collections.sort(sortedHeaders, String.CASE_INSENSITIVE_ORDER);
StringBuilder buffer = new StringBuilder();
for (String header : sortedHeaders) {
if (buffer.length() > 0) {
buffer.append(";");
}
buffer.append(header.toLowerCase());
}
return buffer.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy