KEYCLOAK-11903 Test for XSW attacks

This commit is contained in:
Hynek Mlnarik 2020-02-07 15:55:12 +01:00 committed by Hynek Mlnařík
parent 08319db242
commit f45f882f0c
5 changed files with 414 additions and 3 deletions

View file

@ -507,6 +507,12 @@ public class SAMLEndpoint {
public Response handleSamlResponse(String samlResponse, String relayState, String clientId) { public Response handleSamlResponse(String samlResponse, String relayState, String clientId) {
SAMLDocumentHolder holder = extractResponseDocument(samlResponse); SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
if (holder == null) {
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.detail(Details.REASON, "invalid_saml_document");
event.error(Errors.INVALID_SAML_RESPONSE);
return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_FEDERATED_IDENTITY_ACTION);
}
StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject(); StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject();
// validate destination // validate destination
if (! destinationValidator.validate(session.getContext().getUri().getAbsolutePath(), statusResponse.getDestination())) { if (! destinationValidator.validate(session.getContext().getUri().getAbsolutePath(), statusResponse.getDestination())) {

View file

@ -34,19 +34,31 @@ public class HttpResponseBodyMatcher extends BaseMatcher<HttpResponse> {
private final Matcher<String> matcher; private final Matcher<String> matcher;
private ThreadLocal<String> lastEntity = new ThreadLocal<>();
public HttpResponseBodyMatcher(Matcher<String> matcher) { public HttpResponseBodyMatcher(Matcher<String> matcher) {
this.matcher = matcher; this.matcher = matcher;
} }
@Override @Override
public boolean matches(Object item) { public boolean matches(Object item) {
lastEntity.remove();
try { try {
return (item instanceof HttpResponse) && this.matcher.matches(EntityUtils.toString(((HttpResponse) item).getEntity())); lastEntity.set(EntityUtils.toString(((HttpResponse) item).getEntity()));
return (item instanceof HttpResponse) && this.matcher.matches(lastEntity.get());
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@Override
public void describeMismatch(Object item, Description description) {
Description d = description.appendText("was ").appendValue(item);
if (lastEntity.get() != null) {
d.appendText(" with entity ").appendText(lastEntity.get());
}
}
@Override @Override
public void describeTo(Description description) { public void describeTo(Description description) {
description.appendText("response body matches ").appendDescriptionOf(this.matcher); description.appendText("response body matches ").appendDescriptionOf(this.matcher);

View file

@ -0,0 +1,379 @@
/*
* Copyright 2019 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.adapter.servlet;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
import org.keycloak.protocol.saml.SamlConfigAttributes;
import org.keycloak.protocol.saml.SamlProtocol;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.adapter.AbstractAdapterTest;
import org.keycloak.testsuite.adapter.page.SalesPostAssertionAndResponseSig;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
import org.keycloak.testsuite.updaters.Creator;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.IdentityProviderBuilder;
import org.keycloak.testsuite.util.Matchers;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.RoleBuilder;
import org.keycloak.testsuite.util.RolesBuilder;
import org.junit.Test;
import org.keycloak.testsuite.util.SamlClient.Binding;
import org.keycloak.testsuite.util.SamlClientBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
import java.net.URI;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.ws.rs.core.Response.Status;
import javax.xml.crypto.dsig.XMLSignature;
import org.apache.http.client.methods.CloseableHttpResponse;
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.Assume;
import org.junit.Before;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION_NSURI;
import static org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_NSURI;
import static org.keycloak.testsuite.adapter.AbstractServletsAdapterTest.samlServletDeployment;
import static org.keycloak.testsuite.saml.AbstractSamlTest.REALM_NAME;
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.saml.AbstractSamlTest.REALM_SIGNING_CERTIFICATE;
/**
*
* @author hmlnarik
*/
@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)
public class SamlSignatureTest extends AbstractAdapterTest {
private static final String REQUIRED_ROLE_NAME = "manager";
private static final RoleRepresentation REQUIRED_ROLE = RoleBuilder.create().name(REQUIRED_ROLE_NAME).build();
private static final String BROKER = "broker";
private static final String APP_CLIENT_ID = "http://localhost:8280/sales-post-assertion-and-response-sig/";
// Based on https://github.com/SAMLRaider/SAMLRaider/blob/master/src/main/java/helpers/XSWHelpers.java
public static class XSWHelpers {
/*
* Following are the 8 common XML Signature Wrapping attacks implemented, which were found
* in a paper called "On Breaking SAML: Be Whoever You Want to Be"
* */
public static void applyXSW1(Document document){
Element response = (Element) document.getElementsByTagNameNS(PROTOCOL_NSURI.get(), "Response").item(0);
Element clonedResponse = (Element) response.cloneNode(true);
Element clonedSignature = (Element) clonedResponse.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Response needs to be signed", clonedSignature, notNullValue());
clonedResponse.removeChild(clonedSignature);
Element signature = (Element) response.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
signature.appendChild(clonedResponse);
response.setAttribute("ID", "_evil_response_ID");
}
public static void applyXSW2(Document document){
Element response = (Element) document.getElementsByTagNameNS(PROTOCOL_NSURI.get(), "Response").item(0);
Element clonedResponse = (Element) response.cloneNode(true);
Element clonedSignature = (Element) clonedResponse.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Response needs to be signed", clonedSignature, notNullValue());
clonedResponse.removeChild(clonedSignature);
Element signature = (Element) response.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
response.insertBefore(clonedResponse, signature);
response.setAttribute("ID", "_evil_response_ID");
}
public static void applyXSW3(Document document){
Element assertion = (Element) document.getElementsByTagNameNS(ASSERTION_NSURI.get(), "Assertion").item(0);
Element evilAssertion = (Element) assertion.cloneNode(true);
Element copiedSignature = (Element) evilAssertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Assertion needs to be signed", copiedSignature, notNullValue());
evilAssertion.setAttribute("ID", "_evil_assertion_ID");
evilAssertion.removeChild(copiedSignature);
document.getDocumentElement().insertBefore(evilAssertion, assertion);
}
public static void applyXSW4(Document document){
Element assertion = (Element) document.getElementsByTagNameNS(ASSERTION_NSURI.get(), "Assertion").item(0);
Element evilAssertion = (Element) assertion.cloneNode(true);
Element copiedSignature = (Element) evilAssertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Assertion needs to be signed", copiedSignature, notNullValue());
evilAssertion.setAttribute("ID", "_evil_assertion_ID");
evilAssertion.removeChild(copiedSignature);
document.getDocumentElement().appendChild(evilAssertion);
evilAssertion.appendChild(assertion);
}
public static void applyXSW5(Document document){
Element evilAssertion = (Element) document.getElementsByTagNameNS(ASSERTION_NSURI.get(), "Assertion").item(0);
Element assertion = (Element) evilAssertion.cloneNode(true);
Element copiedSignature = (Element) assertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Assertion needs to be signed", copiedSignature, notNullValue());
assertion.removeChild(copiedSignature);
document.getDocumentElement().appendChild(assertion);
evilAssertion.setAttribute("ID", "_evil_assertion_ID");
}
public static void applyXSW6(Document document){
Element evilAssertion = (Element) document.getElementsByTagNameNS(ASSERTION_NSURI.get(), "Assertion").item(0);
Element originalSignature = (Element) evilAssertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Element assertion = (Element) evilAssertion.cloneNode(true);
Element copiedSignature = (Element) assertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Assertion needs to be signed", copiedSignature, notNullValue());
assertion.removeChild(copiedSignature);
originalSignature.appendChild(assertion);
evilAssertion.setAttribute("ID", "_evil_assertion_ID");
}
public static void applyXSW7(Document document){
Element assertion = (Element) document.getElementsByTagNameNS(ASSERTION_NSURI.get(), "Assertion").item(0);
Element extensions = document.createElement("Extensions");
document.getDocumentElement().insertBefore(extensions, assertion);
Element evilAssertion = (Element) assertion.cloneNode(true);
Element copiedSignature = (Element) evilAssertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Assertion needs to be signed", copiedSignature, notNullValue());
evilAssertion.removeChild(copiedSignature);
extensions.appendChild(evilAssertion);
}
public static void applyXSW8(Document document){
Element evilAssertion = (Element) document.getElementsByTagNameNS(ASSERTION_NSURI.get(), "Assertion").item(0);
Element originalSignature = (Element) evilAssertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Element assertion = (Element) evilAssertion.cloneNode(true);
Element copiedSignature = (Element) assertion.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
Assume.assumeThat("Assertion needs to be signed", copiedSignature, notNullValue());
assertion.removeChild(copiedSignature);
Element object = document.createElement("Object");
originalSignature.appendChild(object);
object.appendChild(assertion);
}
}
@Page
private SalesPostAssertionAndResponseSig salesPostAssertionAndResponseSigPage;
private UserRepresentation user;
@Deployment(name = SalesPostAssertionAndResponseSig.DEPLOYMENT_NAME)
protected static WebArchive salesPostAssertionAndResponseSig() {
return samlServletDeployment(SalesPostAssertionAndResponseSig.DEPLOYMENT_NAME, SendUsernameServlet.class);
}
@Override
protected boolean isImportAfterEachMethod() {
return false;
}
private static ClientBuilder signingSamlClient(String clientId) {
return ClientBuilder.create()
.protocol(SamlProtocol.LOGIN_PROTOCOL)
.enabled(true)
.attribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, "true")
.attribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE, "username")
.attribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true")
.attribute(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM, "RSA_SHA256")
.attribute(SamlConfigAttributes.SAML_AUTHNSTATEMENT, "true")
.clientId(clientId);
}
@Override
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
final ClientBuilder salesPostClient = signingSamlClient(APP_CLIENT_ID)
.baseUrl("http://localhost:8080/sales-post-assertion-and-response-sig")
.redirectUris("http://localhost:8080/sales-post-assertion-and-response-sig/*");
final String brokerBaseUrl = getAuthServerRoot() + "realms/" + BROKER;
final ClientBuilder brokerRealmIdPClient = signingSamlClient(brokerBaseUrl)
.baseUrl(brokerBaseUrl + "/broker/" + REALM_NAME + "/endpoint")
.redirectUris(brokerBaseUrl + "/broker/" + REALM_NAME + "/endpoint");
testRealms.add(RealmBuilder.create()
.name(REALM_NAME)
.publicKey(REALM_PUBLIC_KEY)
.privateKey(REALM_PRIVATE_KEY)
.client(salesPostClient)
.client(brokerRealmIdPClient)
.roles(RolesBuilder.create().realmRole(REQUIRED_ROLE))
.build()
);
testRealms.add(RealmBuilder.create()
.name(BROKER)
.publicKey(REALM_PUBLIC_KEY)
.privateKey(REALM_PRIVATE_KEY)
.client(salesPostClient)
.identityProvider(IdentityProviderBuilder.create()
.alias(REALM_NAME)
.providerId(SAMLIdentityProviderFactory.PROVIDER_ID)
.setAttribute(SAMLIdentityProviderConfig.SINGLE_SIGN_ON_SERVICE_URL, getAuthServerRoot() + "realms/" + REALM_NAME + "/protocol/saml")
.setAttribute(SAMLIdentityProviderConfig.POST_BINDING_AUTHN_REQUEST, "true")
.setAttribute(SAMLIdentityProviderConfig.POST_BINDING_RESPONSE, "true")
.setAttribute(SAMLIdentityProviderConfig.SIGNING_CERTIFICATE_KEY, REALM_SIGNING_CERTIFICATE)
.setAttribute(SAMLIdentityProviderConfig.WANT_ASSERTIONS_SIGNED, "true")
.setAttribute(SAMLIdentityProviderConfig.VALIDATE_SIGNATURE, "true")
)
.roles(RolesBuilder.create().realmRole(REQUIRED_ROLE))
.build()
);
}
@Before
public void addFreshUserToDemoRealm() {
this.user = UserBuilder.edit(createUserRepresentation(("U-" + UUID.randomUUID().toString()).toLowerCase(), "a@b.c", "A", "B", true))
.password("password")
.build();
Creator<UserResource> c = Creator.create(adminClient.realm(REALM_NAME), user);
getCleanup(REALM_NAME).addCleanup(c);
List<RoleRepresentation> reqRoleToJoin = c.resource().roles().realmLevel().listAvailable().stream().filter(r -> r.getName().equals(REQUIRED_ROLE_NAME)).collect(Collectors.toList());
c.resource().roles().realmLevel().add(reqRoleToJoin);
}
private void testSamlResponseModifications(Consumer<Document> samlResponseModifier, boolean shouldPass) throws Exception {
final Consumer<CloseableHttpResponse> clientAssertions = shouldPass ? this::assertCorrectUserLoggedIn : SamlSignatureTest::assertUserAccessDenied;
final Consumer<CloseableHttpResponse> brokerAssertions = shouldPass ? SamlSignatureTest::assertUpdateProfilePage : SamlSignatureTest::assertNotUpdateProfilePage;
testSamlResponseModificationsClient(samlResponseModifier, clientAssertions);
testSamlResponseModificationsBroker(samlResponseModifier, brokerAssertions);
}
private void testSamlResponseModificationsBroker(Consumer<Document> samlResponseModifier, Consumer<CloseableHttpResponse> assertions) throws Exception {
new SamlClientBuilder()
.authnRequest(new URI(getAuthServerRoot() + "realms/" + BROKER + "/protocol/saml"), APP_CLIENT_ID, salesPostAssertionAndResponseSigPage.toString(), Binding.POST).build()
.login().idp(REALM_NAME).build()
.processSamlResponse(Binding.POST).build()
.login().user(user).build()
.processSamlResponse(Binding.POST).transformDocument(d -> { samlResponseModifier.accept(d); return d; }).build()
.executeAndTransform(r -> { assertions.accept(r); return null; });
}
private void testSamlResponseModificationsClient(Consumer<Document> samlResponseModifier, Consumer<CloseableHttpResponse> assertions) {
new SamlClientBuilder()
.navigateTo(salesPostAssertionAndResponseSigPage)
.processSamlResponse(Binding.POST).build()
.login().user(user).build()
.processSamlResponse(Binding.POST).transformDocument(d -> { samlResponseModifier.accept(d); return d; }).build()
.executeAndTransform(r -> { assertions.accept(r); return null; });
}
private void assertCorrectUserLoggedIn(CloseableHttpResponse response) {
assertThat(response, Matchers.statusCodeHC(is(Status.OK.getStatusCode())));
assertThat(response, Matchers.bodyHC(containsString(user.getUsername())));
}
private static void assertUpdateProfilePage(CloseableHttpResponse response) {
assertThat(response, Matchers.statusCodeIsHC(Status.OK));
assertThat(response, Matchers.bodyHC(containsString("Update Account Information")));
}
private static void assertNotUpdateProfilePage(CloseableHttpResponse response) {
assertThat(response, Matchers.statusCodeHC(greaterThanOrEqualTo(400)));
assertThat(response, Matchers.bodyHC(not(containsString("Update Account Information"))));
}
private static void assertUserAccessDenied(CloseableHttpResponse response) {
assertThat(response, Matchers.bodyHC(
anyOf(
containsString("INVALID_SIGNATURE"),
containsString("There was an error")
)
));
}
private static void removeAllSignatures(Document doc) throws DOMException {
NodeList signatures;
while ((signatures = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature")).getLength() > 0) {
Node s = signatures.item(0);
s.getParentNode().removeChild(s);
}
}
@Test
public void testNoChange() throws Exception {
testSamlResponseModifications(r -> {}, true);
}
@Test
public void testRemoveSignatures() throws Exception {
testSamlResponseModifications(SamlSignatureTest::removeAllSignatures, false);
}
@Test
public void testXSW1() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW1, false);
}
@Test
public void testXSW2() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW2, false);
}
@Test
public void testXSW3() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW3, false);
}
@Test
public void testXSW4() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW4, false);
}
@Test
public void testXSW5() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW5, false);
}
@Test
public void testXSW6() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW6, false);
}
@Test
public void testXSW7() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW7, false);
}
@Test
public void testXSW8() throws Exception {
testSamlResponseModifications(XSWHelpers::applyXSW8, false);
}
}

View file

@ -25,6 +25,7 @@ public abstract class AbstractSamlTest extends AbstractAuthTest {
public static final String REALM_NAME = "demo"; 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_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"; public static final String REALM_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
public static final String REALM_SIGNING_CERTIFICATE = "MIIBkTCB+wIGAUkZB1wLMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNVBAMTBGRlbW8wHhcNMTQxMDE2MTI1NDEzWhcNMjQxMDE2MTI1NTUzWjAPMQ0wCwYDVQQDEwRkZW1vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAI9moVwZxiEvzfvyL0zqyzRP4qnEdYQ/l/Nl78OAed25hdKpVpNv8i7DwM1QscWQhrtfGImD0480eoOUfe1rU9k6gNdNpR6kYAz17A/OsovpTFF0cIQE7HPqumpHfdbeW0jEjLNT2Od/PXdaIijVOdbJn8iF//nnItrwPbNUBU75";
public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = AUTH_SERVER_SCHEME + "://localhost:" + (AUTH_SERVER_SSL_REQUIRED ? AUTH_SERVER_PORT : 8080) + "/sales-post/saml"; public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = AUTH_SERVER_SCHEME + "://localhost:" + (AUTH_SERVER_SSL_REQUIRED ? AUTH_SERVER_PORT : 8080) + "/sales-post/saml";
public static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8280/sales-post/"; public static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8280/sales-post/";

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RolesRepresentation; import org.keycloak.representations.idm.RolesRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
@ -124,19 +125,31 @@ public class RealmBuilder {
public RealmBuilder client(ClientRepresentation client) { public RealmBuilder client(ClientRepresentation client) {
if (rep.getClients() == null) { if (rep.getClients() == null) {
rep.setClients(new LinkedList<ClientRepresentation>()); rep.setClients(new LinkedList<>());
} }
rep.getClients().add(client); rep.getClients().add(client);
return this; return this;
} }
public RealmBuilder identityProvider(IdentityProviderBuilder identityProvider) {
return identityProvider(identityProvider.build());
}
public RealmBuilder identityProvider(IdentityProviderRepresentation identityProvider) {
if (rep.getIdentityProviders()== null) {
rep.setIdentityProviders(new LinkedList<>());
}
rep.getIdentityProviders().add(identityProvider);
return this;
}
public RealmBuilder user(UserBuilder user) { public RealmBuilder user(UserBuilder user) {
return user(user.build()); return user(user.build());
} }
public RealmBuilder user(UserRepresentation user) { public RealmBuilder user(UserRepresentation user) {
if (rep.getUsers() == null) { if (rep.getUsers() == null) {
rep.setUsers(new LinkedList<UserRepresentation>()); rep.setUsers(new LinkedList<>());
} }
rep.getUsers().add(user); rep.getUsers().add(user);
return this; return this;