diff --git a/.travis.yml b/.travis.yml index c875dcc06a..4d83796ca0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ env: - TESTS=old - TESTS=crossdc-server - TESTS=crossdc-adapter + - TESTS=broker jdk: - oraclejdk8 diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java index d083eb5a1c..bb98075667 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java @@ -45,8 +45,6 @@ public final class TestContext { private boolean adminLoggedIn; - private final Map customContext = new HashMap<>(); - private Keycloak adminClient; private KeycloakTestingClient testingClient; private List testRealmReps = new ArrayList<>(); @@ -186,14 +184,6 @@ public final class TestContext { } - public Object getCustomValue(Object key) { - return customContext.get(key); - } - - public void setCustomValue(Object key, Object value) { - customContext.put(key, value); - } - public String getAppServerContainerName() { if (isAdapterContainerEnabled()) { //standalone app server return getAppServerInfo().getArquillianContainer().getName(); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java index 5f5da8c328..6e9e768e63 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java @@ -61,6 +61,9 @@ public class AccountManagement extends AuthRealm implements PageWithLogOutAction @FindBy(linkText = "Applications") private WebElement applicationsLink; + @FindBy(linkText = "Federated Identity") + private WebElement federatedIdentityLink; + @FindByJQuery("button[value='Save']") private WebElement save; @@ -111,6 +114,11 @@ public class AccountManagement extends AuthRealm implements PageWithLogOutAction waitForPageToLoad(); } + public void federatedIdentity() { + federatedIdentityLink.click(); + waitForPageToLoad(); + } + public void save() { save.click(); waitForPageToLoad(); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java index 7992ccf1b8..1322d794ed 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java @@ -84,6 +84,10 @@ public class AccountFederatedIdentityPage extends AbstractAccountPage { return errorMessage.getText(); } + public boolean isLinked(String idpAlias) { + return driver.getPageSource().contains("id=\"remove-link-" + idpAlias + "\""); + } + public static class FederatedIdentity { private String providerId; diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountPasswordPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountPasswordPage.java index d62806f0b4..52db026470 100755 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountPasswordPage.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountPasswordPage.java @@ -39,6 +39,9 @@ public class AccountPasswordPage extends AbstractAccountPage { @FindBy(className = "btn-primary") private WebElement submitButton; + @FindBy(className = "alert-error") + private WebElement errorMessage; + private String realmName = "test"; public void changePassword(String password, String newPassword, String passwordConfirm) { @@ -71,4 +74,8 @@ public class AccountPasswordPage extends AbstractAccountPage { public String getPath() { return AccountFormService.passwordUrl(UriBuilder.fromUri(getAuthServerRoot())).build(this.realmName).toString(); } + + public String getError() { + return errorMessage.getText(); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java index 1080a44044..86e7c9bfb7 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/IdpLinkEmailPage.java @@ -28,6 +28,9 @@ public class IdpLinkEmailPage extends AbstractPage { @FindBy(id = "instruction1") private WebElement message; + @FindBy(linkText = "Click here") + private WebElement resendEmailLink; + @Override public boolean isCurrent() { return PageUtils.getPageTitle(driver).startsWith("Link "); @@ -41,4 +44,8 @@ public class IdpLinkEmailPage extends AbstractPage { public String getMessage() { return message.getText(); } + + public void resendEmail() { + resendEmailLink.click(); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/UpdateAccountInformationPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/UpdateAccountInformationPage.java index de24f2da75..c5f18cc22d 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/UpdateAccountInformationPage.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/UpdateAccountInformationPage.java @@ -39,6 +39,21 @@ public class UpdateAccountInformationPage extends AbstractPage { submitButton.click(); } + public void updateAccountInformation(String email, + String firstName, + String lastName) { + emailInput.clear(); + emailInput.sendKeys(email); + + firstNameInput.clear(); + firstNameInput.sendKeys(firstName); + + lastNameInput.clear(); + lastNameInput.sendKeys(lastName); + + submitButton.click(); + } + public void updateAccountInformation(String firstName, String lastName) { firstNameInput.clear(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java index d488c789b4..e0f0e1f42b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java @@ -108,27 +108,6 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest { } } - public static UserRepresentation createUserRepresentation(String username, String email, String firstName, String lastName, boolean enabled) { - UserRepresentation user = new UserRepresentation(); - user.setUsername(username); - user.setEmail(email); - user.setFirstName(firstName); - user.setLastName(lastName); - user.setEnabled(enabled); - return user; - } - - public static UserRepresentation createUserRepresentation(String username, String email, String firstName, String lastName, boolean enabled, String password) { - UserRepresentation user = createUserRepresentation(username, email, firstName, lastName, enabled); - setPasswordFor(user, password); - return user; - } - - public static UserRepresentation createUserRepresentation(String username, String password) { - UserRepresentation user = createUserRepresentation(username, null, null, null, true, password); - return user; - } - protected void deleteAllCookiesForTestRealm() { deleteAllCookiesForRealm(testRealmAccountPage); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java index 797722466c..23c7c8aa38 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java @@ -26,7 +26,6 @@ import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.logging.Logger; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.AuthenticationManagementResource; @@ -53,33 +52,19 @@ import org.keycloak.testsuite.auth.page.account.Account; import org.keycloak.testsuite.auth.page.login.OIDCLogin; import org.keycloak.testsuite.auth.page.login.UpdatePassword; import org.keycloak.testsuite.client.KeycloakTestingClient; +import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; import org.keycloak.testsuite.util.AdminClientUtil; import org.keycloak.testsuite.util.DroneUtils; import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.TestCleanup; import org.keycloak.testsuite.util.TestEventsLogger; import org.openqa.selenium.WebDriver; -import org.wildfly.extras.creaper.commands.undertow.AddUndertowListener; -import org.wildfly.extras.creaper.commands.undertow.RemoveUndertowListener; -import org.wildfly.extras.creaper.commands.undertow.SslVerifyClient; -import org.wildfly.extras.creaper.commands.undertow.UndertowListenerType; -import org.wildfly.extras.creaper.core.CommandFailedException; -import org.wildfly.extras.creaper.core.online.CliException; -import org.wildfly.extras.creaper.core.online.OnlineManagementClient; -import org.wildfly.extras.creaper.core.online.operations.Address; -import org.wildfly.extras.creaper.core.online.operations.OperationException; -import org.wildfly.extras.creaper.core.online.operations.Operations; -import org.wildfly.extras.creaper.core.online.operations.admin.Administration; import javax.ws.rs.NotFoundException; import javax.ws.rs.core.UriBuilder; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintWriter; @@ -92,7 +77,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Scanner; -import java.util.concurrent.TimeoutException; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -146,11 +130,16 @@ public abstract class AbstractKeycloakTest { @Page protected Account accountPage; + @Page protected OIDCLogin loginPage; + @Page protected UpdatePassword updatePasswordPage; + @Page + protected LoginPasswordUpdatePage passwordUpdatePage; + @Page protected WelcomePage welcomePage; @@ -483,14 +472,36 @@ public abstract class AbstractKeycloakTest { * @return ID of the newly created user */ public String createUser(String realm, String username, String password, String... requiredActions) { - List requiredUserActions = Arrays.asList(requiredActions); + UserRepresentation homer = createUserRepresentation(username, password); + homer.setRequiredActions(Arrays.asList(requiredActions)); - UserRepresentation homer = new UserRepresentation(); - homer.setEnabled(true); - homer.setUsername(username); - homer.setRequiredActions(requiredUserActions); + return ApiUtil.createUserWithAdminClient(adminClient.realm(realm), homer); + } - return ApiUtil.createUserAndResetPasswordWithAdminClient(adminClient.realm(realm), homer, password); + public String createUser(String realm, String username, String password, String firstName, String lastName, String email) { + UserRepresentation homer = createUserRepresentation(username, email, firstName, lastName, true, password); + return ApiUtil.createUserWithAdminClient(adminClient.realm(realm), homer); + } + + public static UserRepresentation createUserRepresentation(String username, String email, String firstName, String lastName, boolean enabled) { + UserRepresentation user = new UserRepresentation(); + user.setUsername(username); + user.setEmail(email); + user.setFirstName(firstName); + user.setLastName(lastName); + user.setEnabled(enabled); + return user; + } + + public static UserRepresentation createUserRepresentation(String username, String email, String firstName, String lastName, boolean enabled, String password) { + UserRepresentation user = createUserRepresentation(username, email, firstName, lastName, enabled); + setPasswordFor(user, password); + return user; + } + + public static UserRepresentation createUserRepresentation(String username, String password) { + UserRepresentation user = createUserRepresentation(username, null, null, null, true, password); + return user; } public void setRequiredActionEnabled(String realm, String requiredAction, boolean enabled, boolean defaultAction) { @@ -569,7 +580,7 @@ public abstract class AbstractKeycloakTest { return Time.currentTime(); } - private String invokeTimeOffset(int offset) { + protected String invokeTimeOffset(int offset) { // adminClient depends on Time.offset for auto-refreshing tokens Time.setOffset(offset); Map result = testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(offset))); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java index e04b7d5cf2..c00d6b99aa 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java @@ -21,22 +21,36 @@ import java.util.List; import org.hamcrest.Matchers; import org.apache.commons.lang.StringUtils; +import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.graphene.page.Page; +import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.After; -import org.keycloak.admin.client.resource.RealmResource; +import org.junit.Before; +import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.Assert; import org.keycloak.common.util.Retry; -import org.keycloak.testsuite.admin.ApiUtil; +import org.keycloak.testsuite.auth.page.account2.ChangePasswordPage; +import org.keycloak.testsuite.pages.AccountApplicationsPage; +import org.keycloak.testsuite.pages.AccountFederatedIdentityPage; import org.keycloak.testsuite.pages.AccountPasswordPage; import org.keycloak.testsuite.pages.AccountUpdateProfilePage; import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.IdpConfirmLinkPage; +import org.keycloak.testsuite.pages.IdpLinkEmailPage; +import org.keycloak.testsuite.pages.InfoPage; +import org.keycloak.testsuite.pages.LoginConfigTotpPage; +import org.keycloak.testsuite.pages.LoginExpiredPage; import org.keycloak.testsuite.pages.LoginPage; +import org.keycloak.testsuite.pages.LoginTotpPage; +import org.keycloak.testsuite.pages.OAuthGrantPage; +import org.keycloak.testsuite.pages.ProceedPage; import org.keycloak.testsuite.pages.UpdateAccountInformationPage; +import org.keycloak.testsuite.pages.VerifyEmailPage; +import org.keycloak.testsuite.runonserver.RunOnServerDeployment; +import org.keycloak.testsuite.util.MailServer; import org.openqa.selenium.TimeoutException; import static org.junit.Assert.assertThat; @@ -69,6 +83,41 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest { @Page protected IdpConfirmLinkPage idpConfirmLinkPage; + @Page + protected ProceedPage proceedPage; + + @Page + protected InfoPage infoPage; + + @Page + protected IdpLinkEmailPage idpLinkEmailPage; + + @Page + protected LoginExpiredPage loginExpiredPage; + + @Page + protected LoginTotpPage loginTotpPage; + + @Page + protected LoginConfigTotpPage totpPage; + + @Page + protected VerifyEmailPage verifyEmailPage; + + @Page + protected AccountFederatedIdentityPage accountFederatedIdentityPage; + + @Page + protected AccountApplicationsPage accountApplicationsPage; + + @Page + protected OAuthGrantPage grantPage; + + @Page + protected ChangePasswordPage changePasswordPage; + + protected TimeBasedOTP totp = new TimeBasedOTP(); + protected BrokerConfiguration bc = getBrokerConfiguration(); protected String userId; @@ -79,32 +128,28 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest { */ protected abstract BrokerConfiguration getBrokerConfiguration(); - @Override public void addTestRealms(List testRealms) { - RealmRepresentation providerRealm = bc.createProviderRealm(); - RealmRepresentation consumerRealm = bc.createConsumerRealm(); - testRealms.add(providerRealm); - testRealms.add(consumerRealm); } + @Before + public void beforeBrokerTest() { + importRealm(bc.createConsumerRealm()); + importRealm(bc.createProviderRealm()); + } @After public void cleanupUsers() { - RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); - UserRepresentation userRep = ApiUtil.findUserByUsername(providerRealm, bc.getUserLogin()); - if (userRep != null) { - providerRealm.users().get(userRep.getId()).remove(); - } - - RealmResource childRealm = adminClient.realm(bc.consumerRealmName()); - userRep = ApiUtil.findUserByUsername(childRealm, bc.getUserLogin()); - if (userRep != null) { - childRealm.users().get(userRep.getId()).remove(); - } + adminClient.realm(bc.consumerRealmName()).remove(); + adminClient.realm(bc.providerRealmName()).remove(); + MailServer.stop(); } + @Deployment + public static WebArchive deploy() { + return RunOnServerDeployment.create(BrokerRunOnServerUtil.class); + } protected void logInAsUserInIDP() { driver.navigate().to(getAccountUrl(bc.consumerRealmName())); @@ -194,6 +239,7 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest { protected void assertLoggedInAccountManagement() { + waitForPage(driver, "keycloak account management", true); Assert.assertTrue(accountUpdateProfilePage.isCurrent()); Assert.assertEquals(accountUpdateProfilePage.getUsername(), bc.getUserLogin()); Assert.assertEquals(accountUpdateProfilePage.getEmail(), bc.getUserEmail()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java index 667538dc37..ec9190b48b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java @@ -1,44 +1,81 @@ package org.keycloak.testsuite.broker; +import com.google.common.collect.ImmutableMap; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; +import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.drone.api.annotation.Drone; +import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Test; +import org.keycloak.admin.client.resource.AuthenticationManagementResource; import org.keycloak.admin.client.resource.IdentityProviderResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory; +import org.keycloak.broker.provider.HardcodedUserSessionAttributeMapper; +import org.keycloak.common.util.Time; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; +import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; +import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.services.Urls; +import org.keycloak.storage.UserStorageProvider; import org.keycloak.testsuite.Assert; +import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory; import org.keycloak.testsuite.pages.ConsentPage; +import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; +import org.keycloak.testsuite.runonserver.RunOnServerDeployment; import org.keycloak.testsuite.util.*; import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.TimeoutException; +import java.net.URI; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; 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.keycloak.models.utils.DefaultAuthenticationFlows.IDP_REVIEW_PROFILE_CONFIG_ALIAS; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; import static org.keycloak.testsuite.admin.ApiUtil.removeUserByUsername; import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.assertHardCodedSessionNote; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configurePostBrokerLoginWithOTP; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.disablePostBrokerLoginFlow; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.grantReadTokenRole; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.revokeReadTokenRole; import static org.keycloak.testsuite.broker.BrokerTestConstants.USER_EMAIL; import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl; import org.jboss.arquillian.graphene.page.Page; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import javax.mail.internet.MimeMessage; +import javax.ws.rs.client.Client; +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 static org.hamcrest.Matchers.hasItems; @@ -56,6 +93,9 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe @SecondBrowser protected WebDriver driver2; + @Page + ConsentPage consentPage; + @Test public void testLogInAsUserInIDP() { loginUser(); @@ -66,19 +106,9 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe protected void loginUser() { driver.navigate().to(getAccountUrl(bc.consumerRealmName())); - log.debug("Clicking social " + bc.getIDPAlias()); - accountLoginPage.clickSocial(bc.getIDPAlias()); - - waitForPage(driver, "log in to", true); - - Assert.assertTrue("Driver should be on the provider realm page right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); - - log.debug("Logging in"); - accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + logInWithBroker(bc); waitForPage(driver, "update account information", false); - updateAccountInformationPage.assertCurrent(); Assert.assertTrue("We must be on correct realm right now", driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); @@ -105,6 +135,568 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe isUserFound); } + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testErrorPageWhenDuplicationNotAllowed_updateProfileOn + */ + @Test + public void testErrorExistingUserWithUpdateProfile() { + createUser("consumer"); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); + log.debug("Updating info on updateAccount page"); + updateAccountInformationPage.updateAccountInformation("consumer", "consumer-user@redhat.com", "FirstName", "LastName"); + + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with username consumer already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByReauthenticationWithPassword + */ + @Test + public void testLinkAccountByReauthenticationWithPassword() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + String existingUser = createUser("consumer"); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + idpConfirmLinkPage.clickLinkAccount(); + + assertEquals("Authenticate as consumer to link your account with " + bc.getIDPAlias(), loginPage.feedbackMessage().getText()); + + try { + this.accountLoginPage.findSocialButton(bc.getIDPAlias()); + Assert.fail("Not expected to see social button with " + bc.getIDPAlias()); + } catch (NoSuchElementException expected) { + } + + try { + this.accountLoginPage.clickRegister(); + Assert.fail("Not expected to see register link"); + } catch (NoSuchElementException expected) { + } + + accountLoginPage.login("password"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + assertNumFederatedIdentities(existingUser, 1); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testAccountManagementLinkIdentity + */ + @Test + public void testAccountManagementLinkIdentity() { + createUser("consumer"); + // Login as pedroigor to account management + accountFederatedIdentityPage.realm(bc.consumerRealmName()); + accountFederatedIdentityPage.open(); + accountLoginPage.login("consumer", "password"); + assertTrue(accountFederatedIdentityPage.isCurrent()); + + accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias()); + this.accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + // Assert identity linked in account management + assertTrue(accountFederatedIdentityPage.isCurrent()); + assertTrue(accountFederatedIdentityPage.isLinked(bc.getIDPAlias())); + + // Revoke grant in account mgmt + accountFederatedIdentityPage.clickRemoveProvider(bc.getIDPAlias()); + + // Logout from account management + accountFederatedIdentityPage.logout(); + + // Assert I am logged immediately to account management due to previously linked "test-user" identity + logInWithBroker(bc); + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + + accountLoginPage.login(bc.getUserPassword()); + + accountFederatedIdentityPage.assertCurrent(); + assertTrue(accountFederatedIdentityPage.isLinked(bc.getIDPAlias())); + + // Unlink my "test-user" + accountFederatedIdentityPage.clickRemoveProvider(bc.getIDPAlias()); + assertFalse(accountFederatedIdentityPage.isLinked(bc.getIDPAlias())); + + // Logout from account management + accountFederatedIdentityPage.logout(); + + // Try to login. Previous link is not valid anymore, so now it should try to register new user + accountLoginPage.clickSocial(bc.getIDPAlias()); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testAccountManagementLinkedIdentityAlreadyExists + */ + @Test + public void testAccountManagementLinkedIdentityAlreadyExists() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + createUser(bc.consumerRealmName(), "consumer", "password", "FirstName", "LastName", "consumer@localhost.com"); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + logoutFromRealm(bc.providerRealmName()); + logoutFromRealm(bc.consumerRealmName()); + + accountFederatedIdentityPage.realm(bc.consumerRealmName()); + accountFederatedIdentityPage.open(); + accountLoginPage.login("consumer", "password"); + assertTrue(accountFederatedIdentityPage.isCurrent()); + + accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias()); + this.accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + assertTrue(accountFederatedIdentityPage.isCurrent()); + assertEquals("Federated identity returned by " + bc.getIDPAlias() + " is already linked to another user.", accountFederatedIdentityPage.getError()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testTokenStorageAndRetrievalByApplication + */ + @Test + public void testRetrieveToken() throws Exception { + updateExecutions(AbstractBrokerTest::enableRequirePassword); + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + IdentityProviderRepresentation idpRep = identityProviderResource.toRepresentation(); + + idpRep.setStoreToken(true); + + identityProviderResource.update(idpRep); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + updatePasswordPage.updatePasswords("password", "password"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + String username = bc.getUserLogin(); + + testingClient.server(bc.consumerRealmName()).run(grantReadTokenRole(username)); + + OAuthClient.AccessTokenResponse accessTokenResponse = oauth.realm(bc.consumerRealmName()).clientId("broker-app").doGrantAccessTokenRequest("broker-app-secret", bc.getUserLogin(), bc.getUserPassword()); + AtomicReference accessToken = (AtomicReference) new AtomicReference<>(accessTokenResponse.getAccessToken()); + Client client = javax.ws.rs.client.ClientBuilder.newBuilder().register((ClientRequestFilter) request -> request.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken.get())).build(); + + try { + WebTarget target = client.target(Urls.identityProviderRetrieveToken(URI.create(BrokerTestTools.getAuthRoot(suiteContext) + "/auth"), bc.getIDPAlias(), bc.consumerRealmName())); + + try (Response response = target.request().get()) { + assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertNotNull(response.readEntity(String.class)); + } + + testingClient.server(bc.consumerRealmName()).run(revokeReadTokenRole(username)); + + accessTokenResponse = oauth.realm(bc.consumerRealmName()).clientId("broker-app").doGrantAccessTokenRequest("broker-app-secret", bc.getUserLogin(), bc.getUserPassword()); + accessToken.set(accessTokenResponse.getAccessToken()); + + try (Response response = target.request().get()) { + assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.getStatus()); + } + } finally { + client.close(); + } + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByReauthenticationWithPassword_browserButtons + */ + @Test + public void testLinkAccountByLogInAsUserUsingBrowserButtons() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + String userId = createUser("consumer"); + UserResource providerUser = adminClient.realm(bc.providerRealmName()).users().get(this.userId); + UserRepresentation userResource = providerUser.toRepresentation(); + + userResource.setEmail(USER_EMAIL); + userResource.setFirstName("FirstName"); + userResource.setLastName("LastName"); + + providerUser.update(userResource); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + + // we need to force a login failure in order to be able to use back button to go back to login page at the provider + accountLoginPage.login("invalid", bc.getUserPassword()); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + waitForPage(driver, "account already exists", false); + + // Click browser 'back' and then 'forward' and then continue + driver.navigate().back(); + assertTrue(driver.getPageSource().contains("You are already logged in.")); + driver.navigate().forward(); + idpConfirmLinkPage.assertCurrent(); + + // Click browser 'back' on review profile page + idpConfirmLinkPage.clickReviewProfile(); + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + driver.navigate().back(); + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation(bc.getUserEmail(), "FirstName", "LastName"); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + + // Login screen shown. Username is prefilled and disabled. Registration link and social buttons are not shown + assertEquals("consumer", accountLoginPage.getUsername()); + assertFalse(accountLoginPage.isUsernameInputEnabled()); + + assertEquals("Authenticate as consumer to link your account with " + bc.getIDPAlias(), this.loginPage.feedbackMessage().getText()); + + try { + accountLoginPage.findSocialButton(bc.getIDPAlias()); + Assert.fail("Not expected to see social button with " + bc.getIDPAlias()); + } catch (NoSuchElementException expected) { + } + + // Use correct password now + accountLoginPage.login("password"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + assertNumFederatedIdentities(userId, 1); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByReauthentication_forgetPassword + */ + @Test + public void testLinkAccountByLogInAsUserAfterResettingPassword() throws InterruptedException { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + realmRep.setResetPasswordAllowed(true); + + realm.update(realmRep); + + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + String existingUser = createUser("consumer"); + UserResource providerUser = adminClient.realm(bc.providerRealmName()).users().get(userId); + UserRepresentation userResource = providerUser.toRepresentation(); + + userResource.setEmail(USER_EMAIL); + userResource.setFirstName("FirstName"); + userResource.setLastName("LastName"); + + providerUser.update(userResource); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + + configureSMTPServer(); + + this.accountLoginPage.resetPassword(); + assertEquals("You should receive an email shortly with further instructions.", this.loginPage.feedbackMessage().getText()); + assertEquals(1, MailServer.getReceivedMessages().length); + MimeMessage message = MailServer.getLastReceivedMessage(); + String linkFromMail = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "credentials", false); + + driver.navigate().to(linkFromMail.trim()); + + // Need to update password now + this.passwordUpdatePage.assertCurrent(); + this.passwordUpdatePage.changePassword("password", "password"); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + assertNumFederatedIdentities(existingUser, 1); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByReauthentication_forgetPassword_differentBrowser + */ + @Test + public void testLinkAccountByLogInAsUserAfterResettingPasswordUsingDifferentBrowsers() throws InterruptedException { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + realmRep.setResetPasswordAllowed(true); + + realm.update(realmRep); + + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + String existingUser = createUser("consumer"); + UserResource providerUser = adminClient.realm(bc.providerRealmName()).users().get(userId); + UserRepresentation userResource = providerUser.toRepresentation(); + + userResource.setEmail(USER_EMAIL); + userResource.setFirstName("FirstName"); + userResource.setLastName("LastName"); + + providerUser.update(userResource); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + + configureSMTPServer(); + + this.accountLoginPage.resetPassword(); + assertEquals("You should receive an email shortly with further instructions.", this.loginPage.feedbackMessage().getText()); + assertEquals(1, MailServer.getReceivedMessages().length); + MimeMessage message = MailServer.getLastReceivedMessage(); + String linkFromMail = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "credentials", false); + + driver2.navigate().to(linkFromMail.trim()); + removeSMTPConfiguration(realm); + + // Need to update password now + LoginPasswordUpdatePage passwordUpdatePage = PageFactory.initElements(driver2, LoginPasswordUpdatePage.class); + passwordUpdatePage.changePassword("password", "password"); + + assertNumFederatedIdentities(existingUser, 0); + + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + + try { + waitForPage(driver, "account already exists", false); + } catch (Exception e) { + // this is a workaround to make this test work for both oidc and saml. when doing oidc the browser is redirected to the login page to finish the linking + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + } + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + + accountLoginPage.login("password"); + assertNumFederatedIdentities(existingUser, 1); + } + + @Test + public void testFirstBrokerLoginFlowUpdateProfileOff() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testErrorPageWhenDuplicationNotAllowed_updateProfileOff + */ + @Test + public void testUserExistsFirstBrokerLoginFlowUpdateProfileOff() { + UserResource userResource = adminClient.realm(bc.consumerRealmName()).users().get(createUser("consumer")); + UserRepresentation consumerUser = userResource.toRepresentation(); + + consumerUser.setEmail(bc.getUserEmail()); + userResource.update(consumerUser); + + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testErrorPageWhenDuplicationNotAllowed_updateProfileOff + */ + @Test + public void testUserExistsFirstBrokerLoginFlowUpdateProfileOn() { + createUser("consumer"); + + updateExecutions(AbstractBrokerTest::enableUpdateProfileOnFirstLogin); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); + + log.debug("Updating info on updateAccount page"); + updateAccountInformationPage.updateAccountInformation("consumer", "consumer-user@redhat.com", "FirstName", "LastName"); + + waitForPage(driver, "we're sorry...", false); + assertEquals("User with username consumer already exists. Please login to account management to link the account.", errorPage.getError()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testRegistrationWithPasswordUpdateRequired + */ + @Test + public void testRequiredUpdatedPassword() { + updateExecutions(AbstractBrokerTest::enableRequirePassword); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); + + log.debug("Updating info on updateAccount page"); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + + waitForPage(driver, "update password", false); + updatePasswordPage.updatePasswords("password", "password"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testFixDuplicationsByReviewProfile + */ + @Test + public void testFixDuplicationsByReviewProfile() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + + UserResource userResource = realm.users().get(createUser("consumer")); + UserRepresentation consumerUser = userResource.toRepresentation(); + + consumerUser.setEmail(bc.getUserEmail()); + userResource.update(consumerUser); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + idpConfirmLinkPage.clickReviewProfile(); + + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + updateAccountInformationPage.updateAccountInformation("consumer", "test@localhost.com", "FirstName", "LastName"); + + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with username consumer already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + idpConfirmLinkPage.clickReviewProfile(); + + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + updateAccountInformationPage.updateAccountInformation("test", "test@localhost.com", "FirstName", "LastName"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testHardcodedUserSessionNoteIsSetAfterFristBrokerLogin() + */ + @Test + public void testHardcodedUserSessionNoteIsSetAfterFristBrokerLogin() { + updateExecutions(AbstractBrokerTest::enableUpdateProfileOnFirstLogin); + + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + + IdentityProviderResource idpResource = realm.identityProviders().get(bc.getIDPAlias()); + IdentityProviderMapperRepresentation hardCodedSessionNoteMapper = new IdentityProviderMapperRepresentation(); + + hardCodedSessionNoteMapper.setName("static-session-note"); + hardCodedSessionNoteMapper.setIdentityProviderAlias(bc.getIDPAlias()); + hardCodedSessionNoteMapper.setIdentityProviderMapper(HardcodedUserSessionAttributeMapper.PROVIDER_ID); + hardCodedSessionNoteMapper.setConfig(ImmutableMap.builder() + .put(HardcodedUserSessionAttributeMapper.ATTRIBUTE_VALUE, "sessionvalue") + .put(HardcodedUserSessionAttributeMapper.ATTRIBUTE, "user-session-attr") + .build()); + + Response response = idpResource.addMapper(hardCodedSessionNoteMapper); + response.close(); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + + logInWithBroker(bc); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + testingClient.server().run(assertHardCodedSessionNote()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testRegistrationWithEmailAsUsername + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() + */ + @Test + public void testRequiredRegistrationEmailAsUserName() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + updateExecutions(AbstractBrokerTest::enableUpdateProfileOnFirstLogin); + realmRep.setRegistrationEmailAsUsername(true); + realm.update(realmRep); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); + + log.debug("Updating info on updateAccount page"); + try { + updateAccountInformationPage.updateAccountInformation("test", "test@redhat.com", "FirstName", "LastName"); + Assert.fail("It is not expected to see username field"); + } catch (NoSuchElementException ignore) { + } + + updateAccountInformationPage.updateAccountInformation("test@redhat.com", "FirstName", "LastName"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + assertEquals(1, realm.users().search("test@redhat.com").size()); + } + @Test public void loginWithExistingUser() { testLogInAsUserInIDP(); @@ -112,142 +704,322 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe Integer userCount = adminClient.realm(bc.consumerRealmName()).users().count(); driver.navigate().to(getAccountUrl(bc.consumerRealmName())); - - log.debug("Clicking social " + bc.getIDPAlias()); - accountLoginPage.clickSocial(bc.getIDPAlias()); - - waitForPage(driver, "log in to", true); - - Assert.assertTrue("Driver should be on the provider realm page right now", driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); - - accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + logInWithBroker(bc); assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl()); - assertEquals(userCount, adminClient.realm(bc.consumerRealmName()).users().count()); } // KEYCLOAK-2957 @Test public void testLinkAccountWithEmailVerified() { - //start mail server - MailServer.start(); - MailServer.createEmailAccount(USER_EMAIL, "password"); - - try { - configureSMPTServer(); + RealmResource realm = adminClient.realm(bc.consumerRealmName()); - //create user on consumer's site who should be linked later - String linkedUserId = createUser("consumer"); - - //test - driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + configureSMTPServer(); - log.debug("Clicking social " + bc.getIDPAlias()); - accountLoginPage.clickSocial(bc.getIDPAlias()); + //create user on consumer's site who should be linked later + String linkedUserId = createUser("consumer"); - waitForPage(driver, "log in to", true); + //test + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); - Assert.assertTrue("Driver should be on the provider realm page right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); - log.debug("Logging in"); - accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + log.debug("Updating info on updateAccount page"); + updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname"); - waitForPage(driver, "update account information", false); + //link account by email + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.clickLinkAccount(); - Assert.assertTrue(updateAccountInformationPage.isCurrent()); - Assert.assertTrue("We must be on correct realm right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); + String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "Someone wants to link your ", false); - log.debug("Updating info on updateAccount page"); - updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname"); + log.info("navigating to url from email: " + url); + driver.navigate().to(url); - //link account by email - waitForPage(driver, "account already exists", false); - idpConfirmLinkPage.clickLinkAccount(); - - String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, - "Someone wants to link your ", false); + //test if user is logged in + assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl()); - log.info("navigating to url from email: " + url); - driver.navigate().to(url); + //test if the user has verified email + assertTrue(realm.users().get(linkedUserId).toRepresentation().isEmailVerified()); + } - //test if user is logged in - assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl()); - - //test if the user has verified email - assertTrue(adminClient.realm(bc.consumerRealmName()).users().get(linkedUserId).toRepresentation().isEmailVerified()); - } finally { - removeUserByUsername(adminClient.realm(bc.consumerRealmName()), "consumer"); - // stop mail server - MailServer.stop(); - } + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled + */ + @Test + public void testLinkAccountWithUntrustedEmailVerified() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + realmRep.setVerifyEmail(true); + + realm.update(realmRep); + + IdentityProviderRepresentation idpRep = identityProviderResource.toRepresentation(); + + idpRep.setTrustEmail(false); + + identityProviderResource.update(idpRep); + + configureSMTPServer(); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + + verifyEmailPage.assertCurrent(); + + String verificationUrl = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "verify your email address", false); + + driver.navigate().to(verificationUrl.trim()); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled + */ + @Test + public void testVerifyEmailRequiredActionWhenEmailIsNotVerifiedDuringFirstLogin() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + realmRep.setVerifyEmail(true); + + realm.update(realmRep); + + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + createUser(bc.providerRealmName(), "no-email", "password", "FirstName", "LastName", null); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login("no-email", "password"); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + List users = realm.users().search("no-email"); + assertEquals(1, users.size()); + List requiredActions = users.get(0).getRequiredActions(); + assertEquals(1, requiredActions.size()); + assertEquals(UserModel.RequiredAction.VERIFY_EMAIL.name(), requiredActions.get(0)); + + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled + */ + @Test + public void testVerifyEmailNotRequiredActionWhenEmailIsTrustedByProvider() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + realmRep.setVerifyEmail(true); + + realm.update(realmRep); + + IdentityProviderRepresentation idpRep = identityProviderResource.toRepresentation(); + + idpRep.setTrustEmail(true); + + identityProviderResource.update(idpRep); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + List users = realm.users().search(bc.getUserLogin()); + assertEquals(1, users.size()); + List requiredActions = users.get(0).getRequiredActions(); + assertEquals(0, requiredActions.size()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin + */ + @Test + public void testVerifyEmailRequiredActionWhenChangingEmailDuringFirstLogin() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realm.toRepresentation(); + + realmRep.setVerifyEmail(true); + + realm.update(realmRep); + + IdentityProviderRepresentation idpRep = identityProviderResource.toRepresentation(); + + idpRep.setTrustEmail(true); + + identityProviderResource.update(idpRep); + + configureSMTPServer(); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("changed@localhost.com", "FirstName", "LastName"); + + verifyEmailPage.assertCurrent(); + + String verificationUrl = assertEmailAndGetUrl(MailServerConfiguration.FROM, "changed@localhost.com", + "verify your email address", false); + + driver.navigate().to(verificationUrl.trim()); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + List users = realm.users().search(bc.getUserLogin()); + assertEquals(1, users.size()); + List requiredActions = users.get(0).getRequiredActions(); + assertEquals(0, requiredActions.size()); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByEmailVerificationTwice + */ + @Test + public void testLinkAccountByEmailVerificationTwice() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + + UserResource userResource = realm.users().get(createUser("consumer")); + UserRepresentation consumerUser = userResource.toRepresentation(); + + consumerUser.setEmail(bc.getUserEmail()); + userResource.update(consumerUser); + configureSMTPServer(); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + //link account by email + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + idpConfirmLinkPage.clickLinkAccount(); + + String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "Someone wants to link your ", false); + driver.navigate().to(url); + //test if user is logged in + assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl()); + //test if the user has verified email + assertTrue(adminClient.realm(bc.consumerRealmName()).users().get(consumerUser.getId()).toRepresentation().isEmailVerified()); + + driver.navigate().to(url); + waitForPage(driver, "you are already logged in.", false); + logoutFromRealm(bc.consumerRealmName()); + + driver.navigate().to(url); + waitForPage(driver, "confirm linking the account testuser of identity provider " + bc.getIDPAlias() + " with your account.", false); + proceedPage.clickProceedLink(); + waitForPage(driver, "you successfully verified your email. please go back to your original browser and continue there with the login.", false); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByEmailVerificationResendEmail + */ + @Test + public void testLinkAccountByEmailVerificationResendEmail() { + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + + UserResource userResource = realm.users().get(createUser("consumer")); + UserRepresentation consumerUser = userResource.toRepresentation(); + + consumerUser.setEmail(bc.getUserEmail()); + userResource.update(consumerUser); + configureSMTPServer(); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + //link account by email + waitForPage(driver, "update account information", false); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + idpConfirmLinkPage.clickLinkAccount(); + + + waitForPage(driver, "link " + bc.getIDPAlias(), false); + assertEquals("an email with instructions to link " + bc.getIDPAlias() + " account testuser with your consumer account has been sent to you.", idpLinkEmailPage.getMessage().toLowerCase()); + idpLinkEmailPage.resendEmail(); + + assertEquals(2, MailServer.getReceivedMessages().length); } @Test public void testVerifyEmailInNewBrowserWithPreserveClient() { - //start mail server - MailServer.start(); - MailServer.createEmailAccount(USER_EMAIL, "password"); + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); - try { - configureSMPTServer(); + configureSMTPServer(); - //create user on consumer's site who should be linked later - String linkedUserId = createUser("consumer"); + //create user on consumer's site who should be linked later + String linkedUserId = createUser("consumer"); - driver.navigate().to(getLoginUrl(bc.consumerRealmName(), "broker-app")); + driver.navigate().to(getLoginUrl(bc.consumerRealmName(), "broker-app")); + logInWithBroker(bc); - log.debug("Clicking social " + bc.getIDPAlias()); - accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "update account information", false); - waitForPage(driver, "log in to", true); + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); - Assert.assertTrue("Driver should be on the provider realm page right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Updating info on updateAccount page"); + updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname"); - log.debug("Logging in"); - accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + //link account by email + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.clickLinkAccount(); - waitForPage(driver, "update account information", false); + String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "Someone wants to link your ", false); - Assert.assertTrue(updateAccountInformationPage.isCurrent()); - Assert.assertTrue("We must be on correct realm right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); + log.info("navigating to url from email in second browser: " + url); - log.debug("Updating info on updateAccount page"); - updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname"); + // navigate to url in the second browser + driver2.navigate().to(url); - //link account by email - waitForPage(driver, "account already exists", false); - idpConfirmLinkPage.clickLinkAccount(); + final WebElement proceedLink = driver2.findElement(By.linkText("» Click here to proceed")); + MatcherAssert.assertThat(proceedLink, Matchers.notNullValue()); - String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, - "Someone wants to link your ", false); + // check if the initial client is preserved + String link = proceedLink.getAttribute("href"); + MatcherAssert.assertThat(link, Matchers.containsString("client_id=broker-app")); + proceedLink.click(); - log.info("navigating to url from email in second browser: " + url); + assertThat(driver2.getPageSource(), Matchers.containsString("You successfully verified your email. Please go back to your original browser and continue there with the login.")); - // navigate to url in the second browser - driver2.navigate().to(url); - - final WebElement proceedLink = driver2.findElement(By.linkText("» Click here to proceed")); - MatcherAssert.assertThat(proceedLink, Matchers.notNullValue()); - - // check if the initial client is preserved - String link = proceedLink.getAttribute("href"); - MatcherAssert.assertThat(link, Matchers.containsString("client_id=broker-app")); - proceedLink.click(); - - assertThat(driver2.getPageSource(), Matchers.containsString("You successfully verified your email. Please go back to your original browser and continue there with the login.")); - - //test if the user has verified email - assertTrue(adminClient.realm(bc.consumerRealmName()).users().get(linkedUserId).toRepresentation().isEmailVerified()); - } finally { - removeUserByUsername(adminClient.realm(bc.consumerRealmName()), "consumer"); - // stop mail server - MailServer.stop(); - } + //test if the user has verified email + assertTrue(consumerRealm.users().get(linkedUserId).toRepresentation().isEmailVerified()); } // KEYCLOAK-3267 @@ -302,9 +1074,6 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe assertEquals("Account is disabled, contact admin.", errorPage.getError()); } - @Page - ConsentPage consentPage; - // KEYCLOAK-4181 @Test public void loginWithExistingUserWithErrorFromProviderIdP() { @@ -319,17 +1088,7 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe .update(ClientBuilder.edit(client).consentRequired(true).build()); driver.navigate().to(getAccountUrl(bc.consumerRealmName())); - - log.debug("Clicking social " + bc.getIDPAlias()); - accountLoginPage.clickSocial(bc.getIDPAlias()); - - waitForPage(driver, "log in to", true); - - Assert.assertTrue("Driver should be on the provider realm page right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); - - log.debug("Logging in"); - accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + logInWithBroker(bc); driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.MINUTES); @@ -346,49 +1105,122 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe } - - - protected void testSingleLogout() { - log.debug("Testing single log out"); - - driver.navigate().to(getAccountUrl(bc.providerRealmName())); - - Assert.assertTrue("Should be logged in the account page", driver.getTitle().endsWith("Account Management")); - + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest.testDisabledUser + */ + @Test + public void testDisabledUser() { + loginUser(); logoutFromRealm(bc.providerRealmName()); - - Assert.assertTrue("Should be on " + bc.providerRealmName() + " realm", driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName())); - - driver.navigate().to(getAccountUrl(bc.consumerRealmName())); - - Assert.assertTrue("Should be on " + bc.consumerRealmName() + " realm on login page", - driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/protocol/openid-connect/")); - } - - protected void createRolesForRealm(String realm) { - RoleRepresentation managerRole = new RoleRepresentation(ROLE_MANAGER,null, false); - RoleRepresentation friendlyManagerRole = new RoleRepresentation(ROLE_FRIENDLY_MANAGER,null, false); - RoleRepresentation userRole = new RoleRepresentation(ROLE_USER,null, false); - - adminClient.realm(realm).roles().create(managerRole); - adminClient.realm(realm).roles().create(friendlyManagerRole); - adminClient.realm(realm).roles().create(userRole); - } - - protected void createRoleMappersForConsumerRealm() { - log.debug("adding mappers to identity provider in realm " + bc.consumerRealmName()); + logoutFromRealm(bc.consumerRealmName()); RealmResource realm = adminClient.realm(bc.consumerRealmName()); + UserRepresentation userRep = realm.users().search(bc.getUserLogin()).get(0); + UserResource user = realm.users().get(userRep.getId()); - IdentityProviderResource idpResource = realm.identityProviders().get(bc.getIDPAlias()); - for (IdentityProviderMapperRepresentation mapper : createIdentityProviderMappers()) { - mapper.setIdentityProviderAlias(bc.getIDPAlias()); - Response resp = idpResource.addMapper(mapper); - resp.close(); - } + userRep.setEnabled(false); + + user.update(userRep); + + logInWithBroker(bc); + errorPage.assertCurrent(); + assertEquals("Account is disabled, contact admin.", errorPage.getError()); } - protected abstract Iterable createIdentityProviderMappers(); + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest.testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail + */ + @Test + public void testUpdateProfileIfMissingInformation() { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + + createUser(bc.providerRealmName(), "no-first-name", "password", null, "LastName", "no-first-name@localhost.com"); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login("no-first-name", "password"); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + logoutFromRealm(bc.providerRealmName()); + logoutFromRealm(bc.consumerRealmName()); + createUser(bc.providerRealmName(), "no-last-name", "password", "FirstName", null, "no-last-name@localhost.com"); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login("no-last-name", "password"); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + logoutFromRealm(bc.providerRealmName()); + logoutFromRealm(bc.consumerRealmName()); + createUser(bc.providerRealmName(), "no-email", "password", "FirstName", "LastName", null); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login("no-email", "password"); + + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("no-email@localhost.com", "FirstName", "LastName"); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest.testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing + */ + @Test + public void testUpdateProfileIfNotMissingInformation() { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + createUser(bc.providerRealmName(), "all-info-set", "password", "FirstName", "LastName", "all-info-set@localhost.com"); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login("all-info-set", "password"); + + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest.testSuccessfulAuthenticationWithoutUpdateProfile + */ + @Test + public void testWithoutUpdateProfile() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + } // KEYCLOAK-3987 @Test @@ -447,16 +1279,251 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe Assert.assertTrue(link.endsWith("/auth/realms/consumer/account")); } - private void configureSMPTServer() { - RealmRepresentation master = adminClient.realm(bc.consumerRealmName()).toRepresentation(); - master.setSmtpServer(suiteContext.getSmtpServer()); - adminClient.realm(bc.consumerRealmName()).update(master); + /** + * Refers to in old testsuite: org.keycloak.testsuite.broker.PostBrokerFlowTest#testPostBrokerLoginWithOTP() + */ + @Test + public void testPostBrokerLoginFlowWithOTP() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + testingClient.server(bc.consumerRealmName()).run(configurePostBrokerLoginWithOTP(bc.getIDPAlias())); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + totpPage.assertCurrent(); + String totpSecret = totpPage.getTotpSecret(); + totpPage.configure(totp.generateTOTP(totpSecret)); + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + assertNumFederatedIdentities(realm.users().search(bc.getUserLogin()).get(0).getId(), 1); + logoutFromRealm(bc.consumerRealmName()); + + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + loginTotpPage.assertCurrent(); + loginTotpPage.login(totp.generateTOTP(totpSecret)); + logoutFromRealm(bc.consumerRealmName()); + + testingClient.server(bc.consumerRealmName()).run(disablePostBrokerLoginFlow(bc.getIDPAlias())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); + log.debug("Logging in"); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); } - private String createUser(String username) { + /** + * Refers to in old testsuite: org.keycloak.testsuite.broker.OIDCKeyCloakServerBrokerBasicTest#testLogoutWorksWithTokenTimeout() + */ + @Test + public void testLogoutWorksWithTokenTimeout() { + try { + updateExecutions(AbstractBrokerTest::enableUpdateProfileOnFirstLogin); + RealmRepresentation realm = adminClient.realm(bc.providerRealmName()).toRepresentation(); + assertNotNull(realm); + realm.setAccessTokenLifespan(1); + adminClient.realm(bc.providerRealmName()).update(realm); + IdentityProviderRepresentation idp = adminClient.realm(bc.consumerRealmName()).identityProviders().get(bc.getIDPAlias()).toRepresentation(); + idp.getConfig().put("backchannelSupported", "false"); + adminClient.realm(bc.consumerRealmName()).identityProviders().get(bc.getIDPAlias()).update(idp); + Time.setOffset(2); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + waitForPage(driver, "update account information", false); + updateAccountInformationPage.assertCurrent(); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + accountPage.logOut(); + waitForPage(driver, "log in to", true); + log.debug("Logging in"); + assertTrue(this.driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/protocol/openid-connect/auth")); + } finally { + Time.setOffset(0); + } + } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testWithLinkedFederationProvider + */ + @Test + public void testWithLinkedFederationProvider() { + try { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + + ComponentRepresentation component = new ComponentRepresentation(); + + component.setId(DummyUserFederationProviderFactory.PROVIDER_NAME); + component.setName(DummyUserFederationProviderFactory.PROVIDER_NAME); + component.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME); + component.setProviderType(UserStorageProvider.class.getName()); + + adminClient.realm(bc.consumerRealmName()).components().add(component); + + createUser(bc.providerRealmName(), "test-user", "password", "FirstName", "LastName", "test-user@localhost.com"); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + accountLoginPage.clickSocial(bc.getIDPAlias()); + accountLoginPage.login("test-user", "password"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + accountPage.password(); + accountPasswordPage.changePassword("bad", "new-password", "new-password"); + assertEquals("Invalid existing password.", accountPasswordPage.getError()); + + accountPasswordPage.changePassword("secret", "new-password", "new-password"); + assertEquals("Your password has been updated.", accountUpdateProfilePage.getSuccess()); + + logoutFromRealm(bc.providerRealmName()); + logoutFromRealm(bc.consumerRealmName()); + + createUser(bc.providerRealmName(), "test-user-noemail", "password", "FirstName", "LastName", "test-user-noemail@localhost.com"); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + accountLoginPage.clickSocial(bc.getIDPAlias()); + accountLoginPage.login("test-user-noemail", "password"); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + accountPage.password(); + accountPasswordPage.changePassword("new-password", "new-password"); + assertEquals("Your password has been updated.", accountUpdateProfilePage.getSuccess()); + } finally { + removeUserByUsername(adminClient.realm(bc.consumerRealmName()), "test-user"); + removeUserByUsername(adminClient.realm(bc.consumerRealmName()), "test-user-noemail"); + } + } + + protected void testSingleLogout() { + log.debug("Testing single log out"); + + driver.navigate().to(getAccountUrl(bc.providerRealmName())); + + Assert.assertTrue("Should be logged in the account page", driver.getTitle().endsWith("Account Management")); + + logoutFromRealm(bc.providerRealmName()); + + Assert.assertTrue("Should be on " + bc.providerRealmName() + " realm", driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName())); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + + Assert.assertTrue("Should be on " + bc.consumerRealmName() + " realm on login page", + driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/protocol/openid-connect/")); + } + + protected void createRolesForRealm(String realm) { + RoleRepresentation managerRole = new RoleRepresentation(ROLE_MANAGER,null, false); + RoleRepresentation friendlyManagerRole = new RoleRepresentation(ROLE_FRIENDLY_MANAGER,null, false); + RoleRepresentation userRole = new RoleRepresentation(ROLE_USER,null, false); + + adminClient.realm(realm).roles().create(managerRole); + adminClient.realm(realm).roles().create(friendlyManagerRole); + adminClient.realm(realm).roles().create(userRole); + } + + protected void createRoleMappersForConsumerRealm() { + log.debug("adding mappers to identity provider in realm " + bc.consumerRealmName()); + + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + + IdentityProviderResource idpResource = realm.identityProviders().get(bc.getIDPAlias()); + for (IdentityProviderMapperRepresentation mapper : createIdentityProviderMappers()) { + mapper.setIdentityProviderAlias(bc.getIDPAlias()); + Response resp = idpResource.addMapper(mapper); + resp.close(); + } + } + + protected abstract Iterable createIdentityProviderMappers(); + + private void configureSMTPServer() { + MailServer.start(); + MailServer.createEmailAccount(USER_EMAIL, "password"); + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation master = realm.toRepresentation(); + master.setSmtpServer(suiteContext.getSmtpServer()); + realm.update(master); + } + + protected String createUser(String username) { UserRepresentation newUser = UserBuilder.create().username(username).email(USER_EMAIL).enabled(true).build(); String userId = createUserWithAdminClient(adminClient.realm(bc.consumerRealmName()), newUser); resetUserPassword(adminClient.realm(bc.consumerRealmName()).users().get(userId), "password", false); return userId; } + + private void removeSMTPConfiguration(RealmResource consumerRealm) { + RealmRepresentation master = consumerRealm.toRepresentation(); + master.setSmtpServer(Collections.emptyMap()); + consumerRealm.update(master); + } + + protected void assertNumFederatedIdentities(String userId, int expected) { + assertEquals(expected, adminClient.realm(bc.consumerRealmName()).users().get(userId).getFederatedIdentity().size()); + } + + static void enableUpdateProfileOnFirstLogin(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) { + if (execution.getProviderId() != null && execution.getProviderId().equals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID)) { + execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.name()); + flows.updateExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, execution); + } else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) { + AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig()); + config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_ON); + flows.updateAuthenticatorConfig(config.getId(), config); + } + } + + static void setUpMissingUpdateProfileOnFirstLogin(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) { + if (execution.getProviderId() != null && execution.getProviderId().equals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID)) { + execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name()); + flows.updateExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, execution); + } else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) { + AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig()); + config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_MISSING); + flows.updateAuthenticatorConfig(config.getId(), config); + } + } + + static void enableRequirePassword(AuthenticationExecutionInfoRepresentation execution, + AuthenticationManagementResource flows) { + String id = execution.getAuthenticationConfig(); + + if (id != null) { + AuthenticatorConfigRepresentation authenticatorConfig = flows.getAuthenticatorConfig(id); + + if (authenticatorConfig != null) { + Map config = authenticatorConfig.getConfig(); + + if (config != null && config.containsKey(IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION)) { + config.put(IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, Boolean.TRUE.toString()); + } + + flows.updateAuthenticatorConfig(authenticatorConfig.getId(), authenticatorConfig); + } + } + } + + static void disableUpdateProfileOnFirstLogin(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) { + if (execution.getProviderId() != null && execution.getProviderId().equals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID)) { + execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name()); + flows.updateExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, execution); + } else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) { + AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig()); + config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_OFF); + flows.updateAuthenticatorConfig(config.getId(), config); + } + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java index d0afd8ddc0..d04f6a9e97 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java @@ -18,13 +18,24 @@ package org.keycloak.testsuite.broker; import org.junit.Before; +import org.keycloak.admin.client.resource.AuthenticationManagementResource; import org.keycloak.admin.client.resource.IdentityProviderResource; import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; +import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.UserRepresentation; import java.util.List; +import java.util.function.BiConsumer; + +import static org.keycloak.models.utils.DefaultAuthenticationFlows.IDP_REVIEW_PROFILE_CONFIG_ALIAS; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; +import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; /** * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc. @@ -33,8 +44,10 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok protected IdentityProviderResource identityProviderResource; + @Override @Before public void beforeBrokerTest() { + super.beforeBrokerTest(); log.debug("creating user for realm " + bc.providerRealmName()); UserRepresentation user = new UserRepresentation(); @@ -48,18 +61,10 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok resetUserPassword(realmResource.users().get(userId), bc.getUserPassword(), false); - if (testContext.isInitialized()) { - if (identityProviderResource == null) { - identityProviderResource = (IdentityProviderResource) testContext.getCustomValue("identityProviderResource"); - } - return; - } - log.debug("adding identity provider to realm " + bc.consumerRealmName()); RealmResource realm = adminClient.realm(bc.consumerRealmName()); realm.identityProviders().create(bc.setUpIdentityProvider(suiteContext)).close(); identityProviderResource = realm.identityProviders().get(bc.getIDPAlias()); - testContext.setCustomValue("identityProviderResource", identityProviderResource); // addClients List clients = bc.createProviderClients(suiteContext); @@ -85,4 +90,20 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok testContext.setInitialized(true); } + protected void logInWithBroker(BrokerConfiguration bc) { + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + log.debug("Logging in"); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + } + + protected void updateExecutions(BiConsumer action) { + AuthenticationManagementResource flows = adminClient.realm(bc.consumerRealmName()).flows(); + + for (AuthenticationExecutionInfoRepresentation execution : flows.getExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW)) { + action.accept(execution, flows); + } + } + } \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java new file mode 100644 index 0000000000..e39cbb93f1 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java @@ -0,0 +1,146 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.testsuite.broker; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.AuthenticationFlowModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.Constants; +import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.testsuite.runonserver.RunOnServer; + +/** + * @author Pedro Igor + */ +final class BrokerRunOnServerUtil { + + static RunOnServer configurePostBrokerLoginWithOTP(String idpAlias) { + return (session) -> { + RealmModel realm = session.getContext().getRealm(); + + // Add post-broker flow with OTP authenticator to the realm + AuthenticationFlowModel postBrokerFlow = new AuthenticationFlowModel(); + postBrokerFlow.setAlias("post-broker"); + postBrokerFlow.setDescription("post-broker flow with OTP"); + postBrokerFlow.setProviderId("basic-flow"); + postBrokerFlow.setTopLevel(true); + postBrokerFlow.setBuiltIn(false); + postBrokerFlow = realm.addAuthenticationFlow(postBrokerFlow); + + AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); + execution.setParentFlow(postBrokerFlow.getId()); + execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); + execution.setAuthenticator("auth-otp-form"); + execution.setPriority(20); + execution.setAuthenticatorFlow(false); + realm.addAuthenticatorExecution(execution); + + IdentityProviderModel idp = realm.getIdentityProviderByAlias(idpAlias); + idp.setPostBrokerLoginFlowId(postBrokerFlow.getId()); + realm.updateIdentityProvider(idp); + }; + } + + static RunOnServer disablePostBrokerLoginFlow(String idpAlias) { + return session -> { + RealmModel realm = session.getContext().getRealm(); + + IdentityProviderModel idp = realm.getIdentityProviderByAlias(idpAlias); + idp.setPostBrokerLoginFlowId(null); + realm.updateIdentityProvider(idp); + }; + } + + static RunOnServer grantReadTokenRole(String username) { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ClientModel brokerClient = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID); + RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE); + UserModel user = session.users().getUserByUsername(username, realm); + user.grantRole(readTokenRole); + }; + } + + static RunOnServer revokeReadTokenRole(String username) { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ClientModel brokerClient = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID); + RoleModel readTokenRole = brokerClient.getRole(Constants.READ_TOKEN_ROLE); + UserModel user = session.users().getUserByUsername(username, realm); + user.deleteRoleMapping(readTokenRole); + }; + } + + static RunOnServer configureAutoLinkFlow(String idpAlias) { + return (session -> { + RealmModel appRealm = session.getContext().getRealm(); + AuthenticationFlowModel newFlow = new AuthenticationFlowModel(); + newFlow.setAlias("AutoLink"); + newFlow.setDescription("AutoLink"); + newFlow.setProviderId("basic-flow"); + newFlow.setBuiltIn(false); + newFlow.setTopLevel(true); + newFlow = appRealm.addAuthenticationFlow(newFlow); + + AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); + execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); + execution.setAuthenticatorFlow(false); + execution.setAuthenticator("idp-create-user-if-unique"); + execution.setPriority(1); + execution.setParentFlow(newFlow.getId()); + execution = appRealm.addAuthenticatorExecution(execution); + + AuthenticationExecutionModel execution2 = new AuthenticationExecutionModel(); + execution2.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); + execution2.setAuthenticatorFlow(false); + execution2.setAuthenticator("idp-auto-link"); + execution2.setPriority(2); + execution2.setParentFlow(newFlow.getId()); + execution2 = appRealm.addAuthenticatorExecution(execution2); + + IdentityProviderModel idp = appRealm.getIdentityProviderByAlias(idpAlias); + idp.setFirstBrokerLoginFlowId(newFlow.getId()); + appRealm.updateIdentityProvider(idp); + }); + } + + static RunOnServer assertHardCodedSessionNote() { + return (session) -> { + RealmModel realm = session.realms().getRealmByName("consumer"); + UserModel user = session.users().getUserByUsername("testuser", realm); + List userSessions = session.sessions().getUserSessions(realm, user); + UserSessionModel sessions = userSessions.get(0); + assertEquals("sessionvalue", sessions.getNote("user-session-attr")); + }; + } + + static RunOnServer removeBrokerExpiredSessions() { + return (RunOnServer) session -> { + RealmModel realm = session.getContext().getRealm(); + session.sessions().removeExpired(realm); + session.authenticationSessions().removeExpired(realm); + }; + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java index ff08b1aadd..56b7727e57 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java @@ -18,12 +18,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.WebDriverWait; -import static org.keycloak.testsuite.broker.BrokerTestConstants.CLIENT_ID; -import static org.keycloak.testsuite.broker.BrokerTestConstants.CLIENT_SECRET; -import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS; import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_PROVIDER_ID; -import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_CONS_NAME; -import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; /** * @@ -48,12 +43,8 @@ public class BrokerTestTools { public static void waitForPage(WebDriver driver, final String title, final boolean isHtmlTitle) { WebDriverWait wait = new WebDriverWait(driver, 5); - ExpectedCondition condition = (WebDriver input) -> isHtmlTitle ? input.getTitle().toLowerCase().contains(title) : PageUtils.getPageTitle(input).toLowerCase().contains(title); - System.out.println("WAIT FOR " + title); - System.out.println(driver.getPageSource()); - wait.until(condition); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java index 5748179fcc..94cfbb1d34 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java @@ -127,6 +127,7 @@ public class KcOidcBrokerConfiguration implements BrokerConfiguration { client.setName("broker-app"); client.setSecret("broker-app-secret"); client.setEnabled(true); + client.setDirectAccessGrantsEnabled(true); client.setRedirectUris(Collections.singletonList(getAuthRoot(suiteContext) + "/auth/*")); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java index 809fa34c57..d0f4261d52 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java @@ -1,8 +1,14 @@ package org.keycloak.testsuite.broker; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.keycloak.testsuite.admin.ApiUtil.removeUserByUsername; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configureAutoLinkFlow; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configurePostBrokerLoginWithOTP; import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; import static org.keycloak.testsuite.broker.BrokerTestTools.getAuthRoot; import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; +import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim; import java.util.List; @@ -15,6 +21,7 @@ import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.broker.oidc.OIDCIdentityProviderConfig; import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper; +import org.keycloak.broker.oidc.mappers.UserAttributeMapper; import org.keycloak.crypto.Algorithm; import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.representations.idm.ClientRepresentation; @@ -22,6 +29,7 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.Assert; +import org.openqa.selenium.NoSuchElementException; public class KcOidcBrokerTest extends AbstractBrokerTest { @@ -69,20 +77,9 @@ public class KcOidcBrokerTest extends AbstractBrokerTest { clients.get(brokerApp.getId()).update(brokerApp); driver.navigate().to(getAccountUrl(bc.consumerRealmName())); - - log.debug("Clicking social " + bc.getIDPAlias()); - accountLoginPage.clickSocial(bc.getIDPAlias()); - - waitForPage(driver, "log in to", true); - - Assert.assertTrue("Driver should be on the provider realm page right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); - - log.debug("Logging in"); - accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + logInWithBroker(bc); waitForPage(driver, "update account information", false); - updateAccountInformationPage.assertCurrent(); Assert.assertTrue("We must be on correct realm right now", driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); @@ -113,4 +110,291 @@ public class KcOidcBrokerTest extends AbstractBrokerTest { clients.get(brokerApp.getId()).update(brokerApp); } } + + /** + * Refers to in old test suite: org.keycloak.testsuite.broker.OIDCBrokerUserPropertyTest + */ + @Test + public void loginFetchingUserFromUserEndpointWithClaimMapper() { + RealmResource realm = realmsResouce().realm(bc.providerRealmName()); + ClientsResource clients = realm.clients(); + ClientRepresentation brokerApp = clients.findByClientId("brokerapp").get(0); + IdentityProviderResource identityProviderResource = getIdentityProviderResource(); + + clients.get(brokerApp.getId()).getProtocolMappers().createMapper(createHardcodedClaim("hard-coded", "hard-coded", "hard-coded", "String", true, true)).close(); + + IdentityProviderMapperRepresentation hardCodedSessionNoteMapper = new IdentityProviderMapperRepresentation(); + + hardCodedSessionNoteMapper.setName("hard-coded"); + hardCodedSessionNoteMapper.setIdentityProviderAlias(bc.getIDPAlias()); + hardCodedSessionNoteMapper.setIdentityProviderMapper(UserAttributeMapper.PROVIDER_ID); + hardCodedSessionNoteMapper.setConfig(ImmutableMap.builder() + .put(UserAttributeMapper.USER_ATTRIBUTE, "hard-coded") + .put(UserAttributeMapper.CLAIM, "hard-coded") + .build()); + + identityProviderResource.addMapper(hardCodedSessionNoteMapper).close(); + + loginFetchingUserFromUserEndpoint(); + + UserRepresentation user = getFederatedIdentity(); + + Assert.assertEquals(1, user.getAttributes().size()); + Assert.assertEquals("hard-coded", user.getAttributes().get("hard-coded").get(0)); + } + + /** + * 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() { + KcSamlBrokerConfiguration samlBrokerConfig = KcSamlBrokerConfiguration.INSTANCE; + ClientRepresentation samlClient = samlBrokerConfig.createProviderClients(suiteContext).get(0); + IdentityProviderRepresentation samlBroker = samlBrokerConfig.setUpIdentityProvider(suiteContext); + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + + try { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + adminClient.realm(bc.providerRealmName()).clients().create(samlClient); + consumerRealm.identityProviders().create(samlBroker); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + + logInWithBroker(samlBrokerConfig); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + logoutFromRealm(bc.consumerRealmName()); + + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + assertTrue(idpConfirmLinkPage.isCurrent()); + assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage()); + idpConfirmLinkPage.clickLinkAccount(); + + assertEquals("Authenticate as testuser to link your account with " + bc.getIDPAlias(), loginPage.feedbackMessage().getText()); + + try { + this.accountLoginPage.findSocialButton(bc.getIDPAlias()); + org.junit.Assert.fail("Not expected to see social button with " + samlBrokerConfig.getIDPAlias()); + } catch (NoSuchElementException expected) { + } + + log.debug("Clicking social " + samlBrokerConfig.getIDPAlias()); + accountLoginPage.clickSocial(samlBrokerConfig.getIDPAlias()); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + assertNumFederatedIdentities(consumerRealm.users().search(samlBrokerConfig.getUserLogin()).get(0).getId(), 2); + } finally { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + removeUserByUsername(consumerRealm, "consumer"); + } + } + + /** + * Tests that user can link federated identity with existing brokered + * account without prompt (KEYCLOAK-7270). + */ + @Test + public void testAutoLinkAccountWithBroker() { + testingClient.server(bc.consumerRealmName()).run(configureAutoLinkFlow(bc.getIDPAlias())); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + RealmResource realm = adminClient.realm(bc.consumerRealmName()); + + assertNumFederatedIdentities(realm.users().search(bc.getUserLogin()).get(0).getId(), 1); + } + + /** + * Refers to in old test suite: OIDCFirstBrokerLoginTest#testMoreIdpAndBackButtonWhenLinkingAccount + */ + @Test + public void testLoginWithDifferentBrokerWhenUpdatingProfile() { + KcSamlBrokerConfiguration samlBrokerConfig = KcSamlBrokerConfiguration.INSTANCE; + ClientRepresentation samlClient = samlBrokerConfig.createProviderClients(suiteContext).get(0); + IdentityProviderRepresentation samlBroker = samlBrokerConfig.setUpIdentityProvider(suiteContext); + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + + try { + updateExecutions(AbstractBrokerTest::enableUpdateProfileOnFirstLogin); + adminClient.realm(bc.providerRealmName()).clients().create(samlClient); + consumerRealm.identityProviders().create(samlBroker); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(samlBrokerConfig); + waitForPage(driver, "update account information", false); + updateAccountInformationPage.updateAccountInformation("FirstName", "LastName"); + logoutFromRealm(bc.consumerRealmName()); + + logInWithBroker(bc); + + // User doesn't want to continue linking account. He rather wants to revert and try the other broker. Click browser "back" 3 times now + driver.navigate().back(); + driver.navigate().back(); + + // User is federated after log in with the original broker + log.debug("Clicking social " + samlBrokerConfig.getIDPAlias()); + accountLoginPage.clickSocial(samlBrokerConfig.getIDPAlias()); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + assertNumFederatedIdentities(consumerRealm.users().search(samlBrokerConfig.getUserLogin()).get(0).getId(), 1); + } finally { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + removeUserByUsername(consumerRealm, "consumer"); + } + } + + /** + * Refers to in old test suite: PostBrokerFlowTest#testBrokerReauthentication_samlBrokerWithOTPRequired + */ + @Test + public void testReauthenticationSamlBrokerWithOTPRequired() throws Exception { + KcSamlBrokerConfiguration samlBrokerConfig = KcSamlBrokerConfiguration.INSTANCE; + ClientRepresentation samlClient = samlBrokerConfig.createProviderClients(suiteContext).get(0); + IdentityProviderRepresentation samlBroker = samlBrokerConfig.setUpIdentityProvider(suiteContext); + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + + try { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + adminClient.realm(bc.providerRealmName()).clients().create(samlClient); + consumerRealm.identityProviders().create(samlBroker); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + testingClient.server(bc.consumerRealmName()).run(configurePostBrokerLoginWithOTP(samlBrokerConfig.getIDPAlias())); + logInWithBroker(samlBrokerConfig); + + totpPage.assertCurrent(); + String totpSecret = totpPage.getTotpSecret(); + totpPage.configure(totp.generateTOTP(totpSecret)); + logoutFromRealm(bc.consumerRealmName()); + + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + + accountLoginPage.clickSocial(samlBrokerConfig.getIDPAlias()); + waitForPage(driver, "log in to", true); + log.debug("Logging in"); + loginTotpPage.login(totp.generateTOTP(totpSecret)); + + assertNumFederatedIdentities(consumerRealm.users().search(samlBrokerConfig.getUserLogin()).get(0).getId(), 2); + } finally { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + removeUserByUsername(consumerRealm, "consumer"); + } + } + + /** + * Refers to in old test suite: PostBrokerFlowTest#testBrokerReauthentication_oidcBrokerWithOTPRequired + */ + @Test + public void testReauthenticationOIDCBrokerWithOTPRequired() throws Exception { + KcSamlBrokerConfiguration samlBrokerConfig = KcSamlBrokerConfiguration.INSTANCE; + ClientRepresentation samlClient = samlBrokerConfig.createProviderClients(suiteContext).get(0); + IdentityProviderRepresentation samlBroker = samlBrokerConfig.setUpIdentityProvider(suiteContext); + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + + try { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + adminClient.realm(bc.providerRealmName()).clients().create(samlClient); + consumerRealm.identityProviders().create(samlBroker); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(samlBrokerConfig); + logoutFromRealm(bc.consumerRealmName()); + + testingClient.server(bc.consumerRealmName()).run(configurePostBrokerLoginWithOTP(bc.getIDPAlias())); + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + logoutFromRealm(bc.providerRealmName()); + + driver.navigate().back(); + logInWithBroker(samlBrokerConfig); + + totpPage.assertCurrent(); + String totpSecret = totpPage.getTotpSecret(); + totpPage.configure(totp.generateTOTP(totpSecret)); + logoutFromRealm(bc.consumerRealmName()); + + assertNumFederatedIdentities(consumerRealm.users().search(samlBrokerConfig.getUserLogin()).get(0).getId(), 2); + } finally { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + removeUserByUsername(consumerRealm, "consumer"); + } + } + + /** + * Refers to in old test suite: PostBrokerFlowTest#testBrokerReauthentication_bothBrokerWithOTPRequired + */ + @Test + public void testReauthenticationBothBrokersWithOTPRequired() throws Exception { + KcSamlBrokerConfiguration samlBrokerConfig = KcSamlBrokerConfiguration.INSTANCE; + ClientRepresentation samlClient = samlBrokerConfig.createProviderClients(suiteContext).get(0); + IdentityProviderRepresentation samlBroker = samlBrokerConfig.setUpIdentityProvider(suiteContext); + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + + try { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + adminClient.realm(bc.providerRealmName()).clients().create(samlClient); + consumerRealm.identityProviders().create(samlBroker); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + testingClient.server(bc.consumerRealmName()).run(configurePostBrokerLoginWithOTP(samlBrokerConfig.getIDPAlias())); + logInWithBroker(samlBrokerConfig); + totpPage.assertCurrent(); + String totpSecret = totpPage.getTotpSecret(); + totpPage.configure(totp.generateTOTP(totpSecret)); + logoutFromRealm(bc.consumerRealmName()); + + testingClient.server(bc.consumerRealmName()).run(configurePostBrokerLoginWithOTP(bc.getIDPAlias())); + logInWithBroker(bc); + + waitForPage(driver, "account already exists", false); + idpConfirmLinkPage.assertCurrent(); + idpConfirmLinkPage.clickLinkAccount(); + logoutFromRealm(bc.providerRealmName()); + + driver.navigate().back(); + logInWithBroker(samlBrokerConfig); + + loginTotpPage.assertCurrent(); + loginTotpPage.login(totp.generateTOTP(totpSecret)); + logoutFromRealm(bc.providerRealmName()); + logoutFromRealm(bc.consumerRealmName()); + + logInWithBroker(bc); + + loginTotpPage.assertCurrent(); + loginTotpPage.login(totp.generateTOTP(totpSecret)); + waitForPage(driver, "keycloak account management", true); + accountUpdateProfilePage.assertCurrent(); + + assertNumFederatedIdentities(consumerRealm.users().search(samlBrokerConfig.getUserLogin()).get(0).getId(), 2); + } finally { + updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin); + removeUserByUsername(consumerRealm, "consumer"); + } + } + + private UserRepresentation getFederatedIdentity() { + List users = realmsResouce().realm(bc.consumerRealmName()).users().search(bc.getUserLogin()); + + Assert.assertEquals(1, users.size()); + + return users.get(0); + } + + private IdentityProviderResource getIdentityProviderResource() { + return realmsResouce().realm(bc.consumerRealmName()).identityProviders().get(bc.getIDPAlias()); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerWithConsentTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerWithConsentTest.java new file mode 100644 index 0000000000..9508213452 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerWithConsentTest.java @@ -0,0 +1,185 @@ +package org.keycloak.testsuite.broker; + +import static org.junit.Assert.assertEquals; +import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.removeBrokerExpiredSessions; +import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.common.util.Time; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; + +public class KcOidcBrokerWithConsentTest extends AbstractInitializedBaseBrokerTest { + + @Override + protected BrokerConfiguration getBrokerConfiguration() { + return KcOidcBrokerConfiguration.INSTANCE; + } + + @Override + public void beforeBrokerTest() { + super.beforeBrokerTest(); + // Require broker to show consent screen + RealmResource brokeredRealm = adminClient.realm(bc.providerRealmName()); + List clients = brokeredRealm.clients().findByClientId("brokerapp"); + org.junit.Assert.assertEquals(1, clients.size()); + ClientRepresentation brokerApp = clients.get(0); + brokerApp.setConsentRequired(true); + brokeredRealm.clients().get(brokerApp.getId()).update(brokerApp); + + + // Change timeouts on realm-with-broker to lower values + RealmResource realmWithBroker = adminClient.realm(bc.consumerRealmName()); + RealmRepresentation realmRep = realmWithBroker.toRepresentation(); + realmRep.setAccessCodeLifespanLogin(30);; + realmRep.setAccessCodeLifespan(30); + realmRep.setAccessCodeLifespanUserAction(30); + realmWithBroker.update(realmRep); + } + + /** + * Referes to in old testsuite: org.keycloak.testsuite.broker.OIDCKeycloakServerBrokerWithConsentTest#testConsentDeniedWithExpiredClientSession + */ + @Test + public void testConsentDeniedWithExpiredClientSession() { + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + log.debug("Clicking social " + bc.getIDPAlias()); + accountLoginPage.clickSocial(bc.getIDPAlias()); + waitForPage(driver, "log in to", true); + log.debug("Logging in"); + accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + // Set time offset + invokeTimeOffset(60); + try { + // User rejected consent + grantPage.assertCurrent(); + grantPage.cancel(); + + // Assert login page with "You took too long to login..." message + org.junit.Assert.assertEquals("You took too long to login. Login process starting from beginning.", accountLoginPage.getError()); + + } finally { + invokeTimeOffset(0); + } + } + + /** + * Referes to in old testsuite: org.keycloak.testsuite.broker.OIDCKeycloakServerBrokerWithConsentTest#testConsentDeniedWithExpiredAndClearedClientSession + */ + @Test + public void testConsentDeniedWithExpiredAndClearedClientSession() { + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + // Set time offset + invokeTimeOffset(60); + try { + + testingClient.server(bc.providerRealmName()).run(removeBrokerExpiredSessions()); + + // User rejected consent + grantPage.assertCurrent(); + grantPage.cancel(); + + // Assert login page with "You took too long to login..." message + Assert.assertEquals("You took too long to login. Login process starting from beginning.", accountLoginPage.getError()); + + } finally { + invokeTimeOffset(0); + } + } + + /** + * Referes to in old testsuite: org.keycloak.testsuite.broker.OIDCKeycloakServerBrokerWithConsentTest#testAccountManagementLinkingAndExpiredClientSession + */ + @Test + public void testAccountManagementLinkingAndExpiredClientSession() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + createUser(bc.consumerRealmName(), "consumer", "password", "FirstName", "LastName", "consumer@localhost.com"); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + accountLoginPage.login("consumer", "password"); + + accountPage.federatedIdentity(); + accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias()); + + this.accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + // Set time offset + invokeTimeOffset(60); + try { + // User rejected consent + grantPage.assertCurrent(); + grantPage.cancel(); + + // Assert account error page with "staleCodeAccount" error displayed + accountFederatedIdentityPage.assertCurrent(); + Assert.assertEquals("The page expired. Please try one more time.", accountFederatedIdentityPage.getError()); + + + // Try to link one more time + accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias()); + + this.accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + invokeTimeOffset(120); + + // User granted consent + grantPage.assertCurrent(); + grantPage.accept(); + + // Assert account error page with "staleCodeAccount" error displayed + accountFederatedIdentityPage.assertCurrent(); + Assert.assertEquals("The page expired. Please try one more time.", accountFederatedIdentityPage.getError()); + + } finally { + invokeTimeOffset(0); + } + } + + /** + * Referes to in old testsuite: org.keycloak.testsuite.broker.OIDCKeycloakServerBrokerWithConsentTest#testLoginCancelConsent + */ + @Test + public void testLoginCancelConsent() { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + + // User rejected consent + grantPage.assertCurrent(); + grantPage.cancel(); + + assertEquals("Log in to " + bc.consumerRealmName(), driver.getTitle()); + } + + /** + * Referes to in old testsuite: org.keycloak.testsuite.broker.OIDCKeycloakServerBrokerWithConsentTest#testAccountManagementLinkingCancelConsent + */ + @Test + public void testAccountManagementLinkingCancelConsent() throws Exception { + updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin); + createUser(bc.consumerRealmName(), "consumer", "password", "FirstName", "LastName", "consumer@localhost.com"); + + driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + accountLoginPage.login("consumer", "password"); + + accountPage.federatedIdentity(); + + accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias()); + this.accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword()); + + // User rejected consent + grantPage.assertCurrent(); + grantPage.cancel(); + + // Assert account error page with "consentDenied" error displayed + accountFederatedIdentityPage.assertCurrent(); + Assert.assertEquals("Consent denied.", accountFederatedIdentityPage.getError()); + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerConfiguration.java index 05f5d6d92c..128b12504b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerConfiguration.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerConfiguration.java @@ -175,6 +175,7 @@ public class KcSamlBrokerConfiguration implements BrokerConfiguration { .name("broker-app") .secret("broker-app-secret") .enabled(true) + .directAccessGrants() .addRedirectUri(getAuthRoot(suiteContext) + "/auth/*") .baseUrl(getAuthRoot(suiteContext) + "/auth/realms/" + REALM_CONS_NAME + "/app") .build() diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java index 04328572e8..e2e89019a2 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java @@ -165,4 +165,9 @@ public class KcSamlBrokerTest extends AbstractBrokerTest { Assert.assertThat(samlResponse.getSamlObject(), isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS)); } + @Test + @Override + public void testUpdateProfileIfNotMissingInformation() { + // skip this test as this provider do not return name and surname so something is missing always + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SamlUserAttributeMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SamlUserAttributeMapperTest.java index 7d01ef7ac7..5de106900e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SamlUserAttributeMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SamlUserAttributeMapperTest.java @@ -6,7 +6,9 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; - +/** + * Refers to in old testsuite: org.keycloak.testsuite.broker.SAMLBrokerUserPropertyTest + */ public class SamlUserAttributeMapperTest extends AbstractUserAttributeMapperTest { @Override diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java index 985f449223..3323f1bda6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailServer.java @@ -106,4 +106,8 @@ public class MailServer { } return null; } + + public static MimeMessage[] getReceivedMessages() { + return greenMail.getReceivedMessages(); + } } diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java deleted file mode 100755 index a364d87272..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.Assert; -import org.junit.Test; -import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory; -import org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticatorFactory; -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.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; -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.InfoPage; -import org.keycloak.testsuite.pages.LoginExpiredPage; -import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; -import org.keycloak.testsuite.pages.LoginUpdateProfileEditUsernameAllowedPage; -import org.keycloak.testsuite.pages.ProceedPage; -import org.keycloak.testsuite.rule.KeycloakRule; -import org.keycloak.testsuite.rule.WebResource; -import org.keycloak.testsuite.rule.WebRule; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; - -import javax.mail.internet.MimeMessage; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.hamcrest.Matchers; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -/** - * @author Marek Posolda - */ -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; - - @WebResource - protected LoginExpiredPage loginExpiredPage; - - - - /** - * 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); - } - - - /** - * Test user registers with IdentityProvider with emailAsUsername - */ - @Test - public void testRegistrationWithEmailAsUsername() { - // Require updatePassword after user registered with broker - brokerServerRule.update(new KeycloakRule.KeycloakSetup() { - - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) { - setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_ON); - realmWithBroker.setRegistrationEmailAsUsername(true); - } - - }, APP_REALM_ID); - - loginIDP("pedroigor"); - this.updateProfileWithUsernamePage.assertCurrent(); - - try { - this.updateProfileWithUsernamePage.update("Test", "User", "some-user@redhat.com", "some-user"); - Assert.fail("It is not expected to see username field"); - } catch (NoSuchElementException expected) { - } - - this.updateProfileWithUsernamePage.update("Test", "User", "some-user@redhat.com"); - - // assert authenticated - assertFederatedUser("some-user@redhat.com", "some-user@redhat.com", "pedroigor"); - - brokerServerRule.update(new KeycloakRule.KeycloakSetup() { - - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) { - setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_MISSING); - realmWithBroker.setRegistrationEmailAsUsername(false); - } - - }, 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 testLinkAccountByEmailVerificationTwice() 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.assertThat( - this.idpLinkEmailPage.getMessage(), - is("An email with instructions to link " + ObjectUtil.capitalize(getProviderId()) + " account pedroigor with your " + APP_REALM_ID + " account has been sent to you.") - ); - - 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"); - - // Assert user's email is verified now - UserModel user = getFederatedUser(); - Assert.assertTrue(user.isEmailVerified()); - - // Attempt to use the link for the second time - driver.navigate().to(linkFromMail.trim()); - - infoPage.assertCurrent(); - Assert.assertThat(infoPage.getInfo(), is("You are already logged in.")); - - // Log out - driver.navigate().to("http://localhost:8081/test-app/logout"); - - // Go to the same link again - driver.navigate().to(linkFromMail.trim()); - - proceedPage.assertCurrent(); - Assert.assertThat(proceedPage.getInfo(), Matchers.containsString("Confirm linking the account")); - proceedPage.clickProceedLink(); - infoPage.assertCurrent(); - Assert.assertThat(infoPage.getInfo(), startsWith("You successfully verified your email. Please go back to your original browser and continue there with the login.")); - } - - @Test - public void testLinkAccountByEmailVerificationResendEmail() throws Exception, Throwable { - 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.assertThat( - this.idpLinkEmailPage.getMessage(), - is("An email with instructions to link " + ObjectUtil.capitalize(getProviderId()) + " account pedroigor with your " + APP_REALM_ID + " account has been sent to you.") - ); - - this.idpLinkEmailPage.clickResendEmail(); - - this.idpLinkEmailPage.assertCurrent(); - Assert.assertThat( - this.idpLinkEmailPage.getMessage(), - is("An email with instructions to link " + ObjectUtil.capitalize(getProviderId()) + " account pedroigor with your " + APP_REALM_ID + " account has been sent to you.") - ); - - Assert.assertEquals(2, 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"); - - // Assert user's email is verified now - UserModel user = getFederatedUser(); - Assert.assertTrue(user.isEmailVerified()); - } - - - /** - * 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 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.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.getInfoMessage()); - - 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); - } - - - /** - * Variation of previous test, which uses browser buttons (back, refresh etc) - */ - @Test - public void testLinkAccountByReauthenticationWithPassword_browserButtons() throws Exception { - // Remove smtp config. The reauthentication by username+password screen will be automatically used then - final Map 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.emptyMap()); - } - - }, APP_REALM_ID); - - - // Use invalid username for the first time - loginIDP("foo"); - assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8082/auth/")); - 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()); - - // Click browser 'back' and then 'forward' and then continue - driver.navigate().back(); - Assert.assertTrue(driver.getPageSource().contains("You are already logged in.")); - driver.navigate().forward(); - this.idpConfirmLinkPage.assertCurrent(); - - // Click browser 'back' on review profile page - this.idpConfirmLinkPage.clickReviewProfile(); - this.updateProfilePage.assertCurrent(); - driver.navigate().back(); - this.updateProfilePage.assertCurrent(); - this.updateProfilePage.update("Pedro", "Igor", "psilva@redhat.com"); - - this.idpConfirmLinkPage.assertCurrent(); - 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.getInfoMessage()); - - 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()); - - // Click browser 'back' and then continue - this.driver.navigate().back(); - this.loginExpiredPage.assertCurrent(); - this.loginExpiredPage.clickLoginContinueLink(); - - // 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); - } - - - /** - * Same like above, but "forget password" link is opened in different browser - */ - @Test - public void testLinkAccountByReauthentication_forgetPassword_differentBrowser() throws Throwable { - 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); - - // Simulate 2nd browser - WebRule webRule2 = new WebRule(this); - try { - webRule2.initProperties(); - - WebDriver driver2 = webRule2.getDriver(); - LoginPasswordUpdatePage passwordUpdatePage2 = webRule2.getPage(LoginPasswordUpdatePage.class); - InfoPage infoPage2 = webRule2.getPage(InfoPage.class); - - driver2.navigate().to(linkFromMail.trim()); - - // Need to update password now - passwordUpdatePage2.assertCurrent(); - passwordUpdatePage2.changePassword("password", "password"); - - // authenticated, but not redirected to app. Just seeing info page. - infoPage2.assertCurrent(); - Assert.assertEquals("Your account has been updated.", infoPage2.getInfo()); - } finally { - // Revert everything - webRule2.after(); - } - - // User is not yet linked with identity provider. He needs to authenticate again in 1st browser - RealmModel realmWithBroker = getRealm(); - Set federatedIdentities = this.session.users().getFederatedIdentities(this.session.users().getUserByUsername("pedroigor", realmWithBroker), realmWithBroker); - assertEquals(0, federatedIdentities.size()); - - // Continue with 1st browser. Note that the user has already authenticated with brokered IdP in the beginning of this test - // so entering their credentials there is now skipped. - loginToIDPWhenAlreadyLoggedIntoProviderIdP("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.assertEquals("Log in to " + APP_REALM_ID, this.driver.getTitle()); - this.loginPage.login("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); - } - - // KEYCLOAK-7696 - @Test - public void testHardcodedUserSessionNoteIsSetAfterFristBrokerLogin() { - brokerServerRule.update(new KeycloakRule.KeycloakSetup() { - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) { - setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_ON); - } - }, APP_REALM_ID); - - loginIDP("pedroigor"); - this.updateProfileWithUsernamePage.assertCurrent(); - - this.updateProfileWithUsernamePage.update("Test", "User", "some-user@redhat.com", "some-new-user"); - - UserSessionModel userSession = session.sessions().getUserSessions(getRealm(), getFederatedUser()).get(0); - assertEquals("sessionvalue", userSession.getNote("user-session-attr")); - brokerServerRule.update(new KeycloakRule.KeycloakSetup() { - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) { - setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_MISSING); - } - }, 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 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 static void setExecutionRequirement(RealmModel realmWithBroker, String flowAlias, String authenticatorProvider, AuthenticationExecutionModel.Requirement requirement) { - AuthenticationFlowModel flowModel = realmWithBroker.getFlowByAlias(flowAlias); - List 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-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java deleted file mode 100644 index d84c80a069..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker; - -import org.junit.Before; -import org.keycloak.broker.oidc.OIDCIdentityProviderFactory; -import org.keycloak.broker.saml.SAMLIdentityProviderFactory; -import org.keycloak.social.facebook.FacebookIdentityProviderFactory; -import org.keycloak.social.github.GitHubIdentityProviderFactory; -import org.keycloak.social.paypal.PayPalIdentityProviderFactory; -import org.keycloak.social.google.GoogleIdentityProviderFactory; -import org.keycloak.social.linkedin.LinkedInIdentityProviderFactory; -import org.keycloak.social.stackoverflow.StackoverflowIdentityProviderFactory; -import org.keycloak.social.twitter.TwitterIdentityProviderFactory; -import org.keycloak.testsuite.model.AbstractModelTest; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * @author pedroigor - */ -public abstract class AbstractIdentityProviderModelTest extends AbstractModelTest { - - private Set expectedProviders; - - @Before - public void onBefore() { - this.expectedProviders = new HashSet(); - - this.expectedProviders.add(SAMLIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(OIDCIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(GoogleIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(FacebookIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(GitHubIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(PayPalIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(TwitterIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(LinkedInIdentityProviderFactory.PROVIDER_ID); - this.expectedProviders.add(StackoverflowIdentityProviderFactory.PROVIDER_ID); - - this.expectedProviders = Collections.unmodifiableSet(this.expectedProviders); - } - - protected Set getExpectedProviders() { - return this.expectedProviders; - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java deleted file mode 100755 index 54004de3a4..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.keycloak.authentication.authenticators.broker.IdpReviewProfileAuthenticatorFactory; -import org.keycloak.common.util.Time; -import org.keycloak.models.AuthenticatorConfigModel; -import org.keycloak.models.FederatedIdentityModel; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionTask; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.utils.DefaultAuthenticationFlows; -import org.keycloak.models.utils.KeycloakModelUtils; -import org.keycloak.representations.IDToken; -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.*; -import org.keycloak.testsuite.rule.GreenMailRule; -import org.keycloak.testsuite.rule.LoggingRule; -import org.keycloak.testsuite.rule.WebResource; -import org.keycloak.testsuite.rule.WebRule; -import org.keycloak.util.JsonSerialization; -import org.openqa.selenium.WebDriver; - -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.internet.MimeMessage; -import javax.ws.rs.core.UriBuilder; -import java.io.IOException; -import java.net.URI; -import java.util.List; -import java.util.Set; - -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.*; - -/** - * @author pedroigor - */ -public abstract class AbstractIdentityProviderTest { - - protected static final URI BASE_URI = UriBuilder.fromUri("http://localhost:8081/auth").build(); - - @ClassRule - public static BrokerKeyCloakRule brokerServerRule = new BrokerKeyCloakRule(); - - @Rule - public LoggingRule loggingRule = new LoggingRule(this); - - @Rule - public WebRule webRule = new WebRule(this); - - @WebResource - protected WebDriver driver; - - @WebResource - protected LoginPage loginPage; - - @WebResource - protected LoginUpdateProfilePage updateProfilePage; - - - @WebResource - protected VerifyEmailPage verifyEmailPage; - - @Rule - public GreenMailRule greenMail = new GreenMailRule(); - - @WebResource - protected OAuthClient oauth; - - @WebResource - protected OAuthGrantPage grantPage; - - @WebResource - AccountUpdateProfilePage accountUpdateProfilePage; - - @WebResource - protected AccountPasswordPage changePasswordPage; - - @WebResource - protected AccountFederatedIdentityPage accountFederatedIdentityPage; - - @WebResource - protected ErrorPage errorPage; - - @WebResource - protected InfoPage infoPage; - - @WebResource - protected ProceedPage proceedPage; - - protected KeycloakSession session; - - protected int logoutTimeOffset = 0; - - @Before - public void onBefore() { - this.session = brokerServerRule.startSession(); - removeTestUsers(); - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - assertNotNull(getIdentityProviderModel()); - } - - @After - public void onAfter() { - revokeGrant(); - brokerServerRule.stopSession(this.session, true); - } - - protected 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 federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm); - - assertEquals(1, federatedIdentities.size()); - - FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next(); - - assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider()); - assertEquals(federatedUser.getUsername(), federatedIdentityModel.getUserName()); - - // test access token timeot on logout - if (logoutTimeOffset > 0) { - Time.setOffset(logoutTimeOffset); - } - try { - driver.navigate().to("http://localhost:8081/test-app/logout"); - } finally { - Time.setOffset(0); - } - - - 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; - - } - - - - protected void doAssertFederatedUserNoEmail(UserModel federatedUser) { - assertEquals("kc-oidc-idp.test-user-noemail", federatedUser.getUsername()); - assertEquals(null, federatedUser.getEmail()); - assertEquals("Test", federatedUser.getFirstName()); - assertEquals("User", federatedUser.getLastName()); - } - - protected void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username, boolean isProfileUpdateExpected) { - loginIDP(username); - - - if (isProfileUpdateExpected) { - String userEmail = "new@email.com"; - String userFirstName = "New first"; - String userLastName = "New last"; - - // update profile - this.updateProfilePage.assertCurrent(); - this.updateProfilePage.update(userFirstName, userLastName, userEmail); - } - - } - - protected void loginIDP(String username) { - driver.navigate().to("http://localhost:8081/test-app"); - - assertThat(this.driver.getCurrentUrl(), startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth")); - - // choose the identity provider - this.loginPage.clickSocial(getProviderId()); - - String currentUrl = this.driver.getCurrentUrl(); - assertThat(currentUrl, startsWith("http://localhost:8082/auth/")); - // log in to identity provider - this.loginPage.login(username, "password"); - doAfterProviderAuthentication(); - } - - protected void loginToIDPWhenAlreadyLoggedIntoProviderIdP(String username) { - driver.navigate().to("http://localhost:8081/test-app"); - - assertThat(this.driver.getCurrentUrl(), startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth")); - - // choose the identity provider - this.loginPage.clickSocial(getProviderId()); - - doAfterProviderAuthentication(); - } - - protected UserModel getFederatedUser() { - UserSessionStatus userSessionStatus = retrieveSessionStatus(); - IDToken idToken = userSessionStatus.getIdToken(); - KeycloakSession samlServerSession = brokerServerRule.startSession(); - RealmModel brokerRealm = samlServerSession.realms().getRealm("realm-with-broker"); - return samlServerSession.users().getUserById(idToken.getSubject(), brokerRealm); - } - - protected void doAfterProviderAuthentication() { - - } - - protected void revokeGrant() { - - } - - protected abstract String getProviderId(); - - - protected IdentityProviderModel getIdentityProviderModel() { - IdentityProviderModel identityProviderModel = getRealm().getIdentityProviderByAlias(getProviderId()); - - assertNotNull(identityProviderModel); - - identityProviderModel.setEnabled(true); - - return identityProviderModel; - } - - - protected RealmModel getRealm() { - return getRealm(this.session); - } - - protected static 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"; - String userLastName = "New last"; - - assertEquals(expectedEmail, federatedUser.getEmail()); - assertEquals(userFirstName, federatedUser.getFirstName()); - assertEquals(userLastName, federatedUser.getLastName()); - } else { - assertEquals(expectedEmail, federatedUser.getEmail()); - assertEquals("Test", federatedUser.getFirstName()); - assertEquals("User", federatedUser.getLastName()); - } - } - - - private void removeTestUsers() { - RealmModel realm = getRealm(); - List users = this.session.users().getUsers(realm, true); - - for (UserModel user : users) { - Set identities = this.session.users().getFederatedIdentities(user, realm); - - for (FederatedIdentityModel fedIdentity : identities) { - this.session.users().removeFederatedIdentity(realm, user, fedIdentity.getIdentityProvider()); - } - - if (!"pedroigor".equals(user.getUsername())) { - this.session.users().removeUser(realm, user); - } - } - } - - - 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 static 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(); - - String htmlChangePwdUrl = MailUtil.getLink(htmlBody); - - // undo changes that may have been made by html sanitizer - htmlChangePwdUrl = htmlChangePwdUrl.replace("=", "="); - htmlChangePwdUrl = htmlChangePwdUrl.replace("..", "."); - htmlChangePwdUrl = htmlChangePwdUrl.replace("&", "&"); - - // TODO Links are working, but not equal for some reason. It's an issue in kcSanitize. -// assertEquals(htmlChangePwdUrl, textVerificationUrl); - - return htmlChangePwdUrl; - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java deleted file mode 100755 index 3d2cf07164..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -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.KeycloakSession; -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.storage.UserStorageProviderModel; -import org.keycloak.testsuite.broker.util.UserSessionStatusServlet; -import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; - -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; -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 java.io.IOException; -import java.net.URI; -import java.util.Set; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.*; - -/** - * @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 testDisabledUser() throws Exception { - KeycloakSession session = brokerServerRule.startSession(); - setUpdateProfileFirstLogin(session.realms().getRealmByName("realm-with-broker"), IdentityProviderRepresentation.UPFLM_OFF); - brokerServerRule.stopSession(session, true); - - driver.navigate().to("http://localhost:8081/test-app"); - loginPage.clickSocial(getProviderId()); - loginPage.login("test-user", "password"); - System.out.println(driver.getPageSource()); - driver.navigate().to("http://localhost:8081/test-app/logout"); - - try { - session = brokerServerRule.startSession(); - session.users().getUserByUsername("test-user", session.realms().getRealmByName("realm-with-broker")).setEnabled(false); - brokerServerRule.stopSession(session, true); - - driver.navigate().to("http://localhost:8081/test-app"); - - loginPage.clickSocial(getProviderId()); - loginPage.login("test-user", "password"); - - assertTrue(errorPage.isCurrent()); - assertEquals("Account is disabled, contact admin.", errorPage.getError()); - } finally { - session = brokerServerRule.startSession(); - session.users().getUserByUsername("test-user", session.realms().getRealmByName("realm-with-broker")).setEnabled(true); - brokerServerRule.stopSession(session, true); - } - } - - @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 { - RealmModel realm = getRealm(); - realm.setVerifyEmail(true); - setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - try { - 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 federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm); - - assertEquals(1, federatedIdentities.size()); - - FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next(); - - assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider()); - assertEquals(federatedUser.getUsername(), 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() throws Exception { - RealmModel realm = getRealm(); - realm.setVerifyEmail(true); - setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - try { - IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - - 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() { - RealmModel realmWithBroker = getRealm(); - realmWithBroker.setVerifyEmail(true); - setUpdateProfileFirstLogin(realmWithBroker, 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 { - RealmModel realm = getRealm(); - realm.setVerifyEmail(true); - setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_ON); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - try { - 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 for KEYCLOAK-3505 - Verify the claims from the claim set returned by the OIDC UserInfo are correctly mapped - * by the user attribute mapper - * - */ - protected void verifyAttributeMapperHandlesUserInfoClaims() { - IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON); - - UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com", true); - Assert.assertEquals("A00", user.getFirstAttribute("tenantid")); - } - - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() throws Exception { - RealmModel realm = getRealm(); - realm.setRegistrationEmailAsUsername(true); - setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - try { - IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - - 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 - 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 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 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 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-link-" + 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()); - this.loginPage.login("test-user", "password"); - doAfterProviderAuthentication(); - assertTrue(accountFederatedIdentityPage.isCurrent()); - assertTrue(driver.getPageSource().contains("id=\"remove-link-" + identityProviderModel.getAlias() + "\"")); - - // Unlink my "test-user" - accountFederatedIdentityPage.clickRemoveProvider(identityProviderModel.getAlias()); - assertTrue(driver.getPageSource().contains("id=\"add-link-" + identityProviderModel.getAlias() + "\"")); - - // Revoke grant in account mgmt - revokeGrant(); - - // 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(); - } - - - // KEYCLOAK-1822 - @Test - public void testAccountManagementLinkedIdentityAlreadyExists() { - // Login as "test-user" through broker - IdentityProviderModel identityProvider = getIdentityProviderModel(); - setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); - - assertSuccessfulAuthentication(identityProvider, "test-user", "test-user@localhost", false); - - // Login as pedroigor to account management - accountFederatedIdentityPage.realm("realm-with-broker"); - accountFederatedIdentityPage.open(); - assertThat(driver.getTitle(), is("Log in to realm-with-broker")); - loginPage.login("pedroigor", "password"); - accountFederatedIdentityPage.assertCurrent(); - - // Try to link my "pedroigor" identity with "test-user" from brokered Keycloak. - accountFederatedIdentityPage.clickAddProvider(identityProvider.getAlias()); - - assertThat(this.driver.getCurrentUrl(), startsWith("http://localhost:8082/auth/")); - this.loginPage.login("test-user", "password"); - doAfterProviderAuthentication(); - - // Error is displayed in account management because federated identity"test-user" already linked to local account "test-user" - accountFederatedIdentityPage.assertCurrent(); - assertEquals("Federated identity returned by " + getProviderId() + " is already linked to another user.", accountFederatedIdentityPage.getError()); - } - - 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(); - - setStoreToken(identityProviderModel, true); - try { - authenticateWithIdentityProvider(identityProviderModel, "test-user", true); - - brokerServerRule.stopSession(session, true); - session = brokerServerRule.startSession(); - - UserModel federatedUser = getFederatedUser(); - RealmModel realm = getRealm(); - Set 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("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")); - } finally { - setStoreToken(identityProviderModel, false); - } - } - - private void setStoreToken(IdentityProviderModel identityProviderModel, boolean storeToken) { - identityProviderModel.setStoreToken(storeToken); - getRealm().updateIdentityProvider(identityProviderModel); - - brokerServerRule.stopSession(session, storeToken); - session = brokerServerRule.startSession(); - } - - protected abstract void doAssertTokenRetrieval(String pageSource); - - @Test - public void testWithLinkedFederationProvider() throws Exception { - setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); - - // Add federationProvider to realm. It's configured with sync registrations - RealmModel realm = getRealm(); - UserStorageProviderModel model = new UserStorageProviderModel(); - model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME); - model.setPriority(1); - model.setName("test-sync-dummy"); - model.setFullSyncPeriod(-1); - model.setChangedSyncPeriod(-1); - model.setLastSync(0); - UserStorageProviderModel dummyModel = new UserStorageProviderModel(realm.addComponentModel(model)); - - brokerServerRule.stopSession(session, true); - session = brokerServerRule.startSession(); - - try { - // Login as user "test-user" to account management. - authenticateWithIdentityProvider(getIdentityProviderModel(), "test-user", false); - changePasswordPage.realm("realm-with-broker"); - changePasswordPage.open(); - assertTrue(changePasswordPage.isCurrent()); - - // Assert changing password with old password "secret" as this is the password from federationProvider (See DummyUserFederationProvider) - changePasswordPage.changePassword("new-password", "new-password"); - Assert.assertEquals("Please specify password.", accountUpdateProfilePage.getError()); - - changePasswordPage.changePassword("bad", "new-password", "new-password"); - Assert.assertEquals("Invalid existing password.", accountUpdateProfilePage.getError()); - - changePasswordPage.changePassword("secret", "new-password", "new-password"); - Assert.assertEquals("Your password has been updated.", accountUpdateProfilePage.getSuccess()); - - // Logout - driver.navigate().to("http://localhost:8081/test-app/logout"); - - - // Login as user "test-user-noemail" . - authenticateWithIdentityProvider(getIdentityProviderModel(), "test-user-noemail", false); - changePasswordPage.open(); - assertTrue(changePasswordPage.isCurrent()); - - // Assert old password is not required as federationProvider doesn't have it for this user - changePasswordPage.changePassword("new-password", "new-password"); - Assert.assertEquals("Your password has been updated.", accountUpdateProfilePage.getSuccess()); - - // Now it is required as it's set on model - changePasswordPage.changePassword("new-password2", "new-password2"); - Assert.assertEquals("Please specify password.", accountUpdateProfilePage.getError()); - - changePasswordPage.changePassword("new-password", "new-password2", "new-password2"); - Assert.assertEquals("Your password has been updated.", accountUpdateProfilePage.getSuccess()); - - // Logout - driver.navigate().to("http://localhost:8081/test-app/logout"); - } finally { - - // remove dummy federation provider for this realm - realm = getRealm(); - realm.removeComponent(dummyModel); - - brokerServerRule.stopSession(session, true); - session = brokerServerRule.startSession(); - } - } - -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java deleted file mode 100755 index 61250cc2f4..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker; - -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.broker.util.UserSessionStatusServlet; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; - -import java.net.URL; - -/** - * @author pedroigor - */ -public class BrokerKeyCloakRule extends AbstractKeycloakRule { - - @Override - protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { - server.importRealm(getClass().getResourceAsStream("/broker-test/test-realm-with-broker.json")); - URL url = getClass().getResource("/broker-test/test-app-keycloak.json"); - - createApplicationDeployment() - .name("test-app").contextPath("/test-app") - .servletClass(UserSessionStatusServlet.class).adapterConfigPath(url.getPath()) - .role("manager").deployApplication(); - - createApplicationDeployment() - .name("test-app-allowed-providers").contextPath("/test-app-allowed-providers") - .servletClass(UserSessionStatusServlet.class).adapterConfigPath(url.getPath()) - .role("manager").deployApplication(); - } - - @Override - protected String[] getTestRealms() { - return new String[] {"realm-with-broker"}; - } - -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCBrokerUserPropertyTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCBrokerUserPropertyTest.java deleted file mode 100755 index 1c5ed9b11a..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCBrokerUserPropertyTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Test; -import org.keycloak.dom.saml.v2.protocol.ResponseType; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; -import org.keycloak.saml.processing.web.util.PostBindingUtil; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; - -import javax.mail.MessagingException; -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -/** - * Test that the broker AttributeMapper maps user properties like email, firstName, and lastName - * @author pedroigor - */ -public class OIDCBrokerUserPropertyTest extends AbstractKeycloakIdentityProviderTest { - - @ClassRule - public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() { - - @Override - protected void configureServer(KeycloakServer server) { - server.getConfig().setPort(8082); - } - - @Override - protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { - server.importRealm(getClass().getResourceAsStream("/broker-test/realm-with-oidc-property-mappers.json")); - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-oidc-idp-property-mappers" }; - } - }; - - @Override - protected String getProviderId() { - return "kc-oidc-idp-property-mappers"; - } - - @Override - protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) { - if (isProfileUpdateExpected) { - super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected); - } else { - assertEquals(expectedEmail, federatedUser.getEmail()); - assertNotNull(federatedUser.getFirstName()); - assertNotNull(federatedUser.getLastName()); - } - } - - @Override - protected void doAssertFederatedUserNoEmail(UserModel federatedUser) { - assertEquals("kc-saml-idp-basic.test-user-noemail", federatedUser.getUsername()); - //assertEquals("", federatedUser.getEmail()); - assertEquals(null, federatedUser.getFirstName()); - assertEquals(null, federatedUser.getLastName()); - } - - @Override - protected void doAssertTokenRetrieval(String pageSource) { - try { - ResponseType responseType = (ResponseType) SAML2Request - .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource)) - .getSamlObject(); - //.getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8"))); - - assertNotNull(responseType); - assertFalse(responseType.getAssertions().isEmpty()); - } catch (Exception e) { - fail("Could not parse token."); - } - } - - /** - * Test for KEYCLOAK-3505 - Verify the claims from the claim set returned by the OIDC UserInfo are correctly mapped - * by the user attribute mapper - * - */ - @Test - public void testSuccessfulAuthentication_verifyAttributeMapperHandlesUserInfoClaims() { - verifyAttributeMapperHandlesUserInfoClaims(); - } - - @Override - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile() { - super.testSuccessfulAuthenticationWithoutUpdateProfile(); - } - - @Test - @Ignore - @Override - public void testSuccessfulAuthentication() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() { - // ignore - } - - @Override - @Ignore - @Test - public void testDisabled() { - // ignore - } - - @Override - @Test - @Ignore - public void testAccountManagementLinkIdentity() { - // ignore - } - - @Override - @Test - @Ignore - public void testAccountManagementLinkedIdentityAlreadyExists() { - // ignore - } - - @Override - @Test - @Ignore - public void testTokenStorageAndRetrievalByApplication() { - // ignore - } - - @Override - @Test - @Ignore - public void testWithLinkedFederationProvider() throws Exception { - // ignore - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCFirstBrokerLoginTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCFirstBrokerLoginTest.java deleted file mode 100644 index c44bbac58a..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCFirstBrokerLoginTest.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -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 java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import org.keycloak.models.AuthenticationFlowModel; -import org.keycloak.models.IdentityProviderModel; -import static org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest.APP_REALM_ID; - -/** - * @author Marek Posolda - */ -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 - linkUserWithSamlBroker("pedroigor", "psilva@redhat.com"); - - - // 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.getInfoMessage()); - - 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 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); - } - - /** - * Tests that user can link federated identity with existing brokered - * account without prompt (KEYCLOAK-7270). - */ - @Test - public void testAutoLinkAccountWithBroker() throws Exception { - final String originalFirstBrokerLoginFlowId = getRealm().getIdentityProviderByAlias(getProviderId()).getFirstBrokerLoginFlowId(); - - brokerServerRule.update(new KeycloakRule.KeycloakSetup() { - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - AuthenticationFlowModel newFlow = new AuthenticationFlowModel(); - newFlow.setAlias("AutoLink"); - newFlow.setDescription("AutoLink"); - newFlow.setProviderId("basic-flow"); - newFlow.setBuiltIn(false); - newFlow.setTopLevel(true); - newFlow = appRealm.addAuthenticationFlow(newFlow); - - AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); - execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); - execution.setAuthenticatorFlow(false); - execution.setAuthenticator("idp-create-user-if-unique"); - execution.setPriority(1); - execution.setParentFlow(newFlow.getId()); - execution = appRealm.addAuthenticatorExecution(execution); - - AuthenticationExecutionModel execution2 = new AuthenticationExecutionModel(); - execution2.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); - execution2.setAuthenticatorFlow(false); - execution2.setAuthenticator("idp-auto-link"); - execution2.setPriority(2); - execution2.setParentFlow(newFlow.getId()); - execution2 = appRealm.addAuthenticatorExecution(execution2); - - IdentityProviderModel idp = appRealm.getIdentityProviderByAlias(getProviderId()); - idp.setFirstBrokerLoginFlowId(newFlow.getId()); - appRealm.updateIdentityProvider(idp); - - } - }, APP_REALM_ID); - - // login through OIDC broker - loginIDP("pedroigor"); - - // 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 federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker); - assertEquals(1, federatedIdentities.size()); - - for (FederatedIdentityModel link : federatedIdentities) { - Assert.assertEquals("pedroigor", link.getUserName()); - Assert.assertTrue(link.getIdentityProvider().equals(getProviderId())); - } - - brokerServerRule.update(new KeycloakRule.KeycloakSetup() { - @Override - public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - IdentityProviderModel idp = appRealm.getIdentityProviderByAlias(getProviderId()); - idp.setFirstBrokerLoginFlowId(originalFirstBrokerLoginFlowId); - appRealm.updateIdentityProvider(idp); - } - }, APP_REALM_ID); - } - - // KEYCLOAK-5936 - @Test - public void testMoreIdpAndBackButtonWhenLinkingAccount() 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_ON); - } - - }, APP_REALM_ID); - - - // First link user with SAML broker and logout - linkUserWithSamlBroker("pedroigor", "psilva@redhat.com"); - - // Try to login through OIDC broker now - loginIDP("pedroigor"); - this.updateProfilePage.assertCurrent(); - - // User doesn't want to continue linking account. He rather wants to revert and try the other broker. Cick browser "back" 2 times now - driver.navigate().back(); - loginExpiredPage.assertCurrent(); - driver.navigate().back(); - - // I am back on the base login screen. Click login with SAML now and login with SAML broker instead - Assert.assertEquals("Log in to realm-with-broker", driver.getTitle()); - this.loginPage.clickSocial("kc-saml-idp-basic"); - - // Login inside SAML broker - this.loginPage.login("pedroigor", "password"); - - // Assert logged successfully - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app")); - UserModel federatedUser = getFederatedUser(); - assertNotNull(federatedUser); - assertEquals("pedroigor", federatedUser.getUsername()); - - // Logout - driver.navigate().to("http://localhost:8081/test-app/logout"); - - 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); - - } - - - private void linkUserWithSamlBroker(String username, String email) { - // 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(username, "password"); - - if (updateProfilePage.isCurrent()) { - updateProfilePage.update("Pedro", "Igor", email); - } - - this.idpConfirmLinkPage.assertCurrent(); - Assert.assertEquals("User with email " + email + " 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"); - } - -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java deleted file mode 100755 index 386218977a..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.ClassRule; -import org.junit.Test; -import org.keycloak.admin.client.Keycloak; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.representations.AccessTokenResponse; -import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.services.Urls; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.Constants; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.pages.AccountApplicationsPage; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; -import org.keycloak.testsuite.rule.WebResource; -import org.keycloak.util.JsonSerialization; -import org.openqa.selenium.NoSuchElementException; - -import javax.ws.rs.core.UriBuilder; -import java.io.IOException; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -/** - * @author pedroigor - */ -public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityProviderTest { - - 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")); - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-oidc-identity-provider" }; - } - }; - - @WebResource - protected AccountApplicationsPage accountApplicationsPage; - - @Override - protected void revokeGrant() { - String currentUrl = driver.getCurrentUrl(); - - String accountAccessPath = Urls.accountApplicationsPage(UriBuilder.fromUri(Constants.AUTH_SERVER_ROOT).port(PORT).build(), "realm-with-oidc-identity-provider").toString(); - accountApplicationsPage.setPath(accountAccessPath); - accountApplicationsPage.open(); - try { - accountApplicationsPage.revokeGrant("broker-app"); - } catch (NoSuchElementException e) { - System.err.println("Couldn't revoke broker-app application, maybe because it wasn't granted or user not logged"); - } - - driver.navigate().to(currentUrl); - } - - @Override - protected void doAfterProviderAuthentication() { - // grant access to broker-app - //grantPage.assertCurrent(); - //grantPage.accept(); - } - - @Override - protected void doAssertTokenRetrieval(String pageSource) { - try { - AccessTokenResponse accessTokenResponse = JsonSerialization.readValue(pageSource, AccessTokenResponse.class); - - assertNotNull(accessTokenResponse.getToken()); - assertNotNull(accessTokenResponse.getIdToken()); - } catch (IOException e) { - fail("Could not parse token."); - } - } - - @Override - protected String getProviderId() { - return "kc-oidc-idp"; - } - - @Test - public void testDisabledUser() throws Exception { - super.testDisabledUser(); - } - - @Test - public void testLogoutWorksWithTokenTimeout() { - try (Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID)) { - RealmRepresentation realm = keycloak.realm("realm-with-oidc-identity-provider").toRepresentation(); - assertNotNull(realm); - int oldLifespan = realm.getAccessTokenLifespan(); - realm.setAccessTokenLifespan(1); - keycloak.realm("realm-with-oidc-identity-provider").update(realm); - IdentityProviderRepresentation idp = keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").toRepresentation(); - idp.getConfig().put("backchannelSupported", "false"); - keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").update(idp); - logoutTimeOffset = 2; - super.testSuccessfulAuthentication(); - logoutTimeOffset = 0; - realm.setAccessTokenLifespan(oldLifespan); - keycloak.realm("realm-with-oidc-identity-provider").update(realm); - idp.getConfig().put("backchannelSupported", "true"); - keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").update(idp); - } - } - - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile() { - super.testSuccessfulAuthenticationWithoutUpdateProfile(); - } - - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() throws Exception { - super.testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled(); - } - - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() throws Exception { - super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername(); - } - - @Test - public void testTokenStorageAndRetrievalByApplication() { - super.testTokenStorageAndRetrievalByApplication(); - } - - @Test - public void testAccountManagementLinkIdentity() { - super.testAccountManagementLinkIdentity(); - } - - @Test - public void testWithLinkedFederationProvider() throws Exception { - super.testWithLinkedFederationProvider(); - } - - @Test - public void testAccountManagementLinkedIdentityAlreadyExists() { - super.testAccountManagementLinkedIdentityAlreadyExists(); - } - -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCKeycloakServerBrokerWithConsentTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCKeycloakServerBrokerWithConsentTest.java deleted file mode 100644 index acee4ed099..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/OIDCKeycloakServerBrokerWithConsentTest.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.keycloak.admin.client.Keycloak; -import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.common.util.Time; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; - -import java.util.List; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * @author Marek Posolda - */ -public class OIDCKeycloakServerBrokerWithConsentTest extends AbstractIdentityProviderTest { - - private static final int PORT = 8082; - - private static Keycloak keycloak1; - private static Keycloak keycloak2; - - @ClassRule - public static AbstractKeycloakRule oidcServerRule = 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")); - - // Disable update profile - RealmModel realm = getRealm(session); - setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF); - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-oidc-identity-provider" }; - } - }; - - - @BeforeClass - public static void before() { - keycloak1 = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID); - keycloak2 = Keycloak.getInstance("http://localhost:8082/auth", "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID); - - // Require broker to show consent screen - RealmResource brokeredRealm = keycloak2.realm("realm-with-oidc-identity-provider"); - List clients = brokeredRealm.clients().findByClientId("broker-app"); - Assert.assertEquals(1, clients.size()); - ClientRepresentation brokerApp = clients.get(0); - brokerApp.setConsentRequired(true); - brokeredRealm.clients().get(brokerApp.getId()).update(brokerApp); - - - // Change timeouts on realm-with-broker to lower values - RealmResource realmWithBroker = keycloak1.realm("realm-with-broker"); - RealmRepresentation realmRep = realmWithBroker.toRepresentation(); - realmRep.setAccessCodeLifespanLogin(30);; - realmRep.setAccessCodeLifespan(30); - realmRep.setAccessCodeLifespanUserAction(30); - realmWithBroker.update(realmRep); - } - - @AfterClass - public static void after() { - keycloak1.close(); - keycloak2.close(); - } - - - @Override - protected String getProviderId() { - return "kc-oidc-idp"; - } - - - // KEYCLOAK-2769 - @Test - public void testConsentDeniedWithExpiredClientSession() throws Exception { - // Login to broker - loginIDP("test-user"); - - // Set time offset - Time.setOffset(60); - try { - // User rejected consent - grantPage.assertCurrent(); - grantPage.cancel(); - - // Assert login page with "You took too long to login..." message - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/login-actions/authenticate")); - Assert.assertEquals("You took too long to login. Login process starting from beginning.", loginPage.getError()); - - } finally { - Time.setOffset(0); - } - } - - - // KEYCLOAK-2769 - @Test - public void testConsentDeniedWithExpiredAndClearedClientSession() throws Exception { - // Login to broker again - loginIDP("test-user"); - - // Set time offset - Time.setOffset(60); - try { - // Manually remove expiredSessions TODO: Will require custom endpoint when migrate to integration-arquillian - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - session.sessions().removeExpired(getRealm()); - session.authenticationSessions().removeExpired(getRealm()); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - // User rejected consent - grantPage.assertCurrent(); - grantPage.cancel(); - - // Assert login page with "You took too long to login..." message - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/login-actions/authenticate")); - Assert.assertEquals("You took too long to login. Login process starting from beginning.", loginPage.getError()); - - } finally { - Time.setOffset(0); - } - } - - - // KEYCLOAK-2801 - @Test - public void testAccountManagementLinkingAndExpiredClientSession() throws Exception { - // Login as pedroigor to account management - loginToAccountManagement("pedroigor"); - - // Link my "pedroigor" identity with "test-user" from brokered Keycloak - accountFederatedIdentityPage.clickAddProvider(getProviderId()); - - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/")); - this.loginPage.login("test-user", "password"); - - // Set time offset - Time.setOffset(60); - try { - // User rejected consent - grantPage.assertCurrent(); - grantPage.cancel(); - - // Assert account error page with "staleCodeAccount" error displayed - accountFederatedIdentityPage.assertCurrent(); - Assert.assertEquals("The page expired. Please try one more time.", accountFederatedIdentityPage.getError()); - - - // Try to link one more time - accountFederatedIdentityPage.clickAddProvider(getProviderId()); - - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/")); - this.loginPage.login("test-user", "password"); - - Time.setOffset(120); - - // User granted consent - grantPage.assertCurrent(); - grantPage.accept(); - - // Assert account error page with "staleCodeAccount" error displayed - accountFederatedIdentityPage.assertCurrent(); - Assert.assertEquals("The page expired. Please try one more time.", accountFederatedIdentityPage.getError()); - - } finally { - Time.setOffset(0); - } - - // Revoke consent - RealmResource brokeredRealm = keycloak2.realm("realm-with-oidc-identity-provider"); - List users = brokeredRealm.users().search("test-user", 0, 1); - brokeredRealm.users().get(users.get(0).getId()).revokeConsent("broker-app"); - } - - - @Test - public void testLoginCancelConsent() throws Exception { - // Try to login - loginIDP("test-user"); - - // User rejected consent - grantPage.assertCurrent(); - grantPage.cancel(); - - // Assert back on login page - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/")); - assertTrue(driver.getTitle().equals("Log in to realm-with-broker")); - } - - - // KEYCLOAK-2802 - @Test - public void testAccountManagementLinkingCancelConsent() throws Exception { - // Login as pedroigor to account management - loginToAccountManagement("pedroigor"); - - // Link my "pedroigor" identity with "test-user" from brokered Keycloak - accountFederatedIdentityPage.clickAddProvider(getProviderId()); - - assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/")); - this.loginPage.login("test-user", "password"); - - // User rejected consent - grantPage.assertCurrent(); - grantPage.cancel(); - - // Assert account error page with "consentDenied" error displayed - accountFederatedIdentityPage.assertCurrent(); - Assert.assertEquals("Consent denied.", accountFederatedIdentityPage.getError()); - } - - - private void loginToAccountManagement(String username) { - accountFederatedIdentityPage.realm("realm-with-broker"); - accountFederatedIdentityPage.open(); - assertTrue(driver.getTitle().equals("Log in to realm-with-broker")); - loginPage.login(username, "password"); - assertTrue(accountFederatedIdentityPage.isCurrent()); - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/PostBrokerFlowTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/PostBrokerFlowTest.java deleted file mode 100644 index 77252e9ca6..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/PostBrokerFlowTest.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -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.AuthenticationFlowModel; -import org.keycloak.models.FederatedIdentityModel; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.utils.DefaultAuthenticationFlows; -import org.keycloak.models.utils.TimeBasedOTP; -import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.pages.IdpConfirmLinkPage; -import org.keycloak.testsuite.pages.LoginConfigTotpPage; -import org.keycloak.testsuite.pages.LoginTotpPage; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; -import org.keycloak.testsuite.rule.WebResource; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -/** - * @author Marek Posolda - */ -public class PostBrokerFlowTest extends AbstractIdentityProviderTest { - - private static final int PORT = 8082; - - private static String POST_BROKER_FLOW_ID; - - private static final String APP_REALM_ID = "realm-with-broker"; - - @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")); - - RealmModel realmWithBroker = getRealm(session); - - // Disable "idp-email-verification" authenticator in firstBrokerLogin flow. Disable updateProfileOnFirstLogin page - AbstractFirstBrokerLoginTest.setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW, - IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.DISABLED); - setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF); - - // Add post-broker flow with OTP authenticator to the realm - AuthenticationFlowModel postBrokerFlow = new AuthenticationFlowModel(); - postBrokerFlow.setAlias("post-broker"); - postBrokerFlow.setDescription("post-broker flow with OTP"); - postBrokerFlow.setProviderId("basic-flow"); - postBrokerFlow.setTopLevel(true); - postBrokerFlow.setBuiltIn(false); - postBrokerFlow = realmWithBroker.addAuthenticationFlow(postBrokerFlow); - - POST_BROKER_FLOW_ID = postBrokerFlow.getId(); - - AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); - execution.setParentFlow(postBrokerFlow.getId()); - execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); - execution.setAuthenticator("auth-otp-form"); - execution.setPriority(20); - execution.setAuthenticatorFlow(false); - realmWithBroker.addAuthenticatorExecution(execution); - - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-oidc-identity-provider", "realm-with-saml-idp-basic" }; - } - }; - - - @WebResource - protected IdpConfirmLinkPage idpConfirmLinkPage; - - @WebResource - protected LoginTotpPage loginTotpPage; - - @WebResource - protected LoginConfigTotpPage totpPage; - - private TimeBasedOTP totp = new TimeBasedOTP(); - - - @Override - protected String getProviderId() { - return "kc-oidc-idp"; - } - - - @Test - public void testPostBrokerLoginWithOTP() { - // enable post-broker flow - IdentityProviderModel identityProvider = getIdentityProviderModel(); - setPostBrokerFlowForProvider(identityProvider, getRealm(), true); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - // login with broker and assert that OTP needs to be set. - loginIDP("test-user"); - totpPage.assertCurrent(); - String totpSecret = totpPage.getTotpSecret(); - totpPage.configure(totp.generateTOTP(totpSecret)); - - assertFederatedUser("test-user", "test-user@localhost", "test-user", getProviderId()); - - driver.navigate().to("http://localhost:8081/test-app/logout"); - - // Login again and assert that OTP needs to be provided. - loginIDP("test-user"); - loginTotpPage.assertCurrent(); - loginTotpPage.login(totp.generateTOTP(totpSecret)); - - assertFederatedUser("test-user", "test-user@localhost", "test-user", getProviderId()); - - driver.navigate().to("http://localhost:8081/test-app/logout"); - - // Disable post-broker and ensure that OTP is not required anymore - setPostBrokerFlowForProvider(identityProvider, getRealm(), false); - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - loginIDP("test-user"); - assertFederatedUser("test-user", "test-user@localhost", "test-user", getProviderId()); - driver.navigate().to("http://localhost:8081/test-app/logout"); - } - - - @Test - public void testBrokerReauthentication_samlBrokerWithOTPRequired() throws Exception { - RealmModel realmWithBroker = getRealm(); - - // Enable OTP just for SAML provider - IdentityProviderModel samlIdentityProvider = realmWithBroker.getIdentityProviderByAlias("kc-saml-idp-basic"); - setPostBrokerFlowForProvider(samlIdentityProvider, realmWithBroker, true); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - // ensure TOTP setup is required during SAML broker firstLogin and during reauthentication for link OIDC broker too - reauthenticateOIDCWithSAMLBroker(true, false); - - // Disable TOTP for SAML provider - realmWithBroker = getRealm(); - samlIdentityProvider = realmWithBroker.getIdentityProviderByAlias("kc-saml-idp-basic"); - setPostBrokerFlowForProvider(samlIdentityProvider, realmWithBroker, false); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - } - - @Test - public void testBrokerReauthentication_oidcBrokerWithOTPRequired() throws Exception { - - // Enable OTP just for OIDC provider - IdentityProviderModel oidcIdentityProvider = getIdentityProviderModel(); - setPostBrokerFlowForProvider(oidcIdentityProvider, getRealm(), true); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - // ensure TOTP setup is not required during SAML broker firstLogin, but during reauthentication for link OIDC broker - reauthenticateOIDCWithSAMLBroker(false, true); - - // Disable TOTP for SAML provider - oidcIdentityProvider = getIdentityProviderModel(); - setPostBrokerFlowForProvider(oidcIdentityProvider, getRealm(), false); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - } - - @Test - public void testBrokerReauthentication_bothBrokerWithOTPRequired() throws Exception { - RealmModel realmWithBroker = getRealm(); - - // Enable OTP for both OIDC and SAML provider - IdentityProviderModel samlIdentityProvider = realmWithBroker.getIdentityProviderByAlias("kc-saml-idp-basic"); - setPostBrokerFlowForProvider(samlIdentityProvider, realmWithBroker, true); - - IdentityProviderModel oidcIdentityProvider = getIdentityProviderModel(); - setPostBrokerFlowForProvider(oidcIdentityProvider, getRealm(), true); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - - // ensure TOTP setup is required during SAML broker firstLogin and during reauthentication for link OIDC broker too - reauthenticateOIDCWithSAMLBroker(true, true); - - // Disable TOTP for both SAML and OIDC provider - realmWithBroker = getRealm(); - samlIdentityProvider = realmWithBroker.getIdentityProviderByAlias("kc-saml-idp-basic"); - setPostBrokerFlowForProvider(samlIdentityProvider, realmWithBroker, false); - - oidcIdentityProvider = getIdentityProviderModel(); - setPostBrokerFlowForProvider(oidcIdentityProvider, getRealm(), false); - - brokerServerRule.stopSession(this.session, true); - this.session = brokerServerRule.startSession(); - } - - - private void reauthenticateOIDCWithSAMLBroker(boolean samlBrokerTotpEnabled, boolean oidcBrokerTotpEnabled) { - // First login as "testuser" with SAML broker - 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("test-user", "password"); - - // Ensure user needs to setup TOTP if SAML broker requires that - String totpSecret = null; - if (samlBrokerTotpEnabled) { - totpPage.assertCurrent(); - totpSecret = totpPage.getTotpSecret(); - totpPage.configure(totp.generateTOTP(totpSecret)); - } - - 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("test-user"); - - this.idpConfirmLinkPage.assertCurrent(); - Assert.assertEquals("User with email test-user@localhost 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 test-user to link your account with " + getProviderId(), this.loginPage.getInfoMessage()); - - // reauthenticate with SAML broker. OTP authentication is required as well - this.loginPage.clickSocial("kc-saml-idp-basic"); - Assert.assertEquals("Log in to realm-with-saml-idp-basic", this.driver.getTitle()); - this.loginPage.login("test-user", "password"); - - if (samlBrokerTotpEnabled) { - // User already set TOTP during first login with SAML broker - loginTotpPage.assertCurrent(); - loginTotpPage.login(totp.generateTOTP(totpSecret)); - } else if (oidcBrokerTotpEnabled) { - // User needs to set TOTP as first login with SAML broker didn't require that - totpPage.assertCurrent(); - totpSecret = totpPage.getTotpSecret(); - totpPage.configure(totp.generateTOTP(totpSecret)); - } - - // authenticated and redirected to app. User is linked with both identity providers - assertFederatedUser("test-user", "test-user@localhost", "test-user", getProviderId(), "kc-saml-idp-basic"); - } - - private void setPostBrokerFlowForProvider(IdentityProviderModel identityProvider, RealmModel realm, boolean enable) { - if (enable) { - identityProvider.setPostBrokerLoginFlowId(POST_BROKER_FLOW_ID); - } else { - identityProvider.setPostBrokerLoginFlowId(null); - } - realm.updateIdentityProvider(identityProvider); - } - - private void assertFederatedUser(String expectedUsername, String expectedEmail, String expectedFederatedUsername, String... expectedLinkedProviders) { - 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 federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker); - - List expectedProvidersList = Arrays.asList(expectedLinkedProviders); - assertEquals(expectedProvidersList.size(), federatedIdentities.size()); - for (FederatedIdentityModel federatedIdentityModel : federatedIdentities) { - String providerAlias = federatedIdentityModel.getIdentityProvider(); - Assert.assertTrue(expectedProvidersList.contains(providerAlias)); - assertEquals(expectedFederatedUsername, federatedIdentityModel.getUserName()); - } - } - -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java deleted file mode 100755 index 25fd7a4394..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Test; -import org.keycloak.dom.saml.v2.protocol.ResponseType; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; -import org.keycloak.saml.processing.web.util.PostBindingUtil; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; - -import javax.mail.MessagingException; -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -/** - * @author pedroigor - */ -public class SAMLBrokerUserPropertyTest extends AbstractKeycloakIdentityProviderTest { - - @ClassRule - public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() { - - @Override - protected void configureServer(KeycloakServer server) { - server.getConfig().setPort(8082); - } - - @Override - protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { - server.importRealm(getClass().getResourceAsStream("/broker-test/realm-with-saml-property-mappers.json")); - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-saml-idp-property-mappers" }; - } - }; - - @Override - protected String getProviderId() { - return "kc-saml-idp-property-mappers"; - } - - @Override - protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) { - if (isProfileUpdateExpected) { - super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected); - } else { - assertEquals(expectedEmail, federatedUser.getEmail()); - assertNotNull(federatedUser.getFirstName()); - assertNotNull(federatedUser.getLastName()); - } - } - - @Override - protected void doAssertFederatedUserNoEmail(UserModel federatedUser) { - assertEquals("kc-saml-idp-basic.test-user-noemail", federatedUser.getUsername()); - //assertEquals("", federatedUser.getEmail()); - assertEquals(null, federatedUser.getFirstName()); - assertEquals(null, federatedUser.getLastName()); - } - - @Override - protected void doAssertTokenRetrieval(String pageSource) { - try { - ResponseType responseType = (ResponseType) SAML2Request - .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource)) - .getSamlObject(); - //.getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8"))); - - assertNotNull(responseType); - assertFalse(responseType.getAssertions().isEmpty()); - } catch (Exception e) { - fail("Could not parse token."); - } - } - - @Override - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile() { - super.testSuccessfulAuthenticationWithoutUpdateProfile(); - } - - @Test - @Ignore - @Override - public void testSuccessfulAuthentication() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException { - // ignore - } - - @Override - @Ignore - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() { - // ignore - } - - @Override - @Ignore - @Test - public void testDisabled() { - // ignore - } - - @Override - @Test - @Ignore - public void testAccountManagementLinkIdentity() { - // ignore - } - - @Override - @Test - @Ignore - public void testAccountManagementLinkedIdentityAlreadyExists() { - // ignore - } - - @Override - @Test - @Ignore - public void testTokenStorageAndRetrievalByApplication() { - // ignore - } - - @Override - @Test - @Ignore - public void testWithLinkedFederationProvider() throws Exception { - // ignore - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLFirstBrokerLoginTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLFirstBrokerLoginTest.java deleted file mode 100644 index 234617b482..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLFirstBrokerLoginTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.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; -import org.junit.Test; - -/** - * @author Marek Posolda - */ -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-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java deleted file mode 100755 index 5e177796df..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.ClassRule; -import org.junit.Test; -import org.keycloak.dom.saml.v2.protocol.ResponseType; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; -import org.keycloak.saml.processing.web.util.PostBindingUtil; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * @author pedroigor - */ -public class SAMLKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityProviderTest { - - @ClassRule - public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() { - - @Override - protected void configureServer(KeycloakServer server) { - server.getConfig().setPort(8082); - } - - @Override - protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { - server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml.json")); - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-saml-idp-basic" }; - } - }; - - @Override - protected String getProviderId() { - return "kc-saml-idp-basic"; - } - - @Override - protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) { - if (isProfileUpdateExpected) { - super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected); - } else { - if (expectedEmail == null) { - // Need to handle differences for various databases (like Oracle) - assertTrue(federatedUser.getEmail() == null || federatedUser.getEmail().equals("")); - } else { - assertEquals(expectedEmail, federatedUser.getEmail()); - } - assertNull(federatedUser.getFirstName()); - assertNull(federatedUser.getLastName()); - } - } - - @Override - protected void doAssertFederatedUserNoEmail(UserModel federatedUser) { - assertEquals("kc-saml-idp-basic.test-user-noemail", federatedUser.getUsername()); - //assertEquals("", federatedUser.getEmail()); - assertEquals(null, federatedUser.getFirstName()); - assertEquals(null, federatedUser.getLastName()); - } - - @Override - protected void doAssertTokenRetrieval(String pageSource) { - try { - ResponseType responseType = (ResponseType) SAML2Request - .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource)) - .getSamlObject(); - //.getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8"))); - - assertNotNull(responseType); - assertFalse(responseType.getAssertions().isEmpty()); - } catch (Exception e) { - fail("Could not parse token."); - } - } - - @Override - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile() { - super.testSuccessfulAuthenticationWithoutUpdateProfile(); - } - - @Override - @Test - public void testSuccessfulAuthentication() { - super.testSuccessfulAuthentication(); - } - - @Test - public void testAccountManagementLinkIdentity() { - super.testAccountManagementLinkIdentity(); - } - - @Test - public void testTokenStorageAndRetrievalByApplication() { - super.testTokenStorageAndRetrievalByApplication(); - } - - @Test - public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() throws Exception { - super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername(); - } - - @Test - public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() { - // skip this test as this provider do not return name and surname so something is missing always - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java deleted file mode 100755 index a0ee823d9b..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.testsuite.broker; - -import org.junit.ClassRule; -import org.junit.Test; -import org.keycloak.dom.saml.v2.protocol.ResponseType; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; -import org.keycloak.saml.processing.web.util.PostBindingUtil; -import org.keycloak.services.managers.RealmManager; -import org.keycloak.testsuite.KeycloakServer; -import org.keycloak.testsuite.rule.AbstractKeycloakRule; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * @author pedroigor - */ -public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractKeycloakIdentityProviderTest { - - @ClassRule - public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() { - - @Override - protected void configureServer(KeycloakServer server) { - server.getConfig().setPort(8082); - } - - @Override - protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { - server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml-with-signature.json")); - } - - @Override - protected String[] getTestRealms() { - return new String[] { "realm-with-saml-signed-idp" }; - } - }; - - // @Test - public void testSleep() throws Exception { - Thread.sleep(100000000); - } - - @Override - protected String getProviderId() { - return "kc-saml-signed-idp"; - } - - @Override - protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) { - if (isProfileUpdateExpected) { - super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected); - } else { - if (expectedEmail == null) { - // Need to handle differences for various databases (like Oracle) - assertTrue(federatedUser.getEmail() == null || federatedUser.getEmail().equals("")); - } else { - assertEquals(expectedEmail, federatedUser.getEmail()); - } - assertNull(federatedUser.getFirstName()); - assertNull(federatedUser.getLastName()); - } - } - - @Override - protected void doAssertFederatedUserNoEmail(UserModel federatedUser) { - assertEquals("kc-saml-signed-idp.test-user-noemail", federatedUser.getUsername()); - //assertEquals("", federatedUser.getEmail()); - assertEquals(null, federatedUser.getFirstName()); - assertEquals(null, federatedUser.getLastName()); - } - - @Override - protected void doAssertTokenRetrieval(String pageSource) { - try { - ResponseType responseType = (ResponseType) SAML2Request - .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource)) - .getSamlObject(); - - assertNotNull(responseType); - assertFalse(responseType.getAssertions().isEmpty()); - } catch (Exception e) { - fail("Could not parse token."); - } - } - - @Override - @Test - public void testSuccessfulAuthentication() { - super.testSuccessfulAuthentication(); - } - - @Test - public void testTokenStorageAndRetrievalByApplication() { - super.testTokenStorageAndRetrievalByApplication(); - } - - @Test - public void testAccountManagementLinkIdentity() { - super.testAccountManagementLinkIdentity(); - } - - @Test - public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() { - // skip this test as this provider do not return name and surname so something is missing always - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java deleted file mode 100755 index 7b70924936..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker.provider; - -import org.keycloak.broker.provider.AbstractIdentityProvider; -import org.keycloak.broker.provider.AuthenticationRequest; -import org.keycloak.models.FederatedIdentityModel; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; - -import javax.ws.rs.core.Response; - -/** - * @author pedroigor - */ -public class CustomIdentityProvider extends AbstractIdentityProvider { - - public CustomIdentityProvider(KeycloakSession session, IdentityProviderModel config) { - super(session, config); - } - - @Override - public Response performLogin(AuthenticationRequest request) { - return null; - } - - @Override - public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) { - return null; - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProviderFactory.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProviderFactory.java deleted file mode 100644 index 88dab79118..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProviderFactory.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker.provider; - -import org.keycloak.broker.provider.AbstractIdentityProviderFactory; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; - -/** - * @author pedroigor - */ -public class CustomIdentityProviderFactory extends AbstractIdentityProviderFactory { - - public static final String PROVIDER_ID = "testsuite-custom-identity-provider"; - - @Override - public String getName() { - return "Testsuite Custom Identity Provider"; - } - - @Override - public CustomIdentityProvider create(KeycloakSession session, IdentityProviderModel model) { - return new CustomIdentityProvider(session, model); - } - - @Override - public String getId() { - return PROVIDER_ID; - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java deleted file mode 100755 index 26622b2306..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker.provider.social; - -import org.keycloak.broker.provider.AbstractIdentityProvider; -import org.keycloak.broker.provider.AuthenticationRequest; -import org.keycloak.broker.social.SocialIdentityProvider; -import org.keycloak.models.FederatedIdentityModel; -import org.keycloak.models.IdentityProviderModel; -import org.keycloak.models.KeycloakSession; - -import javax.ws.rs.core.Response; - -/** - * @author pedroigor - */ -public class CustomSocialProvider extends AbstractIdentityProvider implements SocialIdentityProvider { - - public CustomSocialProvider(KeycloakSession session, IdentityProviderModel config) { - super(session, config); - } - - @Override - public Response performLogin(AuthenticationRequest request) { - return null; - } - - @Override - public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) { - return null; - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProviderFactory.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProviderFactory.java deleted file mode 100755 index 5a0a3c2d15..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProviderFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker.provider.social; - -import org.keycloak.broker.provider.AbstractIdentityProviderFactory; -import org.keycloak.broker.social.SocialIdentityProviderFactory; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.IdentityProviderModel; - -/** - * @author pedroigor - */ -public class CustomSocialProviderFactory extends AbstractIdentityProviderFactory implements SocialIdentityProviderFactory { - - public static final String PROVIDER_ID = "testsuite-custom-social-provider"; - - @Override - public String getName() { - return "Testsuite Dummy Custom Social Provider"; - } - - @Override - public CustomSocialProvider create(KeycloakSession session, IdentityProviderModel model) { - return new CustomSocialProvider(session, model); - } - - @Override - public String getId() { - return PROVIDER_ID; - } -} diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java deleted file mode 100755 index affaff84c0..0000000000 --- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.testsuite.broker.util; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.IDToken; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriBuilder; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Serializable; - -/** - * @author pedroigor - */ -public class UserSessionStatusServlet extends HttpServlet { - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (req.getRequestURI().toString().endsWith("logout")) { - String redirect = UriBuilder.fromUri("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/logout") - .queryParam("redirect_uri", "http://localhost:8081/test-app").build().toString(); - resp.sendRedirect(redirect); - //resp.setStatus(200); - //req.logout(); - return; - } - - writeSessionStatus(req, resp); - } - - private void writeSessionStatus(HttpServletRequest req, HttpServletResponse resp) throws IOException { - KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName()); - IDToken idToken = context.getIdToken(); - AccessToken accessToken = context.getToken(); - JsonNode jsonNode = new ObjectMapper().valueToTree(new UserSessionStatus(idToken, accessToken, context.getTokenString())); - PrintWriter writer = resp.getWriter(); - - writer.println(jsonNode.toString()); - - writer.flush(); - } - - public static class UserSessionStatus implements Serializable { - - private String accessTokenString; - private AccessToken accessToken; - private IDToken idToken; - - public UserSessionStatus() { - - } - - public UserSessionStatus(IDToken idToken, AccessToken accessToken, String tokenString) { - this.idToken = idToken; - this.accessToken = accessToken; - this.accessTokenString = tokenString; - } - - public IDToken getIdToken() { - return this.idToken; - } - - public void setIdToken(IDToken idToken) { - this.idToken = idToken; - } - - public AccessToken getAccessToken() { - return this.accessToken; - } - - public void setAccessToken(AccessToken accessToken) { - this.accessToken = accessToken; - } - - public String getAccessTokenString() { - return this.accessTokenString; - } - } -} diff --git a/testsuite/integration-deprecated/src/test/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory b/testsuite/integration-deprecated/src/test/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory deleted file mode 100644 index cbe3fa4b96..0000000000 --- a/testsuite/integration-deprecated/src/test/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright 2016 Red Hat, Inc. and/or its affiliates -# and other contributors as indicated by the @author tags. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.keycloak.testsuite.broker.provider.CustomIdentityProviderFactory \ No newline at end of file diff --git a/testsuite/integration-deprecated/src/test/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory b/testsuite/integration-deprecated/src/test/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory deleted file mode 100644 index 31589c2485..0000000000 --- a/testsuite/integration-deprecated/src/test/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright 2016 Red Hat, Inc. and/or its affiliates -# and other contributors as indicated by the @author tags. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.keycloak.testsuite.broker.provider.social.CustomSocialProviderFactory \ No newline at end of file diff --git a/travis-run-tests.sh b/travis-run-tests.sh index b5af69180c..55278cdf9c 100755 --- a/travis-run-tests.sh +++ b/travis-run-tests.sh @@ -65,7 +65,7 @@ if [ $1 == "server-group1" ]; then fi if [ $1 == "server-group2" ]; then - run-server-tests org.keycloak.testsuite.ac*.**.*Test,org.keycloak.testsuite.b*.**.*Test,org.keycloak.testsuite.cli*.**.*Test,org.keycloak.testsuite.co*.**.*Test + run-server-tests org.keycloak.testsuite.ac*.**.*Test,org.keycloak.testsuite.cli*.**.*Test,org.keycloak.testsuite.co*.**.*Test fi if [ $1 == "server-group3" ]; then @@ -99,3 +99,7 @@ if [ $1 == "crossdc-adapter" ]; then java -cp ../../../utils/target/classes org.keycloak.testsuite.LogTrimmer exit ${PIPESTATUS[0]} fi + +if [ $1 == "broker" ]; then + run-server-tests org.keycloak.testsuite.broker.**.*Test +fi