keycloak-aplcache

Merge pull request #938 from pedroigor/KEYCLOAK-883 [KEYCLOAK-883]

1/29/2015 9:11:39 AM

Changes

Details

diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index c389b1d..8dc36a1 100644
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -199,7 +199,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
 
     private void validateSignature(SAML2Request saml2Request) throws ProcessingException {
         if (getConfig().isValidateSignature()) {
-            X509Certificate certificate = XMLSignatureUtil.getX509CertificateFromKeyInfoString(getConfig().getSigningPublicKey().replaceAll("\\s", ""));
+            X509Certificate certificate = XMLSignatureUtil.getX509CertificateFromKeyInfoString(getConfig().getSigningCertificate().replaceAll("\\s", ""));
             SAMLDocumentHolder samlDocumentHolder = saml2Request.getSamlDocumentHolder();
             Document samlDocument = samlDocumentHolder.getSamlDocument();
 
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
index e4be0eb..98ebb28 100644
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
@@ -55,20 +55,20 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
         getConfig().put("forceAuthn", String.valueOf(forceAuthn));
     }
 
-    public String getSigningPublicKey() {
-        return getConfig().get("signingPublicKey");
+    public String getSigningCertificate() {
+        return getConfig().get("signingCertificate");
     }
 
-    public void setSigningPublicKey(String signingPublicKey) {
-        getConfig().put("signingPublicKey", signingPublicKey);
+    public void setSigningCertificate(String signingCertificate) {
+        getConfig().put("signingCertificate", signingCertificate);
     }
 
     public String getNameIDPolicyFormat() {
         return getConfig().get("nameIDPolicyFormat");
     }
 
-    public void setNameIDPolicyFormat(String signingPublicKey) {
-        getConfig().put("nameIDPolicyFormat", signingPublicKey);
+    public void setNameIDPolicyFormat(String nameIDPolicyFormat) {
+        getConfig().put("nameIDPolicyFormat", nameIDPolicyFormat);
     }
 
     public boolean isWantAuthnRequestsSigned() {
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
index 9b1e551..613e8fc 100644
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
@@ -83,7 +83,7 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
                         samlIdentityProviderConfig.setPostBindingResponse(true);
 
                         List<KeyDescriptorType> keyDescriptor = idpDescriptor.getKeyDescriptor();
-                        String defaultPublicKey = null;
+                        String defaultCertificate = null;
 
                         if (keyDescriptor != null) {
                             for (KeyDescriptorType keyDescriptorType : keyDescriptor) {
@@ -91,22 +91,22 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
                                 Element x509KeyInfo = DocumentUtil.getChildElement(keyInfo, new QName("dsig", "X509Certificate"));
 
                                 if (KeyTypes.SIGNING.equals(keyDescriptorType.getUse())) {
-                                    samlIdentityProviderConfig.setSigningPublicKey(x509KeyInfo.getTextContent());
+                                    samlIdentityProviderConfig.setSigningCertificate(x509KeyInfo.getTextContent());
                                 } else if (KeyTypes.ENCRYPTION.equals(keyDescriptorType.getUse())) {
                                     samlIdentityProviderConfig.setEncryptionPublicKey(x509KeyInfo.getTextContent());
                                 } else if (keyDescriptorType.getUse() ==  null) {
-                                    defaultPublicKey = x509KeyInfo.getTextContent();
+                                    defaultCertificate = x509KeyInfo.getTextContent();
                                 }
                             }
                         }
 
-                        if (defaultPublicKey != null) {
-                            if (samlIdentityProviderConfig.getSigningPublicKey() == null) {
-                                samlIdentityProviderConfig.setSigningPublicKey(defaultPublicKey);
+                        if (defaultCertificate != null) {
+                            if (samlIdentityProviderConfig.getSigningCertificate() == null) {
+                                samlIdentityProviderConfig.setSigningCertificate(defaultCertificate);
                             }
 
                             if (samlIdentityProviderConfig.getEncryptionPublicKey() == null) {
-                                samlIdentityProviderConfig.setEncryptionPublicKey(defaultPublicKey);
+                                samlIdentityProviderConfig.setEncryptionPublicKey(defaultCertificate);
                             }
                         }
 
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
index 5a87057..e5ba81f 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
@@ -52,11 +52,11 @@
                         <span tooltip-placement="right" tooltip="Specifies the URI reference corresponding to a name identifier format. Defaults to urn:oasis:names:tc:SAML:2.0:nameid-format:persistent." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group clearfix" data-ng-show="!importFile">
-                        <label class="col-sm-2 control-label" for="signingPublicKey">Signing Public Key</label>
+                        <label class="col-sm-2 control-label" for="signingCertificate">Validating X509 Certificate</label>
                         <div class="col-sm-4">
-                            <textarea class="form-control" id="signingPublicKey" ng-model="identityProvider.config.signingPublicKey"/>
+                            <textarea class="form-control" id="signingCertificate" ng-model="identityProvider.config.signingCertificate"/>
                         </div>
-                        <span tooltip-placement="right" tooltip="The public key that must be used to check for signatures." class="fa fa-info-circle"></span>
+                        <span tooltip-placement="right" tooltip="The certificate in PEM format that must be used to check for signatures." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group" data-ng-show="!importFile">
                         <label class="col-sm-2 control-label" for="wantAuthnRequestsSigned">Want AuthnRequests Signed</label>
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index 0a13d92..bfc5a95 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -124,7 +124,12 @@ public class CachedRealm {
 
         requiredCredentials = model.getRequiredCredentials();
         userFederationProviders = model.getUserFederationProviders();
-        identityProviders = model.getIdentityProviders();
+
+        this.identityProviders = new ArrayList<IdentityProviderModel>();
+
+        for (IdentityProviderModel identityProviderModel : model.getIdentityProviders()) {
+            this.identityProviders.add(new IdentityProviderModel(identityProviderModel));
+        }
 
         smtpConfig.putAll(model.getSmtpConfig());
         browserSecurityHeaders.putAll(model.getBrowserSecurityHeaders());
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
index 60feca8..5dc22d2 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
@@ -72,7 +72,7 @@ public class Urls {
         UriBuilder uriBuilder = UriBuilder.fromUri(baseURI)
                 .path(AuthenticationBrokerResource.class)
                 .path(AuthenticationBrokerResource.class, "performLogin")
-                .replaceQueryParam("provider_id", identityProvider.getProviderId());
+                .replaceQueryParam("provider_id", identityProvider.getId());
 
         if (accessCode != null) {
             uriBuilder.replaceQueryParam(OAuth2Constants.CODE, accessCode);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
new file mode 100644
index 0000000..fdf0dbe
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.broker;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
+import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+import java.io.IOException;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author pedroigor
+ */
+public abstract class AbstractIdentityProviderTest {
+
+    @ClassRule
+    public static AbstractKeycloakRule brokerServerRule = new AbstractKeycloakRule() {
+
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            server.importRealm(getClass().getResourceAsStream("/broker-test/test-realm-with-broker.json"));
+            URL url = getClass().getResource("/broker-test/test-app-keycloak.json");
+            deployApplication("test-app", "/test-app", UserSessionStatusServlet.class, url.getPath(), "manager");
+        }
+    };
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @WebResource
+    private WebDriver driver;
+
+    @WebResource
+    private LoginPage loginPage;
+
+    @WebResource
+    private LoginUpdateProfilePage updateProfilePage;
+
+    protected void assertSuccessfulAuthentication(String providerId) {
+        this.driver.navigate().to("http://localhost:8081/test-app/");
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+
+        // choose the identity provider
+        this.loginPage.clickSocial(providerId);
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml"));
+
+        // log in to identity provider
+        this.loginPage.login("saml.user", "password");
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/broker/realm-with-broker/" + providerId));
+
+        // update profile
+        this.updateProfilePage.assertCurrent();
+
+        String userEmail = "new@email.com";
+        String userFirstName = "New first";
+        String userLastName = "New last";
+
+        this.updateProfilePage.update(userFirstName, userLastName, userEmail);
+
+        // authenticated and redirected to app
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app/"));
+
+        KeycloakSession samlServerSession = brokerServerRule.startSession();
+        RealmModel brokerRealm = samlServerSession.realms().getRealm("realm-with-broker");
+
+        UserModel federatedUser = samlServerSession.users().getUserByEmail(userEmail, brokerRealm);
+
+        // user created
+        assertNotNull(federatedUser);
+        assertEquals(userFirstName, federatedUser.getFirstName());
+        assertEquals(userLastName, federatedUser.getLastName());
+
+        driver.navigate().to("http://localhost:8081/test-app/logout");
+        driver.navigate().to("http://localhost:8081/test-app/");
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+
+        // choose the identity provider
+        this.loginPage.clickSocial(providerId);
+
+        // already authenticated in saml idp and redirected to app
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app/"));
+    }
+
+    private UserSessionStatus retrieveSessionStatus() {
+        UserSessionStatus sessionStatus = null;
+
+        try {
+            ObjectMapper objectMapper = new ObjectMapper();
+            String pageSource = this.driver.getPageSource();
+
+            sessionStatus = objectMapper.readValue(pageSource.getBytes(), UserSessionStatus.class);
+
+            assertNotNull(retrieveSessionStatus());
+        } catch (IOException e) {
+            throw new RuntimeException("Could not retrieve session status.", e);
+        }
+
+        return sessionStatus;
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java
index 0320a0a..8a0d6cc 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java
@@ -24,7 +24,7 @@ import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.social.SocialIdentityProvider;
 import org.keycloak.social.SocialIdentityProviderFactory;
 import org.keycloak.testsuite.broker.provider.CustomIdentityProvider;
-import org.keycloak.testsuite.broker.social.CustomSocialProvider;
+import org.keycloak.testsuite.broker.provider.social.CustomSocialProvider;
 
 import java.util.Set;
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
index 3b011cc..7ef78c0 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
@@ -144,7 +144,11 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
             String providerId = identityProvider.getProviderId();
 
             if (SAMLIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
-                assertSamlIdentityProviderConfig(identityProvider);
+                if (identityProvider.getId().equals("saml-signed-idp")) {
+                    assertSamlIdentityProviderConfig(identityProvider);
+                } else {
+                    continue;
+                }
             } else if (GoogleIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
                 assertGoogleIdentityProviderConfig(identityProvider);
             } else if (OIDCIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
@@ -184,14 +188,14 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         SAMLIdentityProvider samlIdentityProvider = new SAMLIdentityProviderFactory().create(identityProvider);
         SAMLIdentityProviderConfig config = samlIdentityProvider.getConfig();
 
-        assertEquals("saml-idp", config.getId());
+        assertEquals("saml-signed-idp", config.getId());
         assertEquals(SAMLIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("SAML IdP", config.getName());
+        assertEquals("SAML Signed IdP", config.getName());
         assertEquals(true, config.isEnabled());
         assertEquals(true, config.isUpdateProfileFirstLogin());
-        assertEquals("http://localhost:8080/idp/", config.getSingleSignOnServiceUrl());
+        assertEquals("http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", config.getSingleSignOnServiceUrl());
         assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", config.getNameIDPolicyFormat());
-        assertEquals("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", config.getSigningPublicKey());
+        assertEquals("MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin", config.getSigningCertificate());
         assertEquals(true, config.isWantAuthnRequestsSigned());
         assertEquals(true, config.isForceAuthn());
         assertEquals(true, config.isPostBindingAuthnRequest());
@@ -258,10 +262,10 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
     }
 
     private RealmModel installTestRealm() throws IOException {
-        RealmRepresentation realmRepresentation = loadJson("model/test-realm-with-identity-provider.json");
+        RealmRepresentation realmRepresentation = loadJson("broker-test/test-realm-with-broker.json");
 
         assertNotNull(realmRepresentation);
-        assertEquals("test-realm-with-identity-provider", realmRepresentation.getRealm());
+        assertEquals("realm-with-broker", realmRepresentation.getRealm());
 
         RealmModel realmModel = this.realmManager.importRealm(realmRepresentation);
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
new file mode 100755
index 0000000..d51eb0e
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.broker;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.keycloak.testutils.KeycloakServer;
+
+/**
+ * @author pedroigor
+ */
+public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderTest {
+
+    @ClassRule
+    public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
+
+        @Override
+        protected void configureServer(KeycloakServer server) {
+            server.getConfig().setPort(8082);
+        }
+
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml.json"));
+        }
+    };
+
+    @Test
+    public void testSuccessfulAuthentication() {
+        assertSuccessfulAuthentication("saml-idp-basic");
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
new file mode 100755
index 0000000..8c2d341
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
@@ -0,0 +1,34 @@
+package org.keycloak.testsuite.broker;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.keycloak.testutils.KeycloakServer;
+
+/**
+ * @author pedroigor
+ */
+public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityProviderTest {
+
+    @ClassRule
+    public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
+
+        @Override
+        protected void configureServer(KeycloakServer server) {
+            server.getConfig().setPort(8082);
+        }
+
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml-with-signature.json"));
+        }
+    };
+
+    @Test
+    public void testSuccessfulAuthentication() {
+        assertSuccessfulAuthentication("saml-signed-idp");
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
new file mode 100644
index 0000000..c2a6fdd
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
@@ -0,0 +1,80 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.broker.util;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.representations.IDToken;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Serializable;
+
+/**
+ * @author pedroigor
+ */
+public class UserSessionStatusServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        if (req.getRequestURI().toString().endsWith("logout")) {
+            resp.setStatus(200);
+            req.logout();
+            return;
+        }
+
+        writeSessionStatus(req, resp);
+    }
+
+    private void writeSessionStatus(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
+        IDToken idToken = context.getIdToken();
+        JsonNode jsonNode = new ObjectMapper().valueToTree(new UserSessionStatus(idToken));
+        PrintWriter writer = resp.getWriter();
+
+        writer.println(jsonNode.toString());
+
+        writer.flush();
+    }
+
+    public static class UserSessionStatus implements Serializable {
+
+        private IDToken idToken;
+
+        public UserSessionStatus() {
+
+        }
+
+        public UserSessionStatus(IDToken idToken) {
+            this.idToken = idToken;
+        }
+
+        public IDToken getIdToken() {
+            return this.idToken;
+        }
+
+        public void setIdToken(IDToken idToken) {
+            this.idToken = idToken;
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
index a3e0234..169ff3a 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
@@ -41,6 +41,9 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
     protected void before() throws Throwable {
         server = new KeycloakServer();
+
+        configureServer(server);
+
         server.start();
 
         removeTestRealms();
@@ -48,6 +51,10 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
         setupKeycloak();
     }
 
+    protected void configureServer(KeycloakServer server) {
+
+    }
+
     public UserRepresentation getUser(String realm, String name) {
         KeycloakSession session = server.getSessionFactory().create();
         session.getTransaction().begin();
diff --git a/testsuite/integration/src/test/resources/broker-test/test-app-keycloak.json b/testsuite/integration/src/test/resources/broker-test/test-app-keycloak.json
new file mode 100755
index 0000000..439e271
--- /dev/null
+++ b/testsuite/integration/src/test/resources/broker-test/test-app-keycloak.json
@@ -0,0 +1,11 @@
+{
+    "realm": "realm-with-broker",
+    "resource": "test-app",
+    "realm-public-key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
+    "auth-server-url": "http://localhost:8081/auth",
+    "ssl-required" : "external",
+    "expose-token": true,
+    "credentials": {
+        "secret": "password"
+    }
+}
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
new file mode 100755
index 0000000..058a463
--- /dev/null
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
@@ -0,0 +1,40 @@
+{
+    "id": "realm-with-saml-identity-provider",
+    "realm": "realm-with-saml-identity-provider",
+    "enabled": true,
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "foo", "bar" ],
+    "privateKey": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCCPyvTTb14vSMkpe/pds2P5Cqxk7bkeFnQiNMS1vyZ+HS2O79fxzp1eAguHnBTs4XTRT7SZJhIT/6utgqZjmDigKV5N7X5ptq8BM/W1qa1cYBRip261pc+tWf3IywJYQ9yFI9mUQarmIEl0D7GH16NSZklheaWfbodRVarvX+ML0amNtGYVDft/RftYmgbKKrK218qQp9R4GZFtf/Q/RmboNXN7weMINU8GWVkTRrccKBIXSunT6zXGfuj3Wp1YpVq20BWwY2OMM/P+yDAc7LKEO1LJqPBdT4r9BRn2lXiaga3AL24gTKZPKU/tu7uqfFciF+i4Rr58SMDNOzQcnklAgMBAAECggEAc0eibJYEO5d8QXW1kPgcHV2gBChv2mxDYnWYDLbIQSdNdfYP/qABt/MTmm5KkWr16fcCEYoD1w0mqFBrtVn1msSusUmEAYGTXJMNumOmjjX1kzaTQMmqeFBrwqwYz/xehWR5P+A7fSmwNV3KEeW19GvN5w5K96w0TLAQdFV3TQVPSytusDunwuR1yltMe1voaEDZ9z0Pi08YiEk2f6xhj5CMkoiw3mNImzfruphHullxU4FD05fH6tDeJ381527ILpAzDsgYZh4aFLKjUHem96bX4EL7FIzBJ6okgN78AZnUC/EaVfgFTw0qfhoWvZV4ruVXXiMhCg4CMMRDq/k9iQKBgQDBNWsJMT84OnnWmQoJmZogkFV+tsGrSK6Re+aJxLWpishh7dwAnT2OcagZvVdUb0FwNWu1D0B9/SKDDMRnnHBhOGDpH57m/eQdRU0oX1BD27xvffk0lLcfD4BTxnR5e9jss8K4twc9jf0P1rxC/loGJ2NtCH0BrPHgz54Ea+96ewKBgQCsk3JDaaPnFwzVYm2BXlhxOxLPsF4wvD2rIRAswZV4C5xebjand8nwiMmVpNd0PRLkEnkI+waURGv2EY/P3JsssoiY8Xqe8f/1G+SQKre7lbqOas8rFoALepC0BYDiZDFy0Z9ZnRAFzRI5sgIt7jpoMRD4xDNlmiV8X+yBxc3Y3wKBgQChDQsU1YUyNKQ8+sLAL9anEEkD4Ald4q8JPHN2IY+gLLxNzT0XEfsu0pTiJ8805axxgUYv3e/PVYNAJBNPnrqaf6lgiegl+jr9Hzhqz9CTUAYqFaL2boSakoxQyNtsLI0s+cb1vDN/3uy0GDZDzcty18BsMagqDmRtFgNNAj/UIwKBgQCahbeFBv0cOPZjxisY8Bou4N8aGehsqNBq/0LVYExuXa8YmoTTdJ3bgw9Er4G/ccQNdUDsuqAMeCtW/CiRzQ0ge4d1sprB4Rv3I4+HSsiS7SFKzfZLtWzXWlpg5qCdlWr1TR7qhYjIOPO9t1beO3YOvwhcRoliyyAPenBxTmTfbwKBgDtm2WJ5VlQgNpIdOs1CCiqd0DFmWOmvBPspPC1kySiy+Ndr9jNohRZkR7pEjgqA5E8rdzc88LirUN7bY5HFHRWN9KXrs5/o3O1K3GFCp64N6nvnPEYZ2zSJalcMC2fjSsJg26z8Dg1H+gfTIDUMoGiEAAnJXuqk+WayPU+fZMLn",
+    "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
+    "applications": [
+        {
+            "name": "http://localhost:8081/auth/",
+            "enabled": true,
+            "redirectUris": [
+                "http://localhost:8081/auth/broker/realm-with-broker/saml-idp-basic"
+            ],
+            "attributes": {
+                "saml.authnstatement": "true"
+            }
+        }
+    ],
+    "users": [
+        {
+            "username" : "saml.user",
+            "enabled": true,
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": ["manager"]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "manager",
+                "description": "Have Manager privileges"
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
new file mode 100755
index 0000000..50eda96
--- /dev/null
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
@@ -0,0 +1,46 @@
+{
+    "id": "realm-with-saml-identity-provider",
+    "realm": "realm-with-saml-identity-provider",
+    "enabled": true,
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "foo", "bar" ],
+    "privateKey": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCCPyvTTb14vSMkpe/pds2P5Cqxk7bkeFnQiNMS1vyZ+HS2O79fxzp1eAguHnBTs4XTRT7SZJhIT/6utgqZjmDigKV5N7X5ptq8BM/W1qa1cYBRip261pc+tWf3IywJYQ9yFI9mUQarmIEl0D7GH16NSZklheaWfbodRVarvX+ML0amNtGYVDft/RftYmgbKKrK218qQp9R4GZFtf/Q/RmboNXN7weMINU8GWVkTRrccKBIXSunT6zXGfuj3Wp1YpVq20BWwY2OMM/P+yDAc7LKEO1LJqPBdT4r9BRn2lXiaga3AL24gTKZPKU/tu7uqfFciF+i4Rr58SMDNOzQcnklAgMBAAECggEAc0eibJYEO5d8QXW1kPgcHV2gBChv2mxDYnWYDLbIQSdNdfYP/qABt/MTmm5KkWr16fcCEYoD1w0mqFBrtVn1msSusUmEAYGTXJMNumOmjjX1kzaTQMmqeFBrwqwYz/xehWR5P+A7fSmwNV3KEeW19GvN5w5K96w0TLAQdFV3TQVPSytusDunwuR1yltMe1voaEDZ9z0Pi08YiEk2f6xhj5CMkoiw3mNImzfruphHullxU4FD05fH6tDeJ381527ILpAzDsgYZh4aFLKjUHem96bX4EL7FIzBJ6okgN78AZnUC/EaVfgFTw0qfhoWvZV4ruVXXiMhCg4CMMRDq/k9iQKBgQDBNWsJMT84OnnWmQoJmZogkFV+tsGrSK6Re+aJxLWpishh7dwAnT2OcagZvVdUb0FwNWu1D0B9/SKDDMRnnHBhOGDpH57m/eQdRU0oX1BD27xvffk0lLcfD4BTxnR5e9jss8K4twc9jf0P1rxC/loGJ2NtCH0BrPHgz54Ea+96ewKBgQCsk3JDaaPnFwzVYm2BXlhxOxLPsF4wvD2rIRAswZV4C5xebjand8nwiMmVpNd0PRLkEnkI+waURGv2EY/P3JsssoiY8Xqe8f/1G+SQKre7lbqOas8rFoALepC0BYDiZDFy0Z9ZnRAFzRI5sgIt7jpoMRD4xDNlmiV8X+yBxc3Y3wKBgQChDQsU1YUyNKQ8+sLAL9anEEkD4Ald4q8JPHN2IY+gLLxNzT0XEfsu0pTiJ8805axxgUYv3e/PVYNAJBNPnrqaf6lgiegl+jr9Hzhqz9CTUAYqFaL2boSakoxQyNtsLI0s+cb1vDN/3uy0GDZDzcty18BsMagqDmRtFgNNAj/UIwKBgQCahbeFBv0cOPZjxisY8Bou4N8aGehsqNBq/0LVYExuXa8YmoTTdJ3bgw9Er4G/ccQNdUDsuqAMeCtW/CiRzQ0ge4d1sprB4Rv3I4+HSsiS7SFKzfZLtWzXWlpg5qCdlWr1TR7qhYjIOPO9t1beO3YOvwhcRoliyyAPenBxTmTfbwKBgDtm2WJ5VlQgNpIdOs1CCiqd0DFmWOmvBPspPC1kySiy+Ndr9jNohRZkR7pEjgqA5E8rdzc88LirUN7bY5HFHRWN9KXrs5/o3O1K3GFCp64N6nvnPEYZ2zSJalcMC2fjSsJg26z8Dg1H+gfTIDUMoGiEAAnJXuqk+WayPU+fZMLn",
+    "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
+    "applications": [
+        {
+            "name": "http://localhost:8081/auth/",
+            "enabled": true,
+            "redirectUris": [
+                "http://localhost:8081/auth/broker/realm-with-broker/saml-signed-idp"
+            ],
+            "attributes": {
+                "saml.assertion.signature": "true",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
+                "saml.signing.certificate": "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin"
+            }
+        }
+    ],
+    "users": [
+        {
+            "username" : "saml.user",
+            "enabled": true,
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": ["manager"]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "manager",
+                "description": "Have Manager privileges"
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory
index 06a646c..e31e0f6 100644
--- a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory
+++ b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory
@@ -1 +1 @@
-org.keycloak.testsuite.broker.social.CustomSocialProviderFactory
\ No newline at end of file
+org.keycloak.testsuite.broker.provider.social.CustomSocialProviderFactory
\ No newline at end of file