All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.identityx.auth.impl.DigestResponseAuthenticator Maven / Gradle / Ivy

Go to download

Client library used for adding authentication to http messages as required by IdentityX Rest Services

There is a newer version: 5.6.0.2
Show newest version
/*
* 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