Author: owulff
Date: Thu Aug 23 16:45:06 2012
New Revision: 1376585

URL: http://svn.apache.org/viewvc?rev=1376585&view=rev
Log:
[FEDIZ-22] Improved support for other claims encoding in SAML attributes

Added:
    
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAMLTokenValidatorOldTest.java
Modified:
    
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java
    
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
    
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
    
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java
    cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config.xml

Modified: 
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java
URL: 
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java?rev=1376585&r1=1376584&r2=1376585&view=diff
==============================================================================
--- 
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java 
(original)
+++ 
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/Claim.java 
Thu Aug 23 16:45:06 2012
@@ -41,6 +41,7 @@ public class Claim implements Serializab
     private Object value;
     private URI namespace = ClaimTypes.URI_BASE;
 
+    // To deprecate as ClaimType is fully qualified
     public URI getNamespace() {
         return namespace;
     }

Modified: 
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
URL: 
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java?rev=1376585&r1=1376584&r2=1376585&view=diff
==============================================================================
--- 
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
 (original)
+++ 
cxf/fediz/trunk/plugins/core/src/main/java/org/apache/cxf/fediz/core/saml/SAMLTokenValidator.java
 Thu Aug 23 16:45:06 2012
@@ -32,6 +32,7 @@ import org.w3c.dom.Element;
 
 import org.apache.cxf.fediz.core.Claim;
 import org.apache.cxf.fediz.core.ClaimCollection;
+import org.apache.cxf.fediz.core.ClaimTypes;
 import org.apache.cxf.fediz.core.TokenValidator;
 import org.apache.cxf.fediz.core.TokenValidatorResponse;
 import org.apache.cxf.fediz.core.config.CertificateValidationMethod;
@@ -182,9 +183,7 @@ public class SAMLTokenValidator implemen
                 URI roleURI = URI.create(fp.getRoleURI());
                 String delim = fp.getRoleDelimiter();
                 for (Claim c : claims) {
-                    URI claimURI = URI.create(c.getNamespace() + "/"
-                            + c.getClaimType());
-                    if (roleURI.equals(claimURI)) {
+                    if (roleURI.equals(c.getClaimType())) {
                         Object oValue = c.getValue();
                         if (oValue instanceof String) {
                             if (delim == null) {
@@ -247,7 +246,32 @@ public class SAMLTokenValidator implemen
                 }
                 Claim c = new Claim();
                 c.setIssuer(assertion.getIssuer());
-                c.setClaimType(URI.create(attribute.getAttributeName()));
+                if (attribute.getAttributeNamespace() != null) {
+                    URI attrName = URI.create(attribute.getAttributeName());
+                    if (attrName.isAbsolute()) {
+                        // Workaround for CXF-4484
+                        c.setClaimType(attrName);
+                        if 
(attribute.getAttributeName().startsWith(attribute.getAttributeNamespace())) {
+                            LOG.info("AttributeName fully qualified '" + 
attribute.getAttributeName()
+                                     + "' but does match with 
AttributeNamespace '"
+                                     + attribute.getAttributeNamespace() + 
"'");
+                        } else {
+                            LOG.warn("AttributeName fully qualified '" + 
attribute.getAttributeName()
+                                     + "' but does NOT match with 
AttributeNamespace (ignored) '"
+                                     + attribute.getAttributeNamespace() + 
"'");
+                        }
+                    } else {
+                        if (attribute.getAttributeNamespace().endsWith("/")) {
+                            
c.setClaimType(URI.create(attribute.getAttributeNamespace()
+                                                      + 
attribute.getAttributeName()));
+                        } else {
+                            
c.setClaimType(URI.create(attribute.getAttributeNamespace()
+                                                      + "/" + 
attribute.getAttributeName()));
+                        }
+                    }
+                } else {
+                    c.setClaimType(URI.create(attribute.getAttributeName()));
+                }
                 List<String> valueList = new ArrayList<String>();
                 for (XMLObject attributeValue : 
attribute.getAttributeValues()) {
                     Element attributeValueElement = attributeValue.getDOM();
@@ -291,8 +315,14 @@ public class SAMLTokenValidator implemen
                     LOG.debug("parsing attribute: " + attribute.getName());
                 }
                 Claim c = new Claim();
-                if 
(attribute.getName().startsWith(c.getNamespace().toString())) {
-                    
c.setClaimType(URI.create(attribute.getName().substring(c.getNamespace().toString().length()
 + 1)));
+                // Workaround for CXF-4484 
+                // Value of Attribute Name not fully qualified
+                // if NameFormat is 
http://schemas.xmlsoap.org/ws/2005/05/identity/claims
+                // but ClaimType value must be fully qualified as Namespace 
attribute goes away
+                URI attrName = URI.create(attribute.getName());
+                if 
(attribute.getNameFormat().equals(ClaimTypes.URI_BASE.toString()) 
+                    && !attrName.isAbsolute()) {
+                    c.setClaimType(URI.create(ClaimTypes.URI_BASE + "/" + 
attribute.getName()));
                 } else {
                     c.setClaimType(URI.create(attribute.getName()));
                 }

Modified: 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
URL: 
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java?rev=1376585&r1=1376584&r2=1376585&view=diff
==============================================================================
--- 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
 (original)
+++ 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
 Thu Aug 23 16:45:06 2012
@@ -20,6 +20,7 @@
 package org.apache.cxf.fediz.core;
 
 
+import java.net.URI;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -65,6 +66,9 @@ public abstract class AbstractSAMLCallba
         MULTI_VALUE, MULTI_ATTR, ENC_VALUE
     };
     
+    public static final URI CLAIM_TYPE_LANGUAGE = 
+        URI.create("http://schemas.mycompany.com/claims/language";);
+    
     protected String subjectName;
     protected String subjectQualifier;
     protected String confirmationMethod;
@@ -84,6 +88,11 @@ public abstract class AbstractSAMLCallba
     protected Map<String, String> claims;
     protected MultiValue multiValueType = MultiValue.MULTI_VALUE;
     protected String roleSeperator = ",";
+    protected String roleAttributeName = 
FederationConstants.DEFAULT_ROLE_URI.toString();
+    protected String countryClaimName = ClaimTypes.COUNTRY.toString();
+    protected String customClaimName = CLAIM_TYPE_LANGUAGE.toString();
+    protected String attributeNameFormat = 
"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified";
+    protected boolean useNameFormatAsNamespace;
     
     public void setSubjectConfirmationData(SubjectConfirmationDataBean 
subjectConfirmationData) {
         this.subjectConfirmationData = subjectConfirmationData;
@@ -150,9 +159,50 @@ public abstract class AbstractSAMLCallba
         this.multiValueType = multiValueType;
     }
     
+    public void setRoleAttributeName(String roleAttributeName) {
+        this.roleAttributeName = roleAttributeName;
+    }
+    
+    public String getRoleAttributeName() {
+        return this.roleAttributeName;
+    }
+    
+    public void setCountryClaimName(String countryClaimName) {
+        this.countryClaimName = countryClaimName;
+    }
+    
+    public String getCountryClaimName() {
+        return this.countryClaimName;
+    }
+
+    public void setCustomClaimName(String customClaimName) {
+        this.customClaimName = customClaimName;
+    }
+    
+    public String getCustomClaimName() {
+        return this.customClaimName;
+    }
+
+    public void setAttributeNameFormat(String attributeNameFormat) {
+        this.attributeNameFormat = attributeNameFormat;
+    }
+    
+    public String getAttributeNameFormat() {
+        return this.attributeNameFormat;
+    }
+    
+    public boolean isUseNameFormatAsNamespace() {
+        return useNameFormatAsNamespace;
+    }
+
+    public void setUseNameFormatAsNamespace(boolean useNameFormatAsNamespace) {
+        this.useNameFormatAsNamespace = useNameFormatAsNamespace;
+    }
+
     /**
      * Note that the SubjectBean parameter should be null for SAML2.0
      */
+    //CHECKSTYLE:OFF
     protected void createAndSetStatement(SubjectBean subjectBean, SAMLCallback 
callback) {
         if (statement == Statement.AUTHN) {
             AuthenticationStatementBean authBean = new 
AuthenticationStatementBean();
@@ -169,11 +219,13 @@ public abstract class AbstractSAMLCallba
             
callback.setAuthenticationStatementData(Collections.singletonList(authBean));
         } else if (statement == Statement.ATTR) {
             AttributeStatementBean attrStateBean = new 
AttributeStatementBean();
+            if (subjectBean != null) {
+                attrStateBean.setSubject(subjectBean);
+            }
             
             if (this.roles == null) {
                 AttributeBean attributeBean = new AttributeBean();
                 if (subjectBean != null) {
-                    attrStateBean.setSubject(subjectBean);
                     attributeBean.setSimpleName("name");
                     attributeBean.setQualifiedName("dummy-ns");
                 } else {
@@ -185,6 +237,8 @@ public abstract class AbstractSAMLCallba
                 return;
             }
             
+            List<AttributeBean> attributeList = new ArrayList<AttributeBean>();
+                        
             if (this.multiValueType.equals(MultiValue.MULTI_VALUE)
                 || this.multiValueType.equals(MultiValue.ENC_VALUE)) {
 //              <saml:Attribute 
xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
@@ -199,11 +253,21 @@ public abstract class AbstractSAMLCallba
 //            </saml:Attribute>
                 AttributeBean attributeBean = new AttributeBean();
                 if (subjectBean != null) {
-                    attrStateBean.setSubject(subjectBean);
-                    attributeBean.setSimpleName("role");
-                    
attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                    // SAML 1.1
+                    if (this.isUseNameFormatAsNamespace()) {
+                        //Workaround for CXF-4484
+                        attributeBean.setSimpleName(this.roleAttributeName);
+                        //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                        
attributeBean.setQualifiedName(ClaimTypes.URI_BASE.toString());
+                    } else {
+                        
attributeBean.setSimpleName(getNameOfClaimType(this.roleAttributeName));
+                        //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                        
attributeBean.setQualifiedName(getNamespaceOfClaimType(this.roleAttributeName));
+                    }
                 } else {
-                    
attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                    // SAML 2.0
+                    attributeBean.setQualifiedName(this.roleAttributeName);
+                    attributeBean.setNameFormat(this.getAttributeNameFormat());
                 }
                 if (this.multiValueType.equals(MultiValue.MULTI_VALUE)) {
                     attributeBean.setAttributeValues(roles);
@@ -215,7 +279,7 @@ public abstract class AbstractSAMLCallba
                     String value = sb.substring(0, sb.length() - 
this.roleSeperator.length());
                     
attributeBean.setAttributeValues(Collections.singletonList(value));
                 }
-                
attrStateBean.setSamlAttributes(Collections.singletonList(attributeBean));
+                attributeList.add(attributeBean);
             } else if (this.multiValueType.equals(MultiValue.MULTI_ATTR)) {
 //              <saml:Attribute 
xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
 //                AttributeNamespace="http://schemas.xmlsoap.org/claims"; 
AttributeName="roles">
@@ -226,21 +290,70 @@ public abstract class AbstractSAMLCallba
 //                <saml:AttributeValue>Value2</saml:AttributeValue>
 //              </saml:Attribute>
                 
-                List<AttributeBean> attrBeans = new ArrayList<AttributeBean>();
+                //List<AttributeBean> attrBeans = new 
ArrayList<AttributeBean>();
                 for (String role: roles) {
                     AttributeBean attributeBean = new AttributeBean();
                     if (subjectBean != null) {
-                        attrStateBean.setSubject(subjectBean);
-                        attributeBean.setSimpleName("role");
-                        
attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                        // SAML 1.1
+                        if (this.isUseNameFormatAsNamespace()) {
+                            //Workaround for CXF-4484
+                            
attributeBean.setSimpleName(this.roleAttributeName);
+                            //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                            
attributeBean.setQualifiedName(ClaimTypes.URI_BASE.toString());
+                        } else {
+                            
attributeBean.setSimpleName(getNameOfClaimType(this.roleAttributeName));
+                            //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                            
attributeBean.setQualifiedName(getNamespaceOfClaimType(this.roleAttributeName));
+                        }
                     } else {
-                        
attributeBean.setQualifiedName(FederationConstants.DEFAULT_ROLE_URI.toString());
+                        // SAML 2.0
+                        attributeBean.setQualifiedName(this.roleAttributeName);
+                        
attributeBean.setNameFormat(this.getAttributeNameFormat());
                     }
                     
attributeBean.setAttributeValues(Collections.singletonList(role));
-                    attrBeans.add(attributeBean);
+                    attributeList.add(attributeBean);
+                }
+            }
+            
+            //ClaimTypes.COUNTRY
+            AttributeBean attributeBean = new AttributeBean();
+            if (subjectBean != null) {
+                //SAML 1.1
+                
attributeBean.setSimpleName(getNameOfClaimType(this.countryClaimName));
+                //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                
attributeBean.setQualifiedName(getNamespaceOfClaimType(this.countryClaimName));
+                
+            } else {
+                //SAML 2.0
+                attributeBean.setQualifiedName(this.countryClaimName);
+                attributeBean.setNameFormat(this.getAttributeNameFormat());
+            }
+            attributeBean.setAttributeValues(Collections.singletonList("CH"));
+            attributeList.add(attributeBean);
+            
+            //custom claim language
+            AttributeBean attributeBean2 = new AttributeBean();
+            if (subjectBean != null) {
+                // SAML 1.1
+                if (this.isUseNameFormatAsNamespace()) {
+                    //Workaround for CXF-4484
+                    attributeBean2.setSimpleName(this.customClaimName);
+                    //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                    
attributeBean2.setQualifiedName(ClaimTypes.URI_BASE.toString());
+                } else {
+                    
attributeBean2.setSimpleName(getNameOfClaimType(this.customClaimName));
+                    //QualifiedName maps to AttributeNamespace in 
SAML1ComponentBuilder.createSamlv1Attribute()
+                    
attributeBean2.setQualifiedName(getNamespaceOfClaimType(this.customClaimName));
                 }
-                attrStateBean.setSamlAttributes(attrBeans);
+            } else {
+                // SAML 2
+                attributeBean2.setQualifiedName(this.customClaimName);
+                attributeBean2.setNameFormat(this.getAttributeNameFormat());
             }
+            attributeBean2.setAttributeValues(Collections.singletonList("CH"));
+            attributeList.add(attributeBean2);
+            
+            attrStateBean.setSamlAttributes(attributeList);
             
callback.setAttributeStatementData(Collections.singletonList(attrStateBean));
                        
         } else {
@@ -293,4 +406,14 @@ public abstract class AbstractSAMLCallba
         }
         return keyInfo;
     }
+    
+    protected String getNamespaceOfClaimType(String claimType) {
+        int i = claimType.lastIndexOf("/");
+        return claimType.substring(0, i);
+    }
+    
+    protected String getNameOfClaimType(String claimType) {
+        int i = claimType.lastIndexOf("/");
+        return claimType.substring(i + 1);
+    }
 }

Modified: 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java
URL: 
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java?rev=1376585&r1=1376584&r2=1376585&view=diff
==============================================================================
--- 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java
 (original)
+++ 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/FederationProcessorTest.java
 Thu Aug 23 16:45:06 2012
@@ -225,6 +225,8 @@ public class FederationProcessorTest {
         Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
                             .size());
         Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+        
     }
     
     /**
@@ -304,6 +306,82 @@ public class FederationProcessorTest {
     }
     
     /**
+     * Validate SAML 2 token where role information is provided
+     * within another SAML attribute
+     */
+    @org.junit.Test
+    public void validateSAML2TokenDifferentRoleURI() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        
callbackHandler.setRoleAttributeName("http://schemas.mycompany.com/claims/role";);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey", true);
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = 
getFederationConfigurator().getFederationContext("CUSTOMROLEURI");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER, 
wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, 
wfRes.getRoles().size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+    }
+    
+    /**
+     * Validate SAML 2 token where role information is provided
+     * within another SAML attribute
+     */
+    @org.junit.Test
+    public void validateSAML1TokenDifferentRoleURI() throws Exception {
+        SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+        callbackHandler.setStatement(SAML1CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        
callbackHandler.setRoleAttributeName("http://schemas.mycompany.com/claims/role";);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey", true);
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = 
getFederationConfigurator().getFederationContext("CUSTOMROLEURI");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER, 
wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, 
wfRes.getRoles().size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+    }
+    
+    /**
      * Validate SAML 2 token which includes role attribute
      * but RoleURI is not configured
      */
@@ -361,6 +439,7 @@ public class FederationProcessorTest {
         samlParms.setSAMLVersion(SAMLVersion.VERSION_11);
         AssertionWrapper assertion = new AssertionWrapper(samlParms);
         String rstr = createSamlToken(assertion, "mystskey", true);
+        
         FederationRequest wfReq = new FederationRequest();
         wfReq.setWa(FederationConstants.ACTION_SIGNIN);
         wfReq.setWresult(rstr);
@@ -377,6 +456,7 @@ public class FederationProcessorTest {
         Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
                             .size());
         Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
     }
     
     /**
@@ -454,6 +534,7 @@ public class FederationProcessorTest {
         Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
         Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
                             .size());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
     }
 
     /**
@@ -494,6 +575,7 @@ public class FederationProcessorTest {
         Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
         Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
                             .size());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
     }
     
     /**
@@ -956,6 +1038,15 @@ public class FederationProcessorTest {
         return null;
     }
 
+    private void assertClaims(List<Claim> claims, String roleClaimType) {
+        for (Claim c : claims) {
+            Assert.assertTrue("Invalid ClaimType URI: " + c.getClaimType(), 
+                              c.getClaimType().equals(roleClaimType)
+                              || c.getClaimType().equals(ClaimTypes.COUNTRY)
+                              || 
c.getClaimType().equals(AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE)
+                              );
+        }
+    }
     
 
 }

Added: 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAMLTokenValidatorOldTest.java
URL: 
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAMLTokenValidatorOldTest.java?rev=1376585&view=auto
==============================================================================
--- 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAMLTokenValidatorOldTest.java
 (added)
+++ 
cxf/fediz/trunk/plugins/core/src/test/java/org/apache/cxf/fediz/core/SAMLTokenValidatorOldTest.java
 Thu Aug 23 16:45:06 2012
@@ -0,0 +1,377 @@
+/**
+ * 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;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import junit.framework.Assert;
+
+import org.apache.cxf.fediz.common.STSUtil;
+import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.config.FederationConfigurator;
+import org.apache.cxf.fediz.core.config.FederationContext;
+import org.apache.ws.security.WSPasswordCallback;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.components.crypto.CryptoFactory;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+import org.apache.ws.security.saml.ext.SAMLParms;
+import org.apache.ws.security.saml.ext.bean.ConditionsBean;
+import org.apache.ws.security.saml.ext.builder.SAML1Constants;
+import org.apache.ws.security.saml.ext.builder.SAML2Constants;
+import org.apache.ws.security.util.DOM2Writer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.opensaml.common.SAMLVersion;
+
+
+// This testcases tests the encoding implemented before CXF-4484
+public class SAMLTokenValidatorOldTest {
+    static final String TEST_USER = "alice";
+    static final String TEST_RSTR_ISSUER = "FedizSTSIssuer";
+    static final String TEST_AUDIENCE = "https://localhost/fedizhelloworld";;
+    
+    private static final String CONFIG_FILE = "fediz_test_config.xml";
+    
+    private static Crypto crypto;
+    private static CallbackHandler cbPasswordHandler;
+    private static FederationConfigurator configurator;
+    
+    
+    @BeforeClass
+    public static void init() {
+        try {
+            crypto = CryptoFactory.getInstance("signature.properties");
+            cbPasswordHandler = new KeystoreCallbackHandler();
+            getFederationConfigurator();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Assert.assertNotNull(configurator);
+
+    }
+    
+    @AfterClass
+    public static void cleanup() {
+        SecurityTestUtil.cleanup();
+    }
+    
+
+    private static FederationConfigurator getFederationConfigurator() {
+        if (configurator != null) {
+            return configurator;
+        }
+        try {
+            configurator = new FederationConfigurator();
+            final URL resource = Thread.currentThread().getContextClassLoader()
+                    .getResource(CONFIG_FILE);
+            File f = new File(resource.toURI());
+            configurator.loadConfig(f);
+            return configurator;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+    
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * Roles are encoded as a multi-value saml attribute
+     */
+    @org.junit.Test
+    public void validateSAML2Token() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setCountryClaimName("country");
+        callbackHandler.setRoleAttributeName("role");
+        
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey", true);
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = 
getFederationConfigurator().getFederationContext("ROOT");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+        
+    }
+    
+    /**
+     * Validate SAML 2 token where role information is provided
+     * within another SAML attribute
+     */
+    @org.junit.Test
+    public void validateSAML2TokenDifferentRoleURI() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setCountryClaimName("country");
+        
callbackHandler.setRoleAttributeName("http://schemas.mycompany.com/claims/role";);
+        
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey", true);
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = 
getFederationConfigurator().getFederationContext("CUSTOMROLEURI");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER, 
wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, 
wfRes.getRoles().size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+    }
+    
+    /**
+     * Validate SAML 2 token where role information is provided
+     * within another SAML attribute
+     */
+    @org.junit.Test
+    public void validateSAML1TokenDifferentRoleURI() throws Exception {
+        SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+        callbackHandler.setStatement(SAML1CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setUseNameFormatAsNamespace(true);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        
callbackHandler.setRoleAttributeName("http://schemas.mycompany.com/claims/role";);
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey", true);
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = 
getFederationConfigurator().getFederationContext("CUSTOMROLEURI");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER, 
wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, 
wfRes.getRoles().size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+    }
+    
+    /**
+     * Validate SAML 1.1 token which includes the role attribute with 2 values
+     * Roles are encoded as a multi-value saml attribute
+     */
+    @org.junit.Test
+    public void validateSAML1Token() throws Exception {
+        SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+        callbackHandler.setStatement(SAML1CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML1Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setUseNameFormatAsNamespace(true);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setRoleAttributeName("role");
+        
+        ConditionsBean cp = new ConditionsBean();
+        cp.setAudienceURI(TEST_AUDIENCE);
+        callbackHandler.setConditions(cp);
+        
+        SAMLParms samlParms = new SAMLParms();
+        samlParms.setCallbackHandler(callbackHandler);
+        samlParms.setSAMLVersion(SAMLVersion.VERSION_11);
+        AssertionWrapper assertion = new AssertionWrapper(samlParms);
+        String rstr = createSamlToken(assertion, "mystskey", true);
+        
+        FederationRequest wfReq = new FederationRequest();
+        wfReq.setWa(FederationConstants.ACTION_SIGNIN);
+        wfReq.setWresult(rstr);
+        
+        configurator = null;
+        FederationContext config = 
getFederationConfigurator().getFederationContext("ROOT");
+        
+        FederationProcessor wfProc = new FederationProcessorImpl();
+        FederationResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, 
wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, 
wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), 
callbackHandler.getRoleAttributeName());
+    }
+    
+    
+    private String createSamlToken(AssertionWrapper assertion, String alias, 
boolean sign)
+        throws IOException, UnsupportedCallbackException, WSSecurityException, 
Exception {
+        return createSamlToken(assertion, alias, sign, 
STSUtil.SAMPLE_RSTR_COLL_MSG);
+    }
+    
+    private String createSamlToken(AssertionWrapper 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);
+    }
+    
+
+    
+    
+    /**
+     * Returns the first element that matches <code>name</code> and
+     * <code>namespace</code>. <p/> This is a replacement for a XPath lookup
+     * <code>//name</code> with the given namespace. It's somewhat faster than
+     * XPath, and we do not deal with prefixes, just with the real namespace 
URI
+     * 
+     * @param startNode Where to start the search
+     * @param name Local name of the element
+     * @param namespace Namespace URI of the element
+     * @return The found element or <code>null</code>
+     */
+    public static Element findElement(Node startNode, String name, String 
namespace) {
+        //
+        // Replace the formerly recursive implementation with a 
depth-first-loop
+        // lookup
+        //
+        if (startNode == null) {
+            return null;
+        }
+        Node startParent = startNode.getParentNode();
+        Node processedNode = null;
+
+        while (startNode != null) {
+            // start node processing at this point
+            if (startNode.getNodeType() == Node.ELEMENT_NODE
+                && startNode.getLocalName().equals(name)) {
+                String ns = startNode.getNamespaceURI();
+                if (ns != null && ns.equals(namespace)) {
+                    return (Element)startNode;
+                }
+
+                if ((namespace == null || namespace.length() == 0)
+                    && (ns == null || ns.length() == 0)) {
+                    return (Element)startNode;
+                }
+            }
+            processedNode = startNode;
+            startNode = startNode.getFirstChild();
+
+            // no child, this node is done.
+            if (startNode == null) {
+                // close node processing, get sibling
+                startNode = processedNode.getNextSibling();
+            }
+            // no more siblings, get parent, all children
+            // of parent are processed.
+            while (startNode == null) {
+                processedNode = processedNode.getParentNode();
+                if (processedNode == startParent) {
+                    return null;
+                }
+                // close parent node processing (processed node now)
+                startNode = processedNode.getNextSibling();
+            }
+        }
+        return null;
+    }
+    
+    private void assertClaims(List<Claim> claims, String roleClaimType) {
+        for (Claim c : claims) {
+            Assert.assertTrue("Invalid ClaimType URI: " + c.getClaimType(), 
+                              c.getClaimType().equals(roleClaimType)
+                              || c.getClaimType().equals(ClaimTypes.COUNTRY)
+                              || 
c.getClaimType().equals(AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE)
+                              );
+        }
+    }
+
+
+    
+
+}

Modified: cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config.xml
URL: 
http://svn.apache.org/viewvc/cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config.xml?rev=1376585&r1=1376584&r2=1376585&view=diff
==============================================================================
--- cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config.xml 
(original)
+++ cxf/fediz/trunk/plugins/core/src/test/resources/fediz_test_config.xml Thu 
Aug 23 16:45:06 2012
@@ -174,5 +174,37 @@
                                <claimType type="a particular claim type" 
optional="true" />
                        </claimTypesRequested>
                </protocol>
+       </contextConfig>
+       <contextConfig name="CUSTOMROLEURI">
+               <audienceUris>
+                       <audienceItem>http://host_one:port/url</audienceItem>
+               </audienceUris>
+               <certificateStores>
+                       <trustManager>
+                               <keyStore file="stsstore.jks" 
password="stsspass"
+                                       type="JKS" />
+                       </trustManager>         
+               </certificateStores>
+               <trustedIssuers>
+                       <issuer subject=".*CN=www.sts.com.*" 
certificateValidation="ChainTrust"
+                               name="FedizSTSIssuer" />                        
        
+               </trustedIssuers>
+
+               <maximumClockSkew>1000</maximumClockSkew>
+               <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+                       xsi:type="federationProtocolType" version="1.2">
+                       <realm>target realm</realm>
+                       <issuer>http://url_to_the_issuer</issuer>
+                       <roleDelimiter>;</roleDelimiter>
+                       
<roleURI>http://schemas.mycompany.com/claims/role</roleURI>
+                       <authenticationType value="some auth type" 
type="String" />
+                       <homeRealm 
type="Class">org.apache.fediz.realm.MyHomeRealm.class</homeRealm>
+                       <freshness>10000</freshness>
+                       <reply>reply value</reply>
+                       <request>REQUEST</request>
+                       <claimTypesRequested>
+                               <claimType type="a particular claim type" 
optional="true" />
+                       </claimTypesRequested>
+               </protocol>
        </contextConfig>        
 </FedizConfig>


Reply via email to