/* * Copyright (C) 2011-2012 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.security.http; import java.util.ArrayList; import org.apache.commons.lang.StringUtils; /** * This class requires the following libraries: * org.apache.commons.lang.StringUtils from commons-lang * * This class defines the format of the content which is hashed to produce * the HMAC-SHA256 symmetric-key signature for the "MtWilson" authentication * scheme. This class is not tied to the signature algorithm and could also * be used with other signature algorithms. * * This class is used by RequestAuthorization and VerifyAuthorization for the * MtWilson authentication scheme. * * See also HttpSignatureInput for a class that is a little more general * and allows the inclusion of arbitrary headers (including nonce and timestamp) * * @since 0.5.1 * @author jbuhacoff */ public class HmacSignatureInput { public String httpMethod; public String absoluteUrl; public String fromToken; public String nonce; public String body; public String signatureMethod; public String timestamp; /** * Generates the request document to be signed. This document represents the * request because it includes the Http method, request URL, user-id token, * timestamp, signature method, and nonce. * * The parameters must not be null and must not contain any newlines (except for the body parameter, which can be empty string or any non-empty string) * * Sample output: * Request: POST http://example.com/some/path From: username Timestamp: 2012-02-14T08:15:00-08:00 Nonce: FaaKLOOuyG7/kLVD5vQ7iw== Signature-Method: HMAC-SHA256 {"numbers":[1,2,3],"notes":"whatever the payload of the request, whether it's plain text, xml, json, or binary file in text encoding"} * * @param httpMethod for the HTTP request, such as "GET" or "POST"; must not be null * @param absoluteUrl including query string, such as "https://server.example.com/path/to/service?withQuery=yes" * @param fromToken a username or other public identifying token for the client * @param nonce in the form sent to the server; hexadecimal form is recommended * @param body the request body or empty string if the request does not require a body; must not be null * @param signatureMethod the algorithm used to generate the signature, such as "HMAC-SHA1" or "HMAC-SHA256" * @param timestamp the time this request was created, in ISO 8601 format such as "2012-02-14T08:15:00-08:00" * @return */ private String signatureBlock(String httpMethod, String absoluteUrl, String fromToken, String nonce, String body, String signatureMethod, String timestamp) { String[] input = new String[] { httpMethod, absoluteUrl, fromToken, nonce, signatureMethod, timestamp }; // can not be null or empty or contain newlines; body is excluded from this String[] label = new String[] {"HttpMethod","AbsoluteUrl","FromToken","Nonce","SignatureMethod","Timestamp"}; ArrayList<String> errors = new ArrayList<String>(); for(int i=0; i<input.length; i++) { if( input[i] == null ) { errors.add(String.format("%s is null", label[i])); } if( input[i].contains("\n") || input[i].contains("\r") ) { errors.add(String.format("%s contains newlines", label[i])); } } if( body == null ) { body = ""; } // errors.add(String.format("%s is null", "Body")); if( !errors.isEmpty() ) { throw new IllegalArgumentException("Cannot create signature block: "+StringUtils.join(errors, ", ")); } return String.format("Request: %s %s\nFrom: %s\nTimestamp: %s\nNonce: %s\nSignature-Method: %s\n\n%s", httpMethod, absoluteUrl, fromToken, timestamp, nonce, signatureMethod, body); } public String toString() { return signatureBlock(httpMethod, absoluteUrl, fromToken, nonce, body, signatureMethod, timestamp); } }