[KEYCLOAK-8522] - Migrate broker tests from old to new testsuite

This commit is contained in:
Pedro Igor 2019-03-06 13:21:11 -03:00 committed by Marek Posolda
parent 2602c222cd
commit 93965512c5
43 changed files with 2050 additions and 4245 deletions

View file

@ -17,6 +17,7 @@ env:
- TESTS=old - TESTS=old
- TESTS=crossdc-server - TESTS=crossdc-server
- TESTS=crossdc-adapter - TESTS=crossdc-adapter
- TESTS=broker
jdk: jdk:
- oraclejdk8 - oraclejdk8

View file

@ -45,8 +45,6 @@ public final class TestContext {
private boolean adminLoggedIn; private boolean adminLoggedIn;
private final Map<Object, Object> customContext = new HashMap<>();
private Keycloak adminClient; private Keycloak adminClient;
private KeycloakTestingClient testingClient; private KeycloakTestingClient testingClient;
private List<RealmRepresentation> testRealmReps = new ArrayList<>(); private List<RealmRepresentation> 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() { public String getAppServerContainerName() {
if (isAdapterContainerEnabled()) { //standalone app server if (isAdapterContainerEnabled()) { //standalone app server
return getAppServerInfo().getArquillianContainer().getName(); return getAppServerInfo().getArquillianContainer().getName();

View file

@ -61,6 +61,9 @@ public class AccountManagement extends AuthRealm implements PageWithLogOutAction
@FindBy(linkText = "Applications") @FindBy(linkText = "Applications")
private WebElement applicationsLink; private WebElement applicationsLink;
@FindBy(linkText = "Federated Identity")
private WebElement federatedIdentityLink;
@FindByJQuery("button[value='Save']") @FindByJQuery("button[value='Save']")
private WebElement save; private WebElement save;
@ -111,6 +114,11 @@ public class AccountManagement extends AuthRealm implements PageWithLogOutAction
waitForPageToLoad(); waitForPageToLoad();
} }
public void federatedIdentity() {
federatedIdentityLink.click();
waitForPageToLoad();
}
public void save() { public void save() {
save.click(); save.click();
waitForPageToLoad(); waitForPageToLoad();

View file

@ -84,6 +84,10 @@ public class AccountFederatedIdentityPage extends AbstractAccountPage {
return errorMessage.getText(); return errorMessage.getText();
} }
public boolean isLinked(String idpAlias) {
return driver.getPageSource().contains("id=\"remove-link-" + idpAlias + "\"");
}
public static class FederatedIdentity { public static class FederatedIdentity {
private String providerId; private String providerId;

View file

@ -39,6 +39,9 @@ public class AccountPasswordPage extends AbstractAccountPage {
@FindBy(className = "btn-primary") @FindBy(className = "btn-primary")
private WebElement submitButton; private WebElement submitButton;
@FindBy(className = "alert-error")
private WebElement errorMessage;
private String realmName = "test"; private String realmName = "test";
public void changePassword(String password, String newPassword, String passwordConfirm) { public void changePassword(String password, String newPassword, String passwordConfirm) {
@ -71,4 +74,8 @@ public class AccountPasswordPage extends AbstractAccountPage {
public String getPath() { public String getPath() {
return AccountFormService.passwordUrl(UriBuilder.fromUri(getAuthServerRoot())).build(this.realmName).toString(); return AccountFormService.passwordUrl(UriBuilder.fromUri(getAuthServerRoot())).build(this.realmName).toString();
} }
public String getError() {
return errorMessage.getText();
}
} }

View file

@ -28,6 +28,9 @@ public class IdpLinkEmailPage extends AbstractPage {
@FindBy(id = "instruction1") @FindBy(id = "instruction1")
private WebElement message; private WebElement message;
@FindBy(linkText = "Click here")
private WebElement resendEmailLink;
@Override @Override
public boolean isCurrent() { public boolean isCurrent() {
return PageUtils.getPageTitle(driver).startsWith("Link "); return PageUtils.getPageTitle(driver).startsWith("Link ");
@ -41,4 +44,8 @@ public class IdpLinkEmailPage extends AbstractPage {
public String getMessage() { public String getMessage() {
return message.getText(); return message.getText();
} }
public void resendEmail() {
resendEmailLink.click();
}
} }

View file

@ -39,6 +39,21 @@ public class UpdateAccountInformationPage extends AbstractPage {
submitButton.click(); 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, public void updateAccountInformation(String firstName,
String lastName) { String lastName) {
firstNameInput.clear(); firstNameInput.clear();

View file

@ -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() { protected void deleteAllCookiesForTestRealm() {
deleteAllCookiesForRealm(testRealmAccountPage); deleteAllCookiesForRealm(testRealmAccountPage);
} }

View file

@ -26,7 +26,6 @@ import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.AuthenticationManagementResource; 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.OIDCLogin;
import org.keycloak.testsuite.auth.page.login.UpdatePassword; import org.keycloak.testsuite.auth.page.login.UpdatePassword;
import org.keycloak.testsuite.client.KeycloakTestingClient; import org.keycloak.testsuite.client.KeycloakTestingClient;
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
import org.keycloak.testsuite.util.AdminClientUtil; import org.keycloak.testsuite.util.AdminClientUtil;
import org.keycloak.testsuite.util.DroneUtils; import org.keycloak.testsuite.util.DroneUtils;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.TestCleanup; import org.keycloak.testsuite.util.TestCleanup;
import org.keycloak.testsuite.util.TestEventsLogger; import org.keycloak.testsuite.util.TestEventsLogger;
import org.openqa.selenium.WebDriver; 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.NotFoundException;
import javax.ws.rs.core.UriBuilder; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -92,7 +77,6 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.TimeoutException;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -146,11 +130,16 @@ public abstract class AbstractKeycloakTest {
@Page @Page
protected Account accountPage; protected Account accountPage;
@Page @Page
protected OIDCLogin loginPage; protected OIDCLogin loginPage;
@Page @Page
protected UpdatePassword updatePasswordPage; protected UpdatePassword updatePasswordPage;
@Page
protected LoginPasswordUpdatePage passwordUpdatePage;
@Page @Page
protected WelcomePage welcomePage; protected WelcomePage welcomePage;
@ -483,14 +472,36 @@ public abstract class AbstractKeycloakTest {
* @return ID of the newly created user * @return ID of the newly created user
*/ */
public String createUser(String realm, String username, String password, String... requiredActions) { public String createUser(String realm, String username, String password, String... requiredActions) {
List<String> requiredUserActions = Arrays.asList(requiredActions); UserRepresentation homer = createUserRepresentation(username, password);
homer.setRequiredActions(Arrays.asList(requiredActions));
UserRepresentation homer = new UserRepresentation(); return ApiUtil.createUserWithAdminClient(adminClient.realm(realm), homer);
homer.setEnabled(true); }
homer.setUsername(username);
homer.setRequiredActions(requiredUserActions);
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) { public void setRequiredActionEnabled(String realm, String requiredAction, boolean enabled, boolean defaultAction) {
@ -569,7 +580,7 @@ public abstract class AbstractKeycloakTest {
return Time.currentTime(); return Time.currentTime();
} }
private String invokeTimeOffset(int offset) { protected String invokeTimeOffset(int offset) {
// adminClient depends on Time.offset for auto-refreshing tokens // adminClient depends on Time.offset for auto-refreshing tokens
Time.setOffset(offset); Time.setOffset(offset);
Map result = testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(offset))); Map result = testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(offset)));

View file

@ -21,22 +21,36 @@ import java.util.List;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After; 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.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.common.util.Retry; 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.AccountPasswordPage;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage; import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.IdpConfirmLinkPage; 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.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.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 org.openqa.selenium.TimeoutException;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -69,6 +83,41 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest {
@Page @Page
protected IdpConfirmLinkPage idpConfirmLinkPage; 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 BrokerConfiguration bc = getBrokerConfiguration();
protected String userId; protected String userId;
@ -79,32 +128,28 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest {
*/ */
protected abstract BrokerConfiguration getBrokerConfiguration(); protected abstract BrokerConfiguration getBrokerConfiguration();
@Override @Override
public void addTestRealms(List<RealmRepresentation> testRealms) { public void addTestRealms(List<RealmRepresentation> 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 @After
public void cleanupUsers() { public void cleanupUsers() {
RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); adminClient.realm(bc.consumerRealmName()).remove();
UserRepresentation userRep = ApiUtil.findUserByUsername(providerRealm, bc.getUserLogin()); adminClient.realm(bc.providerRealmName()).remove();
if (userRep != null) { MailServer.stop();
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();
}
} }
@Deployment
public static WebArchive deploy() {
return RunOnServerDeployment.create(BrokerRunOnServerUtil.class);
}
protected void logInAsUserInIDP() { protected void logInAsUserInIDP() {
driver.navigate().to(getAccountUrl(bc.consumerRealmName())); driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
@ -194,6 +239,7 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest {
protected void assertLoggedInAccountManagement() { protected void assertLoggedInAccountManagement() {
waitForPage(driver, "keycloak account management", true);
Assert.assertTrue(accountUpdateProfilePage.isCurrent()); Assert.assertTrue(accountUpdateProfilePage.isCurrent());
Assert.assertEquals(accountUpdateProfilePage.getUsername(), bc.getUserLogin()); Assert.assertEquals(accountUpdateProfilePage.getUsername(), bc.getUserLogin());
Assert.assertEquals(accountUpdateProfilePage.getEmail(), bc.getUserEmail()); Assert.assertEquals(accountUpdateProfilePage.getEmail(), bc.getUserEmail());

View file

@ -18,13 +18,24 @@ package org.keycloak.testsuite.broker;
import org.junit.Before; import org.junit.Before;
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
import org.keycloak.admin.client.resource.IdentityProviderResource; import org.keycloak.admin.client.resource.IdentityProviderResource;
import org.keycloak.admin.client.resource.RealmResource; 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.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import java.util.List; 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.createUserWithAdminClient;
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; 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. * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.
@ -33,8 +44,10 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok
protected IdentityProviderResource identityProviderResource; protected IdentityProviderResource identityProviderResource;
@Override
@Before @Before
public void beforeBrokerTest() { public void beforeBrokerTest() {
super.beforeBrokerTest();
log.debug("creating user for realm " + bc.providerRealmName()); log.debug("creating user for realm " + bc.providerRealmName());
UserRepresentation user = new UserRepresentation(); UserRepresentation user = new UserRepresentation();
@ -48,18 +61,10 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok
resetUserPassword(realmResource.users().get(userId), bc.getUserPassword(), false); 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()); log.debug("adding identity provider to realm " + bc.consumerRealmName());
RealmResource realm = adminClient.realm(bc.consumerRealmName()); RealmResource realm = adminClient.realm(bc.consumerRealmName());
realm.identityProviders().create(bc.setUpIdentityProvider(suiteContext)).close(); realm.identityProviders().create(bc.setUpIdentityProvider(suiteContext)).close();
identityProviderResource = realm.identityProviders().get(bc.getIDPAlias()); identityProviderResource = realm.identityProviders().get(bc.getIDPAlias());
testContext.setCustomValue("identityProviderResource", identityProviderResource);
// addClients // addClients
List<ClientRepresentation> clients = bc.createProviderClients(suiteContext); List<ClientRepresentation> clients = bc.createProviderClients(suiteContext);
@ -85,4 +90,20 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok
testContext.setInitialized(true); 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<AuthenticationExecutionInfoRepresentation, AuthenticationManagementResource> action) {
AuthenticationManagementResource flows = adminClient.realm(bc.consumerRealmName()).flows();
for (AuthenticationExecutionInfoRepresentation execution : flows.getExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW)) {
action.accept(execution, flows);
}
}
} }

View file

@ -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 <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
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<UserSessionModel> 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);
};
}
}

View file

@ -18,12 +18,7 @@ import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait; 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.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) { public static void waitForPage(WebDriver driver, final String title, final boolean isHtmlTitle) {
WebDriverWait wait = new WebDriverWait(driver, 5); WebDriverWait wait = new WebDriverWait(driver, 5);
ExpectedCondition<Boolean> condition = (WebDriver input) -> isHtmlTitle ? input.getTitle().toLowerCase().contains(title) : PageUtils.getPageTitle(input).toLowerCase().contains(title); ExpectedCondition<Boolean> 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); wait.until(condition);
} }

View file

@ -127,6 +127,7 @@ public class KcOidcBrokerConfiguration implements BrokerConfiguration {
client.setName("broker-app"); client.setName("broker-app");
client.setSecret("broker-app-secret"); client.setSecret("broker-app-secret");
client.setEnabled(true); client.setEnabled(true);
client.setDirectAccessGrantsEnabled(true);
client.setRedirectUris(Collections.singletonList(getAuthRoot(suiteContext) + client.setRedirectUris(Collections.singletonList(getAuthRoot(suiteContext) +
"/auth/*")); "/auth/*"));

View file

@ -1,8 +1,14 @@
package org.keycloak.testsuite.broker; 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.BrokerTestConstants.REALM_PROV_NAME;
import static org.keycloak.testsuite.broker.BrokerTestTools.getAuthRoot; import static org.keycloak.testsuite.broker.BrokerTestTools.getAuthRoot;
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim;
import java.util.List; 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.admin.client.resource.UsersResource;
import org.keycloak.broker.oidc.OIDCIdentityProviderConfig; import org.keycloak.broker.oidc.OIDCIdentityProviderConfig;
import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper; import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper;
import org.keycloak.broker.oidc.mappers.UserAttributeMapper;
import org.keycloak.crypto.Algorithm; import org.keycloak.crypto.Algorithm;
import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.representations.idm.ClientRepresentation; 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.IdentityProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.openqa.selenium.NoSuchElementException;
public class KcOidcBrokerTest extends AbstractBrokerTest { public class KcOidcBrokerTest extends AbstractBrokerTest {
@ -69,20 +77,9 @@ public class KcOidcBrokerTest extends AbstractBrokerTest {
clients.get(brokerApp.getId()).update(brokerApp); clients.get(brokerApp.getId()).update(brokerApp);
driver.navigate().to(getAccountUrl(bc.consumerRealmName())); driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
logInWithBroker(bc);
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, "update account information", false); waitForPage(driver, "update account information", false);
updateAccountInformationPage.assertCurrent(); updateAccountInformationPage.assertCurrent();
Assert.assertTrue("We must be on correct realm right now", Assert.assertTrue("We must be on correct realm right now",
driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/")); driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/"));
@ -113,4 +110,291 @@ public class KcOidcBrokerTest extends AbstractBrokerTest {
clients.get(brokerApp.getId()).update(brokerApp); 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.<String, String>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<UserRepresentation> 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());
}
} }

View file

@ -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<ClientRepresentation> 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());
}
}

View file

@ -175,6 +175,7 @@ public class KcSamlBrokerConfiguration implements BrokerConfiguration {
.name("broker-app") .name("broker-app")
.secret("broker-app-secret") .secret("broker-app-secret")
.enabled(true) .enabled(true)
.directAccessGrants()
.addRedirectUri(getAuthRoot(suiteContext) + "/auth/*") .addRedirectUri(getAuthRoot(suiteContext) + "/auth/*")
.baseUrl(getAuthRoot(suiteContext) + "/auth/realms/" + REALM_CONS_NAME + "/app") .baseUrl(getAuthRoot(suiteContext) + "/auth/realms/" + REALM_CONS_NAME + "/app")
.build() .build()

View file

@ -165,4 +165,9 @@ public class KcSamlBrokerTest extends AbstractBrokerTest {
Assert.assertThat(samlResponse.getSamlObject(), isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS)); 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
}
} }

View file

@ -6,7 +6,9 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
/**
* Refers to in old testsuite: org.keycloak.testsuite.broker.SAMLBrokerUserPropertyTest
*/
public class SamlUserAttributeMapperTest extends AbstractUserAttributeMapperTest { public class SamlUserAttributeMapperTest extends AbstractUserAttributeMapperTest {
@Override @Override

View file

@ -106,4 +106,8 @@ public class MailServer {
} }
return null; return null;
} }
public static MimeMessage[] getReceivedMessages() {
return greenMail.getReceivedMessages();
}
} }

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public abstract class AbstractFirstBrokerLoginTest extends AbstractIdentityProviderTest {
protected static final String APP_REALM_ID = "realm-with-broker";
@WebResource
protected LoginUpdateProfileEditUsernameAllowedPage updateProfileWithUsernamePage;
@WebResource
protected IdpConfirmLinkPage idpConfirmLinkPage;
@WebResource
protected IdpLinkEmailPage idpLinkEmailPage;
@WebResource
protected LoginPasswordUpdatePage passwordUpdatePage;
@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<String, String> smtpConfig = new HashMap<>();
brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
smtpConfig.putAll(realmWithBroker.getSmtpConfig());
realmWithBroker.setSmtpConfig(Collections.<String, String>emptyMap());
}
}, APP_REALM_ID);
loginIDP("pedroigor");
this.idpConfirmLinkPage.assertCurrent();
Assert.assertEquals("User with email psilva@redhat.com already exists. How do you want to continue?", this.idpConfirmLinkPage.getMessage());
this.idpConfirmLinkPage.clickLinkAccount();
// Login screen shown. Username is prefilled and disabled. Registration link and social buttons are not shown
Assert.assertEquals("Log in to " + APP_REALM_ID, this.driver.getTitle());
Assert.assertEquals("pedroigor", this.loginPage.getUsername());
Assert.assertFalse(this.loginPage.isUsernameInputEnabled());
Assert.assertEquals("Authenticate as pedroigor to link your account with " + getProviderId(), this.loginPage.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<String, String> smtpConfig = new HashMap<>();
brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
smtpConfig.putAll(realmWithBroker.getSmtpConfig());
realmWithBroker.setSmtpConfig(Collections.<String, String>emptyMap());
}
}, APP_REALM_ID);
// 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<FederatedIdentityModel> 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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker);
assertEquals(1, federatedIdentities.size());
FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
assertEquals(expectedFederatedUsername, federatedIdentityModel.getUserName());
}
protected static void setExecutionRequirement(RealmModel realmWithBroker, String flowAlias, String authenticatorProvider, AuthenticationExecutionModel.Requirement requirement) {
AuthenticationFlowModel flowModel = realmWithBroker.getFlowByAlias(flowAlias);
List<AuthenticationExecutionModel> authExecutions = realmWithBroker.getAuthenticationExecutions(flowModel.getId());
for (AuthenticationExecutionModel execution : authExecutions) {
if (execution.getAuthenticator().equals(authenticatorProvider)) {
execution.setRequirement(requirement);
realmWithBroker.updateAuthenticatorExecution(execution);
return;
}
}
throw new IllegalStateException("Execution not found for flow " + flowAlias + " and authenticator " + authenticatorProvider);
}
}

View file

@ -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<String> expectedProviders;
@Before
public void onBefore() {
this.expectedProviders = new HashSet<String>();
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<String> getExpectedProviders() {
return this.expectedProviders;
}
}

View file

@ -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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
assertEquals(1, federatedIdentities.size());
FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
assertEquals(federatedUser.getUsername(), federatedIdentityModel.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<UserModel> users = this.session.users().getUsers(realm, true);
for (UserModel user : users) {
Set<FederatedIdentityModel> 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("&#61;", "=");
htmlChangePwdUrl = htmlChangePwdUrl.replace("..", ".");
htmlChangePwdUrl = htmlChangePwdUrl.replace("&amp;", "&");
// TODO Links are working, but not equal for some reason. It's an issue in kcSanitize.
// assertEquals(htmlChangePwdUrl, textVerificationUrl);
return htmlChangePwdUrl;
}
}

View file

@ -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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
assertEquals(1, federatedIdentities.size());
FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
assertEquals(federatedUser.getUsername(), federatedIdentityModel.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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
assertEquals(1, federatedIdentities.size());
FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
driver.navigate().to("http://localhost:8081/test-app/logout");
driver.navigate().to("http://localhost:8081/test-app");
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
} finally {
getRealm().setRegistrationEmailAsUsername(false);
}
}
@Test
public void 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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
assertFalse(federatedIdentities.isEmpty());
assertEquals(1, federatedIdentities.size());
FederatedIdentityModel identityModel = federatedIdentities.iterator().next();
assertNotNull(identityModel.getToken());
UserSessionStatusServlet.UserSessionStatus userSessionStatus = retrieveSessionStatus();
String accessToken = userSessionStatus.getAccessTokenString();
URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), realm.getName());
final String authHeader = "Bearer " + accessToken;
ClientRequestFilter authFilter = new ClientRequestFilter() {
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
}
};
Client client = ClientBuilder.newBuilder().register(authFilter).build();
WebTarget tokenEndpoint = client.target(tokenEndpointUrl);
Response response = tokenEndpoint.request().get();
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
assertNotNull(response.readEntity(String.class));
revokeGrant();
driver.navigate().to("http://localhost:8081/test-app/logout");
String currentUrl = this.driver.getCurrentUrl();
// System.out.println("after logout currentUrl: " + currentUrl);
assertTrue(currentUrl.startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
unconfigureUserRetrieveToken("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();
}
}
}

View file

@ -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"};
}
}

View file

@ -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
}
}

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class OIDCFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
private static final int PORT = 8082;
@ClassRule
public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
@Override
protected void configureServer(KeycloakServer server) {
server.getConfig().setPort(PORT);
}
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-kc-oidc.json"));
server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml.json"));
}
@Override
protected String[] getTestRealms() {
return new String[] { "realm-with-oidc-identity-provider", "realm-with-saml-idp-basic" };
}
};
@Override
protected String getProviderId() {
return "kc-oidc-idp";
}
/**
* Tests that duplication is detected and user wants to link federatedIdentity with existing account. He will confirm link by reauthentication
* with different broker already linked to his account
*/
@Test
public void testLinkAccountByReauthenticationWithDifferentBroker() throws Exception {
brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW,
IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.DISABLED);
setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_OFF);
}
}, APP_REALM_ID);
// First link "pedroigor" user with SAML broker and logout
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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker);
assertEquals(2, federatedIdentities.size());
for (FederatedIdentityModel link : federatedIdentities) {
Assert.assertEquals("pedroigor", link.getUserName());
Assert.assertTrue(link.getIdentityProvider().equals(getProviderId()) || link.getIdentityProvider().equals("kc-saml-idp-basic"));
}
brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
setExecutionRequirement(realmWithBroker, DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_HANDLE_EXISTING_SUBFLOW,
IdpEmailVerificationAuthenticatorFactory.PROVIDER_ID, AuthenticationExecutionModel.Requirement.ALTERNATIVE);
}
}, APP_REALM_ID);
}
/**
* 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<FederatedIdentityModel> 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");
}
}

View file

@ -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();
}
}

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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<ClientRepresentation> 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<UserRepresentation> 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());
}
}

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realmWithBroker);
List<String> 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());
}
}
}

View file

@ -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
}
}

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class SAMLFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
private static final int PORT = 8082;
@ClassRule
public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
@Override
protected void configureServer(KeycloakServer server) {
server.getConfig().setPort(PORT);
}
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-saml.json"));
}
@Override
protected String[] getTestRealms() {
return new String[] { "realm-with-saml-idp-basic" };
}
};
@Override
protected String getProviderId() {
return "kc-saml-idp-basic";
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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<IdentityProviderModel> {
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;
}
}

View file

@ -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<CustomIdentityProvider> {
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;
}
}

View file

@ -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<IdentityProviderModel> implements SocialIdentityProvider<IdentityProviderModel> {
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;
}
}

View file

@ -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<CustomSocialProvider> implements SocialIdentityProviderFactory<CustomSocialProvider> {
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;
}
}

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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

View file

@ -65,7 +65,7 @@ if [ $1 == "server-group1" ]; then
fi fi
if [ $1 == "server-group2" ]; then 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 fi
if [ $1 == "server-group3" ]; then if [ $1 == "server-group3" ]; then
@ -99,3 +99,7 @@ if [ $1 == "crossdc-adapter" ]; then
java -cp ../../../utils/target/classes org.keycloak.testsuite.LogTrimmer java -cp ../../../utils/target/classes org.keycloak.testsuite.LogTrimmer
exit ${PIPESTATUS[0]} exit ${PIPESTATUS[0]}
fi fi
if [ $1 == "broker" ]; then
run-server-tests org.keycloak.testsuite.broker.**.*Test
fi