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 2018/09/21 16:06:43 UTC

[cxf-fediz] branch master updated (621ce55 -> 6068ce8)

This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/cxf-fediz.git.


    from 621ce55  Updating Tomcat
     new a2aa001  Adding custom claim transformation support to fediz plugin
     new 6f4074b  Refactoring and fix custom claims processing support, adding test cases, refactor role parsing
     new 6068ce8  Fixing some conflicts with the last patch

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |   1 +
 .../main/java/org/apache/cxf/fediz/core/Claim.java |   5 +
 .../cxf/fediz/core/TokenValidatorResponse.java     |  19 ++-
 .../apache/cxf/fediz/core/config/FedizContext.java |  26 ++++
 .../core/processor/AbstractFedizProcessor.java     |  36 ++++++
 .../cxf/fediz/core/processor/ClaimsProcessor.java  |  19 ++-
 .../core/processor/FederationProcessorImpl.java    |  31 +++--
 .../fediz/core/processor/SAMLProcessorImpl.java    |  22 +++-
 .../cxf/fediz/core/saml/SAMLTokenValidator.java    |  41 +++++-
 .../src/main/resources/schemas/FedizConfig.xsd     |   2 +
 .../cxf/fediz/common/ClaimCopyProcessor.java       |  19 +++
 .../cxf/fediz/common/ClaimMutateProcessor.java     |  38 ++++++
 .../fediz/core/config/FedizConfigurationTest.java  |  41 +++++-
 ...tedClaimsTest.java => ClaimsProcessorTest.java} | 142 +++++++++++----------
 .../cxf/fediz/core/federation/CustomValidator.java |   1 -
 .../core/federation/FederationResponseTest.java    |   4 +-
 .../core/federation/SAMLTokenValidatorOldTest.java |   4 +-
 .../cxf/fediz/core/samlsso/CustomValidator.java    |   1 -
 systests/cxf/src/test/resources/fediz_config.xml   |   6 +-
 .../cxfWebapp/src/main/resources/fediz_config.xml  |   6 +-
 20 files changed, 350 insertions(+), 114 deletions(-)
 copy services/idp-core/src/main/java/org/apache/cxf/fediz/service/idp/protocols/ProtocolController.java => plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/ClaimsProcessor.java (60%)
 create mode 100644 plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimCopyProcessor.java
 create mode 100644 plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimMutateProcessor.java
 copy plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/{RequestedClaimsTest.java => ClaimsProcessorTest.java} (75%)


[cxf-fediz] 01/03: Adding custom claim transformation support to fediz plugin

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf-fediz.git

commit a2aa00198bf1188f1dc2982ccc4b0679f54ddc61
Author: Juerg Portmann <ju...@zurich.com>
AuthorDate: Tue Mar 6 15:15:00 2018 +0100

    Adding custom claim transformation support to fediz plugin
---
 .../apache/cxf/fediz/core/config/FedizContext.java | 38 ++++++++++++++++++++++
 .../core/processor/FederationProcessorImpl.java    |  9 ++++-
 .../src/main/resources/schemas/FedizConfig.xsd     | 11 +++++++
 .../fediz/core/config/FedizConfigurationTest.java  |  7 ++++
 systests/cxf/src/test/resources/fediz_config.xml   |  7 ++--
 .../cxfWebapp/src/main/resources/fediz_config.xml  |  7 ++--
 6 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
index 17014c0..4c92994 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
@@ -32,8 +32,10 @@ import java.util.List;
 import java.util.Properties;
 import java.util.regex.Pattern;
 
+import org.apache.cxf.fediz.core.config.jaxb.ArgumentType;
 import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
 import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
+import org.apache.cxf.fediz.core.config.jaxb.ClaimsTransformerType;
 import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
 import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
 import org.apache.cxf.fediz.core.config.jaxb.KeyManagersType;
@@ -44,6 +46,7 @@ import org.apache.cxf.fediz.core.config.jaxb.TrustManagersType;
 import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuerType;
 import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuers;
 import org.apache.cxf.fediz.core.exception.IllegalConfigurationException;
+import org.apache.cxf.fediz.core.processor.ClaimsProcessor;
 import org.apache.cxf.fediz.core.util.CertsUtils;
 import org.apache.wss4j.common.cache.ReplayCache;
 import org.apache.wss4j.common.cache.ReplayCacheFactory;
@@ -260,6 +263,41 @@ public class FedizContext implements Closeable {
         return replayCache;
     }
 
+    public ClaimsProcessor getClaimsTransformer() {
+        ClaimsTransformerType  claimsTransformerType  = config.getClaimsTransformer();
+        if (claimsTransformerType != null) {
+            ArgumentType type = claimsTransformerType.getType();
+            if (type.equals(ArgumentType.CLASS)) {
+                String clazzName = type.value();
+                Class<?> clazz;
+                try {
+                    clazz = getClassloader().loadClass(clazzName);
+                    Object obj = clazz.newInstance();
+                    if (obj instanceof ClaimsProcessor) {
+                        return (ClaimsProcessor) obj;
+                    } else {
+                        LOG.error("The configured ClaimsTransformer is not an instance of ClaimsProcessor !");
+                        return null;
+                    }
+                    
+                } catch (ClassNotFoundException e) {
+                    LOG.error("The specified ClaimsTransformer can not be found. Check your classpath");
+                    return null;
+                
+                } catch (InstantiationException e) {
+                    LOG.error("The specified ClaimsTransformer can not be instantiated.");
+                    return null;
+                
+                } catch (IllegalAccessException e) {
+                    LOG.error("The specified ClaimsTransformer can not be accessed.");
+                    return null;
+                }
+                
+            }
+        }
+        return null;
+    }
+
     public String getName() {
         return config.getName();
     }
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
index 41da510..378c418 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
@@ -47,6 +47,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import org.apache.cxf.fediz.core.Claim;
 import org.apache.cxf.fediz.core.FederationConstants;
 import org.apache.cxf.fediz.core.RequestState;
 import org.apache.cxf.fediz.core.TokenValidator;
@@ -221,8 +222,14 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
             created = lifeTime.getCreated();
         }
 
+        List<Claim> claims = validatorResponse.getClaims();
+        if (config.getClaimsTransformer() != null) {
+            LOG.debug("invoking ClaimsTransformer");
+            claims = config.getClaimsTransformer().processClaims(validatorResponse.getClaims());
+        }
+
         FedizResponse fedResponse = new FedizResponse(validatorResponse.getUsername(), validatorResponse.getIssuer(),
-                                                      validatorResponse.getRoles(), validatorResponse.getClaims(),
+                                                      validatorResponse.getRoles(), claims,
                                                       validatorResponse.getAudience(), created, expires, rst,
                                                       validatorResponse.getUniqueTokenId());
 
diff --git a/plugins/core/src/main/resources/schemas/FedizConfig.xsd b/plugins/core/src/main/resources/schemas/FedizConfig.xsd
index 3b039a8..97cea11 100644
--- a/plugins/core/src/main/resources/schemas/FedizConfig.xsd
+++ b/plugins/core/src/main/resources/schemas/FedizConfig.xsd
@@ -28,6 +28,7 @@
                 <xs:element ref="logoutURL" minOccurs="0" />
                 <xs:element ref="logoutRedirectTo" minOccurs="0" />
                 <xs:element ref="logoutRedirectToConstraint" minOccurs="0" />
+                <xs:element ref="claimsTransformer" minOccurs="0" />
             </xs:sequence>
             <xs:attribute name="name" use="required" type="xs:string" />
 
@@ -222,6 +223,16 @@
         </xs:annotation>
     </xs:element>
 
+    <xs:complexType name="ClaimsTransformerType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="type" type="argumentType" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:element name="claimsTransformer" type="ClaimsTransformerType" />
+
     <xs:element name="issuer" type="CallbackType" />
     <xs:element name="homeRealm" type="CallbackType" />
     <xs:element name="authenticationType" type="CallbackType" />
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java
index 9b25e26..347cede 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java
@@ -35,6 +35,7 @@ import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
 import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
 import org.apache.cxf.fediz.core.config.jaxb.ClaimType;
 import org.apache.cxf.fediz.core.config.jaxb.ClaimTypesRequested;
+import org.apache.cxf.fediz.core.config.jaxb.ClaimsTransformerType;
 import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
 import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
 import org.apache.cxf.fediz.core.config.jaxb.FedizConfig;
@@ -84,6 +85,7 @@ public class FedizConfigurationTest {
     private static final String SUBJECT_VALUE_2 = ".*CN=www.sts2.com.*";
     private static final String SUBJECT_VALUE_3 = ".*CN=www.sts3.com.*";
 
+    private static final String CLAIMSTRANFORMER_CLASS = "org.apache.fediz.MyClaimsTransformer.class";
 
     private static final String CONFIG_FILE = "./target/fedizconfig.xml";
 
@@ -213,6 +215,11 @@ public class FedizConfigurationTest {
         issuer.setValue(ISSUER);
         protocol.setIssuer(issuer);
 
+        ClaimsTransformerType claimsTransformer = new ClaimsTransformerType();
+        claimsTransformer.setType(ArgumentType.CLASS);
+        claimsTransformer.setValue(CLAIMSTRANFORMER_CLASS);
+        config.setClaimsTransformer(claimsTransformer);
+
         return rootConfig;
 
     }
diff --git a/systests/cxf/src/test/resources/fediz_config.xml b/systests/cxf/src/test/resources/fediz_config.xml
index dc30ea6..5f87c36 100644
--- a/systests/cxf/src/test/resources/fediz_config.xml
+++ b/systests/cxf/src/test/resources/fediz_config.xml
@@ -49,13 +49,14 @@
             <homeRealm type="String">urn:org:apache:cxf:fediz:idp:realm-A</homeRealm>
             <claimTypesRequested>
                 <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="false" />
-				<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="true" />
-				<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" optional="true" />
-				<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" optional="true" />
+                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="true" />
+                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" optional="true" />
+                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" optional="true" />
             </claimTypesRequested>
         </protocol>
         <logoutURL>/secure/logout</logoutURL>
         <logoutRedirectTo>/index.html</logoutRedirectTo>
+        <claimsTransformer type="Class">org.apache.cxf.fediz.systests.cxf.ClaimTransformerTest</claimsTransformer>
     </contextConfig>
 </FedizConfig>
 
diff --git a/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml b/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml
index f73ae4d..a30b0d5 100644
--- a/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml
+++ b/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml
@@ -46,13 +46,14 @@
             <homeRealm type="String">urn:org:apache:cxf:fediz:idp:realm-A</homeRealm>
             <claimTypesRequested>
                 <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="false" />
-				<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="true" />
-				<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" optional="true" />
-				<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" optional="true" />
+                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="true" />
+                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" optional="true" />
+                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" optional="true" />
             </claimTypesRequested>
         </protocol>
         <logoutURL>/secure/logout</logoutURL>
         <logoutRedirectTo>/index.html</logoutRedirectTo>
+        <claimsTransformer type="Class">org.apache.cxf.fediz.systests.cxf.ClaimTransformerTest</claimsTransformer>
     </contextConfig>
 </FedizConfig>
 


[cxf-fediz] 03/03: Fixing some conflicts with the last patch

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf-fediz.git

commit 6068ce89d85df09ccda31eda1658476b59ea3c79
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Fri Sep 21 16:34:20 2018 +0100

    Fixing some conflicts with the last patch
---
 .../org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java    | 5 +++--
 .../apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java  | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java
index 533d3e0..0d2043d 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java
@@ -70,6 +70,7 @@ import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean;
 import org.apache.wss4j.common.saml.bean.ConditionsBean;
 import org.apache.wss4j.common.saml.builder.SAML2Constants;
 import org.apache.wss4j.common.util.DOM2Writer;
+import org.apache.wss4j.common.util.XMLUtils;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -327,10 +328,10 @@ public class ClaimsProcessorTest {
         Document doc = STSUtil.toSOAPPart(rstr);
         Element token = assertion.toDOM(doc);
 
-        Element e = SAMLTokenValidatorOldTest.findElement(doc, "RequestedSecurityToken",
+        Element e = XMLUtils.findElement(doc, "RequestedSecurityToken",
                                                         FederationConstants.WS_TRUST_13_NS);
         if (e == null) {
-            e = SAMLTokenValidatorOldTest.findElement(doc, "RequestedSecurityToken",
+            e = XMLUtils.findElement(doc, "RequestedSecurityToken",
                                                     FederationConstants.WS_TRUST_2005_02_NS);
         }
         e.appendChild(token);
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java
index 4c4ab6f..b5baa6b 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java
@@ -155,7 +155,7 @@ public class SAMLTokenValidatorOldTest {
         Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
                             .size());
         Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
-        assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+        assertClaims(wfRes.getClaims(), ClaimTypes.URI_BASE.toString() + "/" + callbackHandler.getRoleAttributeName());
 
     }
 
@@ -289,7 +289,7 @@ public class SAMLTokenValidatorOldTest {
         Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
                             .size());
         Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
-        assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+        assertClaims(wfRes.getClaims(), ClaimTypes.URI_BASE.toString() + "/" + callbackHandler.getRoleAttributeName());
     }
 
 


[cxf-fediz] 02/03: Refactoring and fix custom claims processing support, adding test cases, refactor role parsing

Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf-fediz.git

commit 6f4074b5aa81c2de304e97af54b9f6257b085f2e
Author: Jan Bernhardt <jb...@talend.com>
AuthorDate: Mon Aug 27 11:19:37 2018 +0200

    Refactoring and fix custom claims processing support, adding test cases, refactor role parsing
---
 .gitignore                                         |   1 +
 .../main/java/org/apache/cxf/fediz/core/Claim.java |   5 +
 .../cxf/fediz/core/TokenValidatorResponse.java     |  19 +-
 .../apache/cxf/fediz/core/config/FedizContext.java |  56 ++--
 .../core/processor/AbstractFedizProcessor.java     |  36 +++
 .../cxf/fediz/core/processor/ClaimsProcessor.java  |  39 +++
 .../core/processor/FederationProcessorImpl.java    |  30 +-
 .../fediz/core/processor/SAMLProcessorImpl.java    |  22 +-
 .../cxf/fediz/core/saml/SAMLTokenValidator.java    |  41 ++-
 .../src/main/resources/schemas/FedizConfig.xsd     |  13 +-
 .../cxf/fediz/common/ClaimCopyProcessor.java       |  19 ++
 .../cxf/fediz/common/ClaimMutateProcessor.java     |  38 +++
 .../fediz/core/config/FedizConfigurationTest.java  |  46 ++-
 .../fediz/core/federation/ClaimsProcessorTest.java | 339 +++++++++++++++++++++
 .../cxf/fediz/core/federation/CustomValidator.java |   1 -
 .../core/federation/FederationResponseTest.java    |   4 +-
 .../cxf/fediz/core/samlsso/CustomValidator.java    |   1 -
 systests/cxf/src/test/resources/fediz_config.xml   |   1 -
 .../cxfWebapp/src/main/resources/fediz_config.xml  |   1 -
 19 files changed, 626 insertions(+), 86 deletions(-)

diff --git a/.gitignore b/.gitignore
index 1e8a4b2..1d7af8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ velocity.log
 .externalToolBuilders/
 
 .idea
+bin
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java
index c8e47f5..5155377 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java
@@ -90,5 +90,10 @@ public class Claim implements Serializable {
     public Object getValue() {
         return value;
     }
+    
+    @Override
+    public String toString() {
+        return claimType + " : " + value;
+    }
 
 }
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/TokenValidatorResponse.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/TokenValidatorResponse.java
index c21c9ec..963ea24 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/TokenValidatorResponse.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/TokenValidatorResponse.java
@@ -26,6 +26,7 @@ public class TokenValidatorResponse {
 
     private String username;
     private String uniqueTokenId;
+    @Deprecated
     private List<String> roles;
     private String issuer;
     private String audience;
@@ -33,8 +34,16 @@ public class TokenValidatorResponse {
     private Instant expires;
     private Instant created;
 
+    public TokenValidatorResponse(String uniqueTokenId, String username, String issuer, 
+                                  List<Claim> claims, String audience) {
+        this.username = username;
+        this.issuer = issuer;
+        this.claims = claims;
+        this.audience = audience;
+        this.uniqueTokenId = uniqueTokenId;
+    }
 
-
+    @Deprecated
     public TokenValidatorResponse(String uniqueTokenId, String username, String issuer,
                                   List<String> roles, List<Claim> claims, String audience) {
         this.username = username;
@@ -49,18 +58,24 @@ public class TokenValidatorResponse {
     public String getUsername() {
         return username;
     }
+    
     public String getUniqueTokenId() {
         return uniqueTokenId;
     }
+    
+    @Deprecated
     public List<String> getRoles() {
         return roles;
     }
+    
     public String getIssuer() {
         return issuer;
     }
+    
     public String getAudience() {
         return audience;
     }
+    
     public List<Claim> getClaims() {
         return claims;
     }
@@ -80,6 +95,4 @@ public class TokenValidatorResponse {
     public void setCreated(Instant created) {
         this.created = created;
     }
-
-
 }
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
index 4c92994..84cd035 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
@@ -32,10 +32,8 @@ import java.util.List;
 import java.util.Properties;
 import java.util.regex.Pattern;
 
-import org.apache.cxf.fediz.core.config.jaxb.ArgumentType;
 import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
 import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
-import org.apache.cxf.fediz.core.config.jaxb.ClaimsTransformerType;
 import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
 import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
 import org.apache.cxf.fediz.core.config.jaxb.KeyManagersType;
@@ -76,6 +74,8 @@ public class FedizContext implements Closeable {
     private ClassLoader classloader;
     private Object logoutRedirectToConstraint;
 
+    private List<ClaimsProcessor> claimsProcessor;
+
 
     public FedizContext(ContextConfig config) {
         if (config == null) {
@@ -263,39 +263,27 @@ public class FedizContext implements Closeable {
         return replayCache;
     }
 
-    public ClaimsProcessor getClaimsTransformer() {
-        ClaimsTransformerType  claimsTransformerType  = config.getClaimsTransformer();
-        if (claimsTransformerType != null) {
-            ArgumentType type = claimsTransformerType.getType();
-            if (type.equals(ArgumentType.CLASS)) {
-                String clazzName = type.value();
-                Class<?> clazz;
-                try {
-                    clazz = getClassloader().loadClass(clazzName);
-                    Object obj = clazz.newInstance();
-                    if (obj instanceof ClaimsProcessor) {
-                        return (ClaimsProcessor) obj;
-                    } else {
-                        LOG.error("The configured ClaimsTransformer is not an instance of ClaimsProcessor !");
-                        return null;
-                    }
-                    
-                } catch (ClassNotFoundException e) {
-                    LOG.error("The specified ClaimsTransformer can not be found. Check your classpath");
-                    return null;
-                
-                } catch (InstantiationException e) {
-                    LOG.error("The specified ClaimsTransformer can not be instantiated.");
-                    return null;
-                
-                } catch (IllegalAccessException e) {
-                    LOG.error("The specified ClaimsTransformer can not be accessed.");
-                    return null;
-                }
-                
-            }
+    @SuppressWarnings("unchecked")
+    public List<ClaimsProcessor> getClaimsProcessor() {
+        if (this.claimsProcessor != null) {
+            return this.claimsProcessor;
+        }
+        CallbackType cbt = config.getClaimsProcessor();
+        Object claimsProc = ConfigUtils.loadCallbackType(cbt, "ClaimsProcessor", getClassloader());
+
+        if (claimsProc == null) {
+            return null;
+        } else if (claimsProc instanceof ClaimsProcessor) {
+            this.claimsProcessor = new ArrayList<>();
+            this.claimsProcessor.add((ClaimsProcessor) claimsProc);
+        } else if (claimsProc instanceof List && !((List<?>) claimsProc).isEmpty()
+                && ((List<?>) claimsProc).get(0) instanceof ClaimsProcessor) {
+            this.claimsProcessor = (List<ClaimsProcessor>) claimsProc;
+        } else {
+            LOG.error("The configured ClaimsProcessor is not an instance of ClaimsProcessor!");
+            return null;
         }
-        return null;
+        return this.claimsProcessor;
     }
 
     public String getName() {
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/AbstractFedizProcessor.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/AbstractFedizProcessor.java
index 36e3eb0..f6b3c9e 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/AbstractFedizProcessor.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/AbstractFedizProcessor.java
@@ -21,13 +21,17 @@ package org.apache.cxf.fediz.core.processor;
 
 import java.io.IOException;
 import java.net.MalformedURLException;
+import java.net.URI;
 import java.time.Instant;
+import java.util.Collections;
+import java.util.List;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.cxf.fediz.core.Claim;
 import org.apache.cxf.fediz.core.config.FedizContext;
 import org.apache.cxf.fediz.core.exception.ProcessingException;
 import org.apache.cxf.fediz.core.exception.ProcessingException.TYPE;
@@ -102,7 +106,39 @@ public abstract class AbstractFedizProcessor implements FedizProcessor {
     protected String extractFullContextPath(HttpServletRequest request) throws MalformedURLException {
         return StringUtils.extractFullContextPath(request);
     }
+    
+    
+    protected List<String> getRoles(List<Claim> claims, String roleURI) {
+        if (roleURI == null || roleURI.isEmpty()) {
+            return null;
+        }
+        return getRoles(claims, URI.create(roleURI));
+    }
 
+    protected List<String> getRoles(List<Claim> claims, URI roleURI) {
+        if (claims == null || roleURI == null) {
+            return null;
+        }
+        List<String> roles = null;
+        for (Claim c : claims) {
+            if (roleURI.equals(c.getClaimType())) {
+                Object oValue = c.getValue();
+                if ((oValue instanceof String) && !"".equals((String) oValue)) {
+                    roles = Collections.singletonList((String) oValue);
+                } else if ((oValue instanceof List<?>) && !((List<?>) oValue).isEmpty()) {
+                    @SuppressWarnings("unchecked")
+                    List<String> values = (List<String>) oValue;
+                    roles = Collections.unmodifiableList(values);
+                } else if (!((oValue instanceof String) || (oValue instanceof List<?>))) {
+                    LOG.error("Unsupported value type of Claim value");
+                    throw new IllegalStateException("Unsupported value type of Claim value");
+                }
+                break;
+            }
+        }
+        return roles;
+    }
+    
     protected String resolveReply(HttpServletRequest request, FedizContext config) throws IOException,
         UnsupportedCallbackException {
         Object replyObj = config.getProtocol().getReply();
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/ClaimsProcessor.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/ClaimsProcessor.java
new file mode 100644
index 0000000..b45eaf2
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/ClaimsProcessor.java
@@ -0,0 +1,39 @@
+/**
+ * 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.fediz.core.processor;
+
+import java.util.List;
+
+import org.apache.cxf.fediz.core.Claim;
+
+public interface ClaimsProcessor {
+
+    /**
+     * This operation can be used to transform, filter or trigger other actions
+     * based on the input claims. The response can be the same list of claims as
+     * from the input parameter, a subset of it or a renamed or extended list of
+     * claims.
+     * 
+     * @param claims Claims to be processed
+     * @return List of processed claims
+     */
+    List<Claim> processClaims(List<Claim> claims);
+
+}
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
index 378c418..2d1c2bc 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
@@ -212,10 +212,6 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
             expires = validatorResponse.getExpires();
         }
         testForReplayAttack(validatorResponse.getUniqueTokenId(), config, expires);
-        testForMandatoryClaims(((FederationProtocol)config.getProtocol()).getRoleURI(),
-                              ((FederationProtocol)config.getProtocol()).getClaimTypesRequested(),
-                              validatorResponse.getClaims(),
-                              validatorResponse.getRoles() != null && !validatorResponse.getRoles().isEmpty());
 
         Instant created = validatorResponse.getCreated();
         if (lifeTime != null && lifeTime.getCreated() != null) {
@@ -223,13 +219,23 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
         }
 
         List<Claim> claims = validatorResponse.getClaims();
-        if (config.getClaimsTransformer() != null) {
-            LOG.debug("invoking ClaimsTransformer");
-            claims = config.getClaimsTransformer().processClaims(validatorResponse.getClaims());
+        
+        testForMandatoryClaims(config.getProtocol().getRoleURI(),
+                ((FederationProtocol)config.getProtocol()).getClaimTypesRequested(),
+                claims);
+
+        List<ClaimsProcessor> processors = config.getClaimsProcessor();
+        if (processors != null) {
+            for (ClaimsProcessor cp : processors) {
+                LOG.debug("invoking ClaimsProcessor {}", cp);
+                claims = cp.processClaims(claims);
+            }
         }
 
+        List<String> roles = getRoles(claims, config.getProtocol().getRoleURI());
+        
         FedizResponse fedResponse = new FedizResponse(validatorResponse.getUsername(), validatorResponse.getIssuer(),
-                                                      validatorResponse.getRoles(), claims,
+                                                      roles, claims,
                                                       validatorResponse.getAudience(), created, expires, rst,
                                                       validatorResponse.getUniqueTokenId());
 
@@ -730,8 +736,7 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
 
     private void testForMandatoryClaims(String roleURI,
                                         List<org.apache.cxf.fediz.core.config.Claim> requestedClaims,
-                                        List<org.apache.cxf.fediz.core.Claim> receivedClaims,
-                                        boolean foundRoles
+                                        List<org.apache.cxf.fediz.core.Claim> receivedClaims
     ) throws ProcessingException {
         if (requestedClaims != null) {
             for (org.apache.cxf.fediz.core.config.Claim requestedClaim : requestedClaims) {
@@ -743,11 +748,6 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
                             break;
                         }
                     }
-                    if (!found && foundRoles && roleURI != null && roleURI.equals(requestedClaim.getType())) {
-                        // Maybe the requested claim is a role, which has already been removed
-                        // from the claims collection
-                        found = true;
-                    }
                     if (!found) {
                         LOG.warn("Mandatory claim {} not found in token", requestedClaim.getType());
                         throw new ProcessingException("Mandatory claim not found in token", TYPE.INVALID_REQUEST);
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/SAMLProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/SAMLProcessorImpl.java
index 4b88c92..b44a961 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/SAMLProcessorImpl.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/SAMLProcessorImpl.java
@@ -40,6 +40,7 @@ import javax.servlet.http.HttpServletRequest;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import org.apache.cxf.fediz.core.Claim;
 import org.apache.cxf.fediz.core.RequestState;
 import org.apache.cxf.fediz.core.SAMLSSOConstants;
 import org.apache.cxf.fediz.core.TokenValidator;
@@ -127,9 +128,8 @@ public class SAMLProcessorImpl extends AbstractFedizProcessor {
         return requestState;
     }
 
-    protected FedizResponse processSignInRequest(
-            FedizRequest request, FedizContext config)
-        throws ProcessingException {
+    protected FedizResponse processSignInRequest(FedizRequest request, FedizContext config) throws ProcessingException {
+        
         SAMLProtocol protocol = (SAMLProtocol)config.getProtocol();
         RequestState requestState =
             processRelayState(request.getState(), request.getRequestState());
@@ -222,9 +222,23 @@ public class SAMLProcessorImpl extends AbstractFedizProcessor {
         }
         testForReplayAttack(validatorResponse.getUniqueTokenId(), config, expires);
 
+        List<Claim> claims = validatorResponse.getClaims();
+
+        if (config.getClaimsProcessor() != null) {
+            List<ClaimsProcessor> processors = config.getClaimsProcessor();
+            if (processors != null) {
+                for (ClaimsProcessor cp : processors) {
+                    LOG.debug("invoking ClaimsProcessor {}", cp);
+                    claims = cp.processClaims(claims);
+                }
+            }
+        }
+
+        List<String> roles = getRoles(claims, config.getProtocol().getRoleURI());
+        
         FedizResponse fedResponse = new FedizResponse(
                 validatorResponse.getUsername(), validatorResponse.getIssuer(),
-                validatorResponse.getRoles(), validatorResponse.getClaims(),
+                roles, claims,
                 validatorResponse.getAudience(),
                 validatorResponse.getCreated(),
                 expires,
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
index 9172572..bbbfc09 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
@@ -200,12 +200,12 @@ public class SAMLTokenValidator implements TokenValidator {
                 claims = Collections.emptyList();
             }
 
-            List<String> roles = parseRoles(config, claims);
-
+            claims = parseRoleClaim(config, claims);
+            
             SAMLTokenPrincipal p = new SAMLTokenPrincipalImpl(assertion);
 
             TokenValidatorResponse response = new TokenValidatorResponse(
-                    assertion.getId(), p.getName(), assertionIssuer, roles,
+                    assertion.getId(), p.getName(), assertionIssuer,
                     new ClaimCollection(claims), audience);
             response.setExpires(getExpires(assertion));
             response.setCreated(getCreated(assertion));
@@ -218,6 +218,7 @@ public class SAMLTokenValidator implements TokenValidator {
         }
     }
 
+    @Deprecated
     protected List<String> parseRoles(FedizContext config, List<Claim> claims) {
         List<String> roles = null;
         Protocol protocol = config.getProtocol();
@@ -249,6 +250,38 @@ public class SAMLTokenValidator implements TokenValidator {
 
         return roles;
     }
+    
+    protected List<Claim> parseRoleClaim(FedizContext config, List<Claim> claims) {
+        List<String> roles = null;
+        Protocol protocol = config.getProtocol();
+        if (protocol.getRoleURI() != null) {
+            URI roleURI = URI.create(protocol.getRoleURI());
+            String delim = protocol.getRoleDelimiter();
+            for (Claim c : claims) {
+                if (roleURI.equals(c.getClaimType())) {
+                    Object oValue = c.getValue();
+                    if ((oValue instanceof String) && !"".equals((String)oValue)) {
+                        if (delim == null) {
+                            roles = Collections.singletonList((String)oValue);
+                        } else {
+                            roles = parseRoles((String)oValue, delim);
+                        }
+                    } else if ((oValue instanceof List<?>) && !((List<?>)oValue).isEmpty()) {
+                        @SuppressWarnings("unchecked")
+                        List<String> values = (List<String>)oValue;
+                        roles = Collections.unmodifiableList(values);
+                    } else if (!((oValue instanceof String) || (oValue instanceof List<?>))) {
+                        LOG.error("Unsupported value type of Claim value");
+                        throw new IllegalStateException("Unsupported value type of Claim value");
+                    }
+                    // Replace single role String with role List<String> after parsing
+                    c.setValue(roles);
+                    break;
+                }
+            }
+        }
+        return claims;
+    }
 
     protected List<Claim> parseClaimsInAssertion(
             org.opensaml.saml.saml1.core.Assertion assertion) {
@@ -310,8 +343,6 @@ public class SAMLTokenValidator implements TokenValidator {
         return collection;
     }
 
-
-
     protected List<Claim> parseClaimsInAssertion(
             org.opensaml.saml.saml2.core.Assertion assertion) {
         List<org.opensaml.saml.saml2.core.AttributeStatement> attributeStatements = assertion
diff --git a/plugins/core/src/main/resources/schemas/FedizConfig.xsd b/plugins/core/src/main/resources/schemas/FedizConfig.xsd
index 97cea11..ee0ea9f 100644
--- a/plugins/core/src/main/resources/schemas/FedizConfig.xsd
+++ b/plugins/core/src/main/resources/schemas/FedizConfig.xsd
@@ -25,10 +25,10 @@
                 <xs:element ref="tokenDecryptionKey" />
                 <xs:element ref="trustedIssuers" />
                 <xs:element ref="protocol" />
+                <xs:element ref="claimsProcessor" minOccurs="0" />
                 <xs:element ref="logoutURL" minOccurs="0" />
                 <xs:element ref="logoutRedirectTo" minOccurs="0" />
                 <xs:element ref="logoutRedirectToConstraint" minOccurs="0" />
-                <xs:element ref="claimsTransformer" minOccurs="0" />
             </xs:sequence>
             <xs:attribute name="name" use="required" type="xs:string" />
 
@@ -223,16 +223,6 @@
         </xs:annotation>
     </xs:element>
 
-    <xs:complexType name="ClaimsTransformerType">
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="type" type="argumentType" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:element name="claimsTransformer" type="ClaimsTransformerType" />
-
     <xs:element name="issuer" type="CallbackType" />
     <xs:element name="homeRealm" type="CallbackType" />
     <xs:element name="authenticationType" type="CallbackType" />
@@ -241,6 +231,7 @@
     <xs:element name="signInQuery" type="CallbackType" />
     <xs:element name="signOutQuery" type="CallbackType" />
     <xs:element name="reply" type="CallbackType" />
+    <xs:element name="claimsProcessor" type="CallbackType" />
 
     <xs:simpleType name="argumentType">
         <xs:restriction base="xs:string">
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimCopyProcessor.java b/plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimCopyProcessor.java
new file mode 100644
index 0000000..6b9ba2a
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimCopyProcessor.java
@@ -0,0 +1,19 @@
+package org.apache.cxf.fediz.common;
+
+import java.util.List;
+
+import org.apache.cxf.fediz.core.Claim;
+import org.apache.cxf.fediz.core.processor.ClaimsProcessor;
+
+/**
+ * Returns same list of claims as provided (no changes)
+ *
+ */
+public class ClaimCopyProcessor implements ClaimsProcessor {
+
+    @Override
+    public List<Claim> processClaims(List<Claim> claims) {
+        return claims;
+    }
+
+}
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimMutateProcessor.java b/plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimMutateProcessor.java
new file mode 100644
index 0000000..c11fe79
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/common/ClaimMutateProcessor.java
@@ -0,0 +1,38 @@
+package org.apache.cxf.fediz.common;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cxf.fediz.core.Claim;
+import org.apache.cxf.fediz.core.ClaimTypes;
+import org.apache.cxf.fediz.core.processor.ClaimsProcessor;
+
+/**
+ * Returns same list of claims as provided (no changes)
+ *
+ */
+public class ClaimMutateProcessor implements ClaimsProcessor {
+
+    @Override
+    public List<Claim> processClaims(List<Claim> claims) {
+        List<Claim> newClaimList = new ArrayList<>();
+
+        for (Claim c : claims) {
+            if (ClaimTypes.PRIVATE_PERSONAL_IDENTIFIER.equals(c.getClaimType())) {
+                Claim lowerClaim = new Claim();
+                lowerClaim.setClaimType(ClaimTypes.FIRSTNAME);
+                lowerClaim.setValue(c.getValue().toString().toLowerCase());
+
+                Claim upperClaim = new Claim();
+                upperClaim.setClaimType(ClaimTypes.LASTNAME);
+                upperClaim.setValue(c.getValue().toString().toUpperCase());
+
+                newClaimList.add(lowerClaim);
+                newClaimList.add(upperClaim);
+            }
+        }
+
+        return newClaimList;
+    }
+
+}
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java
index 347cede..2bf7a51 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/config/FedizConfigurationTest.java
@@ -24,18 +24,21 @@ import java.io.IOException;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.math.BigInteger;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 
 import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.ClaimTypes;
 import org.apache.cxf.fediz.core.config.jaxb.ArgumentType;
 import org.apache.cxf.fediz.core.config.jaxb.AudienceUris;
 import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
 import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
 import org.apache.cxf.fediz.core.config.jaxb.ClaimType;
 import org.apache.cxf.fediz.core.config.jaxb.ClaimTypesRequested;
-import org.apache.cxf.fediz.core.config.jaxb.ClaimsTransformerType;
 import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
 import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
 import org.apache.cxf.fediz.core.config.jaxb.FedizConfig;
@@ -46,6 +49,7 @@ import org.apache.cxf.fediz.core.config.jaxb.TrustManagersType;
 import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuerType;
 import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuers;
 import org.apache.cxf.fediz.core.config.jaxb.ValidationType;
+import org.apache.cxf.fediz.core.processor.ClaimsProcessor;
 import org.apache.wss4j.common.cache.EHCacheReplayCache;
 import org.apache.wss4j.common.cache.MemoryReplayCache;
 import org.apache.wss4j.common.cache.ReplayCache;
@@ -59,7 +63,7 @@ public class FedizConfigurationTest {
     //private static final String REQUEST = "request value";
     private static final String REPLY = "reply value";
     private static final String TARGET_REALM = "target realm";
-    private static final String HOME_REALM_CLASS = "org.apache.fediz.realm.MyHomeRealm.class";
+    private static final String HOME_REALM_CLASS = "org.apache.fediz.realm.MyHomeRealm";
     private static final String FRESHNESS_VALUE = "10000";
 
     private static final String CONFIG_NAME = "ROOT";
@@ -79,13 +83,13 @@ public class FedizConfigurationTest {
 
     private static final String ROLE_DELIMITER = ";";
     private static final String ROLE_URI = "http://someserver:8080/path/roles.uri";
-    private static final String CLAIM_TYPE_1 = "a particular claim type";
-    private static final String CLAIM_TYPE_2 = "a second particular claim type";
+    private static final String CLAIM_TYPE_1 = ClaimTypes.FIRSTNAME.toString();
+    private static final String CLAIM_TYPE_2 = ClaimTypes.LASTNAME.toString();
     private static final String SUBJECT_VALUE_1 = ".*CN=www.sts1.com.*";
     private static final String SUBJECT_VALUE_2 = ".*CN=www.sts2.com.*";
     private static final String SUBJECT_VALUE_3 = ".*CN=www.sts3.com.*";
 
-    private static final String CLAIMSTRANFORMER_CLASS = "org.apache.fediz.MyClaimsTransformer.class";
+    private static final String CLAIMS_PROCESSOR_CLASS = "org.apache.cxf.fediz.common.ClaimCopyProcessor";
 
     private static final String CONFIG_FILE = "./target/fedizconfig.xml";
 
@@ -215,10 +219,10 @@ public class FedizConfigurationTest {
         issuer.setValue(ISSUER);
         protocol.setIssuer(issuer);
 
-        ClaimsTransformerType claimsTransformer = new ClaimsTransformerType();
-        claimsTransformer.setType(ArgumentType.CLASS);
-        claimsTransformer.setValue(CLAIMSTRANFORMER_CLASS);
-        config.setClaimsTransformer(claimsTransformer);
+        CallbackType claimsProcessor = new CallbackType();
+        claimsProcessor.setType(ArgumentType.CLASS);
+        claimsProcessor.setValue(CLAIMS_PROCESSOR_CLASS);
+        config.setClaimsProcessor(claimsProcessor);
 
         return rootConfig;
 
@@ -418,5 +422,29 @@ public class FedizConfigurationTest {
         Assert.assertTrue(config.getMaximumClockSkew().intValue() == 5);
         Assert.assertFalse(config.isTokenExpirationValidation());
     }
+    
+    @org.junit.Test
+    public void testClaimProcessor() throws JAXBException, IOException {
+        final JAXBContext jaxbContext = JAXBContext.newInstance(FedizConfig.class);
+        FedizConfigurator configurator = new FedizConfigurator();
+        FedizConfig configOut = createConfiguration(true);
+        StringWriter writer = new StringWriter();
+        jaxbContext.createMarshaller().marshal(configOut, writer);
+        StringReader reader = new StringReader(writer.toString());
+        configurator.loadConfig(reader);
+        
+        FedizContext fedContext = configurator.getFedizContext(CONFIG_NAME);
+        List<ClaimsProcessor> claimsProcessor = fedContext.getClaimsProcessor();
+        Assert.assertNotNull(claimsProcessor);
+        Assert.assertEquals(1, claimsProcessor.size());
+        
+        List<org.apache.cxf.fediz.core.Claim> inputClaims = new ArrayList<>();
+        org.apache.cxf.fediz.core.Claim claim = new org.apache.cxf.fediz.core.Claim();
+        claim.setClaimType(URI.create(CLAIM_TYPE_1));
+        claim.setValue("Alice");
+        inputClaims.add(claim);
+        List<org.apache.cxf.fediz.core.Claim> processedClaims = claimsProcessor.get(0).processClaims(inputClaims);
+        Assert.assertEquals(inputClaims, processedClaims);
+    }
 
 }
\ No newline at end of file
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java
new file mode 100644
index 0000000..533d3e0
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/ClaimsProcessorTest.java
@@ -0,0 +1,339 @@
+/**
+ * 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.fediz.core.federation;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.util.Collections;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+
+import org.apache.cxf.fediz.common.STSUtil;
+import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.Claim;
+import org.apache.cxf.fediz.core.ClaimTypes;
+import org.apache.cxf.fediz.core.FederationConstants;
+import org.apache.cxf.fediz.core.KeystoreCallbackHandler;
+import org.apache.cxf.fediz.core.SAML2CallbackHandler;
+import org.apache.cxf.fediz.core.config.FedizConfigurator;
+import org.apache.cxf.fediz.core.config.FedizContext;
+import org.apache.cxf.fediz.core.config.jaxb.ArgumentType;
+import org.apache.cxf.fediz.core.config.jaxb.AudienceUris;
+import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
+import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
+import org.apache.cxf.fediz.core.config.jaxb.ClaimType;
+import org.apache.cxf.fediz.core.config.jaxb.ClaimTypesRequested;
+import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
+import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.FedizConfig;
+import org.apache.cxf.fediz.core.config.jaxb.KeyStoreType;
+import org.apache.cxf.fediz.core.config.jaxb.ProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustManagersType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuerType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuers;
+import org.apache.cxf.fediz.core.config.jaxb.ValidationType;
+import org.apache.cxf.fediz.core.exception.ProcessingException;
+import org.apache.cxf.fediz.core.processor.FederationProcessorImpl;
+import org.apache.cxf.fediz.core.processor.FedizProcessor;
+import org.apache.cxf.fediz.core.processor.FedizRequest;
+import org.apache.cxf.fediz.core.processor.FedizResponse;
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.ext.WSPasswordCallback;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SAMLCallback;
+import org.apache.wss4j.common.saml.SAMLUtil;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean;
+import org.apache.wss4j.common.saml.bean.ConditionsBean;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+import org.apache.wss4j.common.util.DOM2Writer;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Test for claim transformations with ClaimsProcessor
+ */
+public class ClaimsProcessorTest {
+
+    private static final String ISSUER = "FedizSTSIssuer";
+    private static final String PROTOCOL_VERSION = "1.0.0";
+    //private static final String REQUEST = "request value";
+    private static final String REPLY = "reply value";
+    private static final String TARGET_REALM = "target realm";
+    private static final String FRESHNESS_VALUE = "10000";
+
+    private static final String CONFIG_NAME = "ROOT";
+    private static final String CLOCK_SKEW = "1000";
+
+    private static final String AUTH_TYPE_VALUE = "some auth type";
+
+    private static final String AUDIENCE_URI_1 = "http://host_one:port/url";
+
+    private static final String ROLE_DELIMITER = ";";
+    private static final String ROLE_URI = "http://someserver:8080/path/roles.uri";
+    
+    private static final String COPY_CLAIMS_PROCESSOR_CLASS = "org.apache.cxf.fediz.common.ClaimCopyProcessor";
+    private static final String MUTATE_CLAIMS_PROCESSOR_CLASS = "org.apache.cxf.fediz.common.ClaimMutateProcessor";
+
+    private static Crypto crypto;
+    private static CallbackHandler cbPasswordHandler = new KeystoreCallbackHandler();
+
+    @BeforeClass
+    public static void init() {
+        try {
+            crypto = CryptoFactory.getInstance("signature.properties");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    @AfterClass
+    public static void cleanup() {
+        SecurityTestUtil.cleanup();
+    }
+
+    //CHECKSTYLE:OFF
+    private FedizConfig createConfiguration(String claimsProcessorClass) throws JAXBException {
+
+        FedizConfig rootConfig = new FedizConfig();
+        ContextConfig config = new ContextConfig();
+        rootConfig.getContextConfig().add(config);
+
+        config.setName(CONFIG_NAME);
+        config.setMaximumClockSkew(new BigInteger(CLOCK_SKEW));
+
+        CertificateStores certStores = new CertificateStores();
+
+        TrustManagersType tm0 = new TrustManagersType();
+        KeyStoreType ks0 = new KeyStoreType();
+        ks0.setType("JKS");
+        ks0.setPassword("storepass");
+        ks0.setResource("ststrust.jks");
+        tm0.setKeyStore(ks0);
+
+        certStores.getTrustManager().add(tm0);
+
+        config.setCertificateStores(certStores);
+
+        TrustedIssuers trustedIssuers = new TrustedIssuers();
+
+        TrustedIssuerType ti0 = new TrustedIssuerType();
+        ti0.setCertificateValidation(ValidationType.PEER_TRUST);
+        trustedIssuers.getIssuer().add(ti0);
+
+        config.setTrustedIssuers(trustedIssuers);
+
+        ProtocolType protocol = new FederationProtocolType();
+
+        CallbackType authType = new CallbackType();
+        authType.setType(ArgumentType.STRING);
+        authType.setValue(AUTH_TYPE_VALUE);
+        ((FederationProtocolType)protocol).setAuthenticationType(authType);
+
+        CallbackType freshness = new CallbackType();
+        freshness.setValue(FRESHNESS_VALUE);
+        ((FederationProtocolType)protocol).setFreshness(freshness);
+
+        CallbackType reply = new CallbackType();
+        reply.setValue(REPLY);
+        ((FederationProtocolType)protocol).setReply(reply);
+        ((FederationProtocolType)protocol).setVersion(PROTOCOL_VERSION);
+
+        config.setProtocol(protocol);
+
+        AudienceUris audienceUris = new AudienceUris();
+        audienceUris.getAudienceItem().add(AUDIENCE_URI_1);
+        config.setAudienceUris(audienceUris);
+
+        protocol.setRoleDelimiter(ROLE_DELIMITER);
+        protocol.setRoleURI(ROLE_URI);
+
+        ClaimTypesRequested claimTypeReq = new ClaimTypesRequested();
+        ClaimType claimType = new ClaimType();
+        claimType.setOptional(true);
+        claimType.setType(ClaimTypes.FIRSTNAME.toString());
+        claimTypeReq.getClaimType().add(claimType);
+
+        ClaimType claimType2 = new ClaimType();
+        claimType2.setOptional(true);
+        claimType2.setType(ClaimTypes.LASTNAME.toString());
+        claimTypeReq.getClaimType().add(claimType2);
+
+        protocol.setClaimTypesRequested(claimTypeReq);
+
+        CallbackType realm = new CallbackType();
+        realm.setValue(TARGET_REALM);
+        protocol.setRealm(realm);
+
+        CallbackType issuer = new CallbackType();
+        issuer.setValue(ISSUER);
+        protocol.setIssuer(issuer);
+        
+        if (claimsProcessorClass != null) {
+            CallbackType cpc = new CallbackType();
+            cpc.setType(ArgumentType.CLASS);
+            cpc.setValue(claimsProcessorClass);
+            config.setClaimsProcessor(cpc);
+        }
+
+        return rootConfig;
+
+    }
+
+    @org.junit.Test
+    public void testWithoutCustomClaimProcessor() throws Exception {
+        String originalClaimValue = "Alice";
+        String claimsProcessorClass = null;
+        
+        FedizResponse wfRes = performLogin(ClaimTypes.FIRSTNAME.toString(), originalClaimValue, claimsProcessorClass);
+
+        Object claimValue = null;
+        for (Claim c : wfRes.getClaims()) {
+            if (ClaimTypes.FIRSTNAME.equals(c.getClaimType())) {
+                claimValue = c.getValue();
+            }
+        }
+
+        Assert.assertEquals(originalClaimValue, claimValue);
+    }
+    
+    @org.junit.Test
+    public void testCustomClaimProcessor() throws Exception {
+        String originalClaimValue = "Alice";
+        String claimsProcessorClass = COPY_CLAIMS_PROCESSOR_CLASS;
+        
+        FedizResponse wfRes = performLogin(ClaimTypes.FIRSTNAME.toString(), originalClaimValue, claimsProcessorClass);
+
+        Object claimValue = null;
+        for (Claim c : wfRes.getClaims()) {
+            if (ClaimTypes.FIRSTNAME.equals(c.getClaimType())) {
+                claimValue = c.getValue();
+            }
+        }
+
+        Assert.assertEquals(originalClaimValue, claimValue);
+    }
+    
+    @org.junit.Test
+    public void testClaimModificationProcessor() throws Exception {
+        String originalClaimValue = "Alice";
+        String claimsProcessorClass = MUTATE_CLAIMS_PROCESSOR_CLASS;
+        
+        FedizResponse wfRes = performLogin(ClaimTypes.PRIVATE_PERSONAL_IDENTIFIER.toString(), originalClaimValue, claimsProcessorClass);
+
+        Object firstname = null;
+        Object lastname = null;
+        
+        Assert.assertEquals(2, wfRes.getClaims().size());
+        
+        for (Claim c : wfRes.getClaims()) {
+            if (ClaimTypes.FIRSTNAME.equals(c.getClaimType())) {
+                firstname = c.getValue();
+            } else if (ClaimTypes.LASTNAME.equals(c.getClaimType())) {
+                lastname = c.getValue();
+            }
+        }
+
+        Assert.assertEquals("alice", firstname);
+        Assert.assertEquals("ALICE", lastname);
+    }
+    
+    
+
+    private FedizResponse performLogin(String claimType, String claimValue, String claimsProcessorClass)
+            throws Exception, WSSecurityException, IOException, UnsupportedCallbackException, JAXBException, ProcessingException {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(ISSUER);
+        callbackHandler.setSubjectName("alice");
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setCustomClaimName(claimType);
+        callbackHandler.setCustomAttributeValues(Collections.singletonList(claimValue));
+
+        ConditionsBean cp = new ConditionsBean();
+        AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+        audienceRestriction.getAudienceURIs().add(AUDIENCE_URI_1);
+        cp.setAudienceRestrictions(Collections.singletonList(audienceRestriction));
+        callbackHandler.setConditions(cp);
+
+        SAMLCallback samlCallback = new SAMLCallback();
+        SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
+        SamlAssertionWrapper assertion = new SamlAssertionWrapper(samlCallback);
+
+        String rstr = createSamlToken(assertion, "mystskey", true);
+
+        FedizRequest wfReq = new FedizRequest();
+        wfReq.setAction(FederationConstants.ACTION_SIGNIN);
+        wfReq.setResponseToken(rstr);
+
+        FedizConfig config = createConfiguration(claimsProcessorClass);
+        StringWriter writer = new StringWriter();
+        final JAXBContext jaxbContext = JAXBContext.newInstance(FedizConfig.class);
+        jaxbContext.createMarshaller().marshal(config, writer);
+        StringReader reader = new StringReader(writer.toString());
+
+        FedizConfigurator configurator = new FedizConfigurator();
+        configurator.loadConfig(reader);
+        FedizContext context = configurator.getFedizContext(CONFIG_NAME);
+
+        FedizProcessor wfProc = new FederationProcessorImpl();
+        return wfProc.processRequest(wfReq, context);
+    }
+
+    private String createSamlToken(SamlAssertionWrapper assertion, String alias, boolean sign)
+        throws IOException, UnsupportedCallbackException, WSSecurityException, Exception {
+        return createSamlToken(assertion, alias, sign, STSUtil.SAMPLE_RSTR_COLL_MSG);
+    }
+
+    private String createSamlToken(SamlAssertionWrapper assertion, String alias, boolean sign, String rstr)
+        throws IOException, UnsupportedCallbackException, WSSecurityException, Exception {
+        WSPasswordCallback[] cb = {
+            new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE)
+        };
+        cbPasswordHandler.handle(cb);
+        String password = cb[0].getPassword();
+
+        if (sign) {
+            assertion.signAssertion(alias, password, crypto, false);
+        }
+        Document doc = STSUtil.toSOAPPart(rstr);
+        Element token = assertion.toDOM(doc);
+
+        Element e = SAMLTokenValidatorOldTest.findElement(doc, "RequestedSecurityToken",
+                                                        FederationConstants.WS_TRUST_13_NS);
+        if (e == null) {
+            e = SAMLTokenValidatorOldTest.findElement(doc, "RequestedSecurityToken",
+                                                    FederationConstants.WS_TRUST_2005_02_NS);
+        }
+        e.appendChild(token);
+        return DOM2Writer.nodeToString(doc);
+    }
+}
\ No newline at end of file
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/CustomValidator.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/CustomValidator.java
index 835f94e..3f62983 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/CustomValidator.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/CustomValidator.java
@@ -47,7 +47,6 @@ public class CustomValidator implements TokenValidator {
                                           FederationResponseTest.TEST_USER,
                                           FederationResponseTest.TEST_RSTR_ISSUER,
                                           null,
-                                          null,
                                           FederationResponseTest.TEST_AUDIENCE);
     }
 
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java
index 9ce3b74..6759b71 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java
@@ -22,6 +22,7 @@ package org.apache.cxf.fediz.core.federation;
 import java.io.File;
 import java.io.IOException;
 import java.math.BigInteger;
+import java.net.URI;
 import java.net.URL;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
@@ -1716,9 +1717,10 @@ public class FederationResponseTest {
     }
 
     private void assertClaims(List<Claim> claims, String roleClaimType) {
+        URI roleClaimTypeURI = URI.create(roleClaimType);
         for (Claim c : claims) {
             Assert.assertTrue("Invalid ClaimType URI: " + c.getClaimType(),
-                              c.getClaimType().equals(roleClaimType)
+                              c.getClaimType().equals(roleClaimTypeURI)
                               || c.getClaimType().equals(ClaimTypes.COUNTRY)
                               || c.getClaimType().equals(AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE)
                               );
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/CustomValidator.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/CustomValidator.java
index 7f083dc..baa4c58 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/CustomValidator.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/CustomValidator.java
@@ -47,7 +47,6 @@ public class CustomValidator implements TokenValidator {
                                           SAMLResponseTest.TEST_USER,
                                           SAMLResponseTest.TEST_IDP_ISSUER,
                                           null,
-                                          null,
                                           SAMLResponseTest.TEST_REQUEST_URL);
     }
 
diff --git a/systests/cxf/src/test/resources/fediz_config.xml b/systests/cxf/src/test/resources/fediz_config.xml
index 5f87c36..ef5df85 100644
--- a/systests/cxf/src/test/resources/fediz_config.xml
+++ b/systests/cxf/src/test/resources/fediz_config.xml
@@ -56,7 +56,6 @@
         </protocol>
         <logoutURL>/secure/logout</logoutURL>
         <logoutRedirectTo>/index.html</logoutRedirectTo>
-        <claimsTransformer type="Class">org.apache.cxf.fediz.systests.cxf.ClaimTransformerTest</claimsTransformer>
     </contextConfig>
 </FedizConfig>
 
diff --git a/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml b/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml
index a30b0d5..ad5417b 100644
--- a/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml
+++ b/systests/webapps/cxfWebapp/src/main/resources/fediz_config.xml
@@ -53,7 +53,6 @@
         </protocol>
         <logoutURL>/secure/logout</logoutURL>
         <logoutRedirectTo>/index.html</logoutRedirectTo>
-        <claimsTransformer type="Class">org.apache.cxf.fediz.systests.cxf.ClaimTransformerTest</claimsTransformer>
     </contextConfig>
 </FedizConfig>