You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ow...@apache.org on 2012/03/06 18:33:05 UTC

svn commit: r1297588 [1/2] - in /cxf/trunk/services/sts: sts-core/src/main/java/org/apache/cxf/sts/ sts-core/src/main/java/org/apache/cxf/sts/claims/ sts-core/src/main/java/org/apache/cxf/sts/operation/ sts-core/src/main/java/org/apache/cxf/sts/token/p...

Author: owulff
Date: Tue Mar  6 17:33:04 2012
New Revision: 1297588

URL: http://svn.apache.org/viewvc?rev=1297588&view=rev
Log:
[CXF-3882] Support for Claims transformation in validate or issue RST

Added:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsMapper.java
      - copied, changed from r1297436, cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/Relationship.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/RelationshipResolver.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomClaimsMapper.java
    cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/username_onbehalfof/UsernameTokenValidator.java
Modified:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsManager.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenValidateOperation.java
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.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/operation/CustomIdentityMapper.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlClaimsUnitTest.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/ValidateTokenTransformationUnitTest.java
    cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/SAMLProviderOnBehalfOfTest.java
    cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/common/DoubleItPortTypeImpl.java
    cxf/trunk/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/intermediary_transformation/IntermediaryCachingPortTypeImpl.java
    cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-transport.xml
    cxf/trunk/services/sts/systests/basic/src/test/resources/org/apache/cxf/systest/sts/deployment/cxf-x509.xml

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/STSPropertiesMBean.java Tue Mar  6 17:33:04 2012
@@ -19,9 +19,13 @@
 
 package org.apache.cxf.sts;
 
+import java.util.List;
+
 import javax.security.auth.callback.CallbackHandler;
 
 import org.apache.cxf.sts.service.EncryptionProperties;
+import org.apache.cxf.sts.token.realm.Relationship;
+import org.apache.cxf.sts.token.realm.RelationshipResolver;
 import org.apache.cxf.ws.security.sts.provider.STSException;
 import org.apache.ws.security.components.crypto.Crypto;
 
@@ -159,4 +163,22 @@ public interface STSPropertiesMBean {
      */
     IdentityMapper getIdentityMapper();
     
+    /**
+     * Set the list of Relationship objects to use.
+     * @param relationships the List<Relationship> object to use.
+     */
+    void setRelationships(List<Relationship> relationships);
+
+    /**
+     * Get the list of Relationship objects to use.
+     * @return the List<Relationship> object to use.
+     */
+    List<Relationship> getRelationships();
+    
+    /**
+     * Get the RelationshipResolver objects to use.
+     * @return the RelationshipResolver object to use.
+     */    
+    RelationshipResolver getRelationshipResolver();
+    
 }

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/StaticSTSProperties.java Tue Mar  6 17:33:04 2012
@@ -21,6 +21,7 @@ package org.apache.cxf.sts;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.List;
 import java.util.Properties;
 import java.util.logging.Logger;
 
@@ -32,6 +33,8 @@ import org.apache.cxf.common.logging.Log
 import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.resource.ResourceManager;
 import org.apache.cxf.sts.service.EncryptionProperties;
+import org.apache.cxf.sts.token.realm.Relationship;
+import org.apache.cxf.sts.token.realm.RelationshipResolver;
 import org.apache.cxf.ws.security.sts.provider.STSException;
 import org.apache.ws.security.WSSConfig;
 import org.apache.ws.security.WSSecurityException;
@@ -58,6 +61,8 @@ public class StaticSTSProperties impleme
     private EncryptionProperties encryptionProperties = new EncryptionProperties();
     private RealmParser realmParser;
     private IdentityMapper identityMapper;
+    private List<Relationship> relationships;
+    private RelationshipResolver relationshipResolver;
 
     /**
      * Load the CallbackHandler, Crypto objects, if necessary.
@@ -349,6 +354,18 @@ public class StaticSTSProperties impleme
         }
         return handler;
     }
+
+    public void setRelationships(List<Relationship> relationships) {
+        this.relationships = relationships;
+        this.relationshipResolver = new RelationshipResolver(this.relationships);
+    }
+
+    public List<Relationship> getRelationships() {
+        return relationships;
+    }
     
+    public RelationshipResolver getRelationshipResolver() {
+        return relationshipResolver;      
+    }
     
 }

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsManager.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsManager.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsManager.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsManager.java Tue Mar  6 17:33:04 2012
@@ -20,12 +20,22 @@
 package org.apache.cxf.sts.claims;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.w3c.dom.Element;
+
 import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.sts.token.realm.Relationship;
 import org.apache.cxf.ws.security.sts.provider.STSException;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+import org.opensaml.common.SAMLVersion;
+import org.opensaml.xml.XMLObject;
+
 
 /**
  * This class holds various ClaimsHandler implementations.
@@ -55,22 +65,60 @@ public class ClaimsManager {
             }
         }
     }
-    
+
     public ClaimCollection retrieveClaimValues(RequestClaimCollection claims, ClaimsParameters parameters) {
-        if (claimHandlers != null && claimHandlers.size() > 0 && claims != null && claims.size() > 0) {
-            ClaimCollection returnCollection = new ClaimCollection();
-            for (ClaimsHandler handler : claimHandlers) {
-                ClaimCollection claimCollection = handler.retrieveClaimValues(claims, parameters);
-                if (claimCollection != null && claimCollection.size() != 0) {
-                    returnCollection.addAll(claimCollection);
+        Relationship relationship = null;
+        if (parameters.getAdditionalProperties() != null) {
+            relationship = (Relationship)parameters.getAdditionalProperties().get(
+                    Relationship.class.getName());
+        }
+
+        if (relationship == null || relationship.getType().equals(Relationship.FED_TYPE_IDENTITY)) {
+            // Federate identity. Identity already mapped.
+            // Call all configured claims handlers to retrieve the required claims
+            if (claimHandlers != null && claimHandlers.size() > 0 && claims != null && claims.size() > 0) {
+                ClaimCollection returnCollection = new ClaimCollection();
+                for (ClaimsHandler handler : claimHandlers) {
+                    ClaimCollection claimCollection = handler.retrieveClaimValues(claims, parameters);
+                    if (claimCollection != null && claimCollection.size() != 0) {
+                        returnCollection.addAll(claimCollection);
+                    }
                 }
+                validateClaimValues(claims, returnCollection);
+                return returnCollection;
+            }
+            
+        } else {
+            // Federate claims
+            ClaimsMapper claimsMapper = relationship.getClaimsMapper();
+            if (claimsMapper == null) {
+                LOG.log(Level.SEVERE, "ClaimsMapper required to federate claims but not configured.");
+                throw new STSException("ClaimsMapper required to federate claims but not configured",
+                                       STSException.BAD_REQUEST);
+            }
+            
+            // Get the claims of the received token (only SAML supported)
+            // Consider refactoring to use a CallbackHandler and keep ClaimsManager token independent
+            AssertionWrapper assertion = 
+                (AssertionWrapper)parameters.getAdditionalProperties().get(AssertionWrapper.class.getName());
+            List<Claim> claimList = null;
+            if (assertion.getSamlVersion().equals(SAMLVersion.VERSION_20)) {
+                claimList = this.parseClaimsInAssertion(assertion.getSaml2());
+            } else {
+                claimList = this.parseClaimsInAssertion(assertion.getSaml1());
             }
-            validateClaimValues(claims, returnCollection);
-            return returnCollection;
+            ClaimCollection sourceClaims = new ClaimCollection();
+            sourceClaims.addAll(claimList);
+            
+            ClaimCollection targetClaims = claimsMapper.mapClaims(relationship.getSourceRealm(),
+                    sourceClaims, relationship.getTargetRealm(), parameters);
+            validateClaimValues(claims, targetClaims);
+            return targetClaims;
         }
+
         return null;
     }
-    
+
     private boolean validateClaimValues(RequestClaimCollection requestedClaims, ClaimCollection claims) {
         for (RequestClaim claim : requestedClaims) {
             URI claimType = claim.getClaimType();
@@ -80,6 +128,13 @@ public class ClaimsManager {
                     if (c.getClaimType().equals(claimType)) {
                         found = true;
                         break;
+                    } else {
+                        StringBuffer sb = new StringBuffer();
+                        sb.append(c.getNamespace()).append('/').append(c.getClaimType());
+                        if (sb.toString().equals(claimType.toString())) {
+                            found = true;
+                            break;
+                        }
                     }
                 }
                 if (!found) {
@@ -89,10 +144,94 @@ public class ClaimsManager {
             }
         }
         return true;
-        
+
+    }
+
+
+    protected List<Claim> parseClaimsInAssertion(org.opensaml.saml1.core.Assertion assertion) {
+        List<org.opensaml.saml1.core.AttributeStatement> attributeStatements = 
+            assertion.getAttributeStatements();
+        if (attributeStatements == null || attributeStatements.isEmpty()) {
+            if (LOG.isLoggable(Level.FINEST)) {
+                LOG.finest("No attribute statements found");
+            }            
+            return Collections.emptyList();
+        }
+        ClaimCollection collection = new ClaimCollection();
+
+        for (org.opensaml.saml1.core.AttributeStatement statement : attributeStatements) {
+            if (LOG.isLoggable(Level.FINEST)) {
+                LOG.finest("parsing statement: " + statement.getElementQName());
+            }
+
+            List<org.opensaml.saml1.core.Attribute> attributes = statement.getAttributes();
+            for (org.opensaml.saml1.core.Attribute attribute : attributes) {
+                if (LOG.isLoggable(Level.FINEST)) {
+                    LOG.finest("parsing attribute: " + attribute.getAttributeName());
+                }
+                Claim c = new Claim();
+                c.setIssuer(assertion.getIssuer());
+                c.setClaimType(URI.create(attribute.getAttributeName()));
+                try {
+                    c.setClaimType(new URI(attribute.getAttributeName()));
+                } catch (URISyntaxException e) {
+                    LOG.warning("Invalid attribute name in attributestatement: " + e.getMessage());
+                    continue;
+                }
+                for (XMLObject attributeValue : attribute.getAttributeValues()) {
+                    Element attributeValueElement = attributeValue.getDOM();
+                    String value = attributeValueElement.getTextContent();
+                    if (LOG.isLoggable(Level.FINEST)) {
+                        LOG.finest(" [" + value + "]");
+                    }
+                    c.setValue(value);
+                    collection.add(c);
+                    break;                    
+                }
+            }
+        }
+        return collection;
+    }
+
+    protected List<Claim> parseClaimsInAssertion(org.opensaml.saml2.core.Assertion assertion) {
+        List<org.opensaml.saml2.core.AttributeStatement> attributeStatements = 
+            assertion.getAttributeStatements();
+        if (attributeStatements == null || attributeStatements.isEmpty()) {
+            if (LOG.isLoggable(Level.FINEST)) {
+                LOG.finest("No attribute statements found");
+            }
+            return Collections.emptyList();
+        }
+
+        List<Claim> collection = new ArrayList<Claim>();
+
+        for (org.opensaml.saml2.core.AttributeStatement statement : attributeStatements) {
+            if (LOG.isLoggable(Level.FINEST)) {
+                LOG.finest("parsing statement: " + statement.getElementQName());
+            }
+            List<org.opensaml.saml2.core.Attribute> attributes = statement.getAttributes();
+            for (org.opensaml.saml2.core.Attribute attribute : attributes) {
+                if (LOG.isLoggable(Level.FINEST)) {
+                    LOG.finest("parsing attribute: " + attribute.getName());
+                }
+                Claim c = new Claim();
+                c.setClaimType(URI.create(attribute.getName()));
+                c.setIssuer(assertion.getIssuer().getNameQualifier());
+                for (XMLObject attributeValue : attribute.getAttributeValues()) {
+                    Element attributeValueElement = attributeValue.getDOM();
+                    String value = attributeValueElement.getTextContent();
+                    if (LOG.isLoggable(Level.FINEST)) {
+                        LOG.finest(" [" + value + "]");
+                    }
+                    c.setValue(value);
+                    collection.add(c);
+                    break;
+                }
+            }
+        }
+        return collection;
+
     }
-    
-    
+
 
 }
- 
\ No newline at end of file

Copied: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsMapper.java (from r1297436, cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java)
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsMapper.java?p2=cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsMapper.java&p1=cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java&r1=1297436&r2=1297588&rev=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsMapper.java Tue Mar  6 17:33:04 2012
@@ -16,34 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.cxf.sts.operation;
 
-import java.security.Principal;
-
-import org.apache.cxf.sts.IdentityMapper;
-import org.apache.ws.security.CustomTokenPrincipal;
+package org.apache.cxf.sts.claims;
 
 /**
- * A test implementation of RealmParser.
+ * This interface defines a pluggable way of mapping claims from a source realm to a target
+ * realm.
  */
-public class CustomIdentityMapper implements IdentityMapper {
-
+public interface ClaimsMapper {
+    
     /**
-     * Map a principal in the source realm to the target realm
+     * Map a collection of claims in the source realm to the target realm
      * @param sourceRealm the source realm of the Principal
-     * @param sourcePrincipal the principal in the source realm
+     * @param sourceClaims the claims collection in the source realm
      * @param targetRealm the target realm of the Principal
-     * @return the principal in the target realm
+     * @return claims collection of the target realm
      */
-    public Principal mapPrincipal(String sourceRealm, Principal sourcePrincipal, String targetRealm) {
-        if ("A".equals(sourceRealm)) {
-            String name = sourcePrincipal.getName().toUpperCase();
-            return new CustomTokenPrincipal(name);
-        } else if ("B".equals(sourceRealm)) {
-            String name = sourcePrincipal.getName().toLowerCase();
-            return new CustomTokenPrincipal(name);
-        }
-        return null;
-    }
+    ClaimCollection mapClaims(String sourceRealm,
+            ClaimCollection sourceClaims, String targetRealm, ClaimsParameters parameters);
 
 }

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/AbstractOperation.java Tue Mar  6 17:33:04 2012
@@ -20,6 +20,7 @@
 package org.apache.cxf.sts.operation;
 
 import java.net.URI;
+import java.security.Principal;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -38,6 +39,7 @@ import org.w3c.dom.Element;
 
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.helpers.DOMUtils;
+import org.apache.cxf.sts.IdentityMapper;
 import org.apache.cxf.sts.QNameConstants;
 import org.apache.cxf.sts.RealmParser;
 import org.apache.cxf.sts.STSConstants;
@@ -56,6 +58,8 @@ import org.apache.cxf.sts.service.Servic
 import org.apache.cxf.sts.token.provider.TokenProvider;
 import org.apache.cxf.sts.token.provider.TokenProviderParameters;
 import org.apache.cxf.sts.token.provider.TokenReference;
+import org.apache.cxf.sts.token.realm.Relationship;
+import org.apache.cxf.sts.token.realm.RelationshipResolver;
 import org.apache.cxf.sts.token.validator.TokenValidator;
 import org.apache.cxf.sts.token.validator.TokenValidatorParameters;
 import org.apache.cxf.sts.token.validator.TokenValidatorResponse;
@@ -523,15 +527,16 @@ public abstract class AbstractOperation 
             TokenRequirements tokenRequirements, ReceivedToken token) {
         token.setValidationState(STATE.NONE);
         
-        tokenRequirements.setValidateTarget(token);
-
+        TokenRequirements validateRequirements = new TokenRequirements();
+        validateRequirements.setValidateTarget(token);
+        
         TokenValidatorParameters validatorParameters = new TokenValidatorParameters();
         validatorParameters.setStsProperties(stsProperties);
         validatorParameters.setPrincipal(context.getUserPrincipal());
         validatorParameters.setWebServiceContext(context);
         validatorParameters.setTokenStore(getTokenStore());
         validatorParameters.setKeyRequirements(null);
-        validatorParameters.setTokenRequirements(tokenRequirements);
+        validatorParameters.setTokenRequirements(validateRequirements);
 
         TokenValidatorResponse tokenResponse = null;
         for (TokenValidator tokenValidator : tokenValidators) {
@@ -580,5 +585,55 @@ public abstract class AbstractOperation 
             }
         }
     }
+
+    protected void processValidToken(TokenProviderParameters providerParameters,
+            ReceivedToken validatedToken, TokenValidatorResponse tokenResponse) {
+        // Map the principal (if it exists)
+        Principal responsePrincipal = tokenResponse.getPrincipal();
+        if (responsePrincipal != null) {
+            String targetRealm = providerParameters.getRealm();
+            String sourceRealm = tokenResponse.getTokenRealm();
+    
+            if (sourceRealm != null && !sourceRealm.equals(targetRealm)) {
+                RelationshipResolver relRes = stsProperties.getRelationshipResolver();
+                Relationship relationship = null;
+                if (relRes != null) {
+                    relationship = relRes.resolveRelationship(sourceRealm, targetRealm);
+                    if (relationship != null) {
+                        tokenResponse.getAdditionalProperties().put(
+                                Relationship.class.getName(), relationship);
+                    }
+                }
+    
+                if (relationship == null || relationship.getType().equals(Relationship.FED_TYPE_IDENTITY)) {
+                    // federate identity
+                    IdentityMapper identityMapper = null;
+                    if (relationship == null) {
+                        identityMapper = stsProperties.getIdentityMapper();
+                    } else {
+                        identityMapper = relationship.getIdentityMapper();
+                    }
+                    if (identityMapper != null) {
+                        Principal targetPrincipal = 
+                            identityMapper.mapPrincipal(sourceRealm, responsePrincipal, targetRealm);
+                        validatedToken.setPrincipal(targetPrincipal);
+                    } else {
+                        LOG.log(Level.SEVERE,
+                                "No IdentityMapper configured in STSProperties or Relationship");
+                        throw new STSException("Error in providing a token", STSException.REQUEST_FAILED);
+                    }
+                } else if (relationship.getType().equals(Relationship.FED_TYPE_CLAIMS)) {
+                    // federate claims
+                    // Claims are transformed at the time when the claims are required to create a token
+                    // (ex. ClaimsAttributeStatementProvider)
+                    // principal remains unchanged                            
+    
+                } else  {
+                    LOG.log(Level.SEVERE, "Unkown federation type: " + relationship.getType());
+                    throw new STSException("Error in providing a token", STSException.BAD_REQUEST);
+                }
+            }
+        }
+    }
     
 }

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenIssueOperation.java Tue Mar  6 17:33:04 2012
@@ -19,7 +19,6 @@
 
 package org.apache.cxf.sts.operation;
 
-import java.security.Principal;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -28,7 +27,6 @@ import javax.xml.bind.JAXBElement;
 import javax.xml.ws.WebServiceContext;
 
 import org.apache.cxf.common.logging.LogUtils;
-import org.apache.cxf.sts.IdentityMapper;
 import org.apache.cxf.sts.QNameConstants;
 import org.apache.cxf.sts.claims.RequestClaimCollection;
 import org.apache.cxf.sts.request.KeyRequirements;
@@ -61,7 +59,7 @@ import org.apache.ws.security.WSSecurity
  */
 public class TokenIssueOperation extends AbstractOperation implements IssueOperation, IssueSingleOperation {
 
-    private static final Logger LOG = LogUtils.getL7dLogger(TokenIssueOperation.class);
+    static final Logger LOG = LogUtils.getL7dLogger(TokenIssueOperation.class);
 
 
     public RequestSecurityTokenResponseCollectionType issue(
@@ -99,23 +97,12 @@ public class TokenIssueOperation extends
             ReceivedToken validateTarget = providerParameters.getTokenRequirements().getOnBehalfOf();
             TokenValidatorResponse tokenResponse = validateReceivedToken(
                     context, realm, tokenRequirements, validateTarget);
-            
+
             if (tokenResponse == null) {
                 LOG.fine("No Token Validator has been found that can handle this token");
 
             } else if (validateTarget.getValidationState().equals(STATE.VALID)) {
-                // Map the principal (if it exists)
-                Principal responsePrincipal = tokenResponse.getPrincipal();
-                if (responsePrincipal != null) {
-                    String targetRealm = providerParameters.getRealm();
-                    String sourceRealm = tokenResponse.getTokenRealm();
-                    IdentityMapper identityMapper = stsProperties.getIdentityMapper();
-                    if (sourceRealm != null && !sourceRealm.equals(targetRealm) && identityMapper != null) {
-                        Principal targetPrincipal = 
-                            identityMapper.mapPrincipal(sourceRealm, responsePrincipal, targetRealm);
-                        validateTarget.setPrincipal(targetPrincipal);
-                    }
-                } 
+                processValidToken(providerParameters, validateTarget, tokenResponse); 
             } else {
                 //[TODO] Add plugin for validation out-of-band
                 // Example:

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenValidateOperation.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenValidateOperation.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenValidateOperation.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/operation/TokenValidateOperation.java Tue Mar  6 17:33:04 2012
@@ -19,7 +19,6 @@
 
 package org.apache.cxf.sts.operation;
 
-import java.security.Principal;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -28,7 +27,6 @@ import javax.xml.bind.JAXBElement;
 import javax.xml.ws.WebServiceContext;
 
 import org.apache.cxf.common.logging.LogUtils;
-import org.apache.cxf.sts.IdentityMapper;
 import org.apache.cxf.sts.QNameConstants;
 import org.apache.cxf.sts.RealmParser;
 import org.apache.cxf.sts.STSConstants;
@@ -104,20 +102,7 @@ public class TokenValidateOperation exte
             TokenProviderParameters providerParameters = 
                  createTokenProviderParameters(requestParser, context);
             
-            // Map the principal (if it exists)
-            Principal responsePrincipal = tokenResponse.getPrincipal();
-            if (responsePrincipal != null) {
-                String targetRealm = providerParameters.getRealm();
-                String sourceRealm = tokenResponse.getTokenRealm();
-                IdentityMapper identityMapper = stsProperties.getIdentityMapper();
-                if (sourceRealm != null && !sourceRealm.equals(targetRealm) && identityMapper != null) {
-                    Principal targetPrincipal = 
-                        identityMapper.mapPrincipal(sourceRealm, responsePrincipal, targetRealm);
-                    providerParameters.setPrincipal(targetPrincipal);
-                } else {
-                    providerParameters.setPrincipal(responsePrincipal);
-                }
-            }
+            processValidToken(providerParameters, validateTarget, tokenResponse);
             
             // Check if the requested claims can be handled by the configured claim handlers
             RequestClaimCollection requestedClaims = providerParameters.getRequestedClaims();

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/DefaultSubjectProvider.java Tue Mar  6 17:33:04 2012
@@ -91,13 +91,20 @@ public class DefaultSubjectProvider impl
         String confirmationMethod = getSubjectConfirmationMethod(tokenType, keyType);
         
         Principal principal = null;
-        ReceivedToken receivedToken = providerParameters.getTokenRequirements().getOnBehalfOf();
+        ReceivedToken receivedToken = null;
         //[TODO] ActAs support
         //TokenValidator in IssueOperation has validated the ReceivedToken
         //if validation was successful, the principal was set in ReceivedToken 
-        if (receivedToken != null && receivedToken.getPrincipal() != null 
-                && receivedToken.getValidationState().equals(STATE.VALID)) {
-            principal = receivedToken.getPrincipal();
+        if (providerParameters.getTokenRequirements().getOnBehalfOf() != null) {
+            receivedToken = providerParameters.getTokenRequirements().getOnBehalfOf();    
+            if (receivedToken.getValidationState().equals(STATE.VALID)) {
+                principal = receivedToken.getPrincipal();
+            }
+        } else if (providerParameters.getTokenRequirements().getValidateTarget() != null) {
+            receivedToken = providerParameters.getTokenRequirements().getValidateTarget();
+            if (receivedToken.getValidationState().equals(STATE.VALID)) {
+                principal = receivedToken.getPrincipal();
+            }
         } else {
             principal = providerParameters.getPrincipal();
         }

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/Relationship.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/Relationship.java?rev=1297588&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/Relationship.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/Relationship.java Tue Mar  6 17:33:04 2012
@@ -0,0 +1,88 @@
+/**
+ * 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.realm;
+
+
+import org.apache.cxf.sts.IdentityMapper;
+import org.apache.cxf.sts.claims.ClaimsMapper;
+
+
+/**
+ * This class holds the parameters that will be required to define
+ * a one-way relationship between a source and target realm.
+ * Two types of relationships are supported: FederatedIdentity and FederatedClaims
+ * If the realm of received token in the RST differs with the target realm either
+ * the configured IdentityMapper of ClaimsMapper are called depending on the type of relationship.
+ */
+public class Relationship {
+
+    public static final String FED_TYPE_IDENTITY = "FederatedIdentity";
+    public static final String FED_TYPE_CLAIMS = "FederatedClaims";
+    
+    
+    private String sourceRealm;
+    private String targetRealm;
+    private IdentityMapper identityMapper;
+    private ClaimsMapper claimsMapper;
+    private String type;
+    
+    
+    public void setSourceRealm(String sourceRealm) {
+        this.sourceRealm = sourceRealm;
+    }
+    
+    public String getSourceRealm() {
+        return sourceRealm;
+    }
+    
+    public void setTargetRealm(String targetRealm) {
+        this.targetRealm = targetRealm;
+    }
+    
+    public String getTargetRealm() {
+        return targetRealm;
+    }
+    
+    public void setIdentityMapper(IdentityMapper identityMapper) {
+        this.identityMapper = identityMapper;
+    }
+    
+    public IdentityMapper getIdentityMapper() {
+        return identityMapper;
+    }
+    
+    public void setClaimsMapper(ClaimsMapper claimsMapper) {
+        this.claimsMapper = claimsMapper;
+    }
+    
+    public ClaimsMapper getClaimsMapper() {
+        return claimsMapper;
+    }
+    
+    public void setType(String type) {
+        this.type = type;
+    }
+    
+    public String getType() {
+        return type;
+    }
+    
+}
+

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/RelationshipResolver.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/RelationshipResolver.java?rev=1297588&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/RelationshipResolver.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/realm/RelationshipResolver.java Tue Mar  6 17:33:04 2012
@@ -0,0 +1,51 @@
+/**
+ * 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.realm;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RelationshipResolver {
+
+    private Map<String, Relationship> relationshipMap;
+    
+    
+    public RelationshipResolver(List<Relationship> relationships) {
+        relationshipMap = new HashMap<String, Relationship>();
+        for (Relationship rel : relationships) {
+            String key = generateKey(rel.getSourceRealm(), rel.getTargetRealm());
+            relationshipMap.put(key, rel);
+        }
+    }
+    
+    public Relationship resolveRelationship(String sourceRealm, String targetRealm) {
+        String key = generateKey(sourceRealm, targetRealm);
+        return relationshipMap.get(key);
+    }
+    
+    
+    private String generateKey(String sourceRealm, String targetRealm) {
+        return new StringBuffer().append(sourceRealm).append(">").append(targetRealm).toString();
+        
+    }
+    
+    
+}

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=1297588&r1=1297587&r2=1297588&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 Mar  6 17:33:04 2012
@@ -20,7 +20,9 @@ package org.apache.cxf.sts.token.validat
 
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -223,6 +225,11 @@ public class SAMLTokenValidator implemen
                 }
             }
             
+            // Add the AssertionWrapper to the properties, as the claims are required to be transformed
+            Map<String, Object> addProps = new HashMap<String, Object>();
+            addProps.put(AssertionWrapper.class.getName(), assertion);
+            response.setAdditionalProperties(addProps);
+            
             response.setTokenRealm(tokenRealm);
             response.setValid(true);
         } catch (WSSecurityException ex) {

Added: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomClaimsMapper.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomClaimsMapper.java?rev=1297588&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomClaimsMapper.java (added)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomClaimsMapper.java Tue Mar  6 17:33:04 2012
@@ -0,0 +1,55 @@
+/**
+ * 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.operation;
+
+import org.apache.cxf.sts.claims.Claim;
+import org.apache.cxf.sts.claims.ClaimCollection;
+import org.apache.cxf.sts.claims.ClaimsMapper;
+import org.apache.cxf.sts.claims.ClaimsParameters;
+
+/**
+ * A test implementation of ClaimsMapper.
+ */
+public class CustomClaimsMapper implements ClaimsMapper {
+
+    /**
+     * transforms the claim values to upper-case
+     */
+    public ClaimCollection mapClaims(String sourceRealm,
+            ClaimCollection sourceClaims, String targetRealm,
+            ClaimsParameters parameters) {
+        
+        ClaimCollection targetClaims = new ClaimCollection();
+        
+        for (Claim c : sourceClaims) {
+            Claim nc = new Claim();
+            nc.setClaimType(c.getClaimType());
+            nc.setIssuer(c.getIssuer());
+            nc.setNamespace(c.getNamespace());
+            nc.setOriginalIssuer(c.getOriginalIssuer());
+            nc.setPrincipal(c.getPrincipal());
+            nc.setValue(c.getValue().toUpperCase());
+            targetClaims.add(nc);
+        }
+        
+        return targetClaims;
+    }
+
+}

Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java (original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/CustomIdentityMapper.java Tue Mar  6 17:33:04 2012
@@ -24,7 +24,7 @@ import org.apache.cxf.sts.IdentityMapper
 import org.apache.ws.security.CustomTokenPrincipal;
 
 /**
- * A test implementation of RealmParser.
+ * A test implementation of IdentityMapper.
  */
 public class CustomIdentityMapper implements IdentityMapper {
 

Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java (original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueOnbehalfofUnitTest.java Tue Mar  6 17:33:04 2012
@@ -324,7 +324,7 @@ public class IssueOnbehalfofUnitTest ext
         stsProperties.setIdentityMapper(new CustomIdentityMapper());
         issueOperation.setStsProperties(stsProperties);
         
-        Map<String, SAMLRealm> realms = getSamlRealms();
+        Map<String, SAMLRealm> realms = createSamlRealms();
         
         // Mock up a request
         RequestSecurityTokenType request = new RequestSecurityTokenType();
@@ -391,7 +391,7 @@ public class IssueOnbehalfofUnitTest ext
         assertTrue(tokenString.contains("AttributeStatement"));
         assertTrue(tokenString.contains("ALICE"));
         assertTrue(tokenString.contains(SAML2Constants.CONF_BEARER));
-    }
+    }    
     
 
     /*
@@ -489,7 +489,7 @@ public class IssueOnbehalfofUnitTest ext
         return tokenType;
     }
     
-    private Map<String, SAMLRealm> getSamlRealms() {
+    private Map<String, SAMLRealm> createSamlRealms() {
         // Create Realms
         Map<String, SAMLRealm> samlRealms = new HashMap<String, SAMLRealm>();
         SAMLRealm samlRealm = new SAMLRealm();

Modified: cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlClaimsUnitTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlClaimsUnitTest.java?rev=1297588&r1=1297587&r2=1297588&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlClaimsUnitTest.java (original)
+++ cxf/trunk/services/sts/sts-core/src/test/java/org/apache/cxf/sts/operation/IssueSamlClaimsUnitTest.java Tue Mar  6 17:33:04 2012
@@ -21,9 +21,12 @@ package org.apache.cxf.sts.operation;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
+import javax.security.auth.callback.CallbackHandler;
 import javax.xml.bind.JAXBElement;
 import javax.xml.namespace.QName;
 
@@ -40,23 +43,39 @@ import org.apache.cxf.sts.STSConstants;
 import org.apache.cxf.sts.STSPropertiesMBean;
 import org.apache.cxf.sts.StaticSTSProperties;
 import org.apache.cxf.sts.claims.ClaimTypes;
+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.ClaimsMapper;
+import org.apache.cxf.sts.claims.RequestClaim;
+import org.apache.cxf.sts.claims.RequestClaimCollection;
 import org.apache.cxf.sts.common.CustomAttributeProvider;
 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.TokenRequirements;
+import org.apache.cxf.sts.service.EncryptionProperties;
 import org.apache.cxf.sts.service.ServiceMBean;
 import org.apache.cxf.sts.service.StaticService;
 import org.apache.cxf.sts.token.provider.AttributeStatementProvider;
 import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
 import org.apache.cxf.sts.token.provider.TokenProvider;
+import org.apache.cxf.sts.token.provider.TokenProviderParameters;
+import org.apache.cxf.sts.token.provider.TokenProviderResponse;
+import org.apache.cxf.sts.token.realm.Relationship;
+import org.apache.cxf.sts.token.realm.SAMLRealm;
+import org.apache.cxf.sts.token.validator.IssuerSAMLRealmCodec;
+import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
+import org.apache.cxf.sts.token.validator.TokenValidator;
 import org.apache.cxf.ws.security.sts.provider.model.ClaimsType;
+import org.apache.cxf.ws.security.sts.provider.model.OnBehalfOfType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenResponseCollectionType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenResponseType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestedSecurityTokenType;
 import org.apache.ws.security.CustomTokenPrincipal;
 import org.apache.ws.security.WSConstants;
+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.builder.SAML1Constants;
@@ -155,7 +174,7 @@ public class IssueSamlClaimsUnitTest ext
         assertTrue(tokenString.contains("AttributeStatement"));
         assertTrue(tokenString.contains("alice"));
         assertTrue(tokenString.contains(SAML1Constants.CONF_BEARER));
-        assertTrue(tokenString.contains(ClaimTypes.FIRSTNAME.toString()));
+        assertTrue(tokenString.contains(ClaimTypes.LASTNAME.toString()));
     }
     
     /**
@@ -242,7 +261,7 @@ public class IssueSamlClaimsUnitTest ext
         assertTrue(tokenString.contains("AttributeStatement"));
         assertTrue(tokenString.contains("alice"));
         assertTrue(tokenString.contains(SAML2Constants.CONF_BEARER));
-        assertTrue(tokenString.contains(ClaimTypes.FIRSTNAME.toString()));
+        assertTrue(tokenString.contains(ClaimTypes.LASTNAME.toString()));
     }
     
     /**
@@ -342,9 +361,330 @@ public class IssueSamlClaimsUnitTest ext
         assertTrue(tokenString.contains("AttributeStatement"));
         assertTrue(tokenString.contains("alice"));
         assertTrue(tokenString.contains(SAML1Constants.CONF_BEARER));
-        assertTrue(tokenString.contains(ClaimTypes.FIRSTNAME.toString()));
+        assertTrue(tokenString.contains(ClaimTypes.LASTNAME.toString()));
     }
     
+    /**
+     * Test to successfully issue a SAML 2 token (realm "B") on-behalf-of a SAML 2 token
+     * which was issued by realm "A".
+     * The relationship type between realm A and B is: FederateClaims
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateClaims() throws Exception {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        Map<String, SAMLRealm> realms = createSamlRealms();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+        samlTokenProvider.setRealmMap(realms);
+        List<AttributeStatementProvider> customProviderList = 
+            new ArrayList<AttributeStatementProvider>();
+        customProviderList.add(new ClaimsAttributeStatementProvider());
+        samlTokenProvider.setAttributeStatementProviders(customProviderList);
+        providerList.add(samlTokenProvider);
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        SAMLTokenValidator samlTokenValidator = new SAMLTokenValidator();
+        samlTokenValidator.setSamlRealmCodec(new IssuerSAMLRealmCodec());
+        validatorList.add(samlTokenValidator);
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+        
+        // Add Relationship list
+        List<Relationship> relationshipList = new ArrayList<Relationship>();
+        Relationship rs = createRelationship();
+        relationshipList.add(rs);
+        
+        // Add STSProperties object
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        STSPropertiesMBean stsProperties = createSTSPropertiesMBean(crypto);
+        stsProperties.setRealmParser(new CustomRealmParser());
+        stsProperties.setIdentityMapper(new CustomIdentityMapper());
+        stsProperties.setRelationships(relationshipList);
+        issueOperation.setStsProperties(stsProperties);
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        issueOperation.setClaimsManager(claimsManager);
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Add a ClaimsType
+        ClaimsType claimsType = new ClaimsType();
+        claimsType.setDialect(STSConstants.IDT_NS_05_05);
+        
+        Document doc = DOMUtils.createDocument();
+        Element claimType = createClaimsType(doc);
+        claimsType.getAny().add(claimType);
+        
+        JAXBElement<ClaimsType> claimsTypeJaxb = 
+            new JAXBElement<ClaimsType>(
+                QNameConstants.CLAIMS, ClaimsType.class, claimsType
+            );
+        request.getAny().add(claimsTypeJaxb);
+        
+        //request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        // create a SAML Token via the SAMLTokenProvider which contains claims
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey",
+                    callbackHandler, realms);
+        Document docToken = samlToken.getOwnerDocument();
+        samlToken = (Element)docToken.appendChild(samlToken);
+        String samlString = DOM2Writer.nodeToString(samlToken);
+        assertTrue(samlString.contains("AttributeStatement"));
+        assertTrue(samlString.contains("alice"));
+        assertTrue(samlString.contains("doe"));
+        assertTrue(samlString.contains(SAML2Constants.CONF_BEARER));
+        
+        // add SAML token as On-Behalf-Of element
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+        
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put("url", "https");
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        // run the test
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponseList = 
+            response.getRequestSecurityTokenResponse();
+
+        assertTrue(!securityTokenResponseList.isEmpty());       
+        RequestSecurityTokenResponseType securityTokenResponse = securityTokenResponseList.get(0);
+        
+        // Test the generated token.
+        Element assertion = null;
+        for (Object tokenObject : securityTokenResponse.getAny()) {
+            if (tokenObject instanceof JAXBElement<?>
+                && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement<?>)tokenObject).getName())) {
+                RequestedSecurityTokenType rstType = 
+                    (RequestedSecurityTokenType)((JAXBElement<?>)tokenObject).getValue();
+                assertion = (Element)rstType.getAny();
+                break;
+            }
+        }
+        
+        assertNotNull(assertion);
+        String tokenString = DOM2Writer.nodeToString(assertion);
+        assertTrue(tokenString.contains("AttributeStatement"));
+        assertTrue(tokenString.contains("alice"));  //subject unchanged
+        assertTrue(tokenString.contains("DOE")); //transformed claim (to uppercase)
+        assertTrue(tokenString.contains(SAML2Constants.CONF_BEARER));
+    }
+    
+    /**
+     * Test to successfully issue a SAML 2 token (realm "B") on-behalf-of a SAML 2 token
+     * which was issued by realm "A".
+     * The relationship type between realm A and B is: FederateIdentity
+     * IdentityMapper is configured globally in STSPropertiesMBean
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentityGlobalConfig()
+        throws Exception {
+        runIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentity(true);
+    }
+    
+    
+    /**
+     * Test to successfully issue a SAML 2 token (realm "B") on-behalf-of a SAML 2 token
+     * which was issued by realm "A".
+     * The relationship type between realm A and B is: FederateIdentity
+     * IdentityMapper is configured in the Relationship
+     */
+    @org.junit.Test
+    public void testIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentityRelationshipConfig()
+        throws Exception {
+        runIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentity(false);
+    }
+
+    private void runIssueSaml2TokenOnBehalfOfSaml2DifferentRealmFederateIdentity(
+            boolean useGlobalIdentityMapper) throws WSSecurityException {
+        TokenIssueOperation issueOperation = new TokenIssueOperation();
+        
+        Map<String, SAMLRealm> realms = createSamlRealms();
+        
+        // Add Token Provider
+        List<TokenProvider> providerList = new ArrayList<TokenProvider>();
+        SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+        samlTokenProvider.setRealmMap(realms);
+        List<AttributeStatementProvider> customProviderList = 
+            new ArrayList<AttributeStatementProvider>();
+        customProviderList.add(new ClaimsAttributeStatementProvider());
+        samlTokenProvider.setAttributeStatementProviders(customProviderList);
+        providerList.add(samlTokenProvider);
+        issueOperation.setTokenProviders(providerList);
+        
+        // Add Token Validator
+        List<TokenValidator> validatorList = new ArrayList<TokenValidator>();
+        SAMLTokenValidator samlTokenValidator = new SAMLTokenValidator();
+        samlTokenValidator.setSamlRealmCodec(new IssuerSAMLRealmCodec());
+        validatorList.add(samlTokenValidator);
+        issueOperation.setTokenValidators(validatorList);
+
+        // Add Service
+        ServiceMBean service = new StaticService();
+        service.setEndpoints(Collections.singletonList("http://dummy-service.com/dummy"));
+        issueOperation.setServices(Collections.singletonList(service));
+        
+        // Add Relationship list
+        List<Relationship> relationshipList = new ArrayList<Relationship>();
+        Relationship rs = createRelationship();
+        rs.setType(Relationship.FED_TYPE_IDENTITY);
+        rs.setIdentityMapper(new CustomIdentityMapper());
+        relationshipList.add(rs);
+        
+        // Add STSProperties object
+        Crypto crypto = CryptoFactory.getInstance(getEncryptionProperties());
+        STSPropertiesMBean stsProperties = createSTSPropertiesMBean(crypto);
+        stsProperties.setRealmParser(new CustomRealmParser());
+        
+        if (useGlobalIdentityMapper) {
+            stsProperties.setIdentityMapper(new CustomIdentityMapper());
+        } else { 
+            stsProperties.setRelationships(relationshipList);
+        }  
+
+        issueOperation.setStsProperties(stsProperties);
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        claimsManager.setClaimHandlers(Collections.singletonList((ClaimsHandler)new CustomClaimsHandler()));
+        issueOperation.setClaimsManager(claimsManager);
+        
+        // Mock up a request
+        RequestSecurityTokenType request = new RequestSecurityTokenType();
+        JAXBElement<String> tokenType = 
+            new JAXBElement<String>(
+                QNameConstants.TOKEN_TYPE, String.class, WSConstants.WSS_SAML2_TOKEN_TYPE
+            );
+        request.getAny().add(tokenType);
+        
+        // Add a ClaimsType
+        ClaimsType claimsType = new ClaimsType();
+        claimsType.setDialect(STSConstants.IDT_NS_05_05);
+        
+        Document doc = DOMUtils.createDocument();
+        Element claimType = createClaimsType(doc);
+        claimsType.getAny().add(claimType);
+        
+        JAXBElement<ClaimsType> claimsTypeJaxb = 
+            new JAXBElement<ClaimsType>(
+                QNameConstants.CLAIMS, ClaimsType.class, claimsType
+            );
+        request.getAny().add(claimsTypeJaxb);
+        
+        //request.getAny().add(createAppliesToElement("http://dummy-service.com/dummy"));
+        
+        // create a SAML Token via the SAMLTokenProvider which contains claims
+        CallbackHandler callbackHandler = new PasswordCallbackHandler();
+        Element samlToken = 
+            createSAMLAssertion(WSConstants.WSS_SAML2_TOKEN_TYPE, crypto, "mystskey",
+                    callbackHandler, realms);
+        Document docToken = samlToken.getOwnerDocument();
+        samlToken = (Element)docToken.appendChild(samlToken);
+        String samlString = DOM2Writer.nodeToString(samlToken);
+        assertTrue(samlString.contains("AttributeStatement"));
+        assertTrue(samlString.contains("alice"));
+        assertTrue(samlString.contains("doe"));
+        assertTrue(samlString.contains(SAML2Constants.CONF_BEARER));
+        
+        // add SAML token as On-Behalf-Of element
+        OnBehalfOfType onbehalfof = new OnBehalfOfType();
+        onbehalfof.setAny(samlToken);
+        JAXBElement<OnBehalfOfType> onbehalfofType = 
+            new JAXBElement<OnBehalfOfType>(
+                    QNameConstants.ON_BEHALF_OF, OnBehalfOfType.class, onbehalfof
+            );
+        request.getAny().add(onbehalfofType);
+        
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        msgCtx.put("url", "https");
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        
+        // run the test
+        RequestSecurityTokenResponseCollectionType response = 
+            issueOperation.issue(request, webServiceContext);
+        List<RequestSecurityTokenResponseType> securityTokenResponseList = 
+            response.getRequestSecurityTokenResponse();
+
+        assertTrue(!securityTokenResponseList.isEmpty());       
+        RequestSecurityTokenResponseType securityTokenResponse = securityTokenResponseList.get(0);
+        
+        // Test the generated token.
+        Element assertion = null;
+        for (Object tokenObject : securityTokenResponse.getAny()) {
+            if (tokenObject instanceof JAXBElement<?>
+                && REQUESTED_SECURITY_TOKEN.equals(((JAXBElement<?>)tokenObject).getName())) {
+                RequestedSecurityTokenType rstType = 
+                    (RequestedSecurityTokenType)((JAXBElement<?>)tokenObject).getValue();
+                assertion = (Element)rstType.getAny();
+                break;
+            }
+        }
+        
+        assertNotNull(assertion);
+        String tokenString = DOM2Writer.nodeToString(assertion);
+        assertTrue(tokenString.contains("AttributeStatement"));
+        assertTrue(tokenString.contains("ALICE"));  //subject changed (to uppercase)
+        assertTrue(tokenString.contains("doe"));  //claim unchanged but requested
+        assertTrue(tokenString.contains(SAML2Constants.CONF_BEARER));
+    }
+    
+
+    private Relationship createRelationship() {
+        Relationship rs = new Relationship();
+        ClaimsMapper claimsMapper = new CustomClaimsMapper();
+        rs.setClaimsMapper(claimsMapper);
+        rs.setSourceRealm("A");
+        rs.setTargetRealm("B");
+        rs.setType(Relationship.FED_TYPE_CLAIMS);
+        return rs;
+    }
+    
+    
+    /*
+     * Create STSPropertiesMBean object
+     */
+    private STSPropertiesMBean createSTSPropertiesMBean(Crypto crypto) throws WSSecurityException {
+        STSPropertiesMBean stsProperties = new StaticSTSProperties();
+        stsProperties.setEncryptionCrypto(crypto);
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setEncryptionUsername("myservicekey");
+        stsProperties.setSignatureUsername("mystskey");
+        stsProperties.setCallbackHandler(new PasswordCallbackHandler());
+        stsProperties.setIssuer("STS");
+        return stsProperties;
+    }
+    
+    
     /*
      * Create a security context object
      */
@@ -409,11 +749,102 @@ public class IssueSamlClaimsUnitTest ext
     private Element createClaimsType(Document doc) {
         Element claimType = doc.createElementNS(STSConstants.IDT_NS_05_05, "ClaimType");
         claimType.setAttributeNS(
-            null, "Uri", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
+            null, "Uri", ClaimTypes.LASTNAME.toString()
         );
         claimType.setAttributeNS(WSConstants.XMLNS_NS, "xmlns", STSConstants.IDT_NS_05_05);
         
         return claimType;
     }
     
+    private Map<String, SAMLRealm> createSamlRealms() {
+        // Create Realms
+        Map<String, SAMLRealm> samlRealms = new HashMap<String, SAMLRealm>();
+        SAMLRealm samlRealm = new SAMLRealm();
+        samlRealm.setIssuer("A-Issuer");
+        samlRealms.put("A", samlRealm);
+        samlRealm = new SAMLRealm();
+        samlRealm.setIssuer("B-Issuer");
+        samlRealms.put("B", samlRealm);
+        return samlRealms;
+    }
+    
+    /*
+     * Mock up an SAML assertion element
+     */
+    private Element createSAMLAssertion(
+            String tokenType, Crypto crypto, String signatureUsername, CallbackHandler callbackHandler,
+            Map<String, SAMLRealm> realms
+    ) throws WSSecurityException {
+        
+        SAMLTokenProvider samlTokenProvider = new SAMLTokenProvider();
+        samlTokenProvider.setRealmMap(realms);
+        List<AttributeStatementProvider> customProviderList = 
+            new ArrayList<AttributeStatementProvider>();
+        customProviderList.add(new ClaimsAttributeStatementProvider());
+        samlTokenProvider.setAttributeStatementProviders(customProviderList);
+        
+        TokenProviderParameters providerParameters = 
+            createProviderParameters(
+                    tokenType, STSConstants.BEARER_KEY_KEYTYPE, crypto, signatureUsername, callbackHandler
+            );
+        if (realms != null) {
+            providerParameters.setRealm("A");
+        }
+        
+        // Set the ClaimsManager
+        ClaimsManager claimsManager = new ClaimsManager();
+        ClaimsHandler claimsHandler = new CustomClaimsHandler();
+        claimsManager.setClaimHandlers(Collections.singletonList(claimsHandler));
+        providerParameters.setClaimsManager(claimsManager);
+        
+        RequestClaimCollection requestedClaims = new RequestClaimCollection();
+        RequestClaim requestClaim = new RequestClaim();
+        requestClaim.setClaimType(ClaimTypes.LASTNAME);
+        requestClaim.setOptional(false);
+        requestedClaims.add(requestClaim);
+        providerParameters.setRequestedClaims(requestedClaims);
+        
+        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
+    ) throws WSSecurityException {
+        TokenProviderParameters parameters = new TokenProviderParameters();
+
+        TokenRequirements tokenRequirements = new TokenRequirements();
+        tokenRequirements.setTokenType(tokenType);
+        parameters.setTokenRequirements(tokenRequirements);
+
+        KeyRequirements keyRequirements = new KeyRequirements();
+        keyRequirements.setKeyType(keyType);
+        parameters.setKeyRequirements(keyRequirements);
+
+        parameters.setPrincipal(new CustomTokenPrincipal("alice"));
+        // Mock up message context
+        MessageImpl msg = new MessageImpl();
+        WrappedMessageContext msgCtx = new WrappedMessageContext(msg);
+        WebServiceContextImpl webServiceContext = new WebServiceContextImpl(msgCtx);
+        parameters.setWebServiceContext(webServiceContext);
+
+        parameters.setAppliesToAddress("http://dummy-service.com/dummy");
+
+        // Add STSProperties object
+        StaticSTSProperties stsProperties = new StaticSTSProperties();
+        stsProperties.setSignatureCrypto(crypto);
+        stsProperties.setSignatureUsername(signatureUsername);
+        stsProperties.setCallbackHandler(callbackHandler);
+        stsProperties.setIssuer("STS");
+        parameters.setStsProperties(stsProperties);
+
+        parameters.setEncryptionProperties(new EncryptionProperties());
+
+        return parameters;
+    }
+    
 }