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 E57B410DFB for ; Wed, 5 Mar 2014 15:45:36 +0000 (UTC) Received: (qmail 30708 invoked by uid 500); 5 Mar 2014 15:45:34 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 30589 invoked by uid 500); 5 Mar 2014 15:45:34 -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 30582 invoked by uid 99); 5 Mar 2014 15:45:33 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Mar 2014 15:45:33 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 7800C9372CF; Wed, 5 Mar 2014 15:45:33 +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: git commit: Validate trust in a public key credential supplied for UseKey in the STS Date: Wed, 5 Mar 2014 15:45:33 +0000 (UTC) Repository: cxf Updated Branches: refs/heads/master 7a4023d78 -> 540508c6e Validate trust in a public key credential supplied for UseKey in the STS Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/540508c6 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/540508c6 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/540508c6 Branch: refs/heads/master Commit: 540508c6ef33e77a1b2270c24b954141f9564f92 Parents: 7a4023d Author: Colm O hEigeartaigh Authored: Wed Mar 5 15:44:43 2014 +0000 Committer: Colm O hEigeartaigh Committed: Wed Mar 5 15:45:06 2014 +0000 ---------------------------------------------------------------------- .../org/apache/cxf/sts/STSPropertiesMBean.java | 15 +++ .../org/apache/cxf/sts/StaticSTSProperties.java | 20 ++++ .../token/provider/DefaultSubjectProvider.java | 22 ++++ .../cxf/sts/operation/IssueSamlUnitTest.java | 115 ++++++++++++++++++- 4 files changed, 169 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/540508c6/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java ---------------------------------------------------------------------- diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java index 954eafc..17f56ae 100644 --- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java +++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java @@ -193,5 +193,20 @@ public interface STSPropertiesMBean { * @param samlRealmCodec the SAMLRealmCodec object to use. */ void setSamlRealmCodec(SAMLRealmCodec samlRealmCodec); + + /** + * Get whether to validate a client Public Key or Certificate presented as part of a + * UseKey element. This is true by default. + */ + boolean isValidateUseKey(); + + /** + * Set whether to validate a client Public Key or Certificate presented as part of a + * UseKey element. If this is set to true (the default), the public key must be trusted + * by the Signature Crypto of the STS. + * + * @param validateUseKey whether to validate a client UseKey or not. + */ + void setValidateUseKey(boolean validateUseKey); } http://git-wip-us.apache.org/repos/asf/cxf/blob/540508c6/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java ---------------------------------------------------------------------- diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java index d5c8fb8..afa611b 100644 --- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java +++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java @@ -66,6 +66,7 @@ public class StaticSTSProperties implements STSPropertiesMBean { private RelationshipResolver relationshipResolver; private SAMLRealmCodec samlRealmCodec; private Bus bus; + private boolean validateUseKey = true; /** * Load the CallbackHandler, Crypto objects, if necessary. @@ -409,4 +410,23 @@ public class StaticSTSProperties implements STSPropertiesMBean { public void setBus(Bus bus) { this.bus = bus; } + + /** + * Get whether to validate a client Public Key or Certificate presented as part of a + * UseKey element. This is true by default. + */ + public boolean isValidateUseKey() { + return validateUseKey; + } + + /** + * Set whether to validate a client Public Key or Certificate presented as part of a + * UseKey element. If this is set to true (the default), the public key must be trusted + * by the Signature Crypto of the STS. + * + * @param validateUseKey whether to validate a client UseKey or not. + */ + public void setValidateUseKey(boolean validateUseKey) { + this.validateUseKey = validateUseKey; + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/540508c6/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java ---------------------------------------------------------------------- diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java index bc8d433..188cb8f 100644 --- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java +++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java @@ -164,6 +164,28 @@ public class DefaultSubjectProvider implements SubjectProvider { } } else if (STSConstants.PUBLIC_KEY_KEYTYPE.equals(keyType)) { ReceivedKey receivedKey = keyRequirements.getReceivedKey(); + + // Validate UseKey trust + if (stsProperties.isValidateUseKey() && stsProperties.getSignatureCrypto() != null) { + if (receivedKey.getX509Cert() != null) { + try { + stsProperties.getSignatureCrypto().verifyTrust( + new X509Certificate[]{receivedKey.getX509Cert()}, false); + } catch (WSSecurityException e) { + LOG.log(Level.FINE, "Error in trust validation of UseKey: ", e); + throw new STSException("Error in trust validation of UseKey", STSException.REQUEST_FAILED); + } + } + if (receivedKey.getPublicKey() != null) { + try { + stsProperties.getSignatureCrypto().verifyTrust(receivedKey.getPublicKey()); + } catch (WSSecurityException e) { + LOG.log(Level.FINE, "Error in trust validation of UseKey: ", e); + throw new STSException("Error in trust validation of UseKey", STSException.REQUEST_FAILED); + } + } + } + KeyInfoBean keyInfo = createKeyInfo(receivedKey.getX509Cert(), receivedKey.getPublicKey()); subjectBean.setKeyInfo(keyInfo); } http://git-wip-us.apache.org/repos/asf/cxf/blob/540508c6/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlUnitTest.java ---------------------------------------------------------------------- diff --git a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlUnitTest.java b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlUnitTest.java index 15635d9..28b731b 100644 --- a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlUnitTest.java +++ b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlUnitTest.java @@ -479,7 +479,7 @@ public class IssueSamlUnitTest extends org.junit.Assert { } // Now add UseKey - UseKeyType useKey = createUseKey(crypto); + UseKeyType useKey = createUseKey(crypto, "myclientkey"); JAXBElement useKeyType = new JAXBElement(QNameConstants.USE_KEY, UseKeyType.class, useKey); request.getAny().add(useKeyType); @@ -971,6 +971,115 @@ public class IssueSamlUnitTest extends org.junit.Assert { assertTrue(tokenString.contains(WSConstants.C14N_EXCL_WITH_COMMENTS)); } + /** + * Test to UseKey validation + */ + @org.junit.Test + public void testUseKey() throws Exception { + TokenIssueOperation issueOperation = new TokenIssueOperation(); + + // Add Token Provider + List providerList = new ArrayList(); + providerList.add(new SAMLTokenProvider()); + issueOperation.setTokenProviders(providerList); + + // Add Service + ServiceMBean service = new StaticService(); + service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy")); + issueOperation.setServices(Collections.singletonList(service)); + + // Add STSProperties object + STSPropertiesMBean stsProperties = new StaticSTSProperties(); + Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties()); + stsProperties.setEncryptionCrypto(crypto); + stsProperties.setSignatureCrypto(crypto); + stsProperties.setEncryptionUsername("myservicekey"); + stsProperties.setSignatureUsername("mystskey"); + stsProperties.setCallbackHandler(new PasswordCallbackHandler()); + stsProperties.setIssuer("STS"); + issueOperation.setStsProperties(stsProperties); + + // Mock up a request + RequestSecurityTokenType request = new RequestSecurityTokenType(); + JAXBElement tokenType = + new JAXBElement( + QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE + ); + request.getAny().add(tokenType); + JAXBElement keyType = + new JAXBElement( + QNameConstants.KEY_TYPE, String.class, STSConstants.PUBLIC_KEY_KEYTYPE + ); + request.getAny().add(keyType); + + UseKeyType useKey = createUseKey(crypto, "myclientkey"); + JAXBElement useKeyType = + new JAXBElement(QNameConstants.USE_KEY, UseKeyType.class, useKey); + request.getAny().add(useKeyType); + + request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy")); + + // Mock up message context + MessageImpl msg = new MessageImpl(); + WrappedMessageContext msgCtx = new WrappedMessageContext(msg); + msgCtx.put( + SecurityContext.class.getName(), + createSecurityContext(new CustomTokenPrincipal("alice")) + ); + WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx); + + // Issue a token + RequestSecurityTokenResponseCollectionType response = + issueOperation.issue(request, webServiceContext); + List securityTokenResponse = + response.getRequestSecurityTokenResponse(); + assertTrue(!securityTokenResponse.isEmpty()); + + // Test the generated token. + Element assertion = null; + for (Object tokenObject : securityTokenResponse.get(0).getAny()) { + if (tokenObject instanceof JAXBElement + && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement)tokenObject).getName())) { + RequestedSecurityTokenType rstType = + (RequestedSecurityTokenType)((JAXBElement)tokenObject).getValue(); + assertion = (Element)rstType.getAny(); + } + } + + String tokenString = DOM2Writer.nodeToString(assertion); + assertTrue(tokenString.contains("AttributeStatement")); + assertTrue(tokenString.contains("alice")); + assertTrue(tokenString.contains(SAML2Constants.CONF_HOLDER_KEY)); + + // Now remove the UseKey + send a non-trusted UseKey certificate + request.getAny().remove(useKeyType); + + Properties properties = new Properties(); + properties.put( + "org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin" + ); + properties.put("org.apache.wss4j.crypto.merlin.keystore.password", "evespass"); + properties.put("org.apache.wss4j.crypto.merlin.keystore.file", "eve.jks"); + + useKey = createUseKey(CryptoFactory.getInstance(properties), "eve"); + useKeyType = new JAXBElement(QNameConstants.USE_KEY, UseKeyType.class, useKey); + request.getAny().add(useKeyType); + + // This should fail as the UseKey certificate is not trusted + try { + issueOperation.issue(request, webServiceContext); + fail("Failure expected as the UseKey certificate is not trusted"); + } catch (STSException ex) { + // expected + } + + // Now allow non-trusted UseKey certificates... + stsProperties.setValidateUseKey(false); + response = issueOperation.issue(request, webServiceContext); + securityTokenResponse = response.getRequestSecurityTokenResponse(); + assertTrue(!securityTokenResponse.isEmpty()); + } + /* * Create a security context object */ @@ -1005,9 +1114,9 @@ public class IssueSamlUnitTest extends org.junit.Assert { /* * Mock up a UseKeyType object */ - private UseKeyType createUseKey(Crypto crypto) throws Exception { + private UseKeyType createUseKey(Crypto crypto, String alias) throws Exception { CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); - cryptoType.setAlias("myclientkey"); + cryptoType.setAlias(alias); X509Certificate[] certs = crypto.getX509Certificates(cryptoType); Document doc = DOMUtils.createDocument(); Element x509Data = doc.createElementNS(WSConstants.SIG_NS, "ds:X509Data");