keycloak-aplcache

Changes

Details

diff --git a/common/src/main/java/org/keycloak/common/util/ObjectUtil.java b/common/src/main/java/org/keycloak/common/util/ObjectUtil.java
index 1ade852..bec8acf 100644
--- a/common/src/main/java/org/keycloak/common/util/ObjectUtil.java
+++ b/common/src/main/java/org/keycloak/common/util/ObjectUtil.java
@@ -24,4 +24,8 @@ public class ObjectUtil {
 
         return str1.equals(str2);
     }
+
+    public static String capitalize(String str) {
+        return str.substring(0, 1).toUpperCase() + str.substring(1);
+    }
 }
diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl
index 02923d9..f77eb38 100644
--- a/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl
@@ -12,8 +12,8 @@
         <form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
 
                 <div id="kc-form-buttons" class="${properties.kcFormGroupClass!}">
-                    <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="updateProfile">${msg("confirmLinkIdpReviewProfile")}</button>
-                    <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="linkAccount">${msg("confirmLinkIdpContinue", idpAlias)}</button>
+                    <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" id="updateProfile" value="updateProfile">${msg("confirmLinkIdpReviewProfile")}</button>
+                    <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" id="linkAccount" value="linkAccount">${msg("confirmLinkIdpContinue", idpAlias)}</button>
                 </div>
 
         </form>
diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-email.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-email.ftl
index ab3e83e..0ba0686 100644
--- a/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-email.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-email.ftl
@@ -5,10 +5,10 @@
     <#elseif section = "header">
         ${msg("emailLinkIdpTitle", idpAlias)}
     <#elseif section = "form">
-        <p class="instruction">
+        <p id="instruction1" class="instruction">
             ${msg("emailLinkIdp1", idpAlias, brokerContext.username, realm.name)}
         </p>
-        <p class="instruction">
+        <p id="instruction2" class="instruction">
             ${msg("emailLinkIdp2")} <a href="${url.firstBrokerLoginUrl}">${msg("doClickHere")}</a> ${msg("emailLinkIdp3")}
         </p>
     </#if>
diff --git a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
index 3a04fbf..25b0166 100755
--- a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
+++ b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
@@ -21,6 +21,7 @@ import javax.mail.internet.MimeMultipart;
 
 import org.jboss.logging.Logger;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
+import org.keycloak.common.util.ObjectUtil;
 import org.keycloak.email.EmailException;
 import org.keycloak.email.EmailProvider;
 import org.keycloak.email.freemarker.beans.EventBean;
@@ -89,7 +90,7 @@ public class FreeMarkerEmailProvider implements EmailProvider {
         attributes.put("link", link);
         attributes.put("linkExpiration", expirationInMinutes);
 
-        String realmName = realm.getName().substring(0, 1).toUpperCase() + realm.getName().substring(1);
+        String realmName = ObjectUtil.capitalize(realm.getName());
         attributes.put("realmName", realmName);
 
         send("passwordResetSubject", "password-reset.ftl", attributes);
@@ -102,12 +103,12 @@ public class FreeMarkerEmailProvider implements EmailProvider {
         attributes.put("link", link);
         attributes.put("linkExpiration", expirationInMinutes);
 
-        String realmName = realm.getName().substring(0, 1).toUpperCase() + realm.getName().substring(1);
+        String realmName = ObjectUtil.capitalize(realm.getName());
         attributes.put("realmName", realmName);
 
         BrokeredIdentityContext brokerContext = (BrokeredIdentityContext) this.attributes.get(IDENTITY_PROVIDER_BROKER_CONTEXT);
         String idpAlias = brokerContext.getIdpConfig().getAlias();
-        idpAlias = idpAlias.substring(0, 1).toUpperCase() + idpAlias.substring(1);
+        idpAlias = ObjectUtil.capitalize(idpAlias);
 
         attributes.put("identityProviderContext", brokerContext);
         attributes.put("identityProviderAlias", idpAlias);
@@ -123,7 +124,7 @@ public class FreeMarkerEmailProvider implements EmailProvider {
         attributes.put("link", link);
         attributes.put("linkExpiration", expirationInMinutes);
 
-        String realmName = realm.getName().substring(0, 1).toUpperCase() + realm.getName().substring(1);
+        String realmName = ObjectUtil.capitalize(realm.getName());
         attributes.put("realmName", realmName);
 
         send("executeActionsSubject", "executeActions.ftl", attributes);
@@ -137,7 +138,7 @@ public class FreeMarkerEmailProvider implements EmailProvider {
         attributes.put("link", link);
         attributes.put("linkExpiration", expirationInMinutes);
 
-        String realmName = realm.getName().substring(0, 1).toUpperCase() + realm.getName().substring(1);
+        String realmName = ObjectUtil.capitalize(realm.getName());
         attributes.put("realmName", realmName);
 
         send("emailVerificationSubject", "email-verification.ftl", attributes);
@@ -253,7 +254,7 @@ public class FreeMarkerEmailProvider implements EmailProvider {
     private String toCamelCase(EventType event){
         StringBuilder sb = new StringBuilder("event");
         for(String s : event.name().toString().toLowerCase().split("_")){
-            sb.append(s.substring(0,1).toUpperCase()).append(s.substring(1));
+            sb.append(ObjectUtil.capitalize(s));
         }
         return sb.toString();
     }
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index ef8cc74..d1b4df9 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -22,6 +22,7 @@ import org.keycloak.OAuth2Constants;
 import org.keycloak.authentication.requiredactions.util.UpdateProfileContext;
 import org.keycloak.authentication.requiredactions.util.UserUpdateProfileContext;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
+import org.keycloak.common.util.ObjectUtil;
 import org.keycloak.email.EmailException;
 import org.keycloak.email.EmailProvider;
 import org.keycloak.freemarker.BrowserSecurityHeaderSetup;
@@ -288,7 +289,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
             case LOGIN_IDP_LINK_EMAIL:
                 BrokeredIdentityContext brokerContext = (BrokeredIdentityContext) this.attributes.get(IDENTITY_PROVIDER_BROKER_CONTEXT);
                 String idpAlias = brokerContext.getIdpConfig().getAlias();
-                idpAlias = idpAlias.substring(0, 1).toUpperCase() + idpAlias.substring(1);
+                idpAlias = ObjectUtil.capitalize(idpAlias);
 
                 attributes.put("brokerContext", brokerContext);
                 attributes.put("idpAlias", idpAlias);
@@ -470,7 +471,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
     public Response createIdpLinkEmailPage() {
         BrokeredIdentityContext brokerContext = (BrokeredIdentityContext) this.attributes.get(IDENTITY_PROVIDER_BROKER_CONTEXT);
         String idpAlias = brokerContext.getIdpConfig().getAlias();
-        idpAlias = idpAlias.substring(0, 1).toUpperCase() + idpAlias.substring(1);
+        idpAlias = ObjectUtil.capitalize(idpAlias);;
         setMessage(MessageType.WARNING, Messages.LINK_IDP, idpAlias);
 
         return createResponse(LoginFormsPages.LOGIN_IDP_LINK_EMAIL);
diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
index a874f5e..98e960c 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
@@ -25,8 +25,10 @@ public class DefaultAuthenticationFlows {
 
     public static final String CLIENT_AUTHENTICATION_FLOW = "clients";
     public static final String FIRST_BROKER_LOGIN_FLOW = "first broker login";
+    public static final String FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW = "Handle Existing Account";
 
     public static final String IDP_REVIEW_PROFILE_CONFIG_ALIAS = "review profile config";
+    public static final String IDP_CREATE_UNIQUE_USER_CONFIG_ALIAS = "create unique user config";
 
     public static void addFlows(RealmModel realm) {
         if (realm.getFlowByAlias(BROWSER_FLOW) == null) browserFlow(realm);
@@ -347,7 +349,7 @@ public class DefaultAuthenticationFlows {
 
 
         AuthenticatorConfigModel createUserIfUniqueConfig = new AuthenticatorConfigModel();
-        createUserIfUniqueConfig.setAlias("create unique user config");
+        createUserIfUniqueConfig.setAlias(IDP_CREATE_UNIQUE_USER_CONFIG_ALIAS);
         config = new HashMap<>();
         config.put("require.password.update.after.registration", "false");
         createUserIfUniqueConfig.setConfig(config);
@@ -366,7 +368,7 @@ public class DefaultAuthenticationFlows {
         AuthenticationFlowModel linkExistingAccountFlow = new AuthenticationFlowModel();
         linkExistingAccountFlow.setTopLevel(false);
         linkExistingAccountFlow.setBuiltIn(true);
-        linkExistingAccountFlow.setAlias("Handle Existing Account");
+        linkExistingAccountFlow.setAlias(FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW);
         linkExistingAccountFlow.setDescription("Handle what to do if there is existing account with same email/username like authenticated identity provider");
         linkExistingAccountFlow.setProviderId("basic-flow");
         linkExistingAccountFlow = realm.addAuthenticationFlow(linkExistingAccountFlow);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java
new file mode 100644
index 0000000..7d780cd
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java
@@ -0,0 +1,397 @@
+package org.keycloak.testsuite.broker;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.mail.internet.MimeMessage;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticator;
+import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
+import org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticatorFactory;
+import org.keycloak.authentication.authenticators.broker.IdpReviewProfileAuthenticatorFactory;
+import org.keycloak.common.util.ObjectUtil;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorConfigModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.pages.IdpConfirmLinkPage;
+import org.keycloak.testsuite.pages.IdpLinkEmailPage;
+import org.keycloak.testsuite.pages.LoginPasswordResetPage;
+import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
+import org.keycloak.testsuite.pages.LoginUpdateProfileEditUsernameAllowedPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractFirstBrokerLoginTest extends AbstractIdentityProviderTest {
+
+    protected static final String APP_REALM_ID = "realm-with-broker";
+
+    @WebResource
+    protected LoginUpdateProfileEditUsernameAllowedPage updateProfileWithUsernamePage;
+
+    @WebResource
+    protected IdpConfirmLinkPage idpConfirmLinkPage;
+
+    @WebResource
+    protected IdpLinkEmailPage idpLinkEmailPage;
+
+    @WebResource
+    protected LoginPasswordUpdatePage passwordUpdatePage;
+
+
+
+    /**
+     * Tests that if updateProfile is off and CreateUserIfUnique authenticator mandatory, error page will be shown if user with same email already exists
+     */
+    @Test
+    public void testErrorPageWhenDuplicationNotAllowed_updateProfileOff() {
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.REQUIRED);
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
+            }
+
+        }, APP_REALM_ID);
+
+        loginIDP("pedroigor");
+
+        WebElement element = this.driver.findElement(By.className("instruction"));
+
+        assertNotNull(element);
+
+        assertEquals("User with email psilva@redhat.com already exists. Please login to account management to link the account.", element.getText());
+
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.ALTERNATIVE);
+            }
+
+        }, APP_REALM_ID);
+    }
+
+
+    /**
+     * Tests that if updateProfile is on and CreateUserIfUnique authenticator mandatory, error page will be shown if user with same email already exists
+     */
+    @Test
+    public void testErrorPageWhenDuplicationNotAllowed_updateProfileOn() {
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.REQUIRED);
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_ON);
+            }
+
+        }, APP_REALM_ID);
+
+        loginIDP("test-user");
+
+        this.updateProfileWithUsernamePage.assertCurrent();
+        this.updateProfileWithUsernamePage.update("Test", "User", "test-user@redhat.com", "pedroigor");
+
+        WebElement element = this.driver.findElement(By.className("instruction"));
+
+        assertNotNull(element);
+
+        assertEquals("User with username pedroigor already exists. Please login to account management to link the account.", element.getText());
+
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.ALTERNATIVE);
+            }
+
+        }, APP_REALM_ID);
+    }
+
+
+    /**
+     * Test user registers with IdentityProvider and needs to update password when it's required by IdpCreateUserIfUniqueAuthenticator
+     */
+    @Test
+    public void testRegistrationWithPasswordUpdateRequired() {
+        // Require updatePassword after user registered with broker
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                AuthenticatorConfigModel authenticatorConfig = realmWithBroker.getAuthenticatorConfigByAlias(DefaultAuthenticationFlows.IDP_CREATE_UNIQUE_USER_CONFIG_ALIAS);
+                authenticatorConfig.getConfig().put(IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
+                realmWithBroker.updateAuthenticatorConfig(authenticatorConfig);
+
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_MISSING);
+            }
+
+        }, APP_REALM_ID);
+
+        loginIDP("pedroigor");
+        this.updateProfileWithUsernamePage.assertCurrent();
+        this.updateProfileWithUsernamePage.update("Test", "User", "some-user@redhat.com", "some-user");
+
+        // Need to update password now
+        this.passwordUpdatePage.assertCurrent();
+        this.passwordUpdatePage.changePassword("password1", "password1");
+
+
+        // assert authenticated
+        assertFederatedUser("some-user", "some-user@redhat.com", "pedroigor");
+
+
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                AuthenticatorConfigModel authenticatorConfig = realmWithBroker.getAuthenticatorConfigByAlias(DefaultAuthenticationFlows.IDP_CREATE_UNIQUE_USER_CONFIG_ALIAS);
+                authenticatorConfig.getConfig().put(IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "false");
+                realmWithBroker.updateAuthenticatorConfig(authenticatorConfig);
+            }
+
+        }, APP_REALM_ID);
+    }
+
+
+    /**
+     * Tests that duplication is detected, the confirmation page is displayed, user clicks on "Review profile" and goes back to updateProfile page and resolves duplication
+     * by create new user
+     */
+    @Test
+    public void testFixDuplicationsByReviewProfile() {
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+        loginIDP("pedroigor");
+
+        // There is user with same email. Update profile to use different email
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickReviewProfile();
+
+        this.updateProfileWithUsernamePage.assertCurrent();
+        this.updateProfileWithUsernamePage.update("Test", "User", "testing-user@redhat.com", "pedroigor");
+
+        // There is user with same username. Update profile to use different username
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with username pedroigor already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickReviewProfile();
+
+        this.updateProfileWithUsernamePage.assertCurrent();
+        this.updateProfileWithUsernamePage.update("Test", "User", "testing-user@redhat.com", "testing-user");
+
+        assertFederatedUser("testing-user", "testing-user@redhat.com", "pedroigor");
+    }
+
+    /**
+     * Tests that duplication is detected and user wants to link federatedIdentity with existing account. He will confirm link by email
+     */
+    @Test
+    public void testLinkAccountByEmailVerification() throws Exception {
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+        loginIDP("pedroigor");
+
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickLinkAccount();
+
+        // Confirm linking account by email
+        this.idpLinkEmailPage.assertCurrent();
+        Assert.assertEquals("An email with instructions to link " + ObjectUtil.capitalize(getProviderId()) + " account pedroigor with your " + APP_REALM_ID + " account has been sent to you.", this.idpLinkEmailPage.getMessage());
+
+        Assert.assertEquals(1, greenMail.getReceivedMessages().length);
+        MimeMessage message = greenMail.getReceivedMessages()[0];
+        String linkFromMail = getVerificationEmailLink(message);
+
+        driver.navigate().to(linkFromMail.trim());
+
+        // authenticated and redirected to app. User is linked with identity provider
+        assertFederatedUser("pedroigor", "psilva@redhat.com", "pedroigor");
+    }
+
+
+    /**
+     * Tests that duplication is detected and user wants to link federatedIdentity with existing account. He will confirm link by reauthentication (confirm password on login screen)
+     */
+    @Test
+    public void testLinkAccountByReauthenticationWithPassword() throws Exception {
+        // Remove smtp config. The reauthentication by username+password screen will be automatically used then
+        final Map<String, String> smtpConfig = new HashMap<>();
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
+                smtpConfig.putAll(realmWithBroker.getSmtpConfig());
+                realmWithBroker.setSmtpConfig(Collections.<String, String>emptyMap());
+            }
+
+        }, APP_REALM_ID);
+
+
+        loginIDP("pedroigor");
+
+
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickLinkAccount();
+
+        // Login screen shown. Username is prefilled and disabled. Registration link and social buttons are not shown
+        Assert.assertEquals("Log in to " + APP_REALM_ID, this.driver.getTitle());
+        Assert.assertEquals("pedroigor", this.loginPage.getUsername());
+        Assert.assertFalse(this.loginPage.isUsernameInputEnabled());
+
+        Assert.assertEquals("Authenticate as pedroigor to link your account with " + getProviderId(), this.loginPage.getSuccessMessage());
+
+        try {
+            this.loginPage.findSocialButton(getProviderId());
+            Assert.fail("Not expected to see social button with " + getProviderId());
+        } catch (NoSuchElementException expected) {
+        }
+
+        try {
+            this.loginPage.clickRegister();
+            Assert.fail("Not expected to see register link");
+        } catch (NoSuchElementException expected) {
+        }
+
+        // Use bad password first
+        this.loginPage.login("password1");
+        Assert.assertEquals("Invalid username or password.", this.loginPage.getError());
+
+        // Use correct password now
+        this.loginPage.login("password");
+
+        // authenticated and redirected to app. User is linked with identity provider
+        assertFederatedUser("pedroigor", "psilva@redhat.com", "pedroigor");
+
+
+        // Restore smtp config
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                realmWithBroker.setSmtpConfig(smtpConfig);
+            }
+
+        }, APP_REALM_ID);
+    }
+
+
+    /**
+     * Tests that duplication is detected and user wants to link federatedIdentity with existing account. He will confirm link by reauthentication (confirm password on login screen)
+     * and additionally he goes through "forget password"
+     */
+    @Test
+    public void testLinkAccountByReauthentication_forgetPassword() throws Exception {
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW,
+                        IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.DISABLED);
+
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
+            }
+
+        }, APP_REALM_ID);
+
+        loginIDP("pedroigor");
+
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickLinkAccount();
+
+        // Click "Forget password" on login page. Email sent directly because username is known
+        Assert.assertEquals("Log in to " + APP_REALM_ID, this.driver.getTitle());
+        this.loginPage.resetPassword();
+
+        Assert.assertEquals("Log in to " + APP_REALM_ID, this.driver.getTitle());
+        Assert.assertEquals("You should receive an email shortly with further instructions.", this.loginPage.getSuccessMessage());
+
+        // Click on link from email
+        Assert.assertEquals(1, greenMail.getReceivedMessages().length);
+        MimeMessage message = greenMail.getReceivedMessages()[0];
+        String linkFromMail = getVerificationEmailLink(message);
+
+        driver.navigate().to(linkFromMail.trim());
+
+        // Need to update password now
+        this.passwordUpdatePage.assertCurrent();
+        this.passwordUpdatePage.changePassword("password", "password");
+
+        // authenticated and redirected to app. User is linked with identity provider
+        assertFederatedUser("pedroigor", "psilva@redhat.com", "pedroigor");
+
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW,
+                        IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.ALTERNATIVE);
+
+            }
+
+        }, APP_REALM_ID);
+    }
+
+
+    protected void assertFederatedUser(String expectedUsername, String expectedEmail, String expectedFederatedUsername) {
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+        UserModel federatedUser = getFederatedUser();
+
+        assertNotNull(federatedUser);
+        assertEquals(expectedUsername, federatedUser.getUsername());
+        assertEquals(expectedEmail, federatedUser.getEmail());
+
+        RealmModel realmWithBroker = getRealm();
+        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker);
+        assertEquals(1, federatedIdentities.size());
+
+        FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+        assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+        assertEquals(expectedFederatedUsername, federatedIdentityModel.getUserName());
+    }
+
+
+    protected void setExecutionRequirement(RealmModel realmWithBroker, String flowAlias, String authenticatorProvider, AuthenticationExecutionModel.Requirement requirement) {
+        AuthenticationFlowModel flowModel = realmWithBroker.getFlowByAlias(flowAlias);
+        List<AuthenticationExecutionModel> authExecutions = realmWithBroker.getAuthenticationExecutions(flowModel.getId());
+        for (AuthenticationExecutionModel execution : authExecutions) {
+            if (execution.getAuthenticator().equals(authenticatorProvider)) {
+                execution.setRequirement(requirement);
+                realmWithBroker.updateAuthenticatorExecution(execution);
+                return;
+            }
+        }
+
+        throw new IllegalStateException("Execution not found for flow " + flowAlias + " and authenticator " + authenticatorProvider);
+    }
+
+}
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
index 8af43b2..5248c38 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -42,6 +42,7 @@ import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.Urls;
 import org.keycloak.testsuite.MailUtil;
 import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
 import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
 import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
 import org.keycloak.testsuite.pages.AccountPasswordPage;
@@ -87,7 +88,7 @@ import static org.junit.Assert.fail;
  */
 public abstract class AbstractIdentityProviderTest {
 
-    private static final URI BASE_URI = UriBuilder.fromUri("http://localhost:8081/auth").build();
+    protected static final URI BASE_URI = UriBuilder.fromUri("http://localhost:8081/auth").build();
 
     @ClassRule
     public static BrokerKeyCloakRule brokerServerRule = new BrokerKeyCloakRule();
@@ -99,10 +100,10 @@ public abstract class AbstractIdentityProviderTest {
     protected WebDriver driver;
 
     @WebResource
-    private LoginPage loginPage;
+    protected LoginPage loginPage;
 
     @WebResource
-    private LoginUpdateProfilePage updateProfilePage;
+    protected LoginUpdateProfilePage updateProfilePage;
 
 
     @WebResource
@@ -123,7 +124,7 @@ public abstract class AbstractIdentityProviderTest {
     @WebResource
     protected AccountFederatedIdentityPage accountFederatedIdentityPage;
 
-    private KeycloakSession session;
+    protected KeycloakSession session;
 
     @Before
     public void onBefore() {
@@ -140,87 +141,19 @@ public abstract class AbstractIdentityProviderTest {
         brokerServerRule.stopSession(this.session, true);
     }
 
-    @Test
-    public void testSuccessfulAuthentication() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
-
-        UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com", true);
-        Assert.assertEquals("617-666-7777", user.getFirstAttribute("mobile"));
-    }
-
-    @Test
-    public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_MISSING);
-
-        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
-    }
-
-    @Test
-    public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_MISSING);
-
-        assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", "new@email.com", true);
-    }
-
-    @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-
-        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
-    }
-
-    /**
-     * Test that verify email action is performed if email is provided and email trust is not enabled for the provider
-     * 
-     * @throws MessagingException
-     * @throws IOException
-     */
-    @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException {
-        getRealm().setVerifyEmail(true);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        try {
-            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-            identityProviderModel.setTrustEmail(false);
-
-            UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost", false);
-
-            // email is verified now
-            assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
-
-        } finally {
-            getRealm().setVerifyEmail(false);
-        }
-    }
-
-    private UserModel assertSuccessfulAuthenticationWithEmailVerification(IdentityProviderModel identityProviderModel, String username, String expectedEmail,
-            boolean isProfileUpdateExpected)
-            throws IOException, MessagingException {
+    protected UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail, boolean isProfileUpdateExpected) {
         authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
 
-        // verify email is sent
-        Assert.assertTrue(verifyEmailPage.isCurrent());
-
-        // read email to take verification link from
-        Assert.assertEquals(1, greenMail.getReceivedMessages().length);
-        MimeMessage message = greenMail.getReceivedMessages()[0];
-        String verificationUrl = getVerificationEmailLink(message);
-
-        driver.navigate().to(verificationUrl.trim());
-
         // authenticated and redirected to app
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+        assertTrue("Bad current URL " + this.driver.getCurrentUrl() + " and page source: " + this.driver.getPageSource(),
+                this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
 
         UserModel federatedUser = getFederatedUser();
 
         assertNotNull(federatedUser);
+        assertNotNull(federatedUser.getCreatedTimestamp());
+        // test that timestamp is current with 10s tollerance
+        Assert.assertTrue((System.currentTimeMillis() - federatedUser.getCreatedTimestamp()) < 10000);
 
         doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
 
@@ -245,166 +178,7 @@ public abstract class AbstractIdentityProviderTest {
         return federatedUser;
     }
 
-    /**
-     * Test for KEYCLOAK-1053 - verify email action is not performed if email is not provided, login is normal, but action stays in set to be performed later
-     */
-    @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() {
-        getRealm().setVerifyEmail(true);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        try {
-            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-
-            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null, false);
-
-            assertTrue(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
-
-        } finally {
-            getRealm().setVerifyEmail(false);
-        }
-    }
-
-    /**
-     * Test for KEYCLOAK-1372 - verify email action is not performed if email is provided but email trust is enabled for the provider
-     */
-    @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() {
-        getRealm().setVerifyEmail(true);
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        try {
-            identityProviderModel.setTrustEmail(true);
-
-            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
-
-            assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
-
-        } finally {
-            identityProviderModel.setTrustEmail(false);
-            getRealm().setVerifyEmail(false);
-        }
-    }
-
-    /**
-     * Test for KEYCLOAK-1372 - verify email action is performed if email is provided and email trust is enabled for the provider, but email is changed on First login update profile page
-     * 
-     * @throws MessagingException
-     * @throws IOException
-     */
-    @Test
-    public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException {
-        getRealm().setVerifyEmail(true);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        try {
-            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
-            identityProviderModel.setTrustEmail(true);
-
-            UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com", true);
-            Assert.assertEquals("617-666-7777", user.getFirstAttribute("mobile"));
-        } finally {
-            identityProviderModel.setTrustEmail(false);
-            getRealm().setVerifyEmail(false);
-        }
-    }
-
-    @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
-
-        getRealm().setRegistrationEmailAsUsername(true);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        try {
-            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-
-            authenticateWithIdentityProvider(identityProviderModel, "test-user", false);
-
-            // authenticated and redirected to app
-            assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
-
-            brokerServerRule.stopSession(session, true);
-            session = brokerServerRule.startSession();
-
-            // check correct user is created with email as username and bound to correct federated identity
-            RealmModel realm = getRealm();
-
-            UserModel federatedUser = session.users().getUserByUsername("test-user@localhost", realm);
-
-            assertNotNull(federatedUser);
-
-            assertEquals("test-user@localhost", federatedUser.getUsername());
-
-            doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost", false);
-
-            Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
-
-            assertEquals(1, federatedIdentities.size());
-
-            FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
-
-            assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
-
-            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/auth"));
-
-        } finally {
-            getRealm().setRegistrationEmailAsUsername(false);
-        }
-    }
-
-    @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
-
-        getRealm().setRegistrationEmailAsUsername(true);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        try {
-            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-
-            authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail", false);
-
-            brokerServerRule.stopSession(session, true);
-            session = brokerServerRule.startSession();
 
-            // check correct user is created with username from provider as email is not available
-            RealmModel realm = getRealm();
-            UserModel federatedUser = getFederatedUser();
-            assertNotNull(federatedUser);
-
-            doAssertFederatedUserNoEmail(federatedUser);
-
-            Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
-
-            assertEquals(1, federatedIdentities.size());
-
-            FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
-
-            assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
-            revokeGrant();
-
-            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/auth"));
-
-        } finally {
-            getRealm().setRegistrationEmailAsUsername(false);
-        }
-    }
 
     protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
         assertEquals("kc-oidc-idp.test-user-noemail", federatedUser.getUsername());
@@ -413,316 +187,7 @@ public abstract class AbstractIdentityProviderTest {
         assertEquals("User", federatedUser.getLastName());
     }
 
-    @Test
-    public void testDisabled() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-
-        identityProviderModel.setEnabled(false);
-
-        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/auth"));
-
-        try {
-            this.driver.findElement(By.className(getProviderId()));
-            fail("Provider [" + getProviderId() + "] not disabled.");
-        } catch (NoSuchElementException nsee) {
-
-        }
-    }
-
-    @Test
-    public void testProviderOnLoginPage() {
-        // Provider button is available on login page
-        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/auth"));
-        loginPage.findSocialButton(getProviderId());
-     }
-
-    // TODO: Reenable and adjust to KEYCLOAK-1750 changed behaviour
-    // @Test
-    public void testUserAlreadyExistsWhenUpdatingProfile() {
-        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/auth"));
-
-        // choose the identity provider
-        this.loginPage.clickSocial(getProviderId());
-
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
-
-        // log in to identity provider
-        this.loginPage.login("test-user", "password");
-
-        doAfterProviderAuthentication();
-
-        this.updateProfilePage.assertCurrent();
-        this.updateProfilePage.update("Test", "User", "psilva@redhat.com");
-
-        WebElement element = this.driver.findElement(By.className("kc-feedback-text"));
-
-        assertNotNull(element);
-
-        assertEquals("Email already exists.", element.getText());
-
-        this.updateProfilePage.assertCurrent();
-        this.updateProfilePage.update("Test", "User", "test-user@redhat.com");
-
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
-
-        UserModel federatedUser = getFederatedUser();
-
-        assertNotNull(federatedUser);
-    }
-
-    // TODO: Reenable and adjust to KEYCLOAK-1750 changed behaviour
-    // @Test
-    public void testUserAlreadyExistsWhenNotUpdatingProfile() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-
-        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/auth"));
-
-        // choose the identity provider
-        this.loginPage.clickSocial(getProviderId());
-
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
-
-        // log in to identity provider
-        this.loginPage.login("pedroigor", "password");
-
-        doAfterProviderAuthentication();
-
-        WebElement element = this.driver.findElement(By.className("kc-feedback-text"));
-
-        assertNotNull(element);
-
-        assertEquals("User with email already exists. Please login to account management to link the account.", element.getText());
-    }
-
-    @Test
-    public void testAccountManagementLinkIdentity() {
-        // Login as pedroigor to account management
-        accountFederatedIdentityPage.realm("realm-with-broker");
-        accountFederatedIdentityPage.open();
-        assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
-        loginPage.login("pedroigor", "password");
-        assertTrue(accountFederatedIdentityPage.isCurrent());
-
-        // Link my "pedroigor" identity with "test-user" from brokered Keycloak
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
-        accountFederatedIdentityPage.clickAddProvider(identityProviderModel.getAlias());
-
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
-        this.loginPage.login("test-user", "password");
-        doAfterProviderAuthentication();
-
-        // Assert identity linked in account management
-        assertTrue(accountFederatedIdentityPage.isCurrent());
-        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
-
-        // Revoke grant in account mgmt
-        revokeGrant();
-
-        // Logout from account management
-        accountFederatedIdentityPage.logout();
-        assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
-
-        // Assert I am logged immediately to account management due to previously linked "test-user" identity
-        loginPage.clickSocial(identityProviderModel.getAlias());
-        doAfterProviderAuthentication();
-        assertTrue(accountFederatedIdentityPage.isCurrent());
-        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
-
-        // Unlink my "test-user"
-        accountFederatedIdentityPage.clickRemoveProvider(identityProviderModel.getAlias());
-        assertTrue(driver.getPageSource().contains("id=\"add-" + identityProviderModel.getAlias() + "\""));
-
-        // Revoke grant in account mgmt
-        revokeGrant();
-
-        // Logout from account management
-        System.out.println("*** logout from account management");
-        accountFederatedIdentityPage.logout();
-        assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
-
-        // Try to login. Previous link is not valid anymore, so now it should try to register new user
-        this.loginPage.clickSocial(identityProviderModel.getAlias());
-        this.loginPage.login("test-user", "password");
-        doAfterProviderAuthentication();
-        this.updateProfilePage.assertCurrent();
-    }
-
-    @Test(expected = NoSuchElementException.class)
-    public void testIdentityProviderNotAllowed() {
-        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/auth"));
-
-        driver.findElement(By.className("model-oidc-idp"));
-    }
-
-    protected void configureClientRetrieveToken(String clientId) {
-        RealmModel realm = getRealm();
-        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
-        ClientModel client = realm.getClientByClientId(clientId);
-        if (!client.hasScope(readTokenRole)) client.addScopeMapping(readTokenRole);
-
-        brokerServerRule.stopSession(session, true);
-        session = brokerServerRule.startSession();
-
-    }
-
-    protected void configureUserRetrieveToken(String username) {
-        RealmModel realm = getRealm();
-        UserModel user = session.users().getUserByUsername(username, realm);
-        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
-        if (user != null && !user.hasRole(readTokenRole)) {
-            user.grantRole(readTokenRole);
-        }
-        brokerServerRule.stopSession(session, true);
-        session = brokerServerRule.startSession();
-
-    }
-
-    protected void unconfigureClientRetrieveToken(String clientId) {
-        RealmModel realm = getRealm();
-        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
-        ClientModel client = realm.getClientByClientId(clientId);
-        if (client.hasScope(readTokenRole)) client.deleteScopeMapping(readTokenRole);
-
-        brokerServerRule.stopSession(session, true);
-        session = brokerServerRule.startSession();
-
-    }
-
-    protected void unconfigureUserRetrieveToken(String username) {
-        RealmModel realm = getRealm();
-        UserModel user = session.users().getUserByUsername(username, realm);
-        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
-        if (user != null && user.hasRole(readTokenRole)) {
-            user.deleteRoleMapping(readTokenRole);
-        }
-        brokerServerRule.stopSession(session, true);
-        session = brokerServerRule.startSession();
-
-    }
-
-    @Test
-    public void testTokenStorageAndRetrievalByApplication() {
-        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-
-        identityProviderModel.setStoreToken(true);
-
-        authenticateWithIdentityProvider(identityProviderModel, "test-user", true);
-
-        UserModel federatedUser = getFederatedUser();
-        RealmModel realm = getRealm();
-        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
-
-        assertFalse(federatedIdentities.isEmpty());
-        assertEquals(1, federatedIdentities.size());
-
-        FederatedIdentityModel identityModel = federatedIdentities.iterator().next();
-
-        assertNotNull(identityModel.getToken());
-
-        UserSessionStatus userSessionStatus = retrieveSessionStatus();
-        String accessToken = userSessionStatus.getAccessTokenString();
-        URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), realm.getName());
-        final String authHeader = "Bearer " + accessToken;
-        ClientRequestFilter authFilter = new ClientRequestFilter() {
-            @Override
-            public void filter(ClientRequestContext requestContext) throws IOException {
-                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
-            }
-        };
-        Client client = ClientBuilder.newBuilder().register(authFilter).build();
-        WebTarget tokenEndpoint = client.target(tokenEndpointUrl);
-        Response response = tokenEndpoint.request().get();
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertNotNull(response.readEntity(String.class));
-        revokeGrant();
-
-
-        driver.navigate().to("http://localhost:8081/test-app/logout");
-        String currentUrl = this.driver.getCurrentUrl();
-        System.out.println("after logout currentUrl: " + currentUrl);
-        assertTrue(currentUrl.startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
-
-        unconfigureUserRetrieveToken(getProviderId() + ".test-user");
-        loginIDP("test-user");
-        //authenticateWithIdentityProvider(identityProviderModel, "test-user");
-        assertEquals("http://localhost:8081/test-app", driver.getCurrentUrl());
-
-        userSessionStatus = retrieveSessionStatus();
-        accessToken = userSessionStatus.getAccessTokenString();
-        final String authHeader2 = "Bearer " + accessToken;
-        ClientRequestFilter authFilter2 = new ClientRequestFilter() {
-            @Override
-            public void filter(ClientRequestContext requestContext) throws IOException {
-                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader2);
-            }
-        };
-        client = ClientBuilder.newBuilder().register(authFilter2).build();
-        tokenEndpoint = client.target(tokenEndpointUrl);
-        response = tokenEndpoint.request().get();
-
-        assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
-
-        revokeGrant();
-        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/auth"));
-    }
-
-    protected abstract void doAssertTokenRetrieval(String pageSource);
-
-    private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail, boolean isProfileUpdateExpected) {
-        authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
-
-        // authenticated and redirected to app
-        assertTrue("Bad current URL " + this.driver.getCurrentUrl() + " and page source: " + this.driver.getPageSource(),
-                this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
-
-        UserModel federatedUser = getFederatedUser();
-
-        assertNotNull(federatedUser);
-        assertNotNull(federatedUser.getCreatedTimestamp());
-        // test that timestamp is current with 10s tollerance
-        Assert.assertTrue((System.currentTimeMillis() - federatedUser.getCreatedTimestamp()) < 10000);
-
-        doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
-
-        brokerServerRule.stopSession(session, true);
-        session = brokerServerRule.startSession();
-
-        RealmModel realm = getRealm();
-
-        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
-
-        assertEquals(1, federatedIdentities.size());
-
-        FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
-
-        assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
-        assertEquals(federatedUser.getUsername(), federatedIdentityModel.getIdentityProvider() + "." + federatedIdentityModel.getUserName());
-
-        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/auth"));
-        return federatedUser;
-    }
-
-    private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username, boolean isProfileUpdateExpected) {
+    protected void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username, boolean isProfileUpdateExpected) {
         loginIDP(username);
 
 
@@ -738,7 +203,7 @@ public abstract class AbstractIdentityProviderTest {
 
     }
 
-    private void loginIDP(String username) {
+    protected void loginIDP(String username) {
         driver.navigate().to("http://localhost:8081/test-app");
 
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
@@ -776,6 +241,7 @@ public abstract class AbstractIdentityProviderTest {
 
     protected abstract String getProviderId();
 
+
     protected IdentityProviderModel getIdentityProviderModel() {
         IdentityProviderModel identityProviderModel = getRealm().getIdentityProviderByAlias(getProviderId());
 
@@ -786,10 +252,16 @@ public abstract class AbstractIdentityProviderTest {
         return identityProviderModel;
     }
 
-    private RealmModel getRealm() {
-        return this.session.realms().getRealm("realm-with-broker");
+
+    protected RealmModel getRealm() {
+        return getRealm(this.session);
+    }
+
+    protected RealmModel getRealm(KeycloakSession session) {
+        return session.realms().getRealm("realm-with-broker");
     }
 
+
     protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
         if (isProfileUpdateExpected) {
             String userFirstName = "New first";
@@ -805,19 +277,6 @@ public abstract class AbstractIdentityProviderTest {
         }
     }
 
-    private UserSessionStatus retrieveSessionStatus() {
-        UserSessionStatus sessionStatus = null;
-
-        try {
-            String pageSource = this.driver.getPageSource();
-
-            sessionStatus = JsonSerialization.readValue(pageSource.getBytes(), UserSessionStatus.class);
-        } catch (IOException ignore) {
-            ignore.printStackTrace();
-        }
-
-        return sessionStatus;
-    }
 
     private void removeTestUsers() {
         RealmModel realm = getRealm();
@@ -835,40 +294,60 @@ public abstract class AbstractIdentityProviderTest {
             }
         }
     }
-    
-    private String getVerificationEmailLink(MimeMessage message) throws IOException, MessagingException {
-    	Multipart multipart = (Multipart) message.getContent();
-    	
+
+
+    protected void setUpdateProfileFirstLogin(final String updateProfileFirstLogin) {
+        KeycloakModelUtils.runJobInTransaction(this.session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
+
+            @Override
+            public void run(KeycloakSession session) {
+                RealmModel realm = getRealm(session);
+                setUpdateProfileFirstLogin(realm, updateProfileFirstLogin);
+            }
+
+        });
+    }
+
+    protected void setUpdateProfileFirstLogin(RealmModel realm, String updateProfileFirstLogin) {
+        AuthenticatorConfigModel reviewProfileConfig = realm.getAuthenticatorConfigByAlias(DefaultAuthenticationFlows.IDP_REVIEW_PROFILE_CONFIG_ALIAS);
+        reviewProfileConfig.getConfig().put(IdpReviewProfileAuthenticatorFactory.UPDATE_PROFILE_ON_FIRST_LOGIN, updateProfileFirstLogin);
+        realm.updateAuthenticatorConfig(reviewProfileConfig);
+    }
+
+
+    protected UserSessionStatusServlet.UserSessionStatus retrieveSessionStatus() {
+        UserSessionStatusServlet.UserSessionStatus sessionStatus = null;
+
+        try {
+            String pageSource = this.driver.getPageSource();
+
+            sessionStatus = JsonSerialization.readValue(pageSource.getBytes(), UserSessionStatusServlet.UserSessionStatus.class);
+        } catch (IOException ignore) {
+            ignore.printStackTrace();
+        }
+
+        return sessionStatus;
+    }
+
+    protected String getVerificationEmailLink(MimeMessage message) throws IOException, MessagingException {
+        Multipart multipart = (Multipart) message.getContent();
+
         final String textContentType = multipart.getBodyPart(0).getContentType();
-        
+
         assertEquals("text/plain; charset=UTF-8", textContentType);
-        
+
         final String textBody = (String) multipart.getBodyPart(0).getContent();
         final String textVerificationUrl = MailUtil.getLink(textBody);
-    	
+
         final String htmlContentType = multipart.getBodyPart(1).getContentType();
-        
+
         assertEquals("text/html; charset=UTF-8", htmlContentType);
-        
+
         final String htmlBody = (String) multipart.getBodyPart(1).getContent();
         final String htmlVerificationUrl = MailUtil.getLink(htmlBody);
-        
+
         assertEquals(htmlVerificationUrl, textVerificationUrl);
 
         return htmlVerificationUrl;
     }
-
-    private void setUpdateProfileFirstLogin(final String updateProfileFirstLogin) {
-        KeycloakModelUtils.runJobInTransaction(this.session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
-
-            @Override
-            public void run(KeycloakSession session) {
-                RealmModel realm = session.realms().getRealm("realm-with-broker");
-                AuthenticatorConfigModel reviewProfileConfig = realm.getAuthenticatorConfigByAlias(DefaultAuthenticationFlows.IDP_REVIEW_PROFILE_CONFIG_ALIAS);
-                reviewProfileConfig.getConfig().put(IdpReviewProfileAuthenticatorFactory.UPDATE_PROFILE_ON_FIRST_LOGIN, updateProfileFirstLogin);
-                realm.updateAuthenticatorConfig(reviewProfileConfig);
-            }
-
-        });
-    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
new file mode 100644
index 0000000..904caf6
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -0,0 +1,519 @@
+package org.keycloak.testsuite.broker;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Set;
+
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.internet.MimeMessage;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.services.Urls;
+import org.keycloak.testsuite.MailUtil;
+import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author pedroigor
+ */
+public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdentityProviderTest {
+
+    @Test
+    public void testSuccessfulAuthentication() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
+
+        UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com", true);
+        Assert.assertEquals("617-666-7777", user.getFirstAttribute("mobile"));
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_MISSING);
+
+        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_MISSING);
+
+        assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", "new@email.com", true);
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
+    }
+
+    /**
+     * Test that verify email action is performed if email is provided and email trust is not enabled for the provider
+     *
+     * @throws MessagingException
+     * @throws IOException
+     */
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        try {
+            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+            identityProviderModel.setTrustEmail(false);
+
+            UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost", false);
+
+            // email is verified now
+            assertFalse(federatedUser.getRequiredActions().contains(UserModel.RequiredAction.VERIFY_EMAIL.name()));
+
+        } finally {
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
+    private UserModel assertSuccessfulAuthenticationWithEmailVerification(IdentityProviderModel identityProviderModel, String username, String expectedEmail,
+                                                                          boolean isProfileUpdateExpected)
+            throws IOException, MessagingException {
+        authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
+
+        // verify email is sent
+        Assert.assertTrue(verifyEmailPage.isCurrent());
+
+        // read email to take verification link from
+        Assert.assertEquals(1, greenMail.getReceivedMessages().length);
+        MimeMessage message = greenMail.getReceivedMessages()[0];
+        String verificationUrl = getVerificationEmailLink(message);
+
+        driver.navigate().to(verificationUrl.trim());
+
+        // authenticated and redirected to app
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+
+        UserModel federatedUser = getFederatedUser();
+
+        assertNotNull(federatedUser);
+
+        doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
+
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+        RealmModel realm = getRealm();
+
+        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+        assertEquals(1, federatedIdentities.size());
+
+        FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+        assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+        assertEquals(federatedUser.getUsername(), federatedIdentityModel.getIdentityProvider() + "." + federatedIdentityModel.getUserName());
+
+        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/auth"));
+        return federatedUser;
+    }
+
+    /**
+     * Test for KEYCLOAK-1053 - verify email action is not performed if email is not provided, login is normal, but action stays in set to be performed later
+     */
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        try {
+            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null, false);
+
+            assertTrue(federatedUser.getRequiredActions().contains(UserModel.RequiredAction.VERIFY_EMAIL.name()));
+
+        } finally {
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
+    /**
+     * Test for KEYCLOAK-1372 - verify email action is not performed if email is provided but email trust is enabled for the provider
+     */
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() {
+        getRealm().setVerifyEmail(true);
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        try {
+            identityProviderModel.setTrustEmail(true);
+
+            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
+
+            assertFalse(federatedUser.getRequiredActions().contains(UserModel.RequiredAction.VERIFY_EMAIL.name()));
+
+        } finally {
+            identityProviderModel.setTrustEmail(false);
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
+    /**
+     * Test for KEYCLOAK-1372 - verify email action is performed if email is provided and email trust is enabled for the provider, but email is changed on First login update profile page
+     *
+     * @throws MessagingException
+     * @throws IOException
+     */
+    @Test
+    public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        try {
+            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
+            identityProviderModel.setTrustEmail(true);
+
+            UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com", true);
+            Assert.assertEquals("617-666-7777", user.getFirstAttribute("mobile"));
+        } finally {
+            identityProviderModel.setTrustEmail(false);
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
+
+        getRealm().setRegistrationEmailAsUsername(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        try {
+            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+            authenticateWithIdentityProvider(identityProviderModel, "test-user", false);
+
+            // authenticated and redirected to app
+            assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+
+            brokerServerRule.stopSession(session, true);
+            session = brokerServerRule.startSession();
+
+            // check correct user is created with email as username and bound to correct federated identity
+            RealmModel realm = getRealm();
+
+            UserModel federatedUser = session.users().getUserByUsername("test-user@localhost", realm);
+
+            assertNotNull(federatedUser);
+
+            assertEquals("test-user@localhost", federatedUser.getUsername());
+
+            doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost", false);
+
+            Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+            assertEquals(1, federatedIdentities.size());
+
+            FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+            assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+
+            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/auth"));
+
+        } finally {
+            getRealm().setRegistrationEmailAsUsername(false);
+        }
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
+
+        getRealm().setRegistrationEmailAsUsername(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        try {
+            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+            authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail", false);
+
+            brokerServerRule.stopSession(session, true);
+            session = brokerServerRule.startSession();
+
+            // check correct user is created with username from provider as email is not available
+            RealmModel realm = getRealm();
+            UserModel federatedUser = getFederatedUser();
+            assertNotNull(federatedUser);
+
+            doAssertFederatedUserNoEmail(federatedUser);
+
+            Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+            assertEquals(1, federatedIdentities.size());
+
+            FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+            assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+            revokeGrant();
+
+            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/auth"));
+
+        } finally {
+            getRealm().setRegistrationEmailAsUsername(false);
+        }
+    }
+
+    @Test
+    public void testDisabled() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+
+        identityProviderModel.setEnabled(false);
+
+        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/auth"));
+
+        try {
+            this.driver.findElement(By.className(getProviderId()));
+            fail("Provider [" + getProviderId() + "] not disabled.");
+        } catch (NoSuchElementException nsee) {
+
+        }
+    }
+
+    @Test
+    public void testProviderOnLoginPage() {
+        // Provider button is available on login page
+        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/auth"));
+        loginPage.findSocialButton(getProviderId());
+    }
+
+    @Test
+    public void testAccountManagementLinkIdentity() {
+        // Login as pedroigor to account management
+        accountFederatedIdentityPage.realm("realm-with-broker");
+        accountFederatedIdentityPage.open();
+        assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
+        loginPage.login("pedroigor", "password");
+        assertTrue(accountFederatedIdentityPage.isCurrent());
+
+        // Link my "pedroigor" identity with "test-user" from brokered Keycloak
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
+        accountFederatedIdentityPage.clickAddProvider(identityProviderModel.getAlias());
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
+        this.loginPage.login("test-user", "password");
+        doAfterProviderAuthentication();
+
+        // Assert identity linked in account management
+        assertTrue(accountFederatedIdentityPage.isCurrent());
+        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
+
+        // Revoke grant in account mgmt
+        revokeGrant();
+
+        // Logout from account management
+        accountFederatedIdentityPage.logout();
+        assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
+
+        // Assert I am logged immediately to account management due to previously linked "test-user" identity
+        loginPage.clickSocial(identityProviderModel.getAlias());
+        doAfterProviderAuthentication();
+        assertTrue(accountFederatedIdentityPage.isCurrent());
+        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
+
+        // Unlink my "test-user"
+        accountFederatedIdentityPage.clickRemoveProvider(identityProviderModel.getAlias());
+        assertTrue(driver.getPageSource().contains("id=\"add-" + identityProviderModel.getAlias() + "\""));
+
+        // Revoke grant in account mgmt
+        revokeGrant();
+
+        // Logout from account management
+        System.out.println("*** logout from account management");
+        accountFederatedIdentityPage.logout();
+        assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
+
+        // Try to login. Previous link is not valid anymore, so now it should try to register new user
+        this.loginPage.clickSocial(identityProviderModel.getAlias());
+        this.loginPage.login("test-user", "password");
+        doAfterProviderAuthentication();
+        this.updateProfilePage.assertCurrent();
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testIdentityProviderNotAllowed() {
+        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/auth"));
+
+        driver.findElement(By.className("model-oidc-idp"));
+    }
+
+    protected void configureClientRetrieveToken(String clientId) {
+        RealmModel realm = getRealm();
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (!client.hasScope(readTokenRole)) client.addScopeMapping(readTokenRole);
+
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    protected void configureUserRetrieveToken(String username) {
+        RealmModel realm = getRealm();
+        UserModel user = session.users().getUserByUsername(username, realm);
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
+        if (user != null && !user.hasRole(readTokenRole)) {
+            user.grantRole(readTokenRole);
+        }
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    protected void unconfigureClientRetrieveToken(String clientId) {
+        RealmModel realm = getRealm();
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (client.hasScope(readTokenRole)) client.deleteScopeMapping(readTokenRole);
+
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    protected void unconfigureUserRetrieveToken(String username) {
+        RealmModel realm = getRealm();
+        UserModel user = session.users().getUserByUsername(username, realm);
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
+        if (user != null && user.hasRole(readTokenRole)) {
+            user.deleteRoleMapping(readTokenRole);
+        }
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    @Test
+    public void testTokenStorageAndRetrievalByApplication() {
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON);
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+
+        identityProviderModel.setStoreToken(true);
+
+        authenticateWithIdentityProvider(identityProviderModel, "test-user", true);
+
+        UserModel federatedUser = getFederatedUser();
+        RealmModel realm = getRealm();
+        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+        assertFalse(federatedIdentities.isEmpty());
+        assertEquals(1, federatedIdentities.size());
+
+        FederatedIdentityModel identityModel = federatedIdentities.iterator().next();
+
+        assertNotNull(identityModel.getToken());
+
+        UserSessionStatusServlet.UserSessionStatus userSessionStatus = retrieveSessionStatus();
+        String accessToken = userSessionStatus.getAccessTokenString();
+        URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), realm.getName());
+        final String authHeader = "Bearer " + accessToken;
+        ClientRequestFilter authFilter = new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
+            }
+        };
+        Client client = ClientBuilder.newBuilder().register(authFilter).build();
+        WebTarget tokenEndpoint = client.target(tokenEndpointUrl);
+        Response response = tokenEndpoint.request().get();
+        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+        assertNotNull(response.readEntity(String.class));
+        revokeGrant();
+
+
+        driver.navigate().to("http://localhost:8081/test-app/logout");
+        String currentUrl = this.driver.getCurrentUrl();
+        System.out.println("after logout currentUrl: " + currentUrl);
+        assertTrue(currentUrl.startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
+
+        unconfigureUserRetrieveToken(getProviderId() + ".test-user");
+        loginIDP("test-user");
+        //authenticateWithIdentityProvider(identityProviderModel, "test-user");
+        assertEquals("http://localhost:8081/test-app", driver.getCurrentUrl());
+
+        userSessionStatus = retrieveSessionStatus();
+        accessToken = userSessionStatus.getAccessTokenString();
+        final String authHeader2 = "Bearer " + accessToken;
+        ClientRequestFilter authFilter2 = new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader2);
+            }
+        };
+        client = ClientBuilder.newBuilder().register(authFilter2).build();
+        tokenEndpoint = client.target(tokenEndpointUrl);
+        response = tokenEndpoint.request().get();
+
+        assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.getStatus());
+
+        revokeGrant();
+        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/auth"));
+    }
+
+    protected abstract void doAssertTokenRetrieval(String pageSource);
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCFirstBrokerLoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCFirstBrokerLoginTest.java
new file mode 100644
index 0000000..d689363
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCFirstBrokerLoginTest.java
@@ -0,0 +1,145 @@
+package org.keycloak.testsuite.broker;
+
+import java.util.Set;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticatorFactory;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.KeycloakServer;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.openqa.selenium.NoSuchElementException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
+
+    private static final int PORT = 8082;
+
+    @ClassRule
+    public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
+
+        @Override
+        protected void configureServer(KeycloakServer server) {
+            server.getConfig().setPort(PORT);
+        }
+
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-kc-oidc.json"));
+            server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml.json"));
+        }
+
+        @Override
+        protected String[] getTestRealms() {
+            return new String[] { "realm-with-oidc-identity-provider", "realm-with-saml-idp-basic" };
+        }
+    };
+
+    @Override
+    protected String getProviderId() {
+        return "kc-oidc-idp";
+    }
+
+
+    /**
+     * Tests that duplication is detected and user wants to link federatedIdentity with existing account. He will confirm link by reauthentication
+     * with different broker already linked to his account
+     */
+    @Test
+    public void testLinkAccountByReauthenticationWithDifferentBroker() throws Exception {
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW,
+                        IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.DISABLED);
+
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
+            }
+
+        }, APP_REALM_ID);
+
+        // First link "pedroigor" user with SAML broker and logout
+        driver.navigate().to("http://localhost:8081/test-app");
+        this.loginPage.clickSocial("kc-saml-idp-basic");
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
+        Assert.assertEquals("Log in to realm-with-saml-idp-basic", this.driver.getTitle());
+        this.loginPage.login("pedroigor", "password");
+
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickLinkAccount();
+
+        this.loginPage.login("password");
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+        driver.navigate().to("http://localhost:8081/test-app/logout");
+
+
+        // login through OIDC broker now
+        loginIDP("pedroigor");
+
+        this.idpConfirmLinkPage.assertCurrent();
+        Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
+        this.idpConfirmLinkPage.clickLinkAccount();
+
+        // assert reauthentication with login page. On login page is link to kc-saml-idp-basic as user has it linked already
+        Assert.assertEquals("Log in to " + APP_REALM_ID, this.driver.getTitle());
+        Assert.assertEquals("Authenticate as pedroigor to link your account with " + getProviderId(), this.loginPage.getSuccessMessage());
+
+        try {
+            this.loginPage.findSocialButton(getProviderId());
+            Assert.fail("Not expected to see social button with " + getProviderId());
+        } catch (NoSuchElementException expected) {
+        }
+
+        // reauthenticate with SAML broker
+        this.loginPage.clickSocial("kc-saml-idp-basic");
+        Assert.assertEquals("Log in to realm-with-saml-idp-basic", this.driver.getTitle());
+        this.loginPage.login("pedroigor", "password");
+
+
+        // authenticated and redirected to app. User is linked with identity provider
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+        UserModel federatedUser = getFederatedUser();
+
+        assertNotNull(federatedUser);
+        assertEquals("pedroigor", federatedUser.getUsername());
+        assertEquals("psilva@redhat.com", federatedUser.getEmail());
+
+        RealmModel realmWithBroker = getRealm();
+        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker);
+        assertEquals(2, federatedIdentities.size());
+
+        for (FederatedIdentityModel link : federatedIdentities) {
+            Assert.assertEquals("pedroigor", link.getUserName());
+            Assert.assertTrue(link.getIdentityProvider().equals(getProviderId()) || link.getIdentityProvider().equals("kc-saml-idp-basic"));
+        }
+
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW,
+                        IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.ALTERNATIVE);
+
+            }
+
+        }, APP_REALM_ID);
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
index 0a7ee16..5bfdc1d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
@@ -26,7 +26,7 @@ import static org.junit.Assert.fail;
 /**
  * @author pedroigor
  */
-public class OIDCKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderTest {
+public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityProviderTest {
 
     private static final int PORT = 8082;
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLFirstBrokerLoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLFirstBrokerLoginTest.java
new file mode 100644
index 0000000..66692d4
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLFirstBrokerLoginTest.java
@@ -0,0 +1,40 @@
+package org.keycloak.testsuite.broker;
+
+import org.junit.ClassRule;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.KeycloakServer;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SAMLFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
+
+    private static final int PORT = 8082;
+
+    @ClassRule
+    public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
+
+        @Override
+        protected void configureServer(KeycloakServer server) {
+            server.getConfig().setPort(PORT);
+        }
+
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml.json"));
+        }
+
+        @Override
+        protected String[] getTestRealms() {
+            return new String[] { "realm-with-saml-idp-basic" };
+        }
+    };
+
+    @Override
+    protected String getProviderId() {
+        return "kc-saml-idp-basic";
+    }
+}
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
index 7bbaa20..8be9dcc 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
@@ -24,7 +24,7 @@ import static org.junit.Assert.fail;
 /**
  * @author pedroigor
  */
-public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderTest {
+public class SAMLKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityProviderTest {
 
     @ClassRule
     public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
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
index 249f2e0..197749b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
@@ -24,7 +24,7 @@ import static org.junit.Assert.fail;
 /**
  * @author pedroigor
  */
-public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityProviderTest {
+public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractKeycloakIdentityProviderTest {
 
     @ClassRule
     public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/IdpConfirmLinkPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/IdpConfirmLinkPage.java
new file mode 100644
index 0000000..83596a0
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/IdpConfirmLinkPage.java
@@ -0,0 +1,41 @@
+package org.keycloak.testsuite.pages;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class IdpConfirmLinkPage extends AbstractPage {
+
+    @FindBy(id = "updateProfile")
+    private WebElement updateProfileButton;
+
+    @FindBy(id = "linkAccount")
+    private WebElement linkAccountButton;
+
+    @FindBy(className = "instruction")
+    private WebElement message;
+
+    @Override
+    public boolean isCurrent() {
+        return driver.getTitle().equals("Account already exists");
+    }
+
+    public String getMessage() {
+        return message.getText();
+    }
+
+    public void clickReviewProfile() {
+        updateProfileButton.click();
+    }
+
+    public void clickLinkAccount() {
+        linkAccountButton.click();
+    }
+
+    @Override
+    public void open() throws Exception {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java
new file mode 100644
index 0000000..91387b5
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java
@@ -0,0 +1,27 @@
+package org.keycloak.testsuite.pages;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class IdpLinkEmailPage extends AbstractPage {
+
+    @FindBy(id = "instruction1")
+    private WebElement message;
+
+    @Override
+    public boolean isCurrent() {
+        return driver.getTitle().startsWith("Link ");
+    }
+
+    @Override
+    public void open() throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getMessage() {
+        return message.getText();
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
index f329533..04e5ddd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
@@ -112,6 +112,10 @@ public class LoginPage extends AbstractPage {
         return usernameInput.getAttribute("value");
     }
 
+    public boolean isUsernameInputEnabled() {
+        return usernameInput.isEnabled();
+    }
+
     public String getPassword() {
         return passwordInput.getAttribute("value");
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java
index d67862c..c9038a4 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java
@@ -21,6 +21,8 @@
  */
 package org.keycloak.testsuite.pages;
 
+import org.junit.Assert;
+import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;