KEYCLOAK-5581 Fix SAML identity broker context serialization
This commit is contained in:
parent
1ac9bd510b
commit
fe2f65daac
12 changed files with 365 additions and 27 deletions
|
@ -101,7 +101,7 @@ public class SAMLResponseWriter extends BaseWriter {
|
|||
for (ResponseType.RTChoiceType choiceType : choiceTypes) {
|
||||
AssertionType assertion = choiceType.getAssertion();
|
||||
if (assertion != null) {
|
||||
assertionWriter.write(assertion);
|
||||
assertionWriter.write(assertion, forceWriteDsigNamespace);
|
||||
}
|
||||
|
||||
EncryptedAssertionType encryptedAssertion = choiceType.getEncryptedAssertion();
|
||||
|
|
|
@ -367,7 +367,9 @@ public class XMLSignatureUtil {
|
|||
public static Document sign(Document doc, String keyName, KeyPair keyPair, String digestMethod, String signatureMethod, String referenceURI,
|
||||
X509Certificate x509Certificate, String canonicalizationMethodType)
|
||||
throws GeneralSecurityException, MarshalException, XMLSignatureException {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Document to be signed=" + DocumentUtil.asString(doc));
|
||||
}
|
||||
PrivateKey signingKey = keyPair.getPrivate();
|
||||
PublicKey publicKey = keyPair.getPublic();
|
||||
|
||||
|
@ -398,7 +400,9 @@ public class XMLSignatureUtil {
|
|||
String referenceURI = dto.getReferenceURI();
|
||||
String signatureMethod = dto.getSignatureMethod();
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Document to be signed=" + DocumentUtil.asString(doc));
|
||||
}
|
||||
|
||||
PrivateKey signingKey = keyPair.getPrivate();
|
||||
PublicKey publicKey = keyPair.getPublic();
|
||||
|
@ -407,6 +411,10 @@ public class XMLSignatureUtil {
|
|||
|
||||
signImpl(dsc, digestMethod, signatureMethod, referenceURI, keyName, publicKey, dto.getX509Certificate(), canonicalizationMethodType);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Signed document=" + DocumentUtil.asString(doc));
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,11 +129,16 @@ public class SAMLDataMarshallerTest {
|
|||
ResponseType response = (ResponseType) parsedObject;
|
||||
|
||||
SAMLDataMarshaller serializer = new SAMLDataMarshaller();
|
||||
String serialized = serializer.serialize(response.getAssertions().get(0).getAssertion());
|
||||
String serializedResponse = serializer.serialize(response);
|
||||
String serializedAssertion = serializer.serialize(response.getAssertions().get(0).getAssertion());
|
||||
|
||||
AssertionType deserialized = serializer.deserialize(serialized, AssertionType.class);
|
||||
assertThat(deserialized, CoreMatchers.notNullValue());
|
||||
assertThat(deserialized.getID(), CoreMatchers.is("id-4r-Xj702KQsM0gJyu3Fqpuwfe-LvDrEcQZpxKrhC"));
|
||||
ResponseType deserializedResponse = serializer.deserialize(serializedResponse, ResponseType.class);
|
||||
assertThat(deserializedResponse, CoreMatchers.notNullValue());
|
||||
assertThat(deserializedResponse.getID(), CoreMatchers.is("id-EYgqtumZ-P-Ph7t37f-brUKMwB5MKix0sNjr-0YV"));
|
||||
|
||||
AssertionType deserializedAssertion = serializer.deserialize(serializedAssertion, AssertionType.class);
|
||||
assertThat(deserializedAssertion, CoreMatchers.notNullValue());
|
||||
assertThat(deserializedAssertion.getID(), CoreMatchers.is("id-4r-Xj702KQsM0gJyu3Fqpuwfe-LvDrEcQZpxKrhC"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,13 +31,16 @@ import org.keycloak.testsuite.util.saml.CreateAuthnRequestStepBuilder;
|
|||
import org.keycloak.testsuite.util.saml.CreateLogoutRequestStepBuilder;
|
||||
import org.keycloak.testsuite.util.saml.IdPInitiatedLoginBuilder;
|
||||
import org.keycloak.testsuite.util.saml.LoginBuilder;
|
||||
import org.keycloak.testsuite.util.saml.UpdateProfileBuilder;
|
||||
import org.keycloak.testsuite.util.saml.ModifySamlResponseStepBuilder;
|
||||
import org.keycloak.testsuite.util.saml.RequiredConsentBuilder;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Assert;
|
||||
import org.w3c.dom.Document;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -157,6 +160,11 @@ public class SamlClientBuilder {
|
|||
return addStepBuilder(new LoginBuilder(this));
|
||||
}
|
||||
|
||||
/** Handles update profile page after login */
|
||||
public UpdateProfileBuilder updateProfile() {
|
||||
return addStepBuilder(new UpdateProfileBuilder(this));
|
||||
}
|
||||
|
||||
/** Starts IdP-initiated flow for the given client */
|
||||
public IdPInitiatedLoginBuilder idpInitiatedLogin(URI authServerSamlUrl, String clientId) {
|
||||
return addStepBuilder(new IdPInitiatedLoginBuilder(authServerSamlUrl, clientId, this));
|
||||
|
@ -191,4 +199,14 @@ public class SamlClientBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public SamlClientBuilder followOneRedirect() {
|
||||
return
|
||||
doNotFollowRedirects()
|
||||
.addStep((client, currentURI, currentResponse, context) -> {
|
||||
Assert.assertThat(currentResponse, Matchers.statusCodeIsHC(Status.FOUND));
|
||||
Assert.assertThat("Location header not found", currentResponse.getFirstHeader("Location"), notNullValue());
|
||||
return new HttpGet(currentResponse.getFirstHeader("Location").getValue());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.keycloak.testsuite.util.saml;
|
|||
|
||||
import org.keycloak.testsuite.util.SamlClientBuilder;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.admin.Users;
|
||||
import org.keycloak.testsuite.util.SamlClient.Step;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
|
@ -36,6 +37,7 @@ import org.apache.http.client.protocol.HttpClientContext;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Element;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
@ -52,6 +54,7 @@ public class LoginBuilder implements Step {
|
|||
private final SamlClientBuilder clientBuilder;
|
||||
private UserRepresentation user;
|
||||
private boolean sso = false;
|
||||
private String idpAlias;
|
||||
|
||||
public LoginBuilder(SamlClientBuilder clientBuilder) {
|
||||
this.clientBuilder = clientBuilder;
|
||||
|
@ -66,7 +69,7 @@ public class LoginBuilder implements Step {
|
|||
String loginPageText = EntityUtils.toString(currentResponse.getEntity(), "UTF-8");
|
||||
assertThat(loginPageText, containsString("login"));
|
||||
|
||||
return handleLoginPage(loginPageText);
|
||||
return handleLoginPage(loginPageText, currentURI);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,11 +82,29 @@ public class LoginBuilder implements Step {
|
|||
return this;
|
||||
}
|
||||
|
||||
public LoginBuilder user(String userName, String password) {
|
||||
this.user = new UserRepresentation();
|
||||
this.user.setUsername(userName);
|
||||
Users.setPasswordFor(user, password);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoginBuilder sso(boolean sso) {
|
||||
this.sso = sso;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the step is executed and {@code idpAlias} is not {@code null}, it attempts to find and follow the link to
|
||||
* identity provider with the given alias.
|
||||
* @param idpAlias
|
||||
* @return
|
||||
*/
|
||||
public LoginBuilder idp(String idpAlias) {
|
||||
this.idpAlias = idpAlias;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a GET/POST request for logging the given user into the given login page. The login page is expected
|
||||
* to have at least input fields with id "username" and "password".
|
||||
|
@ -92,7 +113,16 @@ public class LoginBuilder implements Step {
|
|||
* @param loginPage
|
||||
* @return
|
||||
*/
|
||||
private HttpUriRequest handleLoginPage(String loginPage) {
|
||||
private HttpUriRequest handleLoginPage(String loginPage, URI currentURI) {
|
||||
if (idpAlias != null) {
|
||||
org.jsoup.nodes.Document theLoginPage = Jsoup.parse(loginPage);
|
||||
Element zocialLink = theLoginPage.getElementById("zocial-" + this.idpAlias);
|
||||
assertThat("Unknown idp: " + this.idpAlias, zocialLink, Matchers.notNullValue());
|
||||
final String link = zocialLink.attr("href");
|
||||
assertThat("Invalid idp link: " + this.idpAlias, link, Matchers.notNullValue());
|
||||
return new HttpGet(currentURI.resolve(link));
|
||||
}
|
||||
|
||||
return handleLoginPage(user, loginPage);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.apache.http.client.utils.URLEncodedUtils;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
@ -154,7 +155,9 @@ public class ModifySamlResponseStepBuilder extends SamlDocumentStepBuilder<SAML2
|
|||
private HttpUriRequest handlePostBinding(CloseableHttpResponse currentResponse) throws Exception {
|
||||
assertThat(currentResponse, statusCodeIsHC(Status.OK));
|
||||
|
||||
org.jsoup.nodes.Document theResponsePage = Jsoup.parse(EntityUtils.toString(currentResponse.getEntity()));
|
||||
final String htmlBody = EntityUtils.toString(currentResponse.getEntity());
|
||||
assertThat(htmlBody, Matchers.containsString("SAML"));
|
||||
org.jsoup.nodes.Document theResponsePage = Jsoup.parse(htmlBody);
|
||||
Elements samlResponses = theResponsePage.select("input[name=SAMLResponse]");
|
||||
Elements samlRequests = theResponsePage.select("input[name=SAMLRequest]");
|
||||
Elements forms = theResponsePage.select("form");
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed 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.keycloak.testsuite.util.saml;
|
||||
|
||||
import org.keycloak.testsuite.util.SamlClientBuilder;
|
||||
import org.keycloak.testsuite.util.SamlClient.Step;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Element;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class UpdateProfileBuilder implements Step {
|
||||
|
||||
private final SamlClientBuilder clientBuilder;
|
||||
private final Map<String, String> parameters = new HashMap<>();
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(UpdateProfileBuilder.class);
|
||||
|
||||
public UpdateProfileBuilder(SamlClientBuilder clientBuilder) {
|
||||
this.clientBuilder = clientBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpUriRequest perform(CloseableHttpClient client, URI currentURI, CloseableHttpResponse currentResponse, HttpClientContext context) throws Exception {
|
||||
assertThat(currentResponse, statusCodeIsHC(Response.Status.OK));
|
||||
String loginPageText = EntityUtils.toString(currentResponse.getEntity(), "UTF-8");
|
||||
assertThat(loginPageText, containsString("Update Account Information"));
|
||||
|
||||
return handleUpdateProfile(loginPageText, currentURI);
|
||||
}
|
||||
|
||||
public SamlClientBuilder build() {
|
||||
return this.clientBuilder;
|
||||
}
|
||||
|
||||
public UpdateProfileBuilder param(String paramName, String paramValue) {
|
||||
if (paramValue != null) {
|
||||
this.parameters.put(paramName, paramValue);
|
||||
} else {
|
||||
this.parameters.remove(paramName);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateProfileBuilder firstName(String firstName) {
|
||||
return param("firstName", firstName);
|
||||
}
|
||||
|
||||
public UpdateProfileBuilder lastName(String lastName) {
|
||||
return param("lastName", lastName);
|
||||
}
|
||||
|
||||
public UpdateProfileBuilder username(String username) {
|
||||
return param("username", username);
|
||||
}
|
||||
|
||||
public UpdateProfileBuilder email(String email) {
|
||||
return param("email", email);
|
||||
}
|
||||
|
||||
public HttpUriRequest handleUpdateProfile(String loginPage, URI currentURI) {
|
||||
org.jsoup.nodes.Document theUpdateProfilePage = Jsoup.parse(loginPage);
|
||||
Set<String> unusedParams = new HashSet<>(this.parameters.keySet());
|
||||
|
||||
List<NameValuePair> parameters = new LinkedList<>();
|
||||
for (Element form : theUpdateProfilePage.getElementsByTag("form")) {
|
||||
String method = form.attr("method");
|
||||
String action = form.attr("action");
|
||||
boolean isPost = method != null && "post".equalsIgnoreCase(method);
|
||||
|
||||
for (Element input : form.getElementsByTag("input")) {
|
||||
if (this.parameters.containsKey(input.attr("name"))) {
|
||||
parameters.add(new BasicNameValuePair(input.attr("name"), this.parameters.get(input.attr("name"))));
|
||||
unusedParams.remove(input.attr("name"));
|
||||
}
|
||||
}
|
||||
|
||||
if (! unusedParams.isEmpty()) {
|
||||
LOG.warnf("Unused parameter names at Update Profile page: %s", unusedParams);
|
||||
}
|
||||
|
||||
if (isPost) {
|
||||
HttpPost res = new HttpPost(action);
|
||||
|
||||
UrlEncodedFormEntity formEntity;
|
||||
try {
|
||||
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
res.setEntity(formEntity);
|
||||
|
||||
return res;
|
||||
} else {
|
||||
UriBuilder b = UriBuilder.fromPath(action);
|
||||
for (NameValuePair parameter : parameters) {
|
||||
b.queryParam(parameter.getName(), parameter.getValue());
|
||||
}
|
||||
return new HttpGet(b.build());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid update profile form: " + loginPage);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,8 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
|||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.arquillian.SuiteContext;
|
||||
|
||||
import org.keycloak.testsuite.saml.AbstractSamlTest;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -122,7 +124,18 @@ public class KcSamlBrokerConfiguration implements BrokerConfiguration {
|
|||
|
||||
@Override
|
||||
public List<ClientRepresentation> createConsumerClients(SuiteContext suiteContext) {
|
||||
return null;
|
||||
return Arrays.asList(
|
||||
ClientBuilder.create()
|
||||
.clientId(AbstractSamlTest.SAML_CLIENT_ID_SALES_POST)
|
||||
.enabled(true)
|
||||
.fullScopeEnabled(true)
|
||||
.protocol(SamlProtocol.LOGIN_PROTOCOL)
|
||||
.baseUrl("http://localhost:8080/sales-post")
|
||||
.addRedirectUri("http://localhost:8080/sales-post/*")
|
||||
.attribute(SamlConfigAttributes.SAML_AUTHNSTATEMENT, SamlProtocol.ATTRIBUTE_TRUE_VALUE)
|
||||
.attribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE, SamlProtocol.ATTRIBUTE_FALSE_VALUE)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,7 +4,12 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.common.collect.Lists;
|
||||
import org.keycloak.broker.saml.mappers.AttributeToRoleMapper;
|
||||
import org.keycloak.broker.saml.mappers.UserAttributeMapper;
|
||||
import org.keycloak.protocol.saml.SamlProtocol;
|
||||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||
import org.keycloak.services.resources.RealmsResource;
|
||||
import java.net.URI;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriBuilderException;
|
||||
|
||||
public class KcSamlBrokerTest extends AbstractBrokerTest {
|
||||
|
||||
|
@ -35,4 +40,10 @@ public class KcSamlBrokerTest extends AbstractBrokerTest {
|
|||
|
||||
return Lists.newArrayList(attrMapper1, attrMapper2);
|
||||
}
|
||||
|
||||
protected URI getAuthServerSamlEndpoint(String realm) throws IllegalArgumentException, UriBuilderException {
|
||||
return RealmsResource
|
||||
.protocolUrl(UriBuilder.fromUri(getAuthServerRoot()))
|
||||
.build(realm, SamlProtocol.LOGIN_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,42 @@ package org.keycloak.testsuite.broker;
|
|||
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
|
||||
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
||||
import org.keycloak.protocol.saml.SamlConfigAttributes;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
import org.keycloak.saml.common.util.DocumentUtil;
|
||||
import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
|
||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||
import org.keycloak.testsuite.arquillian.SuiteContext;
|
||||
|
||||
import org.keycloak.testsuite.saml.AbstractSamlTest;
|
||||
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
|
||||
import org.keycloak.testsuite.updaters.IdentityProviderAttributeUpdater;
|
||||
import org.keycloak.testsuite.util.SamlClient;
|
||||
import org.keycloak.testsuite.util.SamlClient.Binding;
|
||||
import org.keycloak.testsuite.util.SamlClientBuilder;
|
||||
import java.io.Closeable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import static org.keycloak.testsuite.broker.BrokerTestConstants.*;
|
||||
import static org.keycloak.testsuite.broker.BrokerTestTools.encodeUrl;
|
||||
import static org.keycloak.testsuite.util.Matchers.isSamlResponse;
|
||||
|
||||
public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
|
||||
|
||||
|
@ -138,4 +156,80 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
|
|||
errorPage.assertCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
private Document extractNamespacesToTopLevelElement(Document original) {
|
||||
HashMap<String, String> namespaces = new HashMap<>();
|
||||
enumerateAndRemoveNamespaces(original.getDocumentElement(), namespaces);
|
||||
|
||||
log.infof("Namespaces: %s", namespaces);
|
||||
log.infof("Document: %s", DocumentUtil.asString(original));
|
||||
|
||||
Element rootNode = original.getDocumentElement();
|
||||
for (Entry<String, String> me : namespaces.entrySet()) {
|
||||
rootNode.setAttribute(me.getKey(), me.getValue());
|
||||
}
|
||||
|
||||
log.infof("Updated document: %s", DocumentUtil.asString(original));
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
private void enumerateAndRemoveNamespaces(Element documentElement, HashMap<String, String> namespaces) {
|
||||
final NamedNodeMap attrs = documentElement.getAttributes();
|
||||
if (attrs != null) {
|
||||
final Set<String> found = new HashSet<>();
|
||||
|
||||
for (int i = attrs.getLength() - 1; i >= 0; i--) {
|
||||
Node item = attrs.item(i);
|
||||
String nodeName = item.getNodeName();
|
||||
if (nodeName != null && nodeName.startsWith("xmlns:")) {
|
||||
namespaces.put(nodeName, item.getNodeValue());
|
||||
found.add(nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
found.forEach(documentElement::removeAttribute);
|
||||
}
|
||||
|
||||
NodeList childNodes = documentElement.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i ++) {
|
||||
Node childNode = childNodes.item(i);
|
||||
if (childNode instanceof Element) {
|
||||
enumerateAndRemoveNamespaces((Element) childNode, namespaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KEYCLOAK-5581
|
||||
@Test
|
||||
public void loginUserAllNamespacesInTopElement() throws Exception {
|
||||
AuthnRequestType loginRep = SamlClient.createLoginRequestDocument(AbstractSamlTest.SAML_CLIENT_ID_SALES_POST, AbstractSamlTest.SAML_ASSERTION_CONSUMER_URL_SALES_POST, null);
|
||||
|
||||
Document doc = extractNamespacesToTopLevelElement(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()
|
||||
.transformDocument(this::extractNamespacesToTopLevelElement)
|
||||
.build()
|
||||
|
||||
.login().user(bc.getUserLogin(), bc.getUserPassword()).build()
|
||||
|
||||
.processSamlResponse(Binding.POST) // Response from producer IdP
|
||||
.transformDocument(this::extractNamespacesToTopLevelElement)
|
||||
.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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,26 +19,26 @@ import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
|||
*/
|
||||
public abstract class AbstractSamlTest extends AbstractAuthTest {
|
||||
|
||||
protected static final String REALM_NAME = "demo";
|
||||
protected static final String REALM_PRIVATE_KEY = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=";
|
||||
protected static final String REALM_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
|
||||
public static final String REALM_NAME = "demo";
|
||||
public static final String REALM_PRIVATE_KEY = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=";
|
||||
public static final String REALM_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
|
||||
|
||||
protected static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = "http://localhost:8080/sales-post/";
|
||||
protected static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8081/sales-post/";
|
||||
public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = "http://localhost:8080/sales-post/";
|
||||
public static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8081/sales-post/";
|
||||
|
||||
protected static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST2 = "http://localhost:8080/sales-post2/";
|
||||
protected static final String SAML_CLIENT_ID_SALES_POST2 = "http://localhost:8081/sales-post2/";
|
||||
public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST2 = "http://localhost:8080/sales-post2/";
|
||||
public static final String SAML_CLIENT_ID_SALES_POST2 = "http://localhost:8081/sales-post2/";
|
||||
|
||||
protected static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST_SIG = "http://localhost:8080/sales-post-sig/";
|
||||
protected static final String SAML_CLIENT_ID_SALES_POST_SIG = "http://localhost:8081/sales-post-sig/";
|
||||
protected static final String SAML_URL_SALES_POST_SIG = "http://localhost:8080/sales-post-sig/";
|
||||
protected static final String SAML_CLIENT_SALES_POST_SIG_PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANUbxrvEY3pkiQNt55zJLKBwN+zKmNQw08ThAmOKzwHfXoK+xlDSFxNMtTKJGkeUdnKzaTfESEcEfKYULUA41y/NnOlvjS0CEsc7Wq0Ce63TSSGMB2NHea4tV0aQz/MwLsbmz2IjAFWHA5CHL5WwacIf3UTOSNnhJUSvnkomjJAlAgMBAAECgYANpO2gb/5+g5lSIuNFYov86bJq8r2+ODIW1OE2Rljioc6HSHeiDRF1JuAjECwikRrUVTBTZbnK8jqY14neJsWAKBzGo+ToaQALsNZ9B91DxxL50K5oVOzw5shAS9TnRjN40+KIXFED4ydq4JRdoqb8+cN+N3i0+Cu7tdm+UaHTAQJBAOwFs3ZwqQEqmv9vmgmIFwFpJm1aIw25gEOf3Hy45GP4bL/j0FQgwcXYRbLE5bPqhw/liLKc1GQ97bVm6zs8SvUCQQDnJZA6TFRMiDjezinE1J4e0v4RupyDniVjbE5ArTK5/FRVkjw4Ny0AqZUEyIIqlTeZlCq45pCJy4a2hymDGVJxAj9gzfXNnmezEsZ//kYvoqHM8lPQhifaeTsigW7tuOf0GPCBw+6uksDnZM0xhZCxOoArBPoMSEbU1pGo1Y2lvhUCQF6E5sBgHAybm53Ich4Rz4LNRqWbSIstrR5F2I3sBRU2kInZXZSjQ1zE+7HUCB4/nFfJ1dp8NdiTCEg1Zw072pECQQDnxyQALmWhQbBTl0tq6CwYf9rZDwBzxuY+CXB8Ky1gOmXwan96KZvV4rK8MQQs6HIiYC/j+5lX3A3zlXTFldaz";
|
||||
protected static final String SAML_CLIENT_SALES_POST_SIG_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQAB";
|
||||
public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST_SIG = "http://localhost:8080/sales-post-sig/";
|
||||
public static final String SAML_CLIENT_ID_SALES_POST_SIG = "http://localhost:8081/sales-post-sig/";
|
||||
public static final String SAML_URL_SALES_POST_SIG = "http://localhost:8080/sales-post-sig/";
|
||||
public static final String SAML_CLIENT_SALES_POST_SIG_PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANUbxrvEY3pkiQNt55zJLKBwN+zKmNQw08ThAmOKzwHfXoK+xlDSFxNMtTKJGkeUdnKzaTfESEcEfKYULUA41y/NnOlvjS0CEsc7Wq0Ce63TSSGMB2NHea4tV0aQz/MwLsbmz2IjAFWHA5CHL5WwacIf3UTOSNnhJUSvnkomjJAlAgMBAAECgYANpO2gb/5+g5lSIuNFYov86bJq8r2+ODIW1OE2Rljioc6HSHeiDRF1JuAjECwikRrUVTBTZbnK8jqY14neJsWAKBzGo+ToaQALsNZ9B91DxxL50K5oVOzw5shAS9TnRjN40+KIXFED4ydq4JRdoqb8+cN+N3i0+Cu7tdm+UaHTAQJBAOwFs3ZwqQEqmv9vmgmIFwFpJm1aIw25gEOf3Hy45GP4bL/j0FQgwcXYRbLE5bPqhw/liLKc1GQ97bVm6zs8SvUCQQDnJZA6TFRMiDjezinE1J4e0v4RupyDniVjbE5ArTK5/FRVkjw4Ny0AqZUEyIIqlTeZlCq45pCJy4a2hymDGVJxAj9gzfXNnmezEsZ//kYvoqHM8lPQhifaeTsigW7tuOf0GPCBw+6uksDnZM0xhZCxOoArBPoMSEbU1pGo1Y2lvhUCQF6E5sBgHAybm53Ich4Rz4LNRqWbSIstrR5F2I3sBRU2kInZXZSjQ1zE+7HUCB4/nFfJ1dp8NdiTCEg1Zw072pECQQDnxyQALmWhQbBTl0tq6CwYf9rZDwBzxuY+CXB8Ky1gOmXwan96KZvV4rK8MQQs6HIiYC/j+5lX3A3zlXTFldaz";
|
||||
public static final String SAML_CLIENT_SALES_POST_SIG_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQAB";
|
||||
|
||||
protected static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST_ENC = "http://localhost:8080/sales-post-enc/";
|
||||
protected static final String SAML_CLIENT_ID_SALES_POST_ENC = "http://localhost:8081/sales-post-enc/";
|
||||
protected static final String SAML_CLIENT_SALES_POST_ENC_PRIVATE_KEY = "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t";
|
||||
protected static final String SAML_CLIENT_SALES_POST_ENC_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQAB";
|
||||
public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST_ENC = "http://localhost:8080/sales-post-enc/";
|
||||
public static final String SAML_CLIENT_ID_SALES_POST_ENC = "http://localhost:8081/sales-post-enc/";
|
||||
public static final String SAML_CLIENT_SALES_POST_ENC_PRIVATE_KEY = "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t";
|
||||
public static final String SAML_CLIENT_SALES_POST_ENC_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQAB";
|
||||
|
||||
|
||||
@Override
|
||||
|
|
|
@ -176,6 +176,16 @@ public class ClientBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ClientBuilder protocol(String protocol) {
|
||||
rep.setProtocol(protocol);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientBuilder enabled(Boolean enabled) {
|
||||
rep.setEnabled(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientBuilder authorizationServicesEnabled(boolean enable) {
|
||||
rep.setAuthorizationServicesEnabled(enable);
|
||||
return this;
|
||||
|
|
Loading…
Reference in a new issue