use of com.disney.http.auth.keychain.KeyChain in project groovity by disney.
the class XmlPolicyParser method processSignature.
private static SignatureVerifierImpl processSignature(Element sig, ServletContext context) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException, MalformedURLException, URISyntaxException {
SignatureVerifierImpl config = new SignatureVerifierImpl();
List<KeyChain> keyChains = new ArrayList<KeyChain>();
processCommon(config, sig);
NodeList bcnodes = sig.getChildNodes();
for (int j = 0; j < bcnodes.getLength(); j++) {
Node bcnode = bcnodes.item(j);
if (bcnode instanceof Element) {
Element bcel = (Element) bcnode;
if (bcel.getNodeName().equals("drift")) {
config.setMaxDateDrift(Long.parseLong(bcel.getTextContent().trim()));
} else if (bcel.getNodeName().equals("headers")) {
config.setRequiredHeaders(Arrays.asList(bcel.getTextContent().trim().split("(,\\s*|\\s+)")));
} else if (bcel.getNodeName().equals("keys")) {
keyChains.add(new MapKeyChainImpl(processKeys(bcel)));
} else if (bcel.getNodeName().equals("keystore")) {
keyChains.add(processKeystore(bcel, context));
}
}
}
config.setKeyChains(keyChains);
return config;
}
use of com.disney.http.auth.keychain.KeyChain 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.keychain.KeyChain 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