KEYCLOAK-11416 Fix nil AttributeValue handling
This commit is contained in:
parent
a2b3747d0e
commit
a79d6289de
14 changed files with 571 additions and 224 deletions
|
@ -569,19 +569,20 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAttributeValue(Object attrValue) {
|
private String getAttributeValue(Object attrValue) {
|
||||||
String value = null;
|
if (attrValue == null) {
|
||||||
if (attrValue instanceof String) {
|
return "";
|
||||||
value = (String) attrValue;
|
} else if (attrValue instanceof String) {
|
||||||
|
return (String) attrValue;
|
||||||
} else if (attrValue instanceof Node) {
|
} else if (attrValue instanceof Node) {
|
||||||
Node roleNode = (Node) attrValue;
|
Node roleNode = (Node) attrValue;
|
||||||
value = roleNode.getFirstChild().getNodeValue();
|
return roleNode.getFirstChild().getNodeValue();
|
||||||
} else if (attrValue instanceof NameIDType) {
|
} else if (attrValue instanceof NameIDType) {
|
||||||
NameIDType nameIdType = (NameIDType) attrValue;
|
NameIDType nameIdType = (NameIDType) attrValue;
|
||||||
value = nameIdType.getValue();
|
return nameIdType.getValue();
|
||||||
} else {
|
} else {
|
||||||
log.warn("Unable to extract unknown SAML assertion attribute value type: " + attrValue.getClass().getName());
|
log.warn("Unable to extract unknown SAML assertion attribute value type: " + attrValue.getClass().getName());
|
||||||
}
|
}
|
||||||
return value;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isRole(AttributeType attribute) {
|
protected boolean isRole(AttributeType attribute) {
|
||||||
|
|
|
@ -174,6 +174,8 @@ public class BaseWriter {
|
||||||
writeNameIDTypeAttributeValue((NameIDType) attributeValue);
|
writeNameIDTypeAttributeValue((NameIDType) attributeValue);
|
||||||
} else
|
} else
|
||||||
throw logger.writerUnsupportedAttributeValueError(attributeValue.getClass().getName());
|
throw logger.writerUnsupportedAttributeValueError(attributeValue.getClass().getName());
|
||||||
|
} else {
|
||||||
|
writeStringAttributeValue(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +193,13 @@ public class BaseWriter {
|
||||||
StaxUtil.writeNameSpace(writer, JBossSAMLURIConstants.XSI_PREFIX.get(), JBossSAMLURIConstants.XSI_NSURI.get());
|
StaxUtil.writeNameSpace(writer, JBossSAMLURIConstants.XSI_PREFIX.get(), JBossSAMLURIConstants.XSI_NSURI.get());
|
||||||
StaxUtil.writeNameSpace(writer, "xs", JBossSAMLURIConstants.XMLSCHEMA_NSURI.get());
|
StaxUtil.writeNameSpace(writer, "xs", JBossSAMLURIConstants.XMLSCHEMA_NSURI.get());
|
||||||
StaxUtil.writeAttribute(writer, "xsi", JBossSAMLURIConstants.XSI_NSURI.get(), "type", "xs:string");
|
StaxUtil.writeAttribute(writer, "xsi", JBossSAMLURIConstants.XSI_NSURI.get(), "type", "xs:string");
|
||||||
|
|
||||||
|
if (attributeValue == null) {
|
||||||
|
StaxUtil.writeAttribute(writer, "xsi", JBossSAMLURIConstants.XSI_NSURI.get(), "nil", "true");
|
||||||
|
} else {
|
||||||
StaxUtil.writeCharacters(writer, attributeValue);
|
StaxUtil.writeCharacters(writer, attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
StaxUtil.writeEndElement(writer);
|
StaxUtil.writeEndElement(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -121,7 +122,7 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
if (name != null && name.trim().equals("")) name = null;
|
if (name != null && name.trim().equals("")) name = null;
|
||||||
String friendly = mapperModel.getConfig().get(ATTRIBUTE_FRIENDLY_NAME);
|
String friendly = mapperModel.getConfig().get(ATTRIBUTE_FRIENDLY_NAME);
|
||||||
if (friendly != null && friendly.trim().equals("")) friendly = null;
|
if (friendly != null && friendly.trim().equals("")) friendly = null;
|
||||||
String desiredValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
|
String desiredValue = Optional.ofNullable(mapperModel.getConfig().get(ATTRIBUTE_VALUE)).orElse("");
|
||||||
AssertionType assertion = (AssertionType)context.getContextData().get(SAMLEndpoint.SAML_ASSERTION);
|
AssertionType assertion = (AssertionType)context.getContextData().get(SAMLEndpoint.SAML_ASSERTION);
|
||||||
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
||||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||||
|
@ -129,7 +130,9 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
if (name != null && !name.equals(attr.getName())) continue;
|
if (name != null && !name.equals(attr.getName())) continue;
|
||||||
if (friendly != null && !friendly.equals(attr.getFriendlyName())) continue;
|
if (friendly != null && !friendly.equals(attr.getFriendlyName())) continue;
|
||||||
for (Object val : attr.getAttributeValue()) {
|
for (Object val : attr.getAttributeValue()) {
|
||||||
if (val.equals(desiredValue)) return true;
|
val = Optional.ofNullable(val).orElse("");
|
||||||
|
if (val.equals(desiredValue))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ import java.security.Principal;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.transform.OutputKeys;
|
import javax.xml.transform.OutputKeys;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
|
@ -249,26 +250,42 @@ public class SendUsernameServlet {
|
||||||
return output + "</body></html>";
|
return output + "</body></html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAttributes() {
|
private static String joinList(String delimeter, List<String> list) {
|
||||||
SamlPrincipal principal = (SamlPrincipal) sentPrincipal;
|
if (list == null || list.size() <= 0) return "";
|
||||||
String output = "attribute email: " + principal.getAttribute(X500SAMLProfileConstants.EMAIL.get());
|
|
||||||
output += "<br /> topAttribute: " + principal.getAttribute("topAttribute");
|
StringBuilder sb = new StringBuilder();
|
||||||
output += "<br /> boolean-attribute: " + principal.getAttribute("boolean-attribute");
|
|
||||||
output += "<br /> level2Attribute: " + principal.getAttribute("level2Attribute");
|
for (int i = 0; i < list.size(); i++) {
|
||||||
output += "<br /> group: " + principal.getAttributes("group").toString();
|
|
||||||
output += "<br /> friendlyAttribute email: " + principal.getFriendlyAttribute("email");
|
sb.append(list.get(i));
|
||||||
output += "<br /> phone: " + principal.getAttribute("phone");
|
|
||||||
output += "<br /> friendlyAttribute phone: " + principal.getFriendlyAttribute("phone");
|
// if not the last item
|
||||||
output += "<br /> hardcoded-attribute: ";
|
if (i != list.size() - 1) {
|
||||||
for (String attr : principal.getAttributes("hardcoded-attribute")) {
|
sb.append(delimeter);
|
||||||
output += attr + ",";
|
|
||||||
}
|
|
||||||
output += "<br /> group-attribute: ";
|
|
||||||
for (String attr : principal.getAttributes("group-attribute")) {
|
|
||||||
output += attr + ",";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAttributes() {
|
||||||
|
SamlPrincipal principal = (SamlPrincipal) sentPrincipal;
|
||||||
|
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
for (Entry<String, List<String>> e : principal.getAttributes().entrySet()) {
|
||||||
|
b.append(e.getKey()).append(": ").append(joinList(",", e.getValue())).append("<br />");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String friendlyAttributeName : principal.getFriendlyNames()) {
|
||||||
|
b.append("friendly ")
|
||||||
|
.append(friendlyAttributeName)
|
||||||
|
.append(": ")
|
||||||
|
.append(joinList(",", principal.getFriendlyAttributes(friendlyAttributeName)))
|
||||||
|
.append("<br />");
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
|
|
@ -61,11 +61,12 @@ public class TestCleanup {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addCleanup(Runnable r) {
|
public TestCleanup addCleanup(Runnable r) {
|
||||||
genericCleanups.add(r);
|
genericCleanups.add(r);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCleanup(AutoCloseable c) {
|
public TestCleanup addCleanup(AutoCloseable c) {
|
||||||
genericCleanups.add(() -> {
|
genericCleanups.add(() -> {
|
||||||
try {
|
try {
|
||||||
c.close();
|
c.close();
|
||||||
|
@ -73,6 +74,7 @@ public class TestCleanup {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addUserId(String userId) {
|
public void addUserId(String userId) {
|
||||||
|
|
|
@ -6,19 +6,30 @@ import org.apache.http.client.methods.HttpUriRequest;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.keycloak.admin.client.resource.ProtocolMappersResource;
|
||||||
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||||
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
||||||
|
import org.keycloak.testsuite.auth.page.login.Login;
|
||||||
|
import org.keycloak.testsuite.page.AbstractPage;
|
||||||
|
import org.keycloak.testsuite.util.SamlClient;
|
||||||
|
import org.keycloak.testsuite.util.SamlClientBuilder;
|
||||||
import org.keycloak.testsuite.utils.io.IOUtil;
|
import org.keycloak.testsuite.utils.io.IOUtil;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
|
||||||
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||||
|
|
||||||
public abstract class AbstractSAMLServletAdapterTest extends AbstractServletsAdapterTest {
|
public abstract class AbstractSAMLServletAdapterTest extends AbstractServletsAdapterTest {
|
||||||
|
|
||||||
|
@ -59,4 +70,32 @@ public abstract class AbstractSAMLServletAdapterTest extends AbstractServletsAda
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SamlClientBuilder beginAuthenticationAndLogin(AbstractPage page, SamlClient.Binding binding) {
|
||||||
|
return new SamlClientBuilder()
|
||||||
|
.navigateTo(page.buildUri())
|
||||||
|
.processSamlResponse(binding) // Process AuthnResponse
|
||||||
|
.build()
|
||||||
|
|
||||||
|
.login().user(bburkeUser)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AutoCloseable createProtocolMapper(ProtocolMappersResource resource, String name, String protocol, String protocolMapper, Map<String, String> config) {
|
||||||
|
ProtocolMapperRepresentation representation = new ProtocolMapperRepresentation();
|
||||||
|
representation.setName(name);
|
||||||
|
representation.setProtocol(protocol);
|
||||||
|
representation.setProtocolMapper(protocolMapper);
|
||||||
|
representation.setConfig(config);
|
||||||
|
try (Response response = resource.createMapper(representation)) {
|
||||||
|
String createdId = getCreatedId(response);
|
||||||
|
return () -> resource.delete(createdId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkLoggedOut(AbstractPage page, Login loginPage) {
|
||||||
|
page.navigateTo();
|
||||||
|
waitForPageToLoad();
|
||||||
|
assertCurrentUrlStartsWith(loginPage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.keycloak.testsuite.adapter.servlet;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||||
|
import org.keycloak.testsuite.utils.annotation.UseServletFilter;
|
||||||
|
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mhajas
|
||||||
|
*/
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY_DEPRECATED)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
|
||||||
|
@UseServletFilter(filterName = "saml-filter", filterClass = "org.keycloak.adapters.saml.servlet.SamlFilter",
|
||||||
|
filterDependency = "org.keycloak:keycloak-saml-servlet-filter-adapter")
|
||||||
|
public class SAMLFilterLoginResponseHandlingTest extends SAMLLoginResponseHandlingTest {
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
@Ignore
|
||||||
|
public void testErrorHandlingUnsigned() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
@Ignore
|
||||||
|
public void testErrorHandlingSigned() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,20 +92,6 @@ public class SAMLFilterServletAdapterTest extends SAMLServletAdapterTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Override
|
|
||||||
@Ignore
|
|
||||||
public void testErrorHandlingUnsigned() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Override
|
|
||||||
@Ignore
|
|
||||||
public void testErrorHandlingSigned() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Override
|
@Override
|
||||||
@Ignore
|
@Ignore
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
package org.keycloak.testsuite.adapter.servlet;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.adapters.rotation.PublicKeyLocator;
|
||||||
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
|
import org.keycloak.admin.client.resource.ProtocolMappersResource;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.StatementAbstractType;
|
||||||
|
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
||||||
|
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
||||||
|
import org.keycloak.protocol.saml.mappers.RoleListMapper;
|
||||||
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
|
import org.keycloak.saml.SAML2ErrorResponseBuilder;
|
||||||
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
|
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
|
||||||
|
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
||||||
|
import org.keycloak.testsuite.adapter.page.Employee2Servlet;
|
||||||
|
import org.keycloak.testsuite.adapter.page.EmployeeSigServlet;
|
||||||
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||||
|
import org.keycloak.testsuite.saml.AbstractSamlTest;
|
||||||
|
import org.keycloak.testsuite.util.Matchers;
|
||||||
|
import org.keycloak.testsuite.util.SamlClient;
|
||||||
|
import org.keycloak.testsuite.util.SamlClientBuilder;
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
|
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.keycloak.testsuite.admin.ApiUtil.getCreatedId;
|
||||||
|
import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_PRIVATE_KEY;
|
||||||
|
import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_PUBLIC_KEY;
|
||||||
|
import static org.keycloak.testsuite.util.Matchers.bodyHC;
|
||||||
|
import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
|
||||||
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mhajas
|
||||||
|
*/
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY_DEPRECATED)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT7)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT8)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT9)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_JETTY92)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_JETTY93)
|
||||||
|
@AppServerContainer(ContainerConstants.APP_SERVER_JETTY94)
|
||||||
|
public class SAMLLoginResponseHandlingTest extends AbstractSAMLServletAdapterTest {
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected Employee2Servlet employee2ServletPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected EmployeeSigServlet employeeSigServletPage;
|
||||||
|
|
||||||
|
@Deployment(name = Employee2Servlet.DEPLOYMENT_NAME)
|
||||||
|
protected static WebArchive employee2() {
|
||||||
|
return samlServletDeployment(Employee2Servlet.DEPLOYMENT_NAME, WEB_XML_WITH_ACTION_FILTER, SendUsernameServlet.class, AdapterActionsFilter.class, PublicKeyLocator.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deployment(name = EmployeeSigServlet.DEPLOYMENT_NAME)
|
||||||
|
protected static WebArchive employeeSig() {
|
||||||
|
return samlServletDeployment(EmployeeSigServlet.DEPLOYMENT_NAME, SendUsernameServlet.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNilAttributeValueAttribute() {
|
||||||
|
beginAuthenticationAndLogin(employee2ServletPage, SamlClient.Binding.POST)
|
||||||
|
.processSamlResponse(SamlClient.Binding.POST) // Update response with Nil attribute
|
||||||
|
.transformObject(ob -> {
|
||||||
|
assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
||||||
|
ResponseType resp = (ResponseType) ob;
|
||||||
|
|
||||||
|
Set<StatementAbstractType> statements = resp.getAssertions().get(0).getAssertion().getStatements();
|
||||||
|
|
||||||
|
AttributeStatementType attributeType = (AttributeStatementType) statements.stream()
|
||||||
|
.filter(statement -> statement instanceof AttributeStatementType)
|
||||||
|
.findFirst().orElse(new AttributeStatementType());
|
||||||
|
|
||||||
|
AttributeType attr = new AttributeType("attribute-with-null-attribute-value");
|
||||||
|
attr.addAttributeValue(null);
|
||||||
|
|
||||||
|
attributeType.addAttribute(new AttributeStatementType.ASTChoiceType(attr));
|
||||||
|
resp.getAssertions().get(0).getAssertion().addStatement(attributeType);
|
||||||
|
|
||||||
|
return ob;
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
.navigateTo(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build())
|
||||||
|
.execute(response -> {
|
||||||
|
Assert.assertThat(response, statusCodeIsHC(Response.Status.OK));
|
||||||
|
Assert.assertThat(response, bodyHC(containsString("attribute-with-null-attribute-value: <br />")));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testErrorHandlingUnsigned() throws Exception {
|
||||||
|
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
|
||||||
|
.destination(employeeSigServletPage.toString() + "/saml")
|
||||||
|
.issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
|
||||||
|
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
|
||||||
|
Document document = builder.buildDocument();
|
||||||
|
|
||||||
|
new SamlClientBuilder()
|
||||||
|
.addStep((client, currentURI, currentResponse, context) ->
|
||||||
|
SamlClient.Binding.REDIRECT.createSamlUnsignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document))
|
||||||
|
.execute(closeableHttpResponse -> Assert.assertThat(closeableHttpResponse, bodyHC(containsString("INVALID_SIGNATURE"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testErrorHandlingSigned() throws Exception {
|
||||||
|
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
|
||||||
|
.destination(employeeSigServletPage.toString() + "/saml")
|
||||||
|
.issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
|
||||||
|
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
|
||||||
|
Document document = builder.buildDocument();
|
||||||
|
|
||||||
|
new SamlClientBuilder()
|
||||||
|
.addStep((client, currentURI, currentResponse, context) ->
|
||||||
|
SamlClient.Binding.REDIRECT.createSamlSignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document, REALM_PRIVATE_KEY, REALM_PUBLIC_KEY))
|
||||||
|
.execute(closeableHttpResponse -> Assert.assertThat(closeableHttpResponse, bodyHC(containsString("ERROR_STATUS"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAttributes() throws Exception {
|
||||||
|
ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), AbstractSamlTest.SAML_CLIENT_ID_EMPLOYEE_2);
|
||||||
|
ProtocolMappersResource protocolMappersResource = clientResource.getProtocolMappers();
|
||||||
|
|
||||||
|
Map<String, String> config = new LinkedHashMap<>();
|
||||||
|
config.put("attribute.nameformat", "Basic");
|
||||||
|
config.put("user.attribute", "topAttribute");
|
||||||
|
config.put("attribute.name", "topAttribute");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "topAttribute", "saml", "saml-user-attribute-mapper", config));
|
||||||
|
|
||||||
|
config = new LinkedHashMap<>();
|
||||||
|
config.put("attribute.nameformat", "Basic");
|
||||||
|
config.put("user.attribute", "level2Attribute");
|
||||||
|
config.put("attribute.name", "level2Attribute");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "level2Attribute", "saml", "saml-user-attribute-mapper", config));
|
||||||
|
|
||||||
|
config = new LinkedHashMap<>();
|
||||||
|
config.put("attribute.nameformat", "Basic");
|
||||||
|
config.put("single", "true");
|
||||||
|
config.put("attribute.name", "group");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "groups", "saml", "saml-group-membership-mapper", config));
|
||||||
|
|
||||||
|
setRolesToCheck("manager,user");
|
||||||
|
|
||||||
|
employee2ServletPage.navigateTo();
|
||||||
|
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
||||||
|
testRealmSAMLPostLoginPage.form().login("level2GroupUser", "password");
|
||||||
|
|
||||||
|
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build().toURL());
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains("topAttribute: true");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains("level2Attribute: true");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains(X500SAMLProfileConstants.EMAIL.get() + ": level2@redhat.com");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().not().contains("group: []");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().not().contains("group: null");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().not().contains("group: <br />");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains("group: level2");
|
||||||
|
|
||||||
|
employee2ServletPage.logout();
|
||||||
|
checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
|
||||||
|
|
||||||
|
setRolesToCheck("manager,employee,user");
|
||||||
|
|
||||||
|
employee2ServletPage.navigateTo();
|
||||||
|
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
||||||
|
testRealmSAMLPostLoginPage.form().login(bburkeUser);
|
||||||
|
|
||||||
|
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build().toURL());
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains(X500SAMLProfileConstants.EMAIL.get() + ": bburke@redhat.com");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains("friendly email: bburke@redhat.com");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains("phone: 617");
|
||||||
|
waitUntilElement(By.xpath("//body")).text().not().contains("friendly phone:");
|
||||||
|
|
||||||
|
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAssertionFromDocument").build().toURL());
|
||||||
|
waitForPageToLoad();
|
||||||
|
Assert.assertEquals("", driver.getPageSource());
|
||||||
|
|
||||||
|
employee2ServletPage.logout();
|
||||||
|
checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
|
||||||
|
|
||||||
|
config = new LinkedHashMap<>();
|
||||||
|
config.put("attribute.value", "hard");
|
||||||
|
config.put("attribute.nameformat", "Basic");
|
||||||
|
config.put("attribute.name", "hardcoded-attribute");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "hardcoded-attribute", "saml", "saml-hardcode-attribute-mapper", config));
|
||||||
|
|
||||||
|
config = new LinkedHashMap<>();
|
||||||
|
config.put("role", "hardcoded-role");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "hardcoded-role", "saml", "saml-hardcode-role-mapper", config));
|
||||||
|
|
||||||
|
config = new LinkedHashMap<>();
|
||||||
|
config.put("new.role.name", "pee-on");
|
||||||
|
config.put("role", "http://localhost:8280/employee/.employee");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "renamed-employee-role", "saml", "saml-role-name-mapper", config));
|
||||||
|
|
||||||
|
for (ProtocolMapperRepresentation mapper : clientResource.toRepresentation().getProtocolMappers()) {
|
||||||
|
if (mapper.getName().equals("role-list")) {
|
||||||
|
protocolMappersResource.delete(mapper.getId());
|
||||||
|
Map<String, String> origConfig = new HashMap<>(mapper.getConfig());
|
||||||
|
|
||||||
|
mapper.setId(null);
|
||||||
|
mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
|
||||||
|
mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
|
||||||
|
|
||||||
|
try (Response response = protocolMappersResource.createMapper(mapper)) {
|
||||||
|
String createdId = getCreatedId(response);
|
||||||
|
getCleanup().addCleanup((Runnable) () -> {
|
||||||
|
protocolMappersResource.delete(createdId);
|
||||||
|
mapper.setConfig(origConfig);
|
||||||
|
protocolMappersResource.createMapper(mapper).close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRolesToCheck("pee-on,el-jefe,manager,hardcoded-role");
|
||||||
|
|
||||||
|
config = new LinkedHashMap<>();
|
||||||
|
config.put("new.role.name", "el-jefe");
|
||||||
|
config.put("role", "user");
|
||||||
|
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "renamed-role", "saml", "saml-role-name-mapper", config));
|
||||||
|
|
||||||
|
employee2ServletPage.navigateTo();
|
||||||
|
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
||||||
|
testRealmSAMLPostLoginPage.form().login(bburkeUser);
|
||||||
|
|
||||||
|
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build().toURL());
|
||||||
|
waitUntilElement(By.xpath("//body")).text().contains("hardcoded-attribute: hard");
|
||||||
|
employee2ServletPage.checkRolesEndPoint(false);
|
||||||
|
employee2ServletPage.logout();
|
||||||
|
checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRolesToCheck(String roles) throws Exception {
|
||||||
|
employee2ServletPage.navigateTo();
|
||||||
|
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
||||||
|
testRealmSAMLPostLoginPage.form().login(bburkeUser);
|
||||||
|
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("setCheckRoles").queryParam("roles", roles).build().toURL());
|
||||||
|
WaitUtils.waitUntilElement(By.tagName("body")).text().contains("These roles will be checked:");
|
||||||
|
employee2ServletPage.logout();
|
||||||
|
}
|
||||||
|
}
|
|
@ -515,12 +515,6 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest {
|
||||||
checkLoggedOut(page, loginPage);
|
checkLoggedOut(page, loginPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLoggedOut(AbstractPage page, Login loginPage) {
|
|
||||||
page.navigateTo();
|
|
||||||
waitForPageToLoad();
|
|
||||||
assertCurrentUrlStartsWith(loginPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void disabledClientTest() {
|
public void disabledClientTest() {
|
||||||
ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), AbstractSamlTest.SAML_CLIENT_ID_SALES_POST_SIG);
|
ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), AbstractSamlTest.SAML_CLIENT_ID_SALES_POST_SIG);
|
||||||
|
@ -1152,34 +1146,6 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest {
|
||||||
Assert.assertEquals(driver.getCurrentUrl(), missingAssertionSigPage.getUriBuilder().clone().path("saml").build().toASCIIString());
|
Assert.assertEquals(driver.getCurrentUrl(), missingAssertionSigPage.getUriBuilder().clone().path("saml").build().toASCIIString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testErrorHandlingUnsigned() throws Exception {
|
|
||||||
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
|
|
||||||
.destination(employeeSigServletPage.toString() + "/saml")
|
|
||||||
.issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
|
|
||||||
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
|
|
||||||
Document document = builder.buildDocument();
|
|
||||||
|
|
||||||
new SamlClientBuilder()
|
|
||||||
.addStep((client, currentURI, currentResponse, context) ->
|
|
||||||
Binding.REDIRECT.createSamlUnsignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document))
|
|
||||||
.execute(closeableHttpResponse -> Assert.assertThat(closeableHttpResponse, bodyHC(containsString("INVALID_SIGNATURE"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testErrorHandlingSigned() throws Exception {
|
|
||||||
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
|
|
||||||
.destination(employeeSigServletPage.toString() + "/saml")
|
|
||||||
.issuer("http://localhost:" + System.getProperty("auth.server.http.port", "8180") + "/realms/demo")
|
|
||||||
.status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
|
|
||||||
Document document = builder.buildDocument();
|
|
||||||
|
|
||||||
new SamlClientBuilder()
|
|
||||||
.addStep((client, currentURI, currentResponse, context) ->
|
|
||||||
Binding.REDIRECT.createSamlSignedResponse(URI.create(employeeSigServletPage.toString() + "/saml"), null, document, REALM_PRIVATE_KEY, REALM_PUBLIC_KEY))
|
|
||||||
.execute(closeableHttpResponse -> Assert.assertThat(closeableHttpResponse, bodyHC(containsString("ERROR_STATUS"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRelayStateEncoding() throws Exception {
|
public void testRelayStateEncoding() throws Exception {
|
||||||
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
|
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
|
||||||
|
@ -1381,118 +1347,6 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAttributes() throws Exception {
|
|
||||||
ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), AbstractSamlTest.SAML_CLIENT_ID_EMPLOYEE_2);
|
|
||||||
ProtocolMappersResource protocolMappersResource = clientResource.getProtocolMappers();
|
|
||||||
|
|
||||||
Map<String, String> config = new LinkedHashMap<>();
|
|
||||||
config.put("attribute.nameformat", "Basic");
|
|
||||||
config.put("user.attribute", "topAttribute");
|
|
||||||
config.put("attribute.name", "topAttribute");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "topAttribute", "saml", "saml-user-attribute-mapper", config));
|
|
||||||
|
|
||||||
config = new LinkedHashMap<>();
|
|
||||||
config.put("attribute.nameformat", "Basic");
|
|
||||||
config.put("user.attribute", "level2Attribute");
|
|
||||||
config.put("attribute.name", "level2Attribute");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "level2Attribute", "saml", "saml-user-attribute-mapper", config));
|
|
||||||
|
|
||||||
config = new LinkedHashMap<>();
|
|
||||||
config.put("attribute.nameformat", "Basic");
|
|
||||||
config.put("single", "true");
|
|
||||||
config.put("attribute.name", "group");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "groups", "saml", "saml-group-membership-mapper", config));
|
|
||||||
|
|
||||||
setRolesToCheck("manager,user");
|
|
||||||
|
|
||||||
employee2ServletPage.navigateTo();
|
|
||||||
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
|
||||||
testRealmSAMLPostLoginPage.form().login("level2GroupUser", "password");
|
|
||||||
|
|
||||||
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build().toURL());
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("topAttribute: true");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("level2Attribute: true");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("attribute email: level2@redhat.com");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().not().contains("group: []");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().not().contains("group: null");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("group: [level2]");
|
|
||||||
|
|
||||||
employee2ServletPage.logout();
|
|
||||||
checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
|
|
||||||
|
|
||||||
setRolesToCheck("manager,employee,user");
|
|
||||||
|
|
||||||
employee2ServletPage.navigateTo();
|
|
||||||
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
|
||||||
testRealmSAMLPostLoginPage.form().login(bburkeUser);
|
|
||||||
|
|
||||||
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build().toURL());
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("attribute email: bburke@redhat.com");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("friendlyAttribute email: bburke@redhat.com");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("phone: 617");
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("friendlyAttribute phone: null");
|
|
||||||
|
|
||||||
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAssertionFromDocument").build().toURL());
|
|
||||||
waitForPageToLoad();
|
|
||||||
Assert.assertEquals("", driver.getPageSource());
|
|
||||||
|
|
||||||
employee2ServletPage.logout();
|
|
||||||
checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
|
|
||||||
|
|
||||||
config = new LinkedHashMap<>();
|
|
||||||
config.put("attribute.value", "hard");
|
|
||||||
config.put("attribute.nameformat", "Basic");
|
|
||||||
config.put("attribute.name", "hardcoded-attribute");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "hardcoded-attribute", "saml", "saml-hardcode-attribute-mapper", config));
|
|
||||||
|
|
||||||
config = new LinkedHashMap<>();
|
|
||||||
config.put("role", "hardcoded-role");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "hardcoded-role", "saml", "saml-hardcode-role-mapper", config));
|
|
||||||
|
|
||||||
config = new LinkedHashMap<>();
|
|
||||||
config.put("new.role.name", "pee-on");
|
|
||||||
config.put("role", "http://localhost:8280/employee/.employee");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "renamed-employee-role", "saml", "saml-role-name-mapper", config));
|
|
||||||
|
|
||||||
for (ProtocolMapperRepresentation mapper : clientResource.toRepresentation().getProtocolMappers()) {
|
|
||||||
if (mapper.getName().equals("role-list")) {
|
|
||||||
protocolMappersResource.delete(mapper.getId());
|
|
||||||
Map<String, String> origConfig = new HashMap<>(mapper.getConfig());
|
|
||||||
|
|
||||||
mapper.setId(null);
|
|
||||||
mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
|
|
||||||
mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
|
|
||||||
|
|
||||||
try (Response response = protocolMappersResource.createMapper(mapper)) {
|
|
||||||
String createdId = getCreatedId(response);
|
|
||||||
getCleanup().addCleanup((Runnable) () -> {
|
|
||||||
protocolMappersResource.delete(createdId);
|
|
||||||
mapper.setConfig(origConfig);
|
|
||||||
protocolMappersResource.createMapper(mapper).close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setRolesToCheck("pee-on,el-jefe,manager,hardcoded-role");
|
|
||||||
|
|
||||||
config = new LinkedHashMap<>();
|
|
||||||
config.put("new.role.name", "el-jefe");
|
|
||||||
config.put("role", "user");
|
|
||||||
getCleanup().addCleanup(createProtocolMapper(protocolMappersResource, "renamed-role", "saml", "saml-role-name-mapper", config));
|
|
||||||
|
|
||||||
employee2ServletPage.navigateTo();
|
|
||||||
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
|
||||||
testRealmSAMLPostLoginPage.form().login(bburkeUser);
|
|
||||||
|
|
||||||
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("getAttributes").build().toURL());
|
|
||||||
waitUntilElement(By.xpath("//body")).text().contains("hardcoded-attribute: hard");
|
|
||||||
employee2ServletPage.checkRolesEndPoint(false);
|
|
||||||
employee2ServletPage.logout();
|
|
||||||
checkLoggedOut(employee2ServletPage, testRealmSAMLPostLoginPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void idpMetadataValidation() throws Exception {
|
public void idpMetadataValidation() throws Exception {
|
||||||
driver.navigate().to(authServerPage.toString() + "/realms/" + SAMLSERVLETDEMO + "/protocol/saml/descriptor");
|
driver.navigate().to(authServerPage.toString() + "/realms/" + SAMLSERVLETDEMO + "/protocol/saml/descriptor");
|
||||||
|
@ -1939,27 +1793,6 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutoCloseable createProtocolMapper(ProtocolMappersResource resource, String name, String protocol, String protocolMapper, Map<String, String> config) {
|
|
||||||
ProtocolMapperRepresentation representation = new ProtocolMapperRepresentation();
|
|
||||||
representation.setName(name);
|
|
||||||
representation.setProtocol(protocol);
|
|
||||||
representation.setProtocolMapper(protocolMapper);
|
|
||||||
representation.setConfig(config);
|
|
||||||
try (Response response = resource.createMapper(representation)) {
|
|
||||||
String createdId = getCreatedId(response);
|
|
||||||
return () -> resource.delete(createdId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRolesToCheck(String roles) throws Exception {
|
|
||||||
employee2ServletPage.navigateTo();
|
|
||||||
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
|
|
||||||
testRealmSAMLPostLoginPage.form().login(bburkeUser);
|
|
||||||
driver.navigate().to(employee2ServletPage.getUriBuilder().clone().path("setCheckRoles").queryParam("roles", roles).build().toURL());
|
|
||||||
WaitUtils.waitUntilElement(By.tagName("body")).text().contains("These roles will be checked:");
|
|
||||||
employee2ServletPage.logout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertOnForbiddenPage() {
|
private void assertOnForbiddenPage() {
|
||||||
waitUntilElement(By.xpath("//body")).is().present();
|
waitUntilElement(By.xpath("//body")).is().present();
|
||||||
|
|
||||||
|
|
|
@ -79,21 +79,11 @@ public class SAMLServletSessionTimeoutTest extends AbstractSAMLServletAdapterTes
|
||||||
return ob;
|
return ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SamlClientBuilder beginAuthenticationAndLogin() {
|
|
||||||
return new SamlClientBuilder()
|
|
||||||
.navigateTo(employee2ServletPage.buildUri())
|
|
||||||
.processSamlResponse(SamlClient.Binding.POST) // Process AuthnResponse
|
|
||||||
.build()
|
|
||||||
|
|
||||||
.login().user(bburkeUser)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void employee2TestSAMLRefreshingSession() {
|
public void employee2TestSAMLRefreshingSession() {
|
||||||
sessionNotOnOrAfter.set(null);
|
sessionNotOnOrAfter.set(null);
|
||||||
|
|
||||||
beginAuthenticationAndLogin()
|
beginAuthenticationAndLogin(employee2ServletPage, SamlClient.Binding.POST)
|
||||||
.processSamlResponse(SamlClient.Binding.POST) // Update response with SessionNotOnOrAfter
|
.processSamlResponse(SamlClient.Binding.POST) // Update response with SessionNotOnOrAfter
|
||||||
.transformObject(this::addSessionNotOnOrAfter)
|
.transformObject(this::addSessionNotOnOrAfter)
|
||||||
.build()
|
.build()
|
||||||
|
@ -125,7 +115,7 @@ public class SAMLServletSessionTimeoutTest extends AbstractSAMLServletAdapterTes
|
||||||
public void employee2TestSAMLSessionTimeoutOnBothSides() {
|
public void employee2TestSAMLSessionTimeoutOnBothSides() {
|
||||||
sessionNotOnOrAfter.set(null);
|
sessionNotOnOrAfter.set(null);
|
||||||
|
|
||||||
beginAuthenticationAndLogin()
|
beginAuthenticationAndLogin(employee2ServletPage, SamlClient.Binding.POST)
|
||||||
.processSamlResponse(SamlClient.Binding.POST) // Update response with SessionNotOnOrAfter
|
.processSamlResponse(SamlClient.Binding.POST) // Update response with SessionNotOnOrAfter
|
||||||
.transformObject(this::addSessionNotOnOrAfter)
|
.transformObject(this::addSessionNotOnOrAfter)
|
||||||
.build()
|
.build()
|
||||||
|
@ -158,7 +148,7 @@ public class SAMLServletSessionTimeoutTest extends AbstractSAMLServletAdapterTes
|
||||||
try(AutoCloseable c = new RealmAttributeUpdater(adminClient.realm(REALM_NAME))
|
try(AutoCloseable c = new RealmAttributeUpdater(adminClient.realm(REALM_NAME))
|
||||||
.updateWith(r -> r.setSsoSessionMaxLifespan(SESSION_LENGTH_IN_SECONDS))
|
.updateWith(r -> r.setSsoSessionMaxLifespan(SESSION_LENGTH_IN_SECONDS))
|
||||||
.update()) {
|
.update()) {
|
||||||
beginAuthenticationAndLogin()
|
beginAuthenticationAndLogin(employee2ServletPage, SamlClient.Binding.POST)
|
||||||
.processSamlResponse(SamlClient.Binding.POST) // Process response
|
.processSamlResponse(SamlClient.Binding.POST) // Process response
|
||||||
.transformObject(ob -> { // Check sessionNotOnOrAfter is present and it has correct value
|
.transformObject(ob -> { // Check sessionNotOnOrAfter is present and it has correct value
|
||||||
assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
||||||
|
|
|
@ -32,6 +32,7 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe
|
||||||
public static final String ROLE_MANAGER = "manager";
|
public static final String ROLE_MANAGER = "manager";
|
||||||
public static final String ROLE_FRIENDLY_MANAGER = "friendly-manager";
|
public static final String ROLE_FRIENDLY_MANAGER = "friendly-manager";
|
||||||
public static final String ROLE_USER_DOT_GUIDE = "user.guide";
|
public static final String ROLE_USER_DOT_GUIDE = "user.guide";
|
||||||
|
public static final String EMPTY_ATTRIBUTE_ROLE = "empty.attribute.role";
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
ConsentPage consentPage;
|
ConsentPage consentPage;
|
||||||
|
@ -112,11 +113,13 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe
|
||||||
RoleRepresentation friendlyManagerRole = new RoleRepresentation(ROLE_FRIENDLY_MANAGER,null, false);
|
RoleRepresentation friendlyManagerRole = new RoleRepresentation(ROLE_FRIENDLY_MANAGER,null, false);
|
||||||
RoleRepresentation userRole = new RoleRepresentation(ROLE_USER,null, false);
|
RoleRepresentation userRole = new RoleRepresentation(ROLE_USER,null, false);
|
||||||
RoleRepresentation userGuideRole = new RoleRepresentation(ROLE_USER_DOT_GUIDE,null, false);
|
RoleRepresentation userGuideRole = new RoleRepresentation(ROLE_USER_DOT_GUIDE,null, false);
|
||||||
|
RoleRepresentation emptyAttributeRole = new RoleRepresentation(EMPTY_ATTRIBUTE_ROLE, null, false);
|
||||||
|
|
||||||
adminClient.realm(realm).roles().create(managerRole);
|
adminClient.realm(realm).roles().create(managerRole);
|
||||||
adminClient.realm(realm).roles().create(friendlyManagerRole);
|
adminClient.realm(realm).roles().create(friendlyManagerRole);
|
||||||
adminClient.realm(realm).roles().create(userRole);
|
adminClient.realm(realm).roles().create(userRole);
|
||||||
adminClient.realm(realm).roles().create(userGuideRole);
|
adminClient.realm(realm).roles().create(userGuideRole);
|
||||||
|
adminClient.realm(realm).roles().create(emptyAttributeRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enableUpdateProfileOnFirstLogin(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) {
|
static void enableUpdateProfileOnFirstLogin(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) {
|
||||||
|
|
|
@ -4,11 +4,19 @@ import org.keycloak.admin.client.resource.UserResource;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.keycloak.broker.saml.mappers.AttributeToRoleMapper;
|
import org.keycloak.broker.saml.mappers.AttributeToRoleMapper;
|
||||||
import org.keycloak.broker.saml.mappers.UserAttributeMapper;
|
import org.keycloak.broker.saml.mappers.UserAttributeMapper;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.StatementAbstractType;
|
||||||
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
||||||
|
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
||||||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
|
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
|
import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
|
||||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||||
import org.keycloak.testsuite.saml.AbstractSamlTest;
|
import org.keycloak.testsuite.saml.AbstractSamlTest;
|
||||||
|
@ -20,6 +28,8 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -30,7 +40,11 @@ import static org.junit.Assert.assertThat;
|
||||||
import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot;
|
import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot;
|
||||||
import static org.keycloak.testsuite.broker.AbstractBrokerTest.ROLE_MANAGER;
|
import static org.keycloak.testsuite.broker.AbstractBrokerTest.ROLE_MANAGER;
|
||||||
import static org.keycloak.testsuite.broker.AbstractBrokerTest.ROLE_USER;
|
import static org.keycloak.testsuite.broker.AbstractBrokerTest.ROLE_USER;
|
||||||
|
import static org.keycloak.testsuite.saml.RoleMapperTest.ROLE_ATTRIBUTE_NAME;
|
||||||
import static org.keycloak.testsuite.util.Matchers.isSamlResponse;
|
import static org.keycloak.testsuite.util.Matchers.isSamlResponse;
|
||||||
|
import static org.keycloak.testsuite.util.SamlStreams.assertionsUnencrypted;
|
||||||
|
import static org.keycloak.testsuite.util.SamlStreams.attributeStatements;
|
||||||
|
import static org.keycloak.testsuite.util.SamlStreams.attributesUnecrypted;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Final class as it's not intended to be overriden. Feel free to remove "final" if you really know what you are doing.
|
* Final class as it's not intended to be overriden. Feel free to remove "final" if you really know what you are doing.
|
||||||
|
@ -42,6 +56,8 @@ public final class KcSamlBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
return KcSamlBrokerConfiguration.INSTANCE;
|
return KcSamlBrokerConfiguration.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String EMPTY_ATTRIBUTE_NAME = "empty.attribute.name";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Iterable<IdentityProviderMapperRepresentation> createIdentityProviderMappers() {
|
protected Iterable<IdentityProviderMapperRepresentation> createIdentityProviderMappers() {
|
||||||
IdentityProviderMapperRepresentation attrMapper1 = new IdentityProviderMapperRepresentation();
|
IdentityProviderMapperRepresentation attrMapper1 = new IdentityProviderMapperRepresentation();
|
||||||
|
@ -80,7 +96,16 @@ public final class KcSamlBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
.put("role", ROLE_USER_DOT_GUIDE)
|
.put("role", ROLE_USER_DOT_GUIDE)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
return Arrays.asList(new IdentityProviderMapperRepresentation[] { attrMapper1, attrMapper2, attrMapper3, attrMapper4 });
|
IdentityProviderMapperRepresentation attrMapper5 = new IdentityProviderMapperRepresentation();
|
||||||
|
attrMapper5.setName("empty-attribute-to-role-mapper");
|
||||||
|
attrMapper5.setIdentityProviderMapper(AttributeToRoleMapper.PROVIDER_ID);
|
||||||
|
attrMapper5.setConfig(ImmutableMap.<String,String>builder()
|
||||||
|
.put(UserAttributeMapper.ATTRIBUTE_NAME, EMPTY_ATTRIBUTE_NAME)
|
||||||
|
.put(ATTRIBUTE_VALUE, "")
|
||||||
|
.put("role", EMPTY_ATTRIBUTE_ROLE)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
return Arrays.asList(new IdentityProviderMapperRepresentation[] { attrMapper1, attrMapper2, attrMapper3, attrMapper4, attrMapper5 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// KEYCLOAK-3987
|
// KEYCLOAK-3987
|
||||||
|
@ -231,4 +256,64 @@ public final class KcSamlBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
Assert.assertThat(samlResponse.getSamlObject(), isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
Assert.assertThat(samlResponse.getSamlObject(), isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyAttributeToRoleMapperTest() throws ParsingException, ConfigurationException, ProcessingException {
|
||||||
|
createRolesForRealm(bc.consumerRealmName());
|
||||||
|
createRoleMappersForConsumerRealm();
|
||||||
|
|
||||||
|
AuthnRequestType loginRep = SamlClient.createLoginRequestDocument(AbstractSamlTest.SAML_CLIENT_ID_SALES_POST + ".dot/ted", getAuthServerContextRoot() + "/sales-post/saml", null);
|
||||||
|
|
||||||
|
Document doc = SAML2Request.convert(loginRep);
|
||||||
|
|
||||||
|
SAMLDocumentHolder samlResponse = new SamlClientBuilder()
|
||||||
|
.authnRequest(getAuthServerSamlEndpoint(bc.consumerRealmName()), doc, Binding.POST).build() // Request to consumer IdP
|
||||||
|
.login().idp(bc.getIDPAlias()).build()
|
||||||
|
|
||||||
|
.processSamlResponse(Binding.POST) // AuthnRequest to producer IdP
|
||||||
|
.targetAttributeSamlRequest()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
.login().user(bc.getUserLogin(), bc.getUserPassword()).build()
|
||||||
|
|
||||||
|
.processSamlResponse(Binding.POST) // Response from producer IdP
|
||||||
|
.transformObject(ob -> {
|
||||||
|
assertThat(ob, org.keycloak.testsuite.util.Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
||||||
|
ResponseType resp = (ResponseType) ob;
|
||||||
|
|
||||||
|
Set<StatementAbstractType> statements = resp.getAssertions().get(0).getAssertion().getStatements();
|
||||||
|
|
||||||
|
AttributeStatementType attributeType = (AttributeStatementType) statements.stream()
|
||||||
|
.filter(statement -> statement instanceof AttributeStatementType)
|
||||||
|
.findFirst().orElse(new AttributeStatementType());
|
||||||
|
|
||||||
|
AttributeType attr = new AttributeType(EMPTY_ATTRIBUTE_NAME);
|
||||||
|
attr.addAttributeValue(null);
|
||||||
|
|
||||||
|
attributeType.addAttribute(new AttributeStatementType.ASTChoiceType(attr));
|
||||||
|
resp.getAssertions().get(0).getAssertion().addStatement(attributeType);
|
||||||
|
|
||||||
|
return ob;
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// first-broker flow
|
||||||
|
.updateProfile().firstName("a").lastName("b").email(bc.getUserEmail()).username(bc.getUserLogin()).build()
|
||||||
|
.followOneRedirect()
|
||||||
|
|
||||||
|
.getSamlResponse(Binding.POST); // Response from consumer IdP
|
||||||
|
|
||||||
|
Assert.assertThat(samlResponse, Matchers.notNullValue());
|
||||||
|
Assert.assertThat(samlResponse.getSamlObject(), isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
||||||
|
|
||||||
|
Stream<AssertionType> assertionTypeStream = assertionsUnencrypted(samlResponse.getSamlObject());
|
||||||
|
Stream<AttributeType> attributeStatementTypeStream = attributesUnecrypted(attributeStatements(assertionTypeStream));
|
||||||
|
Set<String> attributeValues = attributeStatementTypeStream
|
||||||
|
.filter(a -> a.getName().equals(ROLE_ATTRIBUTE_NAME))
|
||||||
|
.flatMap(a -> a.getAttributeValue().stream())
|
||||||
|
.map(Object::toString)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
assertThat(attributeValues, hasItems(EMPTY_ATTRIBUTE_ROLE));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.keycloak.testsuite.saml;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||||
|
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||||
|
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
||||||
|
import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
|
||||||
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
|
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||||
|
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
|
||||||
|
import org.keycloak.testsuite.updaters.ProtocolMappersUpdater;
|
||||||
|
import org.keycloak.testsuite.util.Matchers;
|
||||||
|
import org.keycloak.testsuite.util.SamlClient;
|
||||||
|
import org.keycloak.testsuite.util.SamlClientBuilder;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.keycloak.testsuite.saml.RoleMapperTest.createSamlProtocolMapper;
|
||||||
|
import static org.keycloak.testsuite.util.SamlStreams.assertionsUnencrypted;
|
||||||
|
import static org.keycloak.testsuite.util.SamlStreams.attributeStatements;
|
||||||
|
import static org.keycloak.testsuite.util.SamlStreams.attributesUnecrypted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mhajas
|
||||||
|
*/
|
||||||
|
public class ProtocolMapperTest extends AbstractSamlTest {
|
||||||
|
|
||||||
|
private ClientAttributeUpdater cau;
|
||||||
|
private ProtocolMappersUpdater pmu;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void cleanMappersAndScopes() {
|
||||||
|
this.cau = ClientAttributeUpdater.forClient(adminClient, REALM_NAME, SAML_CLIENT_ID_EMPLOYEE_2)
|
||||||
|
.setDefaultClientScopes(Collections.EMPTY_LIST)
|
||||||
|
.update();
|
||||||
|
this.pmu = cau.protocolMappers()
|
||||||
|
.clear()
|
||||||
|
.update();
|
||||||
|
|
||||||
|
getCleanup(REALM_NAME)
|
||||||
|
.addCleanup(this.cau)
|
||||||
|
.addCleanup(this.pmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hardcodedAttributeMapperWithNullValueTest() throws Exception {
|
||||||
|
pmu.add(
|
||||||
|
createSamlProtocolMapper(HardcodedAttributeMapper.PROVIDER_ID,
|
||||||
|
AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "HARDCODED_ATTRIBUTE",
|
||||||
|
AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, AttributeStatementHelper.BASIC,
|
||||||
|
HardcodedAttributeMapper.ATTRIBUTE_VALUE, null
|
||||||
|
)
|
||||||
|
).update();
|
||||||
|
|
||||||
|
|
||||||
|
SAMLDocumentHolder samlResponse = new SamlClientBuilder()
|
||||||
|
.authnRequest(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_EMPLOYEE_2, RoleMapperTest.SAML_ASSERTION_CONSUMER_URL_EMPLOYEE_2, SamlClient.Binding.POST)
|
||||||
|
.build()
|
||||||
|
.login().user(bburkeUser).build()
|
||||||
|
.getSamlResponse(SamlClient.Binding.POST);
|
||||||
|
|
||||||
|
assertThat(samlResponse.getSamlObject(), Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
|
||||||
|
|
||||||
|
Stream<AssertionType> assertions = assertionsUnencrypted(samlResponse.getSamlObject());
|
||||||
|
Stream<AttributeType> attributes = attributesUnecrypted(attributeStatements(assertions));
|
||||||
|
Set<Object> attributeValues = attributes
|
||||||
|
.flatMap(a -> a.getAttributeValue().stream())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
assertThat(attributeValues, hasSize(1));
|
||||||
|
assertThat(attributeValues.iterator().next(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue