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/24 21:57:11 UTC
[cxf-fediz] branch master updated: Also test for required claims
for SAML SSO
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
The following commit(s) were added to refs/heads/master by this push:
new d70ec98 Also test for required claims for SAML SSO
d70ec98 is described below
commit d70ec98dfe3c750628dc830b4482f75350a394b8
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Mon Sep 24 17:56:52 2018 -0400
Also test for required claims for SAML SSO
---
.../core/processor/AbstractFedizProcessor.java | 24 +++-
.../core/processor/FederationProcessorImpl.java | 25 +---
.../fediz/core/processor/SAMLProcessorImpl.java | 4 +
.../fediz/core/AbstractSAMLCallbackHandler.java | 26 +++++
.../cxf/fediz/core/samlsso/SAMLResponseTest.java | 128 +++++++++++++++++++--
.../src/test/resources/fediz_test_config_saml.xml | 29 +++++
6 files changed, 199 insertions(+), 37 deletions(-)
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 f6b3c9e..71a04d3 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
@@ -123,7 +123,7 @@ public abstract class AbstractFedizProcessor implements FedizProcessor {
for (Claim c : claims) {
if (roleURI.equals(c.getClaimType())) {
Object oValue = c.getValue();
- if ((oValue instanceof String) && !"".equals((String) oValue)) {
+ if ((oValue instanceof String) && !"".equals(oValue)) {
roles = Collections.singletonList((String) oValue);
} else if ((oValue instanceof List<?>) && !((List<?>) oValue).isEmpty()) {
@SuppressWarnings("unchecked")
@@ -158,4 +158,26 @@ public abstract class AbstractFedizProcessor implements FedizProcessor {
return reply;
}
+ protected void testForMandatoryClaims(String roleURI,
+ List<org.apache.cxf.fediz.core.config.Claim> requestedClaims,
+ List<org.apache.cxf.fediz.core.Claim> receivedClaims
+ ) throws ProcessingException {
+ if (requestedClaims != null) {
+ for (org.apache.cxf.fediz.core.config.Claim requestedClaim : requestedClaims) {
+ if (!requestedClaim.isOptional()) {
+ boolean found = false;
+ for (org.apache.cxf.fediz.core.Claim receivedClaim : receivedClaims) {
+ if (requestedClaim.getType().equals(receivedClaim.getClaimType().toString())) {
+ found = true;
+ break;
+ }
+ }
+ 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/FederationProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
index 2d1c2bc..f62ca7e 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
@@ -221,7 +221,7 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
List<Claim> claims = validatorResponse.getClaims();
testForMandatoryClaims(config.getProtocol().getRoleURI(),
- ((FederationProtocol)config.getProtocol()).getClaimTypesRequested(),
+ config.getProtocol().getClaimTypesRequested(),
claims);
List<ClaimsProcessor> processors = config.getClaimsProcessor();
@@ -734,29 +734,6 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
return wReq;
}
- private void testForMandatoryClaims(String roleURI,
- List<org.apache.cxf.fediz.core.config.Claim> requestedClaims,
- List<org.apache.cxf.fediz.core.Claim> receivedClaims
- ) throws ProcessingException {
- if (requestedClaims != null) {
- for (org.apache.cxf.fediz.core.config.Claim requestedClaim : requestedClaims) {
- if (!requestedClaim.isOptional()) {
- boolean found = false;
- for (org.apache.cxf.fediz.core.Claim receivedClaim : receivedClaims) {
- if (requestedClaim.getType().equals(receivedClaim.getClaimType().toString())) {
- found = true;
- break;
- }
- }
- if (!found) {
- LOG.warn("Mandatory claim {} not found in token", requestedClaim.getType());
- throw new ProcessingException("Mandatory claim not found in token", TYPE.INVALID_REQUEST);
- }
- }
- }
- }
- }
-
private static class DecryptionCallbackHandler implements CallbackHandler {
private final String password;
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 b44a961..9bc26f0 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
@@ -224,6 +224,10 @@ public class SAMLProcessorImpl extends AbstractFedizProcessor {
List<Claim> claims = validatorResponse.getClaims();
+ testForMandatoryClaims(config.getProtocol().getRoleURI(),
+ config.getProtocol().getClaimTypesRequested(),
+ claims);
+
if (config.getClaimsProcessor() != null) {
List<ClaimsProcessor> processors = config.getClaimsProcessor();
if (processors != null) {
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
index fe90905..ef750a8 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
@@ -93,6 +93,7 @@ public abstract class AbstractSAMLCallbackHandler implements CallbackHandler {
protected String customClaimName = CLAIM_TYPE_LANGUAGE.toString();
protected String attributeNameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified";
protected boolean useNameFormatAsNamespace;
+ private boolean addGivenName;
public void setSubjectConfirmationData(SubjectConfirmationDataBean subjectConfirmationData) {
this.subjectConfirmationData = subjectConfirmationData;
@@ -363,6 +364,23 @@ public abstract class AbstractSAMLCallbackHandler implements CallbackHandler {
}
attributeList.add(attributeBean2);
+ if (addGivenName) {
+ AttributeBean attributeBean3 = new AttributeBean();
+ if (subjectBean != null) {
+ //SAML 1.1
+ attributeBean3.setSimpleName(getNameOfClaimType(ClaimTypes.FIRSTNAME.toString()));
+ //QualifiedName maps to AttributeNamespace in SAML1ComponentBuilder.createSamlv1Attribute()
+ attributeBean3.setQualifiedName(getNamespaceOfClaimType((ClaimTypes.FIRSTNAME.toString())));
+
+ } else {
+ //SAML 2.0
+ attributeBean3.setQualifiedName((ClaimTypes.FIRSTNAME.toString()));
+ attributeBean3.setNameFormat(this.getAttributeNameFormat());
+ }
+ attributeBean3.addAttributeValue("alice");
+ attributeList.add(attributeBean3);
+ }
+
attrStateBean.setSamlAttributes(attributeList);
callback.setAttributeStatementData(Collections.singletonList(attrStateBean));
@@ -434,4 +452,12 @@ public abstract class AbstractSAMLCallbackHandler implements CallbackHandler {
public void setAlsoAddAuthnStatement(boolean alsoAddAuthnStatement) {
this.alsoAddAuthnStatement = alsoAddAuthnStatement;
}
+
+ public boolean isAddGivenName() {
+ return addGivenName;
+ }
+
+ public void setAddGivenName(boolean addGivenName) {
+ this.addGivenName = addGivenName;
+ }
}
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLResponseTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLResponseTest.java
index 5334faa..3817169 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLResponseTest.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLResponseTest.java
@@ -22,6 +22,7 @@ package org.apache.cxf.fediz.core.samlsso;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
+import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -48,7 +49,6 @@ import org.apache.cxf.fediz.core.AbstractSAMLCallbackHandler;
import org.apache.cxf.fediz.core.AbstractSAMLCallbackHandler.MultiValue;
import org.apache.cxf.fediz.core.Claim;
import org.apache.cxf.fediz.core.ClaimTypes;
-import org.apache.cxf.fediz.core.FedizConstants;
import org.apache.cxf.fediz.core.KeystoreCallbackHandler;
import org.apache.cxf.fediz.core.RequestState;
import org.apache.cxf.fediz.core.SAML1CallbackHandler;
@@ -200,7 +200,8 @@ public class SAMLResponseTest {
Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
.size());
Assert.assertEquals("Audience wrong", TEST_REQUEST_URL, wfRes.getAudience());
- assertClaims(wfRes.getClaims(), FedizConstants.DEFAULT_ROLE_URI.toString());
+ assertClaims(wfRes.getClaims(), ClaimTypes.COUNTRY);
+ assertClaims(wfRes.getClaims(), AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE);
}
/**
@@ -443,7 +444,8 @@ public class SAMLResponseTest {
Assert.assertEquals("Issuer wrong", TEST_IDP_ISSUER, wfRes.getIssuer());
Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles().size());
Assert.assertEquals("Audience wrong", TEST_REQUEST_URL, wfRes.getAudience());
- assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+ assertClaims(wfRes.getClaims(), ClaimTypes.COUNTRY);
+ assertClaims(wfRes.getClaims(), AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE);
}
/**
@@ -552,7 +554,8 @@ public class SAMLResponseTest {
Assert.assertEquals("Issuer wrong", TEST_IDP_ISSUER, wfRes.getIssuer());
Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles().size());
Assert.assertEquals("Audience wrong", TEST_REQUEST_URL, wfRes.getAudience());
- assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+ assertClaims(wfRes.getClaims(), ClaimTypes.COUNTRY);
+ assertClaims(wfRes.getClaims(), AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE);
}
/**
@@ -605,10 +608,10 @@ public class SAMLResponseTest {
Assert.assertEquals("Principal name wrong", TEST_USER,
wfRes.getUsername());
Assert.assertEquals("Issuer wrong", TEST_IDP_ISSUER, wfRes.getIssuer());
- System.out.println("ROLE: " + wfRes.getRoles().get(0));
Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles().size());
Assert.assertEquals("Audience wrong", TEST_REQUEST_URL, wfRes.getAudience());
- assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+ assertClaims(wfRes.getClaims(), ClaimTypes.COUNTRY);
+ assertClaims(wfRes.getClaims(), AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE);
}
/**
@@ -1400,6 +1403,106 @@ public class SAMLResponseTest {
// expected
}
}
+
+ @org.junit.Test
+ public void validateSAMLResponseWithRequiredClaims() throws Exception {
+ // Mock up a Request
+ FedizContext config = getFederationConfigurator().getFedizContext("REQUIRED_CLAIMS");
+
+ String requestId = URLEncoder.encode(UUID.randomUUID().toString(), "UTF-8");
+
+ String relayState = URLEncoder.encode(UUID.randomUUID().toString(), "UTF-8");
+ RequestState requestState = new RequestState(TEST_REQUEST_URL,
+ TEST_IDP_ISSUER,
+ requestId,
+ TEST_REQUEST_URL,
+ (String)config.getProtocol().getIssuer(),
+ null,
+ relayState,
+ System.currentTimeMillis());
+
+ // Create SAML Response
+ SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+ callbackHandler.setAlsoAddAuthnStatement(true);
+ callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+ callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+ callbackHandler.setIssuer(TEST_IDP_ISSUER);
+ callbackHandler.setSubjectName(TEST_USER);
+ callbackHandler.setAddGivenName(true);
+
+ String responseStr = createSamlResponseStr(callbackHandler, requestId);
+
+ HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
+ EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(TEST_REQUEST_URL));
+ EasyMock.expect(req.getRemoteAddr()).andReturn(TEST_CLIENT_ADDRESS);
+ EasyMock.replay(req);
+
+ FedizRequest wfReq = new FedizRequest();
+ wfReq.setResponseToken(responseStr);
+ wfReq.setState(relayState);
+ wfReq.setRequest(req);
+ wfReq.setRequestState(requestState);
+
+ FedizProcessor wfProc = new SAMLProcessorImpl();
+ FedizResponse wfRes = wfProc.processRequest(wfReq, config);
+
+ Assert.assertEquals("Principal name wrong", TEST_USER,
+ wfRes.getUsername());
+ Assert.assertEquals("Issuer wrong", TEST_IDP_ISSUER, wfRes.getIssuer());
+ Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+ .size());
+ Assert.assertEquals("Audience wrong", TEST_REQUEST_URL, wfRes.getAudience());
+ assertClaims(wfRes.getClaims(), ClaimTypes.COUNTRY);
+ assertClaims(wfRes.getClaims(), AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE);
+ assertClaims(wfRes.getClaims(), ClaimTypes.FIRSTNAME);
+ }
+
+ @org.junit.Test
+ public void validateSAMLResponseWithoutRequiredClaims() throws Exception {
+ // Mock up a Request
+ FedizContext config = getFederationConfigurator().getFedizContext("REQUIRED_CLAIMS");
+
+ String requestId = URLEncoder.encode(UUID.randomUUID().toString(), "UTF-8");
+
+ String relayState = URLEncoder.encode(UUID.randomUUID().toString(), "UTF-8");
+ RequestState requestState = new RequestState(TEST_REQUEST_URL,
+ TEST_IDP_ISSUER,
+ requestId,
+ TEST_REQUEST_URL,
+ (String)config.getProtocol().getIssuer(),
+ null,
+ relayState,
+ System.currentTimeMillis());
+
+ // Create SAML Response
+ SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+ callbackHandler.setAlsoAddAuthnStatement(true);
+ callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+ callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+ callbackHandler.setIssuer(TEST_IDP_ISSUER);
+ callbackHandler.setSubjectName(TEST_USER);
+
+ String responseStr = createSamlResponseStr(callbackHandler, requestId);
+
+ HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
+ EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(TEST_REQUEST_URL));
+ EasyMock.expect(req.getRemoteAddr()).andReturn(TEST_CLIENT_ADDRESS);
+ EasyMock.replay(req);
+
+ FedizRequest wfReq = new FedizRequest();
+ wfReq.setResponseToken(responseStr);
+ wfReq.setState(relayState);
+ wfReq.setRequest(req);
+ wfReq.setRequestState(requestState);
+
+ FedizProcessor wfProc = new SAMLProcessorImpl();
+ try {
+ wfProc.processRequest(wfReq, config);
+ fail("Failure expected on a required claim that isn't present");
+ } catch (ProcessingException ex) {
+ // expected
+ }
+ }
private String createSamlResponseStr(String requestId) throws Exception {
// Create SAML Assertion
@@ -1550,14 +1653,15 @@ public class SAMLResponseTest {
signableObject.releaseChildrenDOM(true);
}
- private void assertClaims(List<Claim> claims, String roleClaimType) {
+ private void assertClaims(List<Claim> claims, URI claimType) {
+ boolean found = false;
for (Claim c : claims) {
- Assert.assertTrue("Invalid ClaimType URI: " + c.getClaimType(),
- c.getClaimType().toString().equals(roleClaimType)
- || c.getClaimType().equals(ClaimTypes.COUNTRY)
- || c.getClaimType().equals(AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE)
- );
+ if (c.getClaimType().equals(claimType)) {
+ found = true;
+ break;
+ }
}
+ Assert.assertTrue(found);
}
private String encodeResponse(Element response) throws IOException {
diff --git a/plugins/core/src/test/resources/fediz_test_config_saml.xml b/plugins/core/src/test/resources/fediz_test_config_saml.xml
index 16eaa80..5d6ca03 100644
--- a/plugins/core/src/test/resources/fediz_test_config_saml.xml
+++ b/plugins/core/src/test/resources/fediz_test_config_saml.xml
@@ -274,4 +274,33 @@
<logoutRedirectTo>/redir.html</logoutRedirectTo>
</contextConfig>
+ <contextConfig name="REQUIRED_CLAIMS">
+ <audienceUris>
+ <audienceItem>http://host_one:port/url</audienceItem>
+ </audienceUris>
+ <certificateStores>
+ <trustManager>
+ <keyStore file="ststrust.jks" password="storepass"
+ type="JKS" />
+ </trustManager>
+ </certificateStores>
+ <trustedIssuers>
+ <issuer certificateValidation="PeerTrust" />
+ </trustedIssuers>
+
+ <maximumClockSkew>1000</maximumClockSkew>
+ <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="samlProtocolType" version="1.2">
+ <issuer>http://url_to_the_issuer</issuer>
+ <roleDelimiter>;</roleDelimiter>
+ <roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI>
+ <claimTypesRequested>
+ <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="false" />
+ </claimTypesRequested>
+ </protocol>
+
+ <logoutURL>secure/logout</logoutURL>
+ <logoutRedirectTo>/redir.html</logoutRedirectTo>
+ </contextConfig>
+
</FedizConfig>