[KEYCLOAK-8522] - Migrate broker tests from old to new testsuite
This commit is contained in:
parent
2602c222cd
commit
93965512c5
43 changed files with 2050 additions and 4245 deletions
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -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());
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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/*"));
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -106,4 +106,8 @@ public class MailServer {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MimeMessage[] getReceivedMessages() {
|
||||||
|
return greenMail.getReceivedMessages();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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("=", "=");
|
|
||||||
htmlChangePwdUrl = htmlChangePwdUrl.replace("..", ".");
|
|
||||||
htmlChangePwdUrl = htmlChangePwdUrl.replace("&", "&");
|
|
||||||
|
|
||||||
// TODO Links are working, but not equal for some reason. It's an issue in kcSanitize.
|
|
||||||
// assertEquals(htmlChangePwdUrl, textVerificationUrl);
|
|
||||||
|
|
||||||
return htmlChangePwdUrl;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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"};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue