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 2013/09/11 18:49:16 UTC

svn commit: r1521930 - in /cxf/branches/2.6.x-fixes/services/sts/sts-core/src: main/java/org/apache/cxf/sts/operation/ main/java/org/apache/cxf/sts/token/delegation/ main/java/org/apache/cxf/sts/token/validator/ test/java/org/apache/cxf/sts/token/valid...

Author: coheigea
Date: Wed Sep 11 16:49:15 2013
New Revision: 1521930

URL: http://svn.apache.org/r1521930
Log:
Backmerging SAML Role Validator fix

Added:
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/DefaultSAMLRoleParser.java
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLRoleParser.java
Modified:
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/delegation/TokenDelegationParameters.java
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/TokenValidatorResponse.java
    cxf/branches/2.6.x-fixes/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java

Modified: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java?rev=1521930&r1=1521929&r2=1521930&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java (original)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java Wed Sep 11 16:49:15 2013
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -36,7 +37,6 @@ import javax.xml.ws.handler.MessageConte
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.sts.IdentityMapper;
@@ -581,13 +581,16 @@ public abstract class AbstractOperation 
     }
     
     protected void performDelegationHandling(
-        RequestParser requestParser, WebServiceContext context, ReceivedToken token
+        RequestParser requestParser, WebServiceContext context, ReceivedToken token,
+        Principal tokenPrincipal, Set<Principal> tokenRoles
     ) {
         TokenDelegationParameters delegationParameters = new TokenDelegationParameters();
         delegationParameters.setStsProperties(stsProperties);
         delegationParameters.setPrincipal(context.getUserPrincipal());
         delegationParameters.setWebServiceContext(context);
         delegationParameters.setTokenStore(getTokenStore());
+        delegationParameters.setTokenPrincipal(tokenPrincipal);
+        delegationParameters.setTokenRoles(tokenRoles);
         
         KeyRequirements keyRequirements = requestParser.getKeyRequirements();
         TokenRequirements tokenRequirements = requestParser.getTokenRequirements();

Modified: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java?rev=1521930&r1=1521929&r2=1521930&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java (original)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java Wed Sep 11 16:49:15 2013
@@ -105,16 +105,6 @@ public class TokenIssueOperation extends
         TokenRequirements tokenRequirements = requestParser.getTokenRequirements();
         String tokenType = tokenRequirements.getTokenType();
 
-        // See whether OnBehalfOf/ActAs is allowed or not
-        if (providerParameters.getTokenRequirements().getOnBehalfOf() != null) {
-            performDelegationHandling(requestParser, context,
-                                providerParameters.getTokenRequirements().getOnBehalfOf());
-        }
-        if (providerParameters.getTokenRequirements().getActAs() != null) {
-            performDelegationHandling(requestParser, context,
-                                providerParameters.getTokenRequirements().getActAs());
-        }
-
         // Validate OnBehalfOf token if present
         if (providerParameters.getTokenRequirements().getOnBehalfOf() != null) {
             ReceivedToken validateTarget = providerParameters.getTokenRequirements().getOnBehalfOf();
@@ -133,14 +123,34 @@ public class TokenIssueOperation extends
                 // If the requestor is in the possession of a certificate (mutual ssl handshake)
                 // the STS trusts the token sent in OnBehalfOf element
             }
+
+            Principal tokenPrincipal = null;
+            Set<Principal> tokenRoles = null;
+                
             if (tokenResponse != null) {
                 Map<String, Object> additionalProperties = tokenResponse.getAdditionalProperties();
                 if (additionalProperties != null) {
                     providerParameters.setAdditionalProperties(additionalProperties);
                 }
+                tokenPrincipal = tokenResponse.getPrincipal();
+                tokenRoles = tokenResponse.getRoles();
             }
+                
+            // See whether OnBehalfOf is allowed or not
+            performDelegationHandling(requestParser, context,
+                                providerParameters.getTokenRequirements().getOnBehalfOf(),
+                                tokenPrincipal, tokenRoles);
         }
 
+        // See whether ActAs is allowed or not
+        // TODO Validate ActAs
+        if (providerParameters.getTokenRequirements().getActAs() != null) {
+            performDelegationHandling(requestParser, context,
+                                providerParameters.getTokenRequirements().getActAs(),
+                                null, null);
+        }
+
+
         // create token
         TokenProviderResponse tokenResponse = null;
         for (TokenProvider tokenProvider : tokenProviders) {

Modified: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/delegation/TokenDelegationParameters.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/delegation/TokenDelegationParameters.java?rev=1521930&r1=1521929&r2=1521930&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/delegation/TokenDelegationParameters.java (original)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/delegation/TokenDelegationParameters.java Wed Sep 11 16:49:15 2013
@@ -20,6 +20,7 @@
 package org.apache.cxf.sts.token.delegation;
 
 import java.security.Principal;
+import java.util.Set;
 
 import javax.xml.ws.WebServiceContext;
 
@@ -44,6 +45,8 @@ public class TokenDelegationParameters {
     private TokenStore tokenStore;
     private ReceivedToken token;
     private String appliesToAddress;
+    private Principal tokenPrincipal;
+    private Set<Principal> tokenRoles;
     
     public ReceivedToken getToken() {
         return token;
@@ -108,5 +111,21 @@ public class TokenDelegationParameters {
     public void setAppliesToAddress(String appliesToAddress) {
         this.appliesToAddress = appliesToAddress;
     }
+
+    public Principal getTokenPrincipal() {
+        return tokenPrincipal;
+    }
+
+    public void setTokenPrincipal(Principal tokenPrincipal) {
+        this.tokenPrincipal = tokenPrincipal;
+    }
+
+    public Set<Principal> getTokenRoles() {
+        return tokenRoles;
+    }
+
+    public void setTokenRoles(Set<Principal> tokenRoles) {
+        this.tokenRoles = tokenRoles;
+    }
     
 }

Added: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/DefaultSAMLRoleParser.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/DefaultSAMLRoleParser.java?rev=1521930&view=auto
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/DefaultSAMLRoleParser.java (added)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/DefaultSAMLRoleParser.java Wed Sep 11 16:49:15 2013
@@ -0,0 +1,148 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.sts.token.validator;
+
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.apache.cxf.common.security.SimplePrincipal;
+import org.apache.cxf.interceptor.security.DefaultSecurityContext;
+import org.apache.cxf.interceptor.security.RolePrefixSecurityContextImpl;
+import org.apache.cxf.interceptor.security.SAMLSecurityContext;
+import org.apache.cxf.ws.security.wss4j.SAMLUtils;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+
+/**
+ * A default implementation to extract roles from a SAML Assertion
+ */
+public class DefaultSAMLRoleParser implements SAMLRoleParser {
+    
+    /**
+     * This configuration tag specifies the default attribute name where the roles are present
+     * The default is "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role".
+     */
+    public static final String SAML_ROLE_ATTRIBUTENAME_DEFAULT =
+        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role";
+    
+    private boolean useJaasSubject = true;
+    private String roleClassifier;
+    private String roleClassifierType = "prefix";
+    private String roleAttributeName = SAML_ROLE_ATTRIBUTENAME_DEFAULT;
+
+    /**
+     * Return the set of User/Principal roles from the Assertion.
+     * @param principal the Principal associated with the Assertion
+     * @param subject the JAAS Subject associated with a successful validation of the Assertion
+     * @param assertion The Assertion object
+     * @return the set of User/Principal roles from the Assertion.
+     */
+    public Set<Principal> parseRolesFromAssertion(
+        Principal principal, Subject subject, SamlAssertionWrapper assertion
+    ) {
+        if (subject != null && useJaasSubject) {
+            if (roleClassifier != null && !"".equals(roleClassifier)) {
+                RolePrefixSecurityContextImpl securityContext =
+                    new RolePrefixSecurityContextImpl(subject, roleClassifier, roleClassifierType);
+                return securityContext.getUserRoles();
+            } else {
+                return new DefaultSecurityContext(principal, subject).getUserRoles();
+            }
+        } 
+        
+        List<String> roles = 
+            SAMLUtils.parseRolesInAssertion(assertion, roleAttributeName);
+        SAMLSecurityContext context = createSecurityContext(principal, roles);
+        return context.getUserRoles();
+    }
+    
+    private SAMLSecurityContext createSecurityContext(final Principal p, final List<String> roles) {
+        final Set<Principal> userRoles;
+        if (roles != null) {
+            userRoles = new HashSet<Principal>();
+            for (String role : roles) {
+                userRoles.add(new SimplePrincipal(role));
+            }
+        } else {
+            userRoles = null;
+        }
+        
+        return new SAMLSecurityContext(p, userRoles);
+    }
+
+    public boolean isUseJaasSubject() {
+        return useJaasSubject;
+    }
+
+    /**
+     * Whether to get roles from the JAAS Subject (if not null) returned from SAML Assertion
+     * Validation or not. The default is true.
+     * @param useJaasSubject whether to get roles from the JAAS Subject or not
+     */
+    public void setUseJaasSubject(boolean useJaasSubject) {
+        this.useJaasSubject = useJaasSubject;
+    }
+
+    public String getRoleClassifier() {
+        return roleClassifier;
+    }
+
+    /**
+     * Set the Subject Role Classifier to use. If this value is not specified, then it tries to
+     * get roles from the supplied JAAS Subject (if not null) using the DefaultSecurityContext 
+     * in cxf-rt-core. Otherwise it uses this value in combination with the 
+     * SUBJECT_ROLE_CLASSIFIER_TYPE to get the roles from the Subject.
+     * @param roleClassifier the Subject Role Classifier to use
+     */
+    public void setRoleClassifier(String roleClassifier) {
+        this.roleClassifier = roleClassifier;
+    }
+
+    public String getRoleClassifierType() {
+        return roleClassifierType;
+    }
+
+    /**
+     * Set the Subject Role Classifier Type to use. Currently accepted values are "prefix" or 
+     * "classname". Must be used in conjunction with the SUBJECT_ROLE_CLASSIFIER. The default 
+     * value is "prefix".
+     * @param roleClassifierType the Subject Role Classifier Type to use
+     */
+    public void setRoleClassifierType(String roleClassifierType) {
+        this.roleClassifierType = roleClassifierType;
+    }
+    
+    
+    public String getRoleAttributeName() {
+        return roleAttributeName;
+    }
+
+    /**
+     * Set the attribute URI of the SAML AttributeStatement where the role information is stored.
+     * The default is "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role".
+     * @param roleAttributeName the Attribute URI where role information is stored
+     */
+    public void setRoleAttributeName(String roleAttributeName) {
+        this.roleAttributeName = roleAttributeName;
+    }
+
+}
\ No newline at end of file

Added: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLRoleParser.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLRoleParser.java?rev=1521930&view=auto
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLRoleParser.java (added)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLRoleParser.java Wed Sep 11 16:49:15 2013
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.sts.token.validator;
+
+import java.security.Principal;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+
+
+/**
+ * This interface defines a way to extract roles from a SAML Assertion
+ */
+public interface SAMLRoleParser {
+    
+    /**
+     * Return the set of User/Principal roles from the Assertion.
+     * @param principal the Principal associated with the Assertion
+     * @param subject the JAAS Subject associated with a successful validation of the Assertion
+     * @param assertion The Assertion object
+     * @return the set of User/Principal roles from the Assertion.
+     */
+    Set<Principal> parseRolesFromAssertion(
+        Principal principal, Subject subject, SamlAssertionWrapper assertion
+    );
+}

Modified: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java?rev=1521930&r1=1521929&r2=1521930&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java (original)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/SAMLTokenValidator.java Wed Sep 11 16:49:15 2013
@@ -25,13 +25,13 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javax.security.auth.callback.CallbackHandler;
 
 import org.w3c.dom.Element;
-
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.sts.STSConstants;
 import org.apache.cxf.sts.STSPropertiesMBean;
@@ -71,6 +71,8 @@ public class SAMLTokenValidator implemen
     
     private SAMLRealmCodec samlRealmCodec;
     
+    private SAMLRoleParser samlRoleParser = new DefaultSAMLRoleParser();
+    
     /**
      * Set a list of Strings corresponding to regular expression constraints on the subject DN
      * of a certificate that was used to sign a received Assertion
@@ -187,7 +189,7 @@ public class SAMLTokenValidator implemen
                 trustCredential.setPublicKey(samlKeyInfo.getPublicKey());
                 trustCredential.setCertificates(samlKeyInfo.getCerts());
     
-                validator.validate(trustCredential, requestData);
+                trustCredential = validator.validate(trustCredential, requestData);
 
                 // Finally check that subject DN of the signing certificate matches a known constraint
                 X509Certificate cert = null;
@@ -198,6 +200,14 @@ public class SAMLTokenValidator implemen
                 if (!certConstraints.matches(cert)) {
                     return response;
                 }
+                
+            }
+            
+            // Parse roles from the validated token
+            if (samlRoleParser != null) {
+                Set<Principal> roles = 
+                    samlRoleParser.parseRolesFromAssertion(samlPrincipal, null, assertion);
+                response.setRoles(roles);
             }
            
             // Get the realm of the SAML token
@@ -327,4 +337,12 @@ public class SAMLTokenValidator implemen
             tokenStore.add(identifier, securityToken);
         }
     }
+
+    public SAMLRoleParser getSamlRoleParser() {
+        return samlRoleParser;
+    }
+
+    public void setSamlRoleParser(SAMLRoleParser samlRoleParser) {
+        this.samlRoleParser = samlRoleParser;
+    }
 }

Modified: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/TokenValidatorResponse.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/TokenValidatorResponse.java?rev=1521930&r1=1521929&r2=1521930&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/TokenValidatorResponse.java (original)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/validator/TokenValidatorResponse.java Wed Sep 11 16:49:15 2013
@@ -20,6 +20,7 @@ package org.apache.cxf.sts.token.validat
 
 import java.security.Principal;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.cxf.sts.request.ReceivedToken;
 
@@ -32,6 +33,7 @@ public class TokenValidatorResponse {
     private Map<String, Object> additionalProperties;
     private String realm;
     private ReceivedToken token;
+    private Set<Principal> roles;
     
     public ReceivedToken getToken() {
         return token;
@@ -64,5 +66,13 @@ public class TokenValidatorResponse {
     public String getTokenRealm() {
         return realm;
     }
+
+    public Set<Principal> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(Set<Principal> roles) {
+        this.roles = roles;
+    }
     
 }

Modified: cxf/branches/2.6.x-fixes/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java?rev=1521930&r1=1521929&r2=1521930&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java (original)
+++ cxf/branches/2.6.x-fixes/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/validator/SAMLTokenValidatorTest.java Wed Sep 11 16:49:15 2013
@@ -19,12 +19,14 @@
 package org.apache.cxf.sts.token.validator;
 
 import java.io.IOException;
+import java.net.URI;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Properties;
+import java.util.Set;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
@@ -32,7 +34,6 @@ import javax.security.auth.callback.Unsu
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-
 import org.apache.cxf.jaxws.context.WebServiceContextImpl;
 import org.apache.cxf.jaxws.context.WrappedMessageContext;
 import org.apache.cxf.message.MessageImpl;
@@ -40,6 +41,11 @@ import org.apache.cxf.sts.STSConstants;
 import org.apache.cxf.sts.StaticSTSProperties;
 import org.apache.cxf.sts.cache.DefaultInMemoryTokenStore;
 import org.apache.cxf.sts.claims.ClaimsAttributeStatementProvider;
+import org.apache.cxf.sts.claims.ClaimsHandler;
+import org.apache.cxf.sts.claims.ClaimsManager;
+import org.apache.cxf.sts.claims.RequestClaim;
+import org.apache.cxf.sts.claims.RequestClaimCollection;
+import org.apache.cxf.sts.common.CustomClaimsHandler;
 import org.apache.cxf.sts.common.PasswordCallbackHandler;
 import org.apache.cxf.sts.request.KeyRequirements;
 import org.apache.cxf.sts.request.Lifetime;
@@ -348,6 +354,77 @@ public class SAMLTokenValidatorTest exte
         assertTrue(validatorResponse.getToken().getState() == STATE.INVALID);
     }
     
+    @org.junit.Test
+    public void testSAML2AssertionWithRolesNoCaching() 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 = 
+            createSAMLAssertionWithRoles(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey", 
+                                         callbackHandler, "manager");
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        
+        ReceivedToken validateTarget = new ReceivedToken(samlToken);
+        tokenRequirements.setValidateTarget(validateTarget);
+        validatorParameters.setToken(validateTarget);
+        
+        // Disable caching
+        validatorParameters.setTokenStore(null);
+        
+        assertTrue(samlTokenValidator.canHandleToken(validateTarget));
+        
+        TokenValidatorResponse validatorResponse = 
+            samlTokenValidator.validateToken(validatorParameters);
+        assertTrue(validatorResponse != null);
+        assertTrue(validatorResponse.getToken() != null);
+        assertTrue(validatorResponse.getToken().getState() == STATE.VALID);
+        
+        Principal principal = validatorResponse.getPrincipal();
+        assertTrue(principal != null && principal.getName() != null);
+        Set<Principal> roles = validatorResponse.getRoles();
+        assertTrue(roles != null && !roles.isEmpty());
+        assertTrue(roles.iterator().next().getName().equals("manager"));
+    }
+    
+    @org.junit.Test
+    public void testSAML2AssertionWithRolesCaching() 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 = 
+            createSAMLAssertionWithRoles(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey", 
+                                         callbackHandler, "employee");
+        Document doc = samlToken.getOwnerDocument();
+        samlToken = (Element)doc.appendChild(samlToken);
+        
+        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);
+        
+        Principal principal = validatorResponse.getPrincipal();
+        assertTrue(principal != null && principal.getName() != null);
+        Set<Principal> roles = validatorResponse.getRoles();
+        assertTrue(roles != null && !roles.isEmpty());
+        assertTrue(roles.iterator().next().getName().equals("employee"));
+    }
+    
     private TokenValidatorParameters createValidatorParameters() throws WSSecurityException {
         TokenValidatorParameters parameters = new TokenValidatorParameters();
         
@@ -395,6 +472,36 @@ public class SAMLTokenValidatorTest exte
         return providerResponse.getToken();
     }
     
+    private Element createSAMLAssertionWithRoles(
+        String tokenType, Crypto crypto, String signatureUsername, CallbackHandler callbackHandler,
+        String role
+    ) throws WSSecurityException {
+        TokenProvider samlTokenProvider = new SAMLTokenProvider();
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(
+                tokenType, STSConstants.BEARER_KEY_KEYTYPE, crypto, signatureUsername, callbackHandler
+            );
+        
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        RequestClaimCollection claims = new RequestClaimCollection();
+        RequestClaim claim = new RequestClaim();
+        claim.setClaimType(URI.create("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"));
+        claim.setClaimValue(role);
+        claims.add(claim);
+        
+        providerParameters.setRequestedPrimaryClaims(claims);
+        
+        TokenProviderResponse providerResponse = samlTokenProvider.createToken(providerParameters);
+        assertTrue(providerResponse != null);
+        assertTrue(providerResponse.getToken() != null && providerResponse.getTokenId() != null);
+
+        return providerResponse.getToken();
+    }
+    
     private Element createSAMLAssertionWithClaimsProvider(
         String tokenType, Crypto crypto, String signatureUsername, CallbackHandler callbackHandler
     ) throws WSSecurityException {