keycloak-aplcache

Merge pull request #4693 from hmlnarik/KEYCLOAK-5349-JS-client-breaks-login-session KEYCLOAK-5349

11/15/2017 9:35:19 AM

Details

diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlIdPInitiatedSsoTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlIdPInitiatedSsoTest.java
index 5659c94..bf136fd 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlIdPInitiatedSsoTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlIdPInitiatedSsoTest.java
@@ -5,42 +5,49 @@
  */
 package org.keycloak.testsuite.broker;
 
+import org.keycloak.admin.client.resource.ClientsResource;
 import org.keycloak.admin.client.resource.UsersResource;
 import org.keycloak.common.util.StreamUtil;
 import org.keycloak.common.util.StringPropertyReplacer;
+import org.keycloak.dom.saml.v2.protocol.ResponseType;
 import org.keycloak.representations.idm.ClientRepresentation;
-import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.Assert;
-import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
-import org.keycloak.testsuite.adapter.page.SalesPostServlet;
-import org.keycloak.testsuite.adapter.servlet.SendUsernameServlet;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
 import org.keycloak.testsuite.util.IOUtil;
 
+import org.keycloak.testsuite.util.Matchers;
+import org.keycloak.testsuite.util.SamlClient.Binding;
+import org.keycloak.testsuite.util.SamlClientBuilder;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import org.jboss.arquillian.container.test.api.Deployment;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.ws.rs.core.Response;
 import org.jboss.arquillian.graphene.page.Page;
-import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Before;
 import org.junit.Test;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.support.ui.ExpectedCondition;
 import org.openqa.selenium.support.ui.WebDriverWait;
 
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
 import static org.keycloak.testsuite.broker.BrokerTestConstants.*;
-import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
 
 /**
  *
@@ -51,6 +58,8 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
     private static final String PROVIDER_REALM_USER_NAME = "test";
     private static final String PROVIDER_REALM_USER_PASSWORD = "test";
 
+    private static final String CONSUMER_CHOSEN_USERNAME = "mytest";
+
     @Page
     protected LoginPage accountLoginPage;
 
@@ -72,6 +81,15 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
         }
     }
 
+    @Before
+    public void cleanupTestUserInConsumerRealm() {
+        final UsersResource users = adminClient.realm(REALM_CONS_NAME).users();
+        users.search(CONSUMER_CHOSEN_USERNAME).stream()
+          .map(UserRepresentation::getId)
+          .map(users::delete)
+          .forEach(Response::close);
+    }
+
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
         Properties p = new Properties();
@@ -79,6 +97,7 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
         p.put("name.realm.consumer", REALM_CONS_NAME);
         p.put("url.realm.provider", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME);
         p.put("url.realm.consumer", getAuthRoot() + "/auth/realms/" + REALM_CONS_NAME);
+        p.put("url.realm.consumer-2", getAuthRoot() + "/auth/realms/" + REALM_CONS_NAME + "-2");
         
         testRealms.add(loadFromClasspath("kc3731-provider-realm.json", p));
         testRealms.add(loadFromClasspath("kc3731-broker-realm.json", p));
@@ -103,7 +122,7 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
                 driver.getCurrentUrl(), containsString("/auth/realms/" + REALM_CONS_NAME + "/"));
 
         log.debug("Updating info on updateAccount page");
-        updateAccountInformationPage.updateAccountInformation("mytest", "test@localhost", "Firstname", "Lastname");
+        updateAccountInformationPage.updateAccountInformation(CONSUMER_CHOSEN_USERNAME, "test@localhost", "Firstname", "Lastname");
 
         UsersResource consumerUsers = adminClient.realm(REALM_CONS_NAME).users();
 
@@ -112,8 +131,8 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
 
         List<UserRepresentation> users = consumerUsers.search("", 0, userCount);
 
-        boolean isUserFound = users.stream().anyMatch(user -> user.getUsername().equals("mytest") && user.getEmail().equals("test@localhost"));
-        Assert.assertTrue("There must be user " + "mytest" + " in realm " + REALM_CONS_NAME, isUserFound);
+        boolean isUserFound = users.stream().anyMatch(user -> user.getUsername().equals(CONSUMER_CHOSEN_USERNAME) && user.getEmail().equals("test@localhost"));
+        Assert.assertTrue("There must be user " + CONSUMER_CHOSEN_USERNAME + " in realm " + REALM_CONS_NAME, isUserFound);
 
         Assert.assertThat(driver.findElement(By.tagName("a")).getAttribute("id"), containsString("account"));
     }
@@ -122,6 +141,10 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
         return getAuthRoot() + "/auth/realms/" + realmName + "/protocol/saml/clients/" + samlIdpInitiatedSsoUrlName;
     }
 
+    private String getSamlBrokerIdpInitiatedUrl(String realmName, String samlIdpInitiatedSsoUrlName) {
+        return getAuthRoot() + "/auth/realms/" + realmName + "/broker/saml-leaf/endpoint/clients/" + samlIdpInitiatedSsoUrlName;
+    }
+
     private void waitForPage(final String title) {
         WebDriverWait wait = new WebDriverWait(driver, 5);
 
@@ -130,4 +153,115 @@ public class KcSamlIdPInitiatedSsoTest extends AbstractKeycloakTest {
         wait.until(condition);
     }
 
+    @Test
+    public void testProviderIdpInitiatedLoginToApp() {
+        SAMLDocumentHolder samlResponse = new SamlClientBuilder()
+          .navigateTo(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker"))
+          // Login in provider realm
+          .login().user(PROVIDER_REALM_USER_NAME, PROVIDER_REALM_USER_PASSWORD).build()
+
+          // Send the response to the consumer realm
+          .processSamlResponse(Binding.POST)
+          .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is(getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales")));
+              return ob;
+          })
+          .build()
+
+          .updateProfile().username(CONSUMER_CHOSEN_USERNAME).email("test@localhost").firstName("Firstname").lastName("Lastname").build()
+          .followOneRedirect()
+
+          // Obtain the response sent to the app
+          .getSamlResponse(Binding.POST);
+
+        assertThat(samlResponse.getSamlObject(), Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+        ResponseType resp = (ResponseType) samlResponse.getSamlObject();
+        assertThat(resp.getDestination(), is("http://localhost:8180/auth/realms/" + REALM_CONS_NAME + "/app/auth"));
+    }
+
+    @Test
+    public void testTwoConsequentIdpInitiatedLogins() {
+        SAMLDocumentHolder samlResponse = new SamlClientBuilder()
+          .navigateTo(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker"))
+          // Login in provider realm
+          .login().user(PROVIDER_REALM_USER_NAME, PROVIDER_REALM_USER_PASSWORD).build()
+
+          // Send the response to the consumer realm
+          .processSamlResponse(Binding.POST)
+            .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is(getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales")));
+              return ob;
+            })
+            .build()
+
+          .updateProfile().username(CONSUMER_CHOSEN_USERNAME).email("test@localhost").firstName("Firstname").lastName("Lastname").build()
+          .followOneRedirect()
+
+          // Obtain the response sent to the app and ignore result
+          .processSamlResponse(Binding.POST)
+            .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is("http://localhost:8180/auth/realms/" + REALM_CONS_NAME + "/app/auth"));
+              return null;
+            })
+            .build()
+
+
+          // Now login to the second app
+          .navigateTo(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker-2"))
+
+          // Login in provider realm
+          .login().sso(true).build()
+
+          // Send the response to the consumer realm
+          .processSamlResponse(Binding.POST)
+            .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is(getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales2")));
+              return ob;
+            })
+            .build()
+
+          .getSamlResponse(Binding.POST);
+
+        assertThat(samlResponse.getSamlObject(), Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+        ResponseType resp = (ResponseType) samlResponse.getSamlObject();
+        assertThat(resp.getDestination(), is("http://localhost:8180/auth/realms/" + REALM_CONS_NAME + "/app/auth/sales2/saml"));
+
+        assertSingleUserSession(REALM_CONS_NAME, CONSUMER_CHOSEN_USERNAME,
+          "http://localhost:8180/auth/realms/" + REALM_CONS_NAME + "/app/auth",
+          "http://localhost:8180/auth/realms/" + REALM_CONS_NAME + "/app/auth2"
+        );
+
+        assertSingleUserSession(REALM_PROV_NAME, PROVIDER_REALM_USER_NAME,
+          getAuthRoot() + "/auth/realms/" + REALM_CONS_NAME,
+          getAuthRoot() + "/auth/realms/" + REALM_CONS_NAME + "-2"
+        );
+    }
+
+    private void assertSingleUserSession(String realmName, String userName, String... expectedClientIds) {
+        final UsersResource users = adminClient.realm(realmName).users();
+        final ClientsResource clients = adminClient.realm(realmName).clients();
+
+        UserRepresentation userRepresentation = users
+          .search(userName).stream()
+          .findFirst().get();
+
+        List<UserSessionRepresentation> userSessions = users.get(userRepresentation.getId()).getUserSessions();
+        assertThat(userSessions, hasSize(1));
+        Map<String, String> clientSessions = userSessions.get(0).getClients();
+
+        Set<String> clientIds = clientSessions.values().stream()
+          .flatMap(c -> clients.findByClientId(c).stream())
+          .map(ClientRepresentation::getClientId)
+          .collect(Collectors.toSet());
+
+        assertThat(clientIds, containsInAnyOrder(expectedClientIds));
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AbstractSamlTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AbstractSamlTest.java
index fbc1e15..f4ed86e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AbstractSamlTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AbstractSamlTest.java
@@ -23,10 +23,10 @@ public abstract class AbstractSamlTest extends AbstractAuthTest {
     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 SAML_ASSERTION_CONSUMER_URL_SALES_POST = "http://localhost:8080/sales-post/";
+    public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST = "http://localhost:8080/sales-post/saml";
     public static final String SAML_CLIENT_ID_SALES_POST = "http://localhost:8081/sales-post/";
 
-    public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST2 = "http://localhost:8080/sales-post2/";
+    public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST2 = "http://localhost:8080/sales-post2/saml";
     public static final String SAML_CLIENT_ID_SALES_POST2 = "http://localhost:8081/sales-post2/";
 
     public static final String SAML_ASSERTION_CONSUMER_URL_SALES_POST_SIG = "http://localhost:8080/sales-post-sig/";
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java
new file mode 100644
index 0000000..2cabc0e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.saml;
+
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.testsuite.util.Matchers;
+import org.keycloak.testsuite.util.SamlClient.Binding;
+import org.keycloak.testsuite.util.SamlClientBuilder;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertThat;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class IdpInitiatedLoginTest extends AbstractSamlTest {
+
+    @Test
+    public void testIdpInitiatedLogin() {
+        new SamlClientBuilder()
+          .idpInitiatedLogin(getAuthServerSamlEndpoint(REALM_NAME), "sales-post").build()
+          .login().user(bburkeUser).build()
+          .processSamlResponse(Binding.POST)
+            .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is(SAML_ASSERTION_CONSUMER_URL_SALES_POST));
+              return null;
+            })
+            .build()
+          .execute()
+        ;
+    }
+
+    @Test
+    public void testTwoConsequentIdpInitiatedLogins() {
+        new SamlClientBuilder()
+          .idpInitiatedLogin(getAuthServerSamlEndpoint(REALM_NAME), "sales-post").build()
+          .login().user(bburkeUser).build()
+          .processSamlResponse(Binding.POST)
+            .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is(SAML_ASSERTION_CONSUMER_URL_SALES_POST));
+              return null;
+            })
+            .build()
+
+          .idpInitiatedLogin(getAuthServerSamlEndpoint(REALM_NAME), "sales-post2").build()
+          .login().sso(true).build()
+          .processSamlResponse(Binding.POST)
+            .transformObject(ob -> {
+              assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
+              ResponseType resp = (ResponseType) ob;
+              assertThat(resp.getDestination(), is(SAML_ASSERTION_CONSUMER_URL_SALES_POST2));
+              return null;
+            })
+            .build()
+
+          .execute()
+        ;
+
+        final UsersResource users = adminClient.realm(REALM_NAME).users();
+        final ClientsResource clients = adminClient.realm(REALM_NAME).clients();
+
+        UserRepresentation bburkeUserRepresentation = users
+          .search(bburkeUser.getUsername()).stream()
+          .findFirst().get();
+
+        List<UserSessionRepresentation> userSessions = users.get(bburkeUserRepresentation.getId()).getUserSessions();
+        assertThat(userSessions, hasSize(1));
+        Map<String, String> clientSessions = userSessions.get(0).getClients();
+
+        Set<String> clientIds = clientSessions.values().stream()
+          .flatMap(c -> clients.findByClientId(c).stream())
+          .map(ClientRepresentation::getClientId)
+          .collect(Collectors.toSet());
+
+        assertThat(clientIds, containsInAnyOrder(SAML_CLIENT_ID_SALES_POST, SAML_CLIENT_ID_SALES_POST2));
+
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json
index aed0231..4f390b9 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/testsaml.json
@@ -188,6 +188,8 @@
                 "http://localhost:8080/sales-post/*"
             ],
             "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8080/sales-post/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8080/sales-post/saml",
                 "saml.authnstatement": "true",
                 "saml_idp_initiated_sso_url_name": "sales-post"
             }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-broker-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-broker-realm.json
index 190bb08..0ed5ed3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-broker-realm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-broker-realm.json
@@ -26,10 +26,32 @@
       "saml.signature.algorithm": "RSA_SHA512",
       "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
       "saml.signing.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",
+      "saml_assertion_consumer_url_post" : "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth",
       "saml_idp_initiated_sso_url_name" : "sales"
     },
     "baseUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth",
     "adminUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth"
+  }, {
+    "clientId": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth2",
+    "enabled": true,
+    "protocol": "saml",
+    "fullScopeAllowed": true,
+    "redirectUris": [
+      "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth2/*"
+    ],
+    "attributes": {
+      "saml.authnstatement": "true",
+      "saml.client.signature": "true",
+      "saml.encrypt": "false",
+      "saml.server.signature": "true",
+      "saml.signature.algorithm": "RSA_SHA512",
+      "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
+      "saml.signing.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",
+      "saml_assertion_consumer_url_post" : "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth/sales2/saml",
+      "saml_idp_initiated_sso_url_name" : "sales2"
+    },
+    "baseUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth2",
+    "adminUrl": "http://localhost:8180/auth/realms/${name.realm.consumer}/app/auth2"
   } ],
   "identityProviders" : [ {
     "alias" : "saml-leaf",
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-provider-realm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-provider-realm.json
index 8804a36..d660118 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-provider-realm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/broker/kc3731-provider-realm.json
@@ -28,7 +28,28 @@
       "saml_assertion_consumer_url_post" : "${url.realm.consumer}/broker/saml-leaf/endpoint/clients/sales",
       "saml_force_name_id_format" : "false",
       "saml_idp_initiated_sso_url_name" : "samlbroker",
-      "saml_name_id_format" : "persistent",
+      "saml_name_id_format": "email",
+      "saml_single_logout_service_url_post" : "${url.realm.consumer}/broker/saml-leaf/endpoint"
+    }
+  }, {
+    "clientId": "${url.realm.consumer-2}",
+    "enabled": true,
+    "protocol": "saml",
+    "fullScopeAllowed": true,
+    "redirectUris": [
+      "${url.realm.consumer}/broker/saml-leaf/endpoint"
+    ],
+    "attributes" : {
+      "saml_name_id_format": "email",
+      "saml.assertion.signature" : "false",
+      "saml.authnstatement" : "true",
+      "saml.client.signature" : "false",
+      "saml.encrypt" : "false",
+      "saml.force.post.binding" : "true",
+      "saml.server.signature" : "false",
+      "saml_assertion_consumer_url_post" : "${url.realm.consumer}/broker/saml-leaf/endpoint/clients/sales2",
+      "saml_force_name_id_format" : "false",
+      "saml_idp_initiated_sso_url_name" : "samlbroker-2",
       "saml_single_logout_service_url_post" : "${url.realm.consumer}/broker/saml-leaf/endpoint"
     }
   } ],