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 2011/11/29 13:11:14 UTC
svn commit: r1207844 - in /cxf/trunk/services/sts/sts-core/src:
main/java/org/apache/cxf/sts/token/provider/
main/java/org/apache/cxf/sts/token/validator/
test/java/org/apache/cxf/sts/token/validator/
Author: coheigea
Date: Tue Nov 29 12:11:13 2011
New Revision: 1207844
URL: http://svn.apache.org/viewvc?rev=1207844&view=rev
Log:
[CXF-3931] - STS SAMLTokenValidator doesn't validate condition
Modified:
cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java
cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java
cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java
cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java
Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java?rev=1207844&r1=1207843&r2=1207844&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultConditionsProvider.java Tue Nov 29 12:11:13 2011
@@ -18,22 +18,97 @@
*/
package org.apache.cxf.sts.token.provider;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.sts.request.Lifetime;
+import org.apache.cxf.ws.security.sts.provider.STSException;
import org.apache.ws.security.saml.ext.bean.ConditionsBean;
+import org.apache.ws.security.util.XmlSchemaDateFormat;
+import org.joda.time.DateTime;
/**
* A default implementation of the ConditionsProvider interface.
*/
public class DefaultConditionsProvider implements ConditionsProvider {
+ public static final long DEFAULT_MAX_LIFETIME = 60L * 60L;
+
+ private static final Logger LOG = LogUtils.getL7dLogger(DefaultConditionsProvider.class);
+
private long lifetime = 300L;
+ private long maxLifetime = DEFAULT_MAX_LIFETIME;
+ private boolean failLifetimeExceedance = true;
+ private boolean acceptClientLifetime;
+
+ /**
+ * Set the default lifetime in seconds for issued SAML tokens
+ * @param default lifetime in seconds
+ */
public void setLifetime(long lifetime) {
this.lifetime = lifetime;
}
+ /**
+ * Get the default lifetime in seconds for issued SAML token where requestor
+ * doesn't specify a lifetime element
+ * @return the lifetime in seconds
+ */
public long getLifetime() {
return lifetime;
}
+
+ /**
+ * Set the maximum lifetime in seconds for issued SAML tokens
+ * @param maximum lifetime in seconds
+ */
+ public void setMaxLifetime(long maxLifetime) {
+ this.maxLifetime = maxLifetime;
+ }
+
+ /**
+ * Get the maximum lifetime in seconds for issued SAML token
+ * if requestor specifies lifetime element
+ * @return the maximum lifetime in seconds
+ */
+ public long getMaxLifetime() {
+ return maxLifetime;
+ }
+
+ /**
+ * Is client lifetime element accepted
+ * Default: false
+ */
+ public boolean isAcceptClientLifetime() {
+ return this.acceptClientLifetime;
+ }
+
+ /**
+ * Set whether client lifetime is accepted
+ */
+ public void setAcceptClientLifetime(boolean acceptClientLifetime) {
+ this.acceptClientLifetime = acceptClientLifetime;
+ }
+
+ /**
+ * If requested lifetime exceeds shall it fail (default)
+ * or overwrite with maximum lifetime
+ */
+ public boolean isFailLifetimeExceedance() {
+ return this.failLifetimeExceedance;
+ }
+
+ /**
+ * If requested lifetime exceeds shall it fail (default)
+ * or overwrite with maximum lifetime
+ */
+ public void setFailLifetimeExceedance(boolean failLifetimeExceedance) {
+ this.failLifetimeExceedance = failLifetimeExceedance;
+ }
+
/**
* Get a ConditionsBean object.
@@ -41,7 +116,41 @@ public class DefaultConditionsProvider i
public ConditionsBean getConditions(TokenProviderParameters providerParameters) {
ConditionsBean conditions = new ConditionsBean();
if (lifetime > 0) {
- conditions.setTokenPeriodMinutes((int)(lifetime / 60L));
+ Lifetime tokenLifetime = providerParameters.getTokenRequirements().getLifetime();
+ if (acceptClientLifetime && tokenLifetime != null) {
+ try {
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ Date creationTime = fmt.parse(tokenLifetime.getCreated());
+ Date expirationTime = fmt.parse(tokenLifetime.getExpires());
+
+ long requestedLifetime = expirationTime.getTime() - creationTime.getTime();
+ if (requestedLifetime > (getMaxLifetime() * 1000L)) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Requested lifetime [").append(requestedLifetime / 1000L);
+ sb.append(" sec] exceed configured maximum lifetime [").append(getMaxLifetime());
+ sb.append(" sec]");
+ LOG.warning(sb.toString());
+ if (isFailLifetimeExceedance()) {
+ throw new STSException("Requested lifetime exceeds maximum lifetime",
+ STSException.INVALID_TIME);
+ } else {
+ expirationTime.setTime(creationTime.getTime() + (getMaxLifetime() * 1000L));
+ }
+ }
+
+ DateTime creationDateTime = new DateTime(creationTime.getTime());
+ DateTime expirationDateTime = new DateTime(expirationTime.getTime());
+
+ conditions.setNotAfter(expirationDateTime);
+ conditions.setNotBefore(creationDateTime);
+ } catch (ParseException e) {
+ LOG.warning("Failed to parse life time element: " + e.getMessage());
+ conditions.setTokenPeriodMinutes((int)(lifetime / 60L));
+ }
+
+ } else {
+ conditions.setTokenPeriodMinutes((int)(lifetime / 60L));
+ }
} else {
conditions.setTokenPeriodMinutes(5);
}
Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java?rev=1207844&r1=1207843&r2=1207844&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/SAMLTokenProvider.java Tue Nov 29 12:11:13 2011
@@ -55,6 +55,9 @@ import org.apache.ws.security.saml.ext.b
import org.apache.ws.security.saml.ext.bean.ConditionsBean;
import org.apache.ws.security.saml.ext.bean.SubjectBean;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLVersion;
+
/**
* A TokenProvider implementation that provides a SAML Token.
*/
@@ -152,7 +155,21 @@ public class SAMLTokenProvider implement
} else {
response.setTokenId(token.getAttribute("AssertionID"));
}
- response.setLifetime(conditionsProvider.getLifetime());
+
+ DateTime validFrom = null;
+ DateTime validTill = null;
+ long lifetime = 0;
+ if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)) {
+ validFrom = assertion.getSaml2().getConditions().getNotBefore();
+ validTill = assertion.getSaml2().getConditions().getNotOnOrAfter();
+ lifetime = validTill.getMillis() - validFrom.getMillis();
+ } else {
+ validFrom = assertion.getSaml1().getConditions().getNotBefore();
+ validTill = assertion.getSaml1().getConditions().getNotOnOrAfter();
+ lifetime = validTill.getMillis() - validFrom.getMillis();
+ }
+ response.setLifetime(lifetime / 1000);
+
response.setEntropy(entropyBytes);
if (keySize > 0) {
response.setKeySize(keySize);
Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java?rev=1207844&r1=1207843&r2=1207844&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java Tue Nov 29 12:11:13 2011
@@ -49,6 +49,8 @@ import org.apache.ws.security.saml.ext.A
import org.apache.ws.security.validate.Credential;
import org.apache.ws.security.validate.SignatureTrustValidator;
import org.apache.ws.security.validate.Validator;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLVersion;
/**
* Validate a SAML Assertion. It is valid if it was issued and signed by this STS.
@@ -179,6 +181,20 @@ public class SAMLTokenValidator implemen
return response;
}
}
+
+ DateTime validFrom = null;
+ DateTime validTill = null;
+ if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)) {
+ validFrom = assertion.getSaml2().getConditions().getNotBefore();
+ validTill = assertion.getSaml2().getConditions().getNotOnOrAfter();
+ } else {
+ validFrom = assertion.getSaml1().getConditions().getNotBefore();
+ validTill = assertion.getSaml1().getConditions().getNotOnOrAfter();
+ }
+ if (!(validFrom.isBeforeNow() && validTill.isAfterNow())) {
+ LOG.log(Level.WARNING, "SAML Token condition not met");
+ return response;
+ }
// Get the realm of the SAML token
String tokenRealm = null;
Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java?rev=1207844&r1=1207843&r2=1207844&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java (original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java Tue Nov 29 12:11:13 2011
@@ -21,6 +21,7 @@ package org.apache.cxf.sts.token.validat
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
import java.util.Properties;
@@ -40,9 +41,11 @@ import org.apache.cxf.sts.cache.DefaultI
import org.apache.cxf.sts.cache.STSTokenStore;
import org.apache.cxf.sts.common.PasswordCallbackHandler;
import org.apache.cxf.sts.request.KeyRequirements;
+import org.apache.cxf.sts.request.Lifetime;
import org.apache.cxf.sts.request.ReceivedToken;
import org.apache.cxf.sts.request.TokenRequirements;
import org.apache.cxf.sts.service.EncryptionProperties;
+import org.apache.cxf.sts.token.provider.DefaultConditionsProvider;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.provider.TokenProvider;
import org.apache.cxf.sts.token.provider.TokenProviderParameters;
@@ -53,6 +56,7 @@ import org.apache.ws.security.WSPassword
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.util.XmlSchemaDateFormat;
import org.junit.BeforeClass;
@@ -191,6 +195,64 @@ public class SAMLTokenValidatorTest exte
assertTrue(validatorResponse != null);
assertFalse(validatorResponse.isValid());
}
+
+
+ /**
+ * Test a SAML 1.1 Assertion with an invalid condition
+ */
+ @org.junit.Test
+ public void testInvalidConditionSAML1Assertion() throws Exception {
+ TokenValidator samlTokenValidator = new SAMLTokenValidator();
+ TokenValidatorParameters validatorParameters = createValidatorParameters();
+ TokenRequirements tokenRequirements = validatorParameters.getTokenRequirements();
+
+ // Create a ValidateTarget consisting of a SAML Assertion
+ Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+ CallbackHandler callbackHandler = new PasswordCallbackHandler();
+ Element samlToken =
+ createSAMLAssertion(WSConstants.WSS_SAML_TOKEN_TYPE, crypto, "mystskey", callbackHandler, 50);
+ Document doc = samlToken.getOwnerDocument();
+ samlToken = (Element)doc.appendChild(samlToken);
+
+ ReceivedToken validateTarget = new ReceivedToken(samlToken);
+ tokenRequirements.setValidateTarget(validateTarget);
+
+ assertTrue(samlTokenValidator.canHandleToken(validateTarget));
+ Thread.sleep(100);
+ TokenValidatorResponse validatorResponse =
+ samlTokenValidator.validateToken(validatorParameters);
+ assertTrue(validatorResponse != null);
+ assertFalse("SAML token is invalid", validatorResponse.isValid());
+ }
+
+ /**
+ * Test a SAML 2.0 Assertion with an invalid condition
+ */
+ @org.junit.Test
+ public void testInvalidConditionSAML2Assertion() throws Exception {
+ TokenValidator samlTokenValidator = new SAMLTokenValidator();
+ TokenValidatorParameters validatorParameters = createValidatorParameters();
+ TokenRequirements tokenRequirements = validatorParameters.getTokenRequirements();
+
+ // Create a ValidateTarget consisting of a SAML Assertion
+ Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+ CallbackHandler callbackHandler = new PasswordCallbackHandler();
+ Element samlToken =
+ createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey", callbackHandler, 50);
+ Document doc = samlToken.getOwnerDocument();
+ samlToken = (Element)doc.appendChild(samlToken);
+
+ ReceivedToken validateTarget = new ReceivedToken(samlToken);
+ tokenRequirements.setValidateTarget(validateTarget);
+
+ assertTrue(samlTokenValidator.canHandleToken(validateTarget));
+ Thread.sleep(100);
+ TokenValidatorResponse validatorResponse =
+ samlTokenValidator.validateToken(validatorParameters);
+ assertTrue(validatorResponse != null);
+ assertFalse("SAML token is invalid", validatorResponse.isValid());
+ }
+
/**
* Test a SAML 1.1 Assertion using Certificate Constraints
@@ -279,6 +341,39 @@ public class SAMLTokenValidatorTest exte
return providerResponse.getToken();
}
+ private Element createSAMLAssertion(
+ String tokenType, Crypto crypto, String signatureUsername,
+ CallbackHandler callbackHandler, long ttlMs
+ ) throws WSSecurityException {
+ SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+ DefaultConditionsProvider conditionsProvider = new DefaultConditionsProvider();
+ conditionsProvider.setAcceptClientLifetime(true);
+ samlTokenProvider.setConditionsProvider(conditionsProvider);
+ TokenProviderParameters providerParameters =
+ createProviderParameters(
+ tokenType, STSConstants.BEARER_KEY_KEYTYPE, crypto, signatureUsername, callbackHandler
+ );
+
+ if (ttlMs != 0) {
+ Lifetime lifetime = new Lifetime();
+ Date creationTime = new Date();
+ Date expirationTime = new Date();
+ expirationTime.setTime(creationTime.getTime() + ttlMs);
+
+ XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+ lifetime.setCreated(fmt.format(creationTime));
+ lifetime.setExpires(fmt.format(expirationTime));
+
+ providerParameters.getTokenRequirements().setLifetime(lifetime);
+ }
+
+ TokenProviderResponse providerResponse = samlTokenProvider.createToken(providerParameters);
+ assertTrue(providerResponse != null);
+ assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+ return providerResponse.getToken();
+ }
+
private TokenProviderParameters createProviderParameters(
String tokenType, String keyType, Crypto crypto,
String signatureUsername, CallbackHandler callbackHandler