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 c145d97768..8fad0c30b6 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 @@ -35,6 +35,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.representations.IDToken; import org.keycloak.services.Urls; +import org.keycloak.testsuite.MailUtil; import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus; import org.keycloak.testsuite.pages.AccountFederatedIdentityPage; @@ -42,6 +43,8 @@ import org.keycloak.testsuite.pages.AccountPasswordPage; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginUpdateProfilePage; import org.keycloak.testsuite.pages.OAuthGrantPage; +import org.keycloak.testsuite.pages.VerifyEmailPage; +import org.keycloak.testsuite.rule.GreenMailRule; import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebRule; import org.openqa.selenium.By; @@ -49,6 +52,8 @@ import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientRequestContext; @@ -58,6 +63,7 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; + import java.io.IOException; import java.net.URI; import java.util.List; @@ -91,6 +97,13 @@ public abstract class AbstractIdentityProviderTest { @WebResource private LoginUpdateProfilePage updateProfilePage; + + @WebResource + protected VerifyEmailPage verifyEmailPage; + + @Rule + public GreenMailRule greenMail = new GreenMailRule(); + @WebResource protected OAuthClient oauth; @@ -123,6 +136,7 @@ public abstract class AbstractIdentityProviderTest { @Test public void testSuccessfulAuthentication() { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); + identityProviderModel.setUpdateProfileFirstLogin(true); UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com"); Assert.assertEquals("617-666-7777", user.getAttribute("mobile")); @@ -136,6 +150,78 @@ public abstract class AbstractIdentityProviderTest { assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost"); } + /** + * 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 { + identityProviderModel.setUpdateProfileFirstLogin(false); + identityProviderModel.setTrustEmail(false); + + UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerifycation(identityProviderModel, "test-user", "test-user@localhost"); + + // email is verified now + assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name())); + + } finally { + getRealm().setVerifyEmail(false); + } + } + + private UserModel assertSuccessfulAuthenticationWithEmailVerifycation(IdentityProviderModel identityProviderModel, String username, String expectedEmail) + throws IOException, MessagingException { + authenticateWithIdentityProvider(identityProviderModel, username); + + // 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 body = (String) message.getContent(); + String verificationUrl = MailUtil.getLink(body); + + 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); + + brokerServerRule.stopSession(session, true); + session = brokerServerRule.startSession(); + + RealmModel realm = getRealm(); + + Set 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 */ @@ -158,6 +244,55 @@ public abstract class AbstractIdentityProviderTest { } } + /** + * 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); + brokerServerRule.stopSession(this.session, true); + this.session = brokerServerRule.startSession(); + + IdentityProviderModel identityProviderModel = getIdentityProviderModel(); + try { + identityProviderModel.setUpdateProfileFirstLogin(false); + identityProviderModel.setTrustEmail(true); + + UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost"); + + 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 { + identityProviderModel.setUpdateProfileFirstLogin(true); + identityProviderModel.setTrustEmail(true); + + UserModel user = assertSuccessfulAuthenticationWithEmailVerifycation(identityProviderModel, "test-user", "new@email.com"); + Assert.assertEquals("617-666-7777", user.getAttribute("mobile")); + } finally { + identityProviderModel.setTrustEmail(false); + getRealm().setVerifyEmail(false); + } + } + @Test public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() { @@ -275,15 +410,10 @@ public abstract class AbstractIdentityProviderTest { @Test public void testProviderOnLoginPage() { - IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - RealmModel realm = getRealm(); - ClientModel clientModel = realm.getClientByClientId("test-app"); - // 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 @@ -390,7 +520,6 @@ public abstract class AbstractIdentityProviderTest { revokeGrant(); // Logout from account management - String pageSource = driver.getPageSource(); System.out.println("*** logout from account management"); accountFederatedIdentityPage.logout(); assertTrue(driver.getTitle().equals("Log in to realm-with-broker")); @@ -400,7 +529,6 @@ public abstract class AbstractIdentityProviderTest { this.loginPage.clickSocial(identityProviderModel.getAlias()); this.loginPage.login("test-user", "password"); doAfterProviderAuthentication(); - String current = driver.getCurrentUrl(); this.updateProfilePage.assertCurrent(); } @@ -637,12 +765,10 @@ public abstract class AbstractIdentityProviderTest { String userLastName = "New last"; assertEquals(expectedEmail, federatedUser.getEmail()); - assertFalse(federatedUser.isEmailVerified()); assertEquals(userFirstName, federatedUser.getFirstName()); assertEquals(userLastName, federatedUser.getLastName()); } else { assertEquals(expectedEmail, federatedUser.getEmail()); - assertFalse(federatedUser.isEmailVerified()); assertEquals("Test", federatedUser.getFirstName()); assertEquals("User", federatedUser.getLastName()); } 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 9e8b239bc7..46bfa3da45 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 @@ -57,10 +57,8 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT if (expectedEmail == null) { // Need to handle differences for various databases (like Oracle) assertTrue(federatedUser.getEmail() == null || federatedUser.getEmail().equals("")); - assertFalse(federatedUser.isEmailVerified()); } else { assertEquals(expectedEmail, federatedUser.getEmail()); - assertTrue(federatedUser.isEmailVerified()); } assertNull(federatedUser.getFirstName()); assertNull(federatedUser.getLastName()); 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 7252d5345a..821fc0e51a 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 @@ -57,10 +57,8 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP if (expectedEmail == null) { // Need to handle differences for various databases (like Oracle) assertTrue(federatedUser.getEmail() == null || federatedUser.getEmail().equals("")); - assertFalse(federatedUser.isEmailVerified()); } else { assertEquals(expectedEmail, federatedUser.getEmail()); - assertFalse(federatedUser.isEmailVerified()); } assertNull(federatedUser.getFirstName()); assertNull(federatedUser.getLastName()); diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json index ceef4ddba9..3da5f75010 100755 --- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json +++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json @@ -7,6 +7,11 @@ "registrationAllowed": true, "privateKey": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCCPyvTTb14vSMkpe/pds2P5Cqxk7bkeFnQiNMS1vyZ+HS2O79fxzp1eAguHnBTs4XTRT7SZJhIT/6utgqZjmDigKV5N7X5ptq8BM/W1qa1cYBRip261pc+tWf3IywJYQ9yFI9mUQarmIEl0D7GH16NSZklheaWfbodRVarvX+ML0amNtGYVDft/RftYmgbKKrK218qQp9R4GZFtf/Q/RmboNXN7weMINU8GWVkTRrccKBIXSunT6zXGfuj3Wp1YpVq20BWwY2OMM/P+yDAc7LKEO1LJqPBdT4r9BRn2lXiaga3AL24gTKZPKU/tu7uqfFciF+i4Rr58SMDNOzQcnklAgMBAAECggEAc0eibJYEO5d8QXW1kPgcHV2gBChv2mxDYnWYDLbIQSdNdfYP/qABt/MTmm5KkWr16fcCEYoD1w0mqFBrtVn1msSusUmEAYGTXJMNumOmjjX1kzaTQMmqeFBrwqwYz/xehWR5P+A7fSmwNV3KEeW19GvN5w5K96w0TLAQdFV3TQVPSytusDunwuR1yltMe1voaEDZ9z0Pi08YiEk2f6xhj5CMkoiw3mNImzfruphHullxU4FD05fH6tDeJ381527ILpAzDsgYZh4aFLKjUHem96bX4EL7FIzBJ6okgN78AZnUC/EaVfgFTw0qfhoWvZV4ruVXXiMhCg4CMMRDq/k9iQKBgQDBNWsJMT84OnnWmQoJmZogkFV+tsGrSK6Re+aJxLWpishh7dwAnT2OcagZvVdUb0FwNWu1D0B9/SKDDMRnnHBhOGDpH57m/eQdRU0oX1BD27xvffk0lLcfD4BTxnR5e9jss8K4twc9jf0P1rxC/loGJ2NtCH0BrPHgz54Ea+96ewKBgQCsk3JDaaPnFwzVYm2BXlhxOxLPsF4wvD2rIRAswZV4C5xebjand8nwiMmVpNd0PRLkEnkI+waURGv2EY/P3JsssoiY8Xqe8f/1G+SQKre7lbqOas8rFoALepC0BYDiZDFy0Z9ZnRAFzRI5sgIt7jpoMRD4xDNlmiV8X+yBxc3Y3wKBgQChDQsU1YUyNKQ8+sLAL9anEEkD4Ald4q8JPHN2IY+gLLxNzT0XEfsu0pTiJ8805axxgUYv3e/PVYNAJBNPnrqaf6lgiegl+jr9Hzhqz9CTUAYqFaL2boSakoxQyNtsLI0s+cb1vDN/3uy0GDZDzcty18BsMagqDmRtFgNNAj/UIwKBgQCahbeFBv0cOPZjxisY8Bou4N8aGehsqNBq/0LVYExuXa8YmoTTdJ3bgw9Er4G/ccQNdUDsuqAMeCtW/CiRzQ0ge4d1sprB4Rv3I4+HSsiS7SFKzfZLtWzXWlpg5qCdlWr1TR7qhYjIOPO9t1beO3YOvwhcRoliyyAPenBxTmTfbwKBgDtm2WJ5VlQgNpIdOs1CCiqd0DFmWOmvBPspPC1kySiy+Ndr9jNohRZkR7pEjgqA5E8rdzc88LirUN7bY5HFHRWN9KXrs5/o3O1K3GFCp64N6nvnPEYZ2zSJalcMC2fjSsJg26z8Dg1H+gfTIDUMoGiEAAnJXuqk+WayPU+fZMLn", "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB", + "smtpServer": { + "from": "auto@keycloak.org", + "host": "localhost", + "port":"3025" + }, "identityProviders" : [ { "alias" : "model-google", @@ -130,7 +135,7 @@ "providerId" : "saml", "enabled": true, "updateProfileFirstLogin" : true, - "trustEmail" : true, + "trustEmail" : false, "addReadTokenRoleOnCreate": true, "config": { "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",