You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2012/04/11 18:23:55 UTC
svn commit: r1324847 - in /cxf/trunk/services/sts:
sts-core/src/main/java/org/apache/cxf/sts/token/renewer/
sts-core/src/test/java/org/apache/cxf/sts/token/renewer/
systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/
Author: coheigea
Date: Wed Apr 11 16:23:54 2012
New Revision: 1324847
URL: http://svn.apache.org/viewvc?rev=1324847&view=rev
Log:
[CXF-4158] - Generate a new ID for a renewed SAML token + Added functionality to test a received AppliesTo address against the audience restriction URI.
Removed:
cxf/trunk/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLTokenValidator.java
Modified:
cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewer.java
cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewerTest.java
cxf/trunk/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewUnitTest.java
Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewer.java?rev=1324847&r1=1324846&r2=1324847&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewer.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewer.java Wed Apr 11 16:23:54 2012
@@ -64,9 +64,13 @@ import org.apache.ws.security.saml.ext.A
import org.apache.ws.security.saml.ext.bean.ConditionsBean;
import org.apache.ws.security.saml.ext.builder.SAML1ComponentBuilder;
import org.apache.ws.security.saml.ext.builder.SAML2ComponentBuilder;
+import org.apache.ws.security.util.UUIDGenerator;
import org.apache.ws.security.util.WSSecurityUtil;
import org.joda.time.DateTime;
import org.opensaml.common.SAMLVersion;
+import org.opensaml.saml1.core.Audience;
+import org.opensaml.saml1.core.AudienceRestrictionCondition;
+import org.opensaml.saml2.core.AudienceRestriction;
/**
* A TokenRenewer implementation that renews a (valid or expired) SAML Token.
@@ -151,31 +155,12 @@ public class SAMLTokenRenewer implements
try {
AssertionWrapper assertion = new AssertionWrapper((Element)tokenToRenew.getToken());
- // Check to see whether the token has expired greater than the configured max expiry time
- if (tokenToRenew.getState() == STATE.EXPIRED) {
- DateTime expiryDate = getExpiryDate(assertion);
- DateTime currentDate = new DateTime();
- if ((currentDate.getMillis() - expiryDate.getMillis()) > (maxExpiry * 1000L)) {
- LOG.log(Level.WARNING, "The token expired too long ago to be renewed");
- throw new STSException(
- "The token expired too long ago to be renewed", STSException.REQUEST_FAILED
- );
- }
- }
-
- ProofOfPossessionValidator popValidator = new ProofOfPossessionValidator();
- if (verifyProofOfPossession
- && !popValidator.checkProofOfPossession(tokenParameters, assertion.getSubjectKeyInfo())) {
- throw new STSException(
- "Failed to verify the proof of possession of the key associated with the "
- + "saml token. No matching key found in the request.",
- STSException.INVALID_REQUEST
- );
- }
+ validateAssertion(assertion, tokenToRenew, tokenParameters);
// Create new Conditions & sign the Assertion
byte[] oldSignature = assertion.getSignatureValue();
createNewConditions(assertion, tokenParameters);
+ String oldId = createNewId(assertion);
signAssertion(assertion, tokenParameters);
Document doc = DOMUtils.createDocument();
@@ -189,7 +174,7 @@ public class SAMLTokenRenewer implements
// Remove the previous token (now expired) from the cache
if (tokenParameters.getTokenStore() != null) {
- tokenParameters.getTokenStore().remove(assertion.getId());
+ tokenParameters.getTokenStore().remove(oldId);
int hash = Arrays.hashCode(oldSignature);
tokenParameters.getTokenStore().remove(Integer.toString(hash));
}
@@ -269,6 +254,100 @@ public class SAMLTokenRenewer implements
return realmMap;
}
+ private void validateAssertion(
+ AssertionWrapper assertion,
+ ReceivedToken tokenToRenew,
+ TokenRenewerParameters tokenParameters
+ ) {
+ // Check to see whether the token has expired greater than the configured max expiry time
+ if (tokenToRenew.getState() == STATE.EXPIRED) {
+ DateTime expiryDate = getExpiryDate(assertion);
+ DateTime currentDate = new DateTime();
+ if ((currentDate.getMillis() - expiryDate.getMillis()) > (maxExpiry * 1000L)) {
+ LOG.log(Level.WARNING, "The token expired too long ago to be renewed");
+ throw new STSException(
+ "The token expired too long ago to be renewed", STSException.REQUEST_FAILED
+ );
+ }
+ }
+
+ // Verify Proof of Possession
+ ProofOfPossessionValidator popValidator = new ProofOfPossessionValidator();
+ if (verifyProofOfPossession
+ && !popValidator.checkProofOfPossession(tokenParameters, assertion.getSubjectKeyInfo())) {
+ throw new STSException(
+ "Failed to verify the proof of possession of the key associated with the "
+ + "saml token. No matching key found in the request.",
+ STSException.INVALID_REQUEST
+ );
+ }
+
+ // Check the AppliesTo address
+ String appliesToAddress = tokenParameters.getAppliesToAddress();
+ if (appliesToAddress != null) {
+ if (assertion.getSaml1() != null) {
+ List<AudienceRestrictionCondition> restrConditions =
+ assertion.getSaml1().getConditions().getAudienceRestrictionConditions();
+ if (!matchSaml1AudienceRestriction(appliesToAddress, restrConditions)) {
+ LOG.log(Level.WARNING, "The AppliesTo address does not match the Audience Restriction");
+ throw new STSException(
+ "The AppliesTo address does not match the Audience Restriction",
+ STSException.INVALID_REQUEST
+ );
+ }
+ } else {
+ List<AudienceRestriction> audienceRestrs =
+ assertion.getSaml2().getConditions().getAudienceRestrictions();
+ if (!matchSaml2AudienceRestriction(appliesToAddress, audienceRestrs)) {
+ LOG.log(Level.WARNING, "The AppliesTo address does not match the Audience Restriction");
+ throw new STSException(
+ "The AppliesTo address does not match the Audience Restriction",
+ STSException.INVALID_REQUEST
+ );
+ }
+ }
+ }
+
+ }
+
+ private boolean matchSaml1AudienceRestriction(
+ String appliesTo, List<AudienceRestrictionCondition> restrConditions
+ ) {
+ boolean found = false;
+ if (restrConditions != null && !restrConditions.isEmpty()) {
+ for (AudienceRestrictionCondition restrCondition : restrConditions) {
+ if (restrCondition.getAudiences() != null) {
+ for (Audience audience : restrCondition.getAudiences()) {
+ if (appliesTo.equals(audience.getUri())) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return found;
+ }
+
+ private boolean matchSaml2AudienceRestriction(
+ String appliesTo, List<AudienceRestriction> audienceRestrictions
+ ) {
+ boolean found = false;
+ if (audienceRestrictions != null && !audienceRestrictions.isEmpty()) {
+ for (AudienceRestriction audienceRestriction : audienceRestrictions) {
+ if (audienceRestriction.getAudiences() != null) {
+ for (org.opensaml.saml2.core.Audience audience : audienceRestriction.getAudiences()) {
+ if (appliesTo.equals(audience.getAudienceURI())) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return found;
+ }
+
private void signAssertion(
AssertionWrapper assertion,
TokenRenewerParameters tokenParameters
@@ -376,6 +455,22 @@ public class SAMLTokenRenewer implements
}
}
+ private String createNewId(AssertionWrapper assertion) {
+ if (assertion.getSaml1() != null) {
+ org.opensaml.saml1.core.Assertion saml1Assertion = assertion.getSaml1();
+ String oldId = saml1Assertion.getID();
+ saml1Assertion.setID("_" + UUIDGenerator.getUUID());
+
+ return oldId;
+ } else {
+ org.opensaml.saml2.core.Assertion saml2Assertion = assertion.getSaml2();
+ String oldId = saml2Assertion.getID();
+ saml2Assertion.setID("_" + UUIDGenerator.getUUID());
+
+ return oldId;
+ }
+ }
+
private void storeTokenInCache(
TokenStore tokenStore,
AssertionWrapper assertion,
Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewerTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewerTest.java?rev=1324847&r1=1324846&r2=1324847&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewerTest.java (original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/renewer/SAMLTokenRenewerTest.java Wed Apr 11 16:23:54 2012
@@ -54,6 +54,7 @@ import org.apache.ws.security.WSConstant
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
import org.apache.ws.security.util.XmlSchemaDateFormat;
import org.junit.BeforeClass;
@@ -120,6 +121,10 @@ public class SAMLTokenRenewerTest extend
assertTrue(renewerResponse != null);
assertTrue(renewerResponse.getToken() != null);
+ String oldId = new AssertionWrapper(samlToken).getId();
+ String newId = new AssertionWrapper((Element)renewerResponse.getToken()).getId();
+ assertFalse(oldId.equals(newId));
+
// Now validate it again
validateTarget = new ReceivedToken(renewerResponse.getToken());
tokenRequirements.setValidateTarget(validateTarget);
@@ -183,6 +188,10 @@ public class SAMLTokenRenewerTest extend
assertTrue(renewerResponse != null);
assertTrue(renewerResponse.getToken() != null);
+ String oldId = new AssertionWrapper(samlToken).getId();
+ String newId = new AssertionWrapper((Element)renewerResponse.getToken()).getId();
+ assertFalse(oldId.equals(newId));
+
// Now validate it again
validateTarget = new ReceivedToken(renewerResponse.getToken());
tokenRequirements.setValidateTarget(validateTarget);
@@ -245,6 +254,10 @@ public class SAMLTokenRenewerTest extend
assertTrue(renewerResponse != null);
assertTrue(renewerResponse.getToken() != null);
+ String oldId = new AssertionWrapper(samlToken).getId();
+ String newId = new AssertionWrapper((Element)renewerResponse.getToken()).getId();
+ assertFalse(oldId.equals(newId));
+
// Now validate it again
validateTarget = new ReceivedToken(renewerResponse.getToken());
tokenRequirements.setValidateTarget(validateTarget);
@@ -308,6 +321,10 @@ public class SAMLTokenRenewerTest extend
assertTrue(renewerResponse != null);
assertTrue(renewerResponse.getToken() != null);
+ String oldId = new AssertionWrapper(samlToken).getId();
+ String newId = new AssertionWrapper((Element)renewerResponse.getToken()).getId();
+ assertFalse(oldId.equals(newId));
+
// Now validate it again
validateTarget = new ReceivedToken(renewerResponse.getToken());
tokenRequirements.setValidateTarget(validateTarget);
@@ -368,6 +385,10 @@ public class SAMLTokenRenewerTest extend
assertTrue(renewerResponse != null);
assertTrue(renewerResponse.getToken() != null);
+ String oldId = new AssertionWrapper(samlToken).getId();
+ String newId = new AssertionWrapper((Element)renewerResponse.getToken()).getId();
+ assertFalse(oldId.equals(newId));
+
// Now validate it again
validateTarget = new ReceivedToken(renewerResponse.getToken());
tokenRequirements.setValidateTarget(validateTarget);
@@ -435,6 +456,58 @@ public class SAMLTokenRenewerTest extend
// Expected
}
}
+
+ /**
+ * Renew a valid SAML1 Assertion but sending a different AppliesTo address.
+ */
+ @org.junit.Test
+ public void renewSAML1AssertionDifferentAppliesTo() throws Exception {
+ // Create the Assertion
+ Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+ CallbackHandler callbackHandler = new PasswordCallbackHandler();
+ Element samlToken =
+ createSAMLAssertion(WSConstants.WSS_SAML_TOKEN_TYPE, crypto, "mystskey", callbackHandler, 50000);
+ Document doc = samlToken.getOwnerDocument();
+ samlToken = (Element)doc.appendChild(samlToken);
+
+ // Validate the Assertion
+ TokenValidator samlTokenValidator = new SAMLTokenValidator();
+ TokenValidatorParameters validatorParameters = createValidatorParameters();
+ TokenRequirements tokenRequirements = validatorParameters.getTokenRequirements();
+ ReceivedToken validateTarget = new ReceivedToken(samlToken);
+ tokenRequirements.setValidateTarget(validateTarget);
+ validatorParameters.setToken(validateTarget);
+
+ assertTrue(samlTokenValidator.canHandleToken(validateTarget));
+
+ TokenValidatorResponse validatorResponse =
+ samlTokenValidator.validateToken(validatorParameters);
+ assertTrue(validatorResponse != null);
+ assertTrue(validatorResponse.getToken() != null);
+ assertTrue(validatorResponse.getToken().getState() == STATE.VALID);
+
+ // Renew the Assertion
+ TokenRenewerParameters renewerParameters = new TokenRenewerParameters();
+ renewerParameters.setAppliesToAddress("http://dummy-service.com/dummy2");
+ renewerParameters.setStsProperties(validatorParameters.getStsProperties());
+ renewerParameters.setPrincipal(new CustomTokenPrincipal("alice"));
+ renewerParameters.setWebServiceContext(validatorParameters.getWebServiceContext());
+ renewerParameters.setKeyRequirements(validatorParameters.getKeyRequirements());
+ renewerParameters.setTokenRequirements(validatorParameters.getTokenRequirements());
+ renewerParameters.setTokenStore(validatorParameters.getTokenStore());
+ renewerParameters.setToken(validatorResponse.getToken());
+
+ TokenRenewer samlTokenRenewer = new SAMLTokenRenewer();
+ samlTokenRenewer.setVerifyProofOfPossession(false);
+ assertTrue(samlTokenRenewer.canHandleToken(validatorResponse.getToken()));
+
+ try {
+ samlTokenRenewer.renewToken(renewerParameters);
+ fail("Failure expected on sending a different AppliesTo address");
+ } catch (Exception ex) {
+ // expected
+ }
+ }
private TokenValidatorParameters createValidatorParameters() throws WSSecurityException {
TokenValidatorParameters parameters = new TokenValidatorParameters();
Modified: cxf/trunk/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewUnitTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewUnitTest.java?rev=1324847&r1=1324846&r2=1324847&view=diff
==============================================================================
--- cxf/trunk/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewUnitTest.java (original)
+++ cxf/trunk/services/sts/systests/advanced/src/test/java/org/apache/cxf/systest/sts/renew/SAMLRenewUnitTest.java Wed Apr 11 16:23:54 2012
@@ -74,7 +74,7 @@ public class SAMLRenewUnitTest extends A
Thread.sleep(5000);
// Renew the token
- SecurityToken renewedToken = renewSecurityToken(bus, wsdlLocation, token);
+ SecurityToken renewedToken = renewSecurityToken(bus, wsdlLocation, token, false);
assertFalse(token.equals(renewedToken));
// Try to validate old token -> fail.
@@ -108,7 +108,7 @@ public class SAMLRenewUnitTest extends A
Thread.sleep(5000);
// Renew the token
- SecurityToken renewedToken = renewSecurityToken(bus, wsdlLocation, token);
+ SecurityToken renewedToken = renewSecurityToken(bus, wsdlLocation, token, false);
assertFalse(token.equals(renewedToken));
// Try to validate old token -> fail.
@@ -147,13 +147,41 @@ public class SAMLRenewUnitTest extends A
// Renew the token - this should fail as the STS will reject an attempt to renew a valid token
// unless it has been configured otherwise
try {
- renewSecurityToken(bus, wsdlLocation, token);
+ renewSecurityToken(bus, wsdlLocation, token, true);
fail("Failure expected on trying to renew a valid token");
} catch (Exception ex) {
// expected
}
}
+ @org.junit.Test
+ public void testRenewSAML2TokenDifferentAppliesTo() throws Exception {
+ SpringBusFactory bf = new SpringBusFactory();
+ URL busFile = SAMLRenewUnitTest.class.getResource("cxf-client-unit.xml");
+
+ Bus bus = bf.createBus(busFile.toString());
+ SpringBusFactory.setDefaultBus(bus);
+ SpringBusFactory.setThreadDefaultBus(bus);
+
+ String wsdlLocation =
+ "https://localhost:" + STSPORT + "/SecurityTokenService/Transport?wsdl";
+
+ // Request the token
+ SecurityToken token = requestSecurityToken(bus, wsdlLocation, WSConstants.WSS_SAML2_TOKEN_TYPE, 5);
+ assertNotNull(token);
+ // Sleep to expire the token
+ Thread.sleep(5000);
+
+ // Renew the token
+ token.setIssuerAddress("http://www.apache.org");
+ try {
+ renewSecurityToken(bus, wsdlLocation, token, true);
+ fail("Failure expected on a different AppliesTo address");
+ } catch (Exception ex) {
+ // expected
+ }
+ }
+
private SecurityToken requestSecurityToken(
Bus bus, String wsdlLocation, String tokenType, int ttl
) throws Exception {
@@ -206,7 +234,7 @@ public class SAMLRenewUnitTest extends A
}
private SecurityToken renewSecurityToken(
- Bus bus, String wsdlLocation, SecurityToken securityToken
+ Bus bus, String wsdlLocation, SecurityToken securityToken, boolean enableAppliesTo
) throws Exception {
STSClient stsClient = new STSClient(bus);
stsClient.setWsdlLocation(wsdlLocation);
@@ -221,7 +249,7 @@ public class SAMLRenewUnitTest extends A
);
properties.put(SecurityConstants.STS_TOKEN_PROPERTIES, "serviceKeystore.properties");
- stsClient.setEnableAppliesTo(false);
+ stsClient.setEnableAppliesTo(enableAppliesTo);
// Request a token with a TTL of 60 minutes
stsClient.setTtl(60 * 60);
stsClient.setEnableLifetime(true);