Repository: cxf
Updated Branches:
refs/heads/2.7.x-fixes 0b9b72228 -> 5b8daa322
Validate trust in a public key credential supplied for UseKey in the STS
Conflicts:
services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/5b8daa32
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/5b8daa32
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/5b8daa32
Branch: refs/heads/2.7.x-fixes
Commit: 5b8daa3229069f49907bd51cdcc45255cba1a492
Parents: 0b9b722
Author: Colm O hEigeartaigh <[email protected]>
Authored: Wed Mar 5 15:44:43 2014 +0000
Committer: Colm O hEigeartaigh <[email protected]>
Committed: Wed Mar 5 16:15:48 2014 +0000
----------------------------------------------------------------------
.../org/apache/cxf/sts/STSPropertiesMBean.java | 15 +++
.../org/apache/cxf/sts/StaticSTSProperties.java | 20 ++++
.../token/provider/DefaultSubjectProvider.java | 28 +++++
.../cxf/sts/operation/IssueSamlUnitTest.java | 116 ++++++++++++++++++-
4 files changed, 176 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/5b8daa32/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 89439cb..3d0110b 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
@@ -195,4 +195,19 @@ public interface STSPropertiesMBean {
*/
void setSamlRealmCodec(SAMLRealmCodec samlRealmCodec);
+ /**
+ * Get whether to validate a client Public Key or Certificate presented as
part of a
+ * UseKey element. This is false 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 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/5b8daa32/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 06486c7..a9da700 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;
@@ -411,4 +412,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/5b8daa32/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 4c4ccb7..cea3bdf 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
@@ -151,6 +151,34 @@ 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 {
+ if (!stsProperties.getSignatureCrypto().verifyTrust(
+ new X509Certificate[]{receivedKey.getX509Cert()},
false)) {
+ LOG.log(Level.FINE, "Error in trust validation of
UseKey");
+ throw new STSException("Error in trust validation
of UseKey", STSException.REQUEST_FAILED);
+ }
+ } 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 {
+ if
(!stsProperties.getSignatureCrypto().verifyTrust(receivedKey.getPublicKey())) {
+ LOG.log(Level.FINE, "Error in trust validation of
UseKey");
+ throw new STSException("Error in trust validation
of UseKey", STSException.REQUEST_FAILED);
+ }
+ } 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/5b8daa32/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 bdd94bf..e6023ac 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
@@ -478,7 +478,7 @@ public class IssueSamlUnitTest extends org.junit.Assert {
}
// Now add UseKey
- UseKeyType useKey = createUseKey(crypto);
+ UseKeyType useKey = createUseKey(crypto, "myclientkey");
JAXBElement<UseKeyType> useKeyType =
new JAXBElement<UseKeyType>(QNameConstants.USE_KEY,
UseKeyType.class, useKey);
request.getAny().add(useKeyType);
@@ -966,6 +966,116 @@ 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<TokenProvider> providerList = new ArrayList<TokenProvider>();
+ 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<String> tokenType =
+ new JAXBElement<String>(
+ QNameConstants.TOKEN_TYPE, String.class,
WSConstants.WSS_SAML2_TOKEN_TYPE
+ );
+ request.getAny().add(tokenType);
+ JAXBElement<String> keyType =
+ new JAXBElement<String>(
+ QNameConstants.KEY_TYPE, String.class,
STSConstants.PUBLIC_KEY_KEYTYPE
+ );
+ request.getAny().add(keyType);
+
+ UseKeyType useKey = createUseKey(crypto, "myclientkey");
+ JAXBElement<UseKeyType> useKeyType =
+ new JAXBElement<UseKeyType>(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<RequestSecurityTokenResponseType> 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.ws.security.crypto.provider",
"org.apache.ws.security.components.crypto.Merlin"
+ );
+
properties.put("org.apache.ws.security.crypto.merlin.keystore.password",
"evespass");
+ properties.put("org.apache.ws.security.crypto.merlin.keystore.file",
"eve.jks");
+
+ useKey = createUseKey(CryptoFactory.getInstance(properties), "eve");
+ useKeyType = new JAXBElement<UseKeyType>(QNameConstants.USE_KEY,
UseKeyType.class, useKey);
+ request.getAny().add(useKeyType);
+
+ // This should work as non-trusted certificates are allowed
+ response = issueOperation.issue(request, webServiceContext);
+ securityTokenResponse = response.getRequestSecurityTokenResponse();
+ assertTrue(!securityTokenResponse.isEmpty());
+
+ // This should fail as the UseKey certificate is not trusted
+ stsProperties.setValidateUseKey(true);
+ try {
+ issueOperation.issue(request, webServiceContext);
+ fail("Failure expected as the UseKey certificate is not trusted");
+ } catch (STSException ex) {
+ // expected
+ }
+
+ }
+
/*
* Create a security context object
*/
@@ -1000,9 +1110,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");