use of com.disney.http.auth.SignatureAuthorization in project groovity by disney.
the class HttpSignatureSigner method doAuthorization.
public SignatureAuthorization doAuthorization(HttpRequest request) throws HttpException {
if (keyId == null || keyId.isEmpty()) {
throw new HttpException("Signer Configuration Error: no KeyId set");
}
// fill in date field if missing from request;
if (request.getLastHeader("x-date") == null && request.getLastHeader("date") == null) {
request.addHeader("Date", DateUtils.formatDate(new Date()));
}
SignatureAuthorization sa = new SignatureAuthorization();
sa.setAlgorithm(algorithm);
sa.setHeaders(headers);
sa.setKeyId(keyId);
String signingString = sa.generateSigningString(new ClientAuthorizationRequest(request));
try {
// System.out.println("Client signing string "+signingString);
String signingAlgorithm = Algorithms.getSecurityAlgorithm(algorithm);
Key key = null;
if (keyLoader != null) {
key = keyLoader.call();
} else if (getKeyPairLoader() != null) {
// always sign with the private key, validate with the public key
key = getKeyPairLoader().call().getPrivate();
} else {
throw new RuntimeException("No key loader provided for HTTP Signature Signer");
}
// keyId must be set, as per protocol
if (signingAlgorithm.startsWith("Hmac")) {
Mac mac = Mac.getInstance(signingAlgorithm);
mac.init(key);
sa.setSignature(mac.doFinal(signingString.getBytes("UTF-8")));
} else if (signingAlgorithm.endsWith("RSA")) {
// rsa
Signature rsaSigner = Signature.getInstance(signingAlgorithm);
rsaSigner.initSign((PrivateKey) key);
rsaSigner.update(signingString.getBytes("UTF-8"));
sa.setSignature(rsaSigner.sign());
} else {
throw new NoSuchAlgorithmException("No known algorithm for " + signingAlgorithm);
}
return sa;
} catch (Exception e) {
throw new HttpException("Invalid Signature Authorization: signer was not correctly configured.", e);
}
}
use of com.disney.http.auth.SignatureAuthorization in project groovity by disney.
the class TestSignatureAuth method testRSA.
@Test
public void testRSA() throws Exception {
HttpGet request = new HttpGet("http://localhost:8080/");
HttpClientContext localContext = new HttpClientContext();
HttpSignatureSigner signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
String keyId = "apiUser123";
String headers = "(request-target) host x-date";
KeyPair pair = KeyUtils.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
KeyObjectKeyLoader privateKeyLoader = new KeyObjectKeyLoader(privateKey);
signer.setAlgorithm("rsa-sha256");
signer.setKeyId(keyId);
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setKeyLoader(privateKeyLoader);
signer.process(request, localContext);
SignatureAuthorization testAuth = new SignatureAuthorization();
testAuth.setAlgorithm("rsa-sha256");
testAuth.setHeaders(signer.getHeaders());
String signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
byte[] encryptedString = signer.doAuthorization(request).getSignature();
boolean verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// can choose algorithm
signer.setAlgorithm("rsa-md5");
signer.process(request, localContext);
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("MD5withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// wrong keyid, not a key loader so no effect
signer.setAlgorithm("rsa-sha256");
signer.setKeyId("something else");
signer.process(request, localContext);
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// different headers
signer.setHeaders(Arrays.asList("host", "x-date"));
signer.process(request, localContext);
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertFalse(verify);
// load plain key from file;
String location = "target/priv.pem";
File pemFile = new File(location);
URIParcel.put(pemFile.toURI(), pair);
URIParcel<KeyPair> pemParcel = new URIParcel<KeyPair>(KeyPair.class, pemFile.toURI());
signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
signer.setKeyId("defaultValue");
signer.setAlgorithm("rsa-sha256");
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setKeyPairLoader(pemParcel);
signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// try using a KeyStoreLoader
signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
signer.setAlgorithm("rsa-sha256");
location = "target/testKeytool.store";
Map<String, Object> config = new HashMap<String, Object>();
config.put(KeyStoreValueHandler.KEYSTORE_PASSWORD, "rachel");
config.put(KeyStoreValueHandler.KEYSTORE_TYPE, "JCEKS");
URIParcel<KeyStore> parcel = new URIParcel<KeyStore>(KeyStore.class, new File(location).toURI(), config);
KeyChain chain = new KeyStoreKeyChainImpl(parcel, "".toCharArray());
KeyChainKeyLoader keystoreLoader = new KeyChainKeyLoader(chain);
keystoreLoader.setAlias("test");
signer.setKeyId("test");
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setKeyLoader(keystoreLoader);
signer.process(request, localContext);
signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
encryptedString = signer.doAuthorization(request).getSignature();
// check again public key
KeyStore importedKeystore = parcel.call();
PublicKey loadedPublicKey = importedKeystore.getCertificate("test").getPublicKey();
verifyRsa("SHA256withRSA", loadedPublicKey, signingString, encryptedString);
Assert.assertTrue(verify);
}
use of com.disney.http.auth.SignatureAuthorization in project groovity by disney.
the class TestSignatureAuth method testHmac.
@Test
public void testHmac() throws Exception {
HttpGet request = new HttpGet("http://localhost:8080/");
HttpClientContext localContext = new HttpClientContext();
HttpSignatureSigner signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
String keyId = "apiUser123";
String keyValue = "someBase64Secret";
String headers = "(request-target) host x-date";
String algorithm = "hmac-sha256";
KeyObjectKeyLoader hmacKey = new KeyObjectKeyLoader(algorithm, keyValue);
signer.setHeaderName(SIGNATURE_HEADER);
signer.setKeyId(keyId);
signer.setKeyLoader(hmacKey);
signer.setAlgorithm(algorithm);
signer.process(request, localContext);
SignatureAuthorization testAuth = new SignatureAuthorization();
testAuth.setHeaders(signer.getHeaders());
Assert.assertNotNull(signer.getHeaderName());
Assert.assertNotNull(getAuthHeader(request));
String signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
byte[] expectedResult = signHmac(algorithm, keyValue, signingString);
byte[] signature = signer.doAuthorization(request).getSignature();
Assert.assertArrayEquals(expectedResult, signature);
// bad signing string
Assert.assertFalse(Arrays.equals(signHmac(algorithm, keyValue, signingString + "invalid"), signature));
// wrong key
signer.setKeyLoader(new KeyObjectKeyLoader(algorithm, "differentKeyValue"));
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Wrong Key", Arrays.equals(expectedResult, signature));
// wrong algorithm
signer.setAlgorithm("hmac-md5");
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Wrong algorithm", Arrays.equals(expectedResult, signature));
// wrong headers
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setAlgorithm(algorithm);
signer.setKeyLoader(hmacKey);
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Incorrect Headers", Arrays.equals(expectedResult, signature));
// wrong header order
signer.setHeaders(Arrays.asList("host (request-target) x-date"));
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Incorrect header order", Arrays.equals(expectedResult, signature));
}
use of com.disney.http.auth.SignatureAuthorization in project groovity by disney.
the class SignatureVerifierImpl method doVerifyInternal.
/**
* Given a request and response, analyze the request Authorization header and
* look up the appropriate key in the keystore; if the
* header is missing, incomplete or invalid, will send a 401 error on the response
* with WWW-Authenticate header and return null.
*
* If the request contains a Digest header, the returned HttpServletRequest
* will wrap the original with one that will lazily verify the request body.
* Consumers should replace the original ServletRequest with the returned one
* for further processing, and be prepared for the possible VerificationException
*
* @param request
* @throws IOException
* @throws GeneralSecurityException
*/
protected VerifierResult doVerifyInternal(ServerAuthorizationRequest request) throws Exception {
VerifierResult result = new VerifierResult();
List<String> authHeader = request.getHeaders(AUTHORIZATION_HEADER);
if (authHeader == null || authHeader.isEmpty() || !authHeader.get(0).startsWith(SIGNATURE_HEADER)) {
authHeader = request.getHeaders(SIGNATURE_HEADER);
}
// System.out.println("Received auth header "+authHeader);
if (authHeader == null || authHeader.isEmpty()) {
challenge(result, ERROR_MISSING_SIGNATURE);
return result;
}
// this will throw an exception if the auth header is not properly formatted
SignatureAuthorization authSig;
try {
authSig = new SignatureAuthorization(authHeader.get(0));
} catch (Exception e) {
challenge(result, e.getMessage());
return result;
}
// now validate that the authSig was signed with all the required headers
for (String required : requiredHeaders) {
if (!authSig.getHeaders().contains(required.toLowerCase())) {
if (required.toLowerCase().equals("date") && authSig.getHeaders().contains("x-date")) {
// allow x-date to substitute for date
continue;
}
challenge(result, MessageFormat.format(ERROR_MISSING_HEADER_FORMAT, required));
return result;
}
}
List<String> reqDateStr = request.getHeaders("x-date");
if (reqDateStr == null || reqDateStr.isEmpty()) {
reqDateStr = request.getHeaders("date");
}
// now validate the date is in range, use x-date if provided (for ajax support)
long reqDate = -1;
if (reqDateStr != null && !reqDateStr.isEmpty()) {
String rd = reqDateStr.get(0);
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
try {
reqDate = dateFormat.parse(rd).getTime();
} catch (ParseException e) {
dateFormat = new SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss zzz");
try {
reqDate = dateFormat.parse(rd).getTime();
} catch (ParseException e1) {
dateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy");
reqDate = dateFormat.parse(rd).getTime();
}
}
}
if ((System.currentTimeMillis() - reqDate) > maxDateDrift) {
challenge(result, ERROR_INVALID_DATE);
return result;
}
// now lookup the key
String errorFormat = ERROR_UNKOWN_KEY_ID_FORMAT;
Key[] keys = null;
for (KeyChain keyChain : keyChains) {
if (keyChain.containsKey(authSig.getKeyId())) {
if (authSig.getAlgorithm().startsWith("hmac")) {
try {
keys = keyChain.getSecretKeys(authSig.getKeyId());
} catch (UnrecoverableKeyException e) {
errorFormat = ERROR_EXPECTED_HMAC_FORMAT;
}
} else {
try {
keys = keyChain.getPublicKeys(authSig.getKeyId());
} catch (UnrecoverableKeyException e) {
errorFormat = ERROR_EXPECTED_RSA_FORMAT;
}
}
}
}
if (keys == null || keys.length == 0) {
challenge(result, MessageFormat.format(errorFormat, authSig.getKeyId()));
return result;
}
String errorMessage = null;
for (Key key : keys) {
// validate key algorithm is appropriate
if (key.getAlgorithm().equals("RSA")) {
if (!authSig.getAlgorithm().startsWith("rsa")) {
errorMessage = MessageFormat.format(ERROR_EXPECTED_HMAC_FORMAT, authSig.getKeyId());
continue;
}
}
if (key.getAlgorithm().startsWith("Hmac")) {
if (!authSig.getAlgorithm().startsWith("hmac")) {
errorMessage = MessageFormat.format(ERROR_EXPECTED_RSA_FORMAT, authSig.getKeyId());
continue;
}
}
// now generate the signature to compare
String toSign = authSig.generateSigningString(request);
// System.out.println("Signing string is "+toSign);
if (verifyMessage(key, toSign, authSig.getSignature(), authSig.getAlgorithm())) {
result.setAuthenticated(true);
result.setPrincipal(new AuthenticatedPrincipal(authSig.getKeyId()));
return result;
} else {
errorMessage = ERROR_VERIFICATION_FAILED;
}
}
challenge(result, errorMessage);
return result;
}
use of com.disney.http.auth.SignatureAuthorization in project groovity by disney.
the class TestHttpSignature method testSigning.
@Test
public void testSigning() throws Exception {
SignatureVerifierImpl verifier = new SignatureVerifierImpl();
verifier.setMaxDateDrift(5000);
final KeyStore testStore = KeyStore.getInstance("JCEKS");
testStore.load(null);
Key hmac256key = new SecretKeySpec("hello world".getBytes(), "HmacSHA256");
testStore.setKeyEntry("hmac256key", hmac256key, new char[0], null);
verifier.setKeyChains(Arrays.asList((KeyChain) new KeyStoreKeyChainImpl(new Callable<KeyStore>() {
@Override
public KeyStore call() throws Exception {
return testStore;
}
}, new char[0])));
DateFormat headerDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
verifier.setRequiredHeaders(Arrays.asList(REQUEST_TARGET, "date"));
MockHttpServletRequest request = new MockHttpServletRequest();
ServerAuthorizationRequest areq = new ServletAuthorizationRequest(request);
// FIRST TEST: missing signature
VerifierResult result = verifier.verify(areq);
Assert.assertEquals(ERROR_MISSING_SIGNATURE, result.getMessage());
SignatureAuthorization signature = new SignatureAuthorization();
signature.setAlgorithm("rsa-sha256");
signature.setKeyId("rsa256key");
signature.setHeaders(new ArrayList<String>());
signature.setSignature(new byte[0]);
request.addHeader("Authorization", "Signature " + signature.toString());
// SECOND TEST: missing REQUEST_TARGET
result = verifier.verify(areq);
Assert.assertEquals(MessageFormat.format(ERROR_MISSING_HEADER_FORMAT, REQUEST_TARGET), result.getMessage());
signature.setHeaders(Arrays.asList(REQUEST_TARGET));
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.addHeader("Authorization", "Signature " + signature.toString());
// THIRD TEST: missing date
result = verifier.verify(areq);
Assert.assertEquals(MessageFormat.format(ERROR_MISSING_HEADER_FORMAT, "date"), result.getMessage());
signature.setHeaders(Arrays.asList(REQUEST_TARGET, "date"));
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.addHeader("Authorization", "Signature " + signature.toString());
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 6000)));
// FOURTH TEST: out-of-range date
result = verifier.verify(areq);
Assert.assertEquals(ERROR_INVALID_DATE, result.getMessage());
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.addHeader("Authorization", "Signature " + signature.toString());
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 3000)));
// FIFTH TEST: unknown key ID
result = verifier.verify(areq);
Assert.assertEquals(MessageFormat.format(ERROR_UNKOWN_KEY_ID_FORMAT, signature.getKeyId()), result.getMessage());
signature.setKeyId("hmac256key");
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.addHeader("Authorization", "Signature " + signature.toString());
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 3000)));
// SIXTH TEST: rsa mismatch
result = verifier.verify(areq);
Assert.assertEquals(MessageFormat.format(ERROR_EXPECTED_RSA_FORMAT, signature.getKeyId()), result.getMessage());
KeyPair keypair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
X509Certificate certificate = generateCertificate(keypair);
testStore.setKeyEntry("rsa256key", keypair.getPrivate(), new char[0], new Certificate[] { certificate });
signature.setKeyId("rsa256key");
signature.setAlgorithm("hmac-sha256");
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.addHeader("Authorization", "Signature " + signature.toString());
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 3000)));
// Seventh TEST: hmac mismatch
result = verifier.verify(areq);
Assert.assertEquals(MessageFormat.format(ERROR_EXPECTED_HMAC_FORMAT, signature.getKeyId()), result.getMessage());
signature.setAlgorithm("rsa-sha256");
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.addHeader("Authorization", "Signature " + signature.toString());
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 3000)));
// EIGHT test: invalid signature
Exception sigEx = null;
try {
verifier.verify(areq);
} catch (Exception e) {
sigEx = e;
}
Assert.assertNotNull(sigEx);
// NINTH test: good signature
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.setMethod("GET");
request.setRequestURI("/");
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 3000)));
String signingString = "(request-target): get /\ndate: " + request.getHeader("date");
byte[] sigBytes = signMessage(keypair.getPrivate(), signingString, "rsa-sha256");
signature.setSignature(sigBytes);
request.addHeader("Authorization", "Signature " + signature.toString());
result = verifier.verify(areq);
Assert.assertTrue("Verification failed", result.isAuthenticated());
// TENTH test: bad signature
request = new MockHttpServletRequest();
areq = new ServletAuthorizationRequest(request);
request.setMethod("GET");
request.setRequestURI("/nogood");
request.addHeader("Date", headerDateFormat.format(new Date(System.currentTimeMillis() - 3000)));
signingString = "(request-target): get /\ndate: " + request.getHeader("date");
sigBytes = signMessage(keypair.getPrivate(), signingString, "rsa-sha256");
signature.setSignature(sigBytes);
request.addHeader("Authorization", "Signature " + signature.toString());
result = verifier.verify(areq);
Assert.assertFalse("Verification succeed when it should have failed", result.isAuthenticated());
Assert.assertEquals(ERROR_VERIFICATION_FAILED, result.getMessage());
}
Aggregations