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