/*
* This code is heavily based on open source code and should not be copyrighted.
*/
package com.intel.mountwilson.http.security.adapter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import com.intel.mtwilson.security.http.HmacAuthorization;
import com.intel.dcsg.cpg.crypto.HmacCredential;
/**
* This class requires the following libraries:
* org.apache.commons.io.IOUtils from commons-io
*
* Uses the RequestAuthorization class to sign requests before sending them
*/
public class SignatureClient {
private final Pattern headerPattern = Pattern.compile("([\\w\\d-]+): (.+)");
private static final String version = "0.0";
private final HmacAuthorization auth;
public SignatureClient(String userId, String secretKey) {
auth = new HmacAuthorization(new HmacCredential(userId, secretKey));
}
/**
* Opens a new HttpURLConnection and adds the Authorization header
* using the userId and secretKey provided to the constructor.
*
* You can add your own headers to the HttpURLConnection before sending the request.
*
* @param method the Http method such as "GET" or "POST"
* @param urlstring the complete URL such as http://example.com/some/path
* @param body the body of the request, or null
* @param headers an array of http headers in "Header-Name: Value" format to be added to the request; or null
* @return an open HttpURLConnection object; you must read the response and close it
* @throws NoSuchAlgorithmException if your environment is missing the HmacSHA256 algorithm
* @throws InvalidKeyException if the secretKey value you provided to the constructor is not suitable for use with HmacSHA256
* @throws IOException if there was a problem generating the nonce
*/
public HttpURLConnection openConnection(String method, String urlstring, String body, String[] headers) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
URL url = new URL(urlstring);
HttpURLConnection c = (HttpURLConnection)url.openConnection();
c.setDoOutput(true);
c.setRequestMethod(method);
c.setRequestProperty("Authorization", auth.getAuthorization(method, urlstring, body));
if( headers != null ) {
for(String h : headers) {
Matcher m = headerPattern.matcher(h);
if( m.matches() ) {
c.setRequestProperty(m.group(1), m.group(2));
}
}
}
OutputStreamWriter out = new OutputStreamWriter(c.getOutputStream());
out.write(body);
out.flush();
out.close();
return c;
}
/**
* Convenience method to make a signed HTTP request and return the response.
* @param method HTTP method such as "GET", "POST", "PUT", "DELETE", "HEAD", or "OPTIONS"
* @param urlstring URL such as http://www.example.com/path/to/resource
* @param body optional; if not needed use null
* @throws IOException
* @return the resonse body only; headers are not available through this method
* @throws NoSuchAlgorithmException if your environment is missing the HmacSHA256 algorithm
* @throws InvalidKeyException if the secretKey value you provided to the constructor is not suitable for use with HmacSHA256
* @throws IOException if there was a problem generating the nonce
*/
public String request(String method, String urlstring, String body, String[] headers) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
HttpURLConnection c = openConnection(method, urlstring, body, headers);
InputStream cin = c.getInputStream();
try {
String content = IOUtils.toString(cin);
return content;
}
finally {
cin.close();
c.disconnect();
}
}
}