Search in sources :

Example 6 with KeyChain

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;
}
Also used : SignatureVerifierImpl(com.disney.http.auth.server.signature.SignatureVerifierImpl) NodeList(org.w3c.dom.NodeList) Node(org.w3c.dom.Node) Element(org.w3c.dom.Element) ArrayList(java.util.ArrayList) KeyChain(com.disney.http.auth.keychain.KeyChain) MapKeyChainImpl(com.disney.http.auth.keychain.MapKeyChainImpl)

Example 7 with KeyChain

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;
}
Also used : KeyChain(com.disney.http.auth.keychain.KeyChain) SignatureException(java.security.SignatureException) IOException(java.io.IOException) GeneralSecurityException(java.security.GeneralSecurityException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) UnrecoverableKeyException(java.security.UnrecoverableKeyException) InvalidKeyException(java.security.InvalidKeyException) ParseException(java.text.ParseException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) AuthenticatedPrincipal(com.disney.http.auth.server.AuthenticatedPrincipal) VerifierResult(com.disney.http.auth.server.VerifierResult) UnrecoverableKeyException(java.security.UnrecoverableKeyException) SignatureAuthorization(com.disney.http.auth.SignatureAuthorization) ParseException(java.text.ParseException) SimpleDateFormat(java.text.SimpleDateFormat) PublicKey(java.security.PublicKey) Key(java.security.Key)

Example 8 with KeyChain

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());
}
Also used : KeyPair(java.security.KeyPair) MockHttpServletRequest(org.springframework.mock.web.MockHttpServletRequest) ServletAuthorizationRequest(com.disney.http.auth.server.ServletAuthorizationRequest) KeyChain(com.disney.http.auth.keychain.KeyChain) KeyStore(java.security.KeyStore) Callable(java.util.concurrent.Callable) Date(java.util.Date) X509Certificate(java.security.cert.X509Certificate) SignatureException(java.security.SignatureException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) SignatureVerifierImpl(com.disney.http.auth.server.signature.SignatureVerifierImpl) KeyStoreKeyChainImpl(com.disney.http.auth.keychain.KeyStoreKeyChainImpl) VerifierResult(com.disney.http.auth.server.VerifierResult) SignatureAuthorization(com.disney.http.auth.SignatureAuthorization) SecretKeySpec(javax.crypto.spec.SecretKeySpec) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) SimpleDateFormat(java.text.SimpleDateFormat) Key(java.security.Key) PrivateKey(java.security.PrivateKey) ServerAuthorizationRequest(com.disney.http.auth.server.ServerAuthorizationRequest) Test(org.junit.Test)

Aggregations

KeyChain (com.disney.http.auth.keychain.KeyChain)8 KeyStoreKeyChainImpl (com.disney.http.auth.keychain.KeyStoreKeyChainImpl)5 HashMap (java.util.HashMap)5 KeyChainKeyLoader (com.disney.http.auth.client.keyloader.KeyChainKeyLoader)4 URIParcel (com.disney.uriparcel.URIParcel)4 File (java.io.File)4 Key (java.security.Key)4 SignatureAuthorization (com.disney.http.auth.SignatureAuthorization)3 SignatureVerifierImpl (com.disney.http.auth.server.signature.SignatureVerifierImpl)3 KeyStore (java.security.KeyStore)3 PrivateKey (java.security.PrivateKey)3 PublicKey (java.security.PublicKey)3 Test (org.junit.Test)3 KeyObjectKeyLoader (com.disney.http.auth.client.keyloader.KeyObjectKeyLoader)2 HttpSignatureSigner (com.disney.http.auth.client.signer.HttpSignatureSigner)2 MapKeyChainImpl (com.disney.http.auth.keychain.MapKeyChainImpl)2 VerifierResult (com.disney.http.auth.server.VerifierResult)2 UnsupportedEncodingException (java.io.UnsupportedEncodingException)2 InvalidKeyException (java.security.InvalidKeyException)2 KeyPair (java.security.KeyPair)2