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);