Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C7074185F4 for ; Mon, 21 Dec 2015 15:20:16 +0000 (UTC) Received: (qmail 66534 invoked by uid 500); 21 Dec 2015 15:20:16 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 66470 invoked by uid 500); 21 Dec 2015 15:20:16 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 66461 invoked by uid 99); 21 Dec 2015 15:20:16 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Dec 2015 15:20:16 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 3D396E04AF; Mon, 21 Dec 2015 15:20:16 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: coheigea@apache.org To: commits@cxf.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: cxf git commit: Default to default identifier if no keyInfo is available Date: Mon, 21 Dec 2015 15:20:16 +0000 (UTC) Repository: cxf Updated Branches: refs/heads/3.1.x-fixes 3af4374dd -> 078d14e09 Default to default identifier if no keyInfo is available Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/078d14e0 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/078d14e0 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/078d14e0 Branch: refs/heads/3.1.x-fixes Commit: 078d14e0926d345d4eb4bc80ba535a5d288483a3 Parents: 3af4374 Author: Colm O hEigeartaigh Authored: Mon Dec 21 15:05:18 2015 +0000 Committer: Colm O hEigeartaigh Committed: Mon Dec 21 15:12:54 2015 +0000 ---------------------------------------------------------------------- .../saml/sso/SAMLProtocolResponseValidator.java | 132 ++++++++++--------- 1 file changed, 72 insertions(+), 60 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/078d14e0/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java index d085a6e..4c084f8 100644 --- a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java +++ b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java @@ -70,27 +70,27 @@ import org.opensaml.xmlsec.signature.support.SignatureValidator; /** * Validate a SAML (1.1 or 2.0) Protocol Response. It validates the Response against the specs, - * the signature of the Response (if it exists), and any internal Assertion stored in the Response + * the signature of the Response (if it exists), and any internal Assertion stored in the Response * - including any signature. It validates the status code of the Response as well. */ public class SAMLProtocolResponseValidator { - - public static final String SAML2_STATUSCODE_SUCCESS = + + public static final String SAML2_STATUSCODE_SUCCESS = "urn:oasis:names:tc:SAML:2.0:status:Success"; public static final String SAML1_STATUSCODE_SUCCESS = "Success"; - + private static final Logger LOG = LogUtils.getL7dLogger(SAMLProtocolResponseValidator.class); - + private Validator assertionValidator = new SamlAssertionValidator(); private Validator signatureValidator = new SignatureTrustValidator(); private boolean keyInfoMustBeAvailable = true; - + /** - * The time in seconds in the future within which the NotBefore time of an incoming + * The time in seconds in the future within which the NotBefore time of an incoming * Assertion is valid. The default is 60 seconds. */ private int futureTTL = 60; - + /** * Validate a SAML 2 Protocol Response * @param samlResponse @@ -116,7 +116,7 @@ public class SAMLProtocolResponseValidator { ); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + if (samlResponse.getIssueInstant() != null) { DateTime currentTime = new DateTime(); currentTime = currentTime.plusSeconds(futureTTL); @@ -125,7 +125,7 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + if (SAMLVersion.VERSION_20 != samlResponse.getVersion()) { LOG.fine( "SAML Version of " + samlResponse.getVersion() @@ -133,16 +133,16 @@ public class SAMLProtocolResponseValidator { ); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + validateResponseSignature(samlResponse, sigCrypto, callbackHandler); Document doc = samlResponse.getDOM().getOwnerDocument(); // Decrypt any encrypted Assertions and add them to the Response (note that this will break any // signature on the Response) for (org.opensaml.saml.saml2.core.EncryptedAssertion assertion : samlResponse.getEncryptedAssertions()) { - + Element decAssertion = decryptAssertion(assertion, sigCrypto, callbackHandler); - + SamlAssertionWrapper wrapper = new SamlAssertionWrapper(decAssertion); samlResponse.getAssertions().add(wrapper.getSaml2()); } @@ -153,7 +153,7 @@ public class SAMLProtocolResponseValidator { validateAssertion(wrapper, sigCrypto, callbackHandler, doc); } } - + /** * Validate a SAML 1.1 Protocol Response * @param samlResponse @@ -190,7 +190,7 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + if (SAMLVersion.VERSION_11 != samlResponse.getVersion()) { LOG.fine( "SAML Version of " + samlResponse.getVersion() @@ -198,7 +198,7 @@ public class SAMLProtocolResponseValidator { ); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + validateResponseSignature(samlResponse, sigCrypto, callbackHandler); // Validate Assertions @@ -209,7 +209,7 @@ public class SAMLProtocolResponseValidator { ); } } - + /** * Validate the Response signature (if it exists) */ @@ -221,13 +221,13 @@ public class SAMLProtocolResponseValidator { if (!samlResponse.isSigned()) { return; } - + validateResponseSignature( samlResponse.getSignature(), samlResponse.getDOM().getOwnerDocument(), sigCrypto, callbackHandler ); } - + /** * Validate the Response signature (if it exists) */ @@ -239,18 +239,18 @@ public class SAMLProtocolResponseValidator { if (!samlResponse.isSigned()) { return; } - + validateResponseSignature( samlResponse.getSignature(), samlResponse.getDOM().getOwnerDocument(), sigCrypto, callbackHandler ); } - + /** * Validate the response signature */ private void validateResponseSignature( - Signature signature, + Signature signature, Document doc, Crypto sigCrypto, CallbackHandler callbackHandler @@ -260,13 +260,13 @@ public class SAMLProtocolResponseValidator { WSSConfig wssConfig = WSSConfig.getNewInstance(); requestData.setWssConfig(wssConfig); requestData.setCallbackHandler(callbackHandler); - + SAMLKeyInfo samlKeyInfo = null; - + KeyInfo keyInfo = signature.getKeyInfo(); if (keyInfo != null) { try { - samlKeyInfo = + samlKeyInfo = SAMLUtil.getCredentialFromKeyInfo( keyInfo.getDOM(), new WSSSAMLKeyInfoProcessor(requestData, new WSDocInfo(doc)), sigCrypto ); @@ -281,7 +281,7 @@ public class SAMLProtocolResponseValidator { LOG.fine("No KeyInfo supplied in the SAMLResponse signature"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // Validate Signature against profiles validateSignatureAgainstProfiles(signature, samlKeyInfo); @@ -297,10 +297,10 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + protected SAMLKeyInfo createKeyInfoFromDefaultAlias(Crypto sigCrypto) throws WSSecurityException { try { - X509Certificate[] certs = RSSecurityUtils.getCertificates(sigCrypto, + X509Certificate[] certs = RSSecurityUtils.getCertificates(sigCrypto, sigCrypto.getDefaultX509Identifier()); SAMLKeyInfo samlKeyInfo = new SAMLKeyInfo(new X509Certificate[]{certs[0]}); samlKeyInfo.setPublicKey(certs[0].getPublicKey()); @@ -310,12 +310,12 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE, ex); } } - + /** * Validate a signature against the profiles */ private void validateSignatureAgainstProfiles( - Signature signature, + Signature signature, SAMLKeyInfo samlKeyInfo ) throws WSSecurityException { // Validate Signature against profiles @@ -343,7 +343,7 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + /** * Validate an internal Assertion */ @@ -355,27 +355,27 @@ public class SAMLProtocolResponseValidator { ) throws WSSecurityException { Credential credential = new Credential(); credential.setSamlAssertion(assertion); - + RequestData requestData = new RequestData(); requestData.setSigVerCrypto(sigCrypto); WSSConfig wssConfig = WSSConfig.getNewInstance(); requestData.setWssConfig(wssConfig); requestData.setCallbackHandler(callbackHandler); - + if (assertion.isSigned()) { if (assertion.getSaml1() != null) { assertion.getSaml1().getDOM().setIdAttributeNS(null, "AssertionID", true); } else { assertion.getSaml2().getDOM().setIdAttributeNS(null, "ID", true); } - + // Verify the signature try { Signature sig = assertion.getSignature(); WSDocInfo docInfo = new WSDocInfo(sig.getDOM().getOwnerDocument()); - + SAMLKeyInfo samlKeyInfo = null; - + KeyInfo keyInfo = sig.getKeyInfo(); if (keyInfo != null) { samlKeyInfo = SAMLUtil.getCredentialFromKeyInfo( @@ -389,12 +389,12 @@ public class SAMLProtocolResponseValidator { LOG.fine("No KeyInfo supplied in the SAMLResponse assertion signature"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + assertion.verifySignature(samlKeyInfo); - + assertion.parseSubject( new WSSSAMLKeyInfoProcessor(requestData, new WSDocInfo(doc)), - requestData.getSigVerCrypto(), + requestData.getSigVerCrypto(), requestData.getCallbackHandler() ); } catch (WSSecurityException e) { @@ -402,7 +402,7 @@ public class SAMLProtocolResponseValidator { throw e; } } - + // Validate the Assertion & verify trust in the signature try { assertionValidator.validate(credential, requestData); @@ -411,13 +411,13 @@ public class SAMLProtocolResponseValidator { throw ex; } } - + private Element decryptAssertion( org.opensaml.saml.saml2.core.EncryptedAssertion assertion, Crypto sigCrypto, CallbackHandler callbackHandler ) throws WSSecurityException { EncryptedData encryptedData = assertion.getEncryptedData(); Element encryptedDataDOM = encryptedData.getDOM(); - + Element encKeyElement = getNode(assertion.getDOM(), WSS4JConstants.ENC_NS, "EncryptedKey", 0); if (encKeyElement == null) { encKeyElement = getNode(encryptedDataDOM, WSS4JConstants.ENC_NS, "EncryptedKey", 0); @@ -426,17 +426,17 @@ public class SAMLProtocolResponseValidator { LOG.log(Level.FINE, "EncryptedKey element is not available"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + X509Certificate cert = loadCertificate(sigCrypto, encKeyElement); if (cert == null) { LOG.fine("X509Certificate cannot be retrieved from EncryptedKey element"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + // now start decrypting String keyEncAlgo = getEncodingMethodAlgorithm(encKeyElement); String digestAlgo = getDigestMethodAlgorithm(encKeyElement); - + Element cipherValue = getNode(encKeyElement, WSS4JConstants.ENC_NS, "CipherValue", 0); if (cipherValue == null) { LOG.fine("CipherValue element is not available"); @@ -447,7 +447,7 @@ public class SAMLProtocolResponseValidator { LOG.fine("A CallbackHandler must be configured to decrypt encrypted Assertions"); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + PrivateKey key = null; try { key = sigCrypto.getPrivateKey(cert, callbackHandler); @@ -455,7 +455,7 @@ public class SAMLProtocolResponseValidator { LOG.log(Level.FINE, "Encrypted key can not be decrypted", ex); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - Cipher cipher = + Cipher cipher = EncryptionUtils.initCipherWithKey(keyEncAlgo, digestAlgo, Cipher.DECRYPT_MODE, key); byte[] decryptedBytes = null; try { @@ -468,9 +468,9 @@ public class SAMLProtocolResponseValidator { LOG.log(Level.FINE, "Encrypted key can not be decrypted", ex); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + String symKeyAlgo = getEncodingMethodAlgorithm(encryptedDataDOM); - + byte[] decryptedPayload = null; try { decryptedPayload = decryptPayload(encryptedDataDOM, decryptedBytes, symKeyAlgo); @@ -478,7 +478,7 @@ public class SAMLProtocolResponseValidator { LOG.log(Level.FINE, "Payload can not be decrypted", ex); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } - + Document payloadDoc = null; try { payloadDoc = StaxUtils.read(new InputStreamReader(new ByteArrayInputStream(decryptedPayload), @@ -489,18 +489,18 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + private Element getNode(Element parent, String ns, String name, int index) { NodeList list = parent.getElementsByTagNameNS(ns, name); if (list != null && list.getLength() >= index + 1) { return (Element)list.item(index); - } + } return null; } private X509Certificate loadCertificate(Crypto crypto, Element encKeyElement) throws WSSecurityException { - Element certNode = + Element certNode = getNode(encKeyElement, Constants.SignatureSpecNS, "X509Certificate", 0); if (certNode != null) { try { @@ -510,7 +510,7 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } } - + certNode = getNode(encKeyElement, Constants.SignatureSpecNS, "X509IssuerSerial", 0); if (certNode != null) { try { @@ -521,9 +521,21 @@ public class SAMLProtocolResponseValidator { } } + if (crypto.getDefaultX509Identifier() != null) { + try { + X509Certificate[] certs = + RSSecurityUtils.getCertificates(crypto, crypto.getDefaultX509Identifier()); + if (certs.length > 0) { + return certs[0]; + } + } catch (Exception ex) { + LOG.log(Level.FINE, "X509Certificate can not be created", ex); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + } return null; } - + private String getEncodingMethodAlgorithm(Element parent) throws WSSecurityException { Element encMethod = getNode(parent, WSS4JConstants.ENC_NS, "EncryptionMethod", 0); if (encMethod == null) { @@ -532,7 +544,7 @@ public class SAMLProtocolResponseValidator { } return encMethod.getAttribute("Algorithm"); } - + private String getDigestMethodAlgorithm(Element parent) { Element encMethod = getNode(parent, WSS4JConstants.ENC_NS, "EncryptionMethod", 0); if (encMethod != null) { @@ -543,14 +555,14 @@ public class SAMLProtocolResponseValidator { } return null; } - - + + private byte[] decryptPayload( Element root, byte[] secretKeyBytes, String symEncAlgo ) throws WSSecurityException { SecretKey key = KeyUtils.prepareSecretKey(symEncAlgo, secretKeyBytes); try { - XMLCipher xmlCipher = + XMLCipher xmlCipher = EncryptionUtils.initXMLCipher(symEncAlgo, XMLCipher.DECRYPT_MODE, key); return xmlCipher.decryptToByteArray(root); } catch (XMLEncryptionException ex) { @@ -569,5 +581,5 @@ public class SAMLProtocolResponseValidator { public void setFutureTTL(int futureTTL) { this.futureTTL = futureTTL; } - + }