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>