parent
1aa3e2d7e3
commit
34b9eed8f0
8 changed files with 120 additions and 308 deletions
|
@ -1,128 +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.pages;
|
|
||||||
|
|
||||||
import org.keycloak.services.Urls;
|
|
||||||
import org.openqa.selenium.By;
|
|
||||||
import org.openqa.selenium.WebElement;
|
|
||||||
import org.openqa.selenium.support.FindBy;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class AccountFederatedIdentityPage extends AbstractAccountPage {
|
|
||||||
|
|
||||||
@FindBy(className = "alert-error")
|
|
||||||
private WebElement errorMessage;
|
|
||||||
|
|
||||||
public AccountFederatedIdentityPage() {};
|
|
||||||
|
|
||||||
private String realmName = "test";
|
|
||||||
|
|
||||||
public void open() {
|
|
||||||
driver.navigate().to(getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void realm(String realmName) {
|
|
||||||
this.realmName = realmName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPath() {
|
|
||||||
return Urls.accountFederatedIdentityPage(getAuthServerRoot(), realmName).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCurrent() {
|
|
||||||
return driver.getTitle().contains("Account Management") && driver.getPageSource().contains("Federated Identities");
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<FederatedIdentity> getIdentities() {
|
|
||||||
List<FederatedIdentity> identities = new LinkedList<>();
|
|
||||||
WebElement identitiesElement = driver.findElement(By.id("federated-identities"));
|
|
||||||
for (WebElement i : identitiesElement.findElements(By.className("row"))) {
|
|
||||||
|
|
||||||
String providerId = i.findElement(By.tagName("label")).getText();
|
|
||||||
String subject = i.findElement(By.tagName("input")).getAttribute("value");
|
|
||||||
WebElement button = i.findElement(By.tagName("button"));
|
|
||||||
|
|
||||||
identities.add(new FederatedIdentity(providerId, subject, button));
|
|
||||||
}
|
|
||||||
return identities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebElement findAddProvider(String providerId) {
|
|
||||||
return driver.findElement(By.id("add-link-" + providerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clickAddProvider(String providerId) {
|
|
||||||
findAddProvider(providerId).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clickRemoveProvider(String providerId) {
|
|
||||||
driver.findElement(By.id("remove-link-" + providerId)).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getError() {
|
|
||||||
return errorMessage.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLinked(String idpAlias) {
|
|
||||||
return driver.getPageSource().contains("id=\"remove-link-" + idpAlias + "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class FederatedIdentity {
|
|
||||||
|
|
||||||
private String providerId;
|
|
||||||
private String subject;
|
|
||||||
private WebElement action;
|
|
||||||
|
|
||||||
public FederatedIdentity(String providerId, String subject, WebElement action) {
|
|
||||||
this.providerId = providerId;
|
|
||||||
this.subject = subject;
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProvider() {
|
|
||||||
return providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProviderId(String providerId) {
|
|
||||||
this.providerId = providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSubject() {
|
|
||||||
return subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubject(String subject) {
|
|
||||||
this.subject = subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebElement getAction() {
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAction(WebElement action) {
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -232,4 +232,9 @@ public class LoginPage extends LanguageComboboxAwarePage {
|
||||||
assertCurrent();
|
assertCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void open(String realm){
|
||||||
|
oauth.realm(realm);
|
||||||
|
oauth.openLoginForm();
|
||||||
|
assertCurrent(realm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.testsuite.broker;
|
package org.keycloak.testsuite.broker;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.AssertTrue;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
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;
|
||||||
|
@ -8,7 +9,6 @@ import org.keycloak.common.Profile;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
||||||
import org.keycloak.models.IdentityProviderSyncMode;
|
import org.keycloak.models.IdentityProviderSyncMode;
|
||||||
import org.keycloak.models.OTPPolicy;
|
|
||||||
import org.keycloak.models.utils.TimeBasedOTP;
|
import org.keycloak.models.utils.TimeBasedOTP;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
@ -27,6 +27,7 @@ import org.keycloak.testsuite.util.AccountHelper;
|
||||||
import org.keycloak.testsuite.util.ClientBuilder;
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.keycloak.testsuite.util.RealmBuilder;
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
|
import org.keycloak.testsuite.util.TestAppHelper;
|
||||||
import org.openqa.selenium.TimeoutException;
|
import org.openqa.selenium.TimeoutException;
|
||||||
|
|
||||||
import jakarta.ws.rs.client.Client;
|
import jakarta.ws.rs.client.Client;
|
||||||
|
@ -34,7 +35,9 @@ import jakarta.ws.rs.client.ClientRequestFilter;
|
||||||
import jakarta.ws.rs.client.WebTarget;
|
import jakarta.ws.rs.client.WebTarget;
|
||||||
import jakarta.ws.rs.core.HttpHeaders;
|
import jakarta.ws.rs.core.HttpHeaders;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -96,29 +99,33 @@ public abstract class AbstractAdvancedBrokerTest extends AbstractBrokerTest {
|
||||||
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testAccountManagementLinkIdentity
|
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testAccountManagementLinkIdentity
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testAccountManagementLinkIdentity() {
|
public void testAccountManagementLinkIdentity() throws URISyntaxException, IOException {
|
||||||
createUser("consumer");
|
createUser("consumer");
|
||||||
// Login as pedroigor to account management
|
TestAppHelper testAppHelper = new TestAppHelper(oauth, loginPage, appPage);
|
||||||
accountFederatedIdentityPage.realm(bc.consumerRealmName());
|
|
||||||
accountFederatedIdentityPage.open();
|
|
||||||
loginPage.login("consumer", "password");
|
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
|
||||||
|
|
||||||
accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias());
|
// Link identity provider through Admin REST api
|
||||||
this.loginPage.login(bc.getUserLogin(), bc.getUserPassword());
|
Response response = AccountHelper.addIdentityProvider(adminClient.realm(bc.consumerRealmName()), "consumer", adminClient.realm(bc.providerRealmName()), bc.getUserLogin(), bc.getIDPAlias());
|
||||||
|
Assert.assertEquals("status", 204, response.getStatus());
|
||||||
|
|
||||||
// Assert identity linked in account management
|
// Assert identity is linked through Admin REST api
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
assertTrue(AccountHelper.isIdentityProviderLinked(adminClient.realm(bc.consumerRealmName()), "consumer", bc.getIDPAlias()));
|
||||||
assertTrue(accountFederatedIdentityPage.isLinked(bc.getIDPAlias()));
|
|
||||||
|
|
||||||
// Revoke grant in account mgmt
|
AccountHelper.logout(adminClient.realm(bc.consumerRealmName()), "consumer");
|
||||||
accountFederatedIdentityPage.clickRemoveProvider(bc.getIDPAlias());
|
|
||||||
|
// Assert I am logged immediately into app page due to previously linked "test-user" identity
|
||||||
|
testAppHelper.login(bc.getUserLogin(), bc.getUserPassword(), bc.consumerRealmName(), "broker-app", bc.getIDPAlias());
|
||||||
|
|
||||||
|
// Unlink idp from consumer
|
||||||
|
AccountHelper.deleteIdentityProvider(adminClient.realm(bc.consumerRealmName()), "consumer", bc.getIDPAlias());
|
||||||
|
assertFalse(AccountHelper.isIdentityProviderLinked(adminClient.realm(bc.consumerRealmName()), "consumer", bc.getIDPAlias()));
|
||||||
|
|
||||||
// Logout from account management
|
// Logout from account management
|
||||||
accountFederatedIdentityPage.logout();
|
AccountHelper.logout(adminClient.realm(bc.consumerRealmName()), "consumer");
|
||||||
|
AccountHelper.logout(adminClient.realm(bc.providerRealmName()), "testuser");
|
||||||
|
|
||||||
|
// Assert I am not logged immediately into app page and first-broker-login appears instead
|
||||||
|
Assert.assertFalse(testAppHelper.login(bc.getUserLogin(), bc.getUserPassword(), bc.consumerRealmName(), "broker-app", bc.getIDPAlias()));
|
||||||
|
|
||||||
// Assert I am logged immediately to account management due to previously linked "test-user" identity
|
|
||||||
logInWithBroker(bc);
|
|
||||||
waitForPage(driver, "update account information", false);
|
waitForPage(driver, "update account information", false);
|
||||||
updateAccountInformationPage.assertCurrent();
|
updateAccountInformationPage.assertCurrent();
|
||||||
updateAccountInformationPage.updateAccountInformation("FirstName", "LastName");
|
updateAccountInformationPage.updateAccountInformation("FirstName", "LastName");
|
||||||
|
@ -128,20 +135,19 @@ public abstract class AbstractAdvancedBrokerTest extends AbstractBrokerTest {
|
||||||
idpConfirmLinkPage.clickLinkAccount();
|
idpConfirmLinkPage.clickLinkAccount();
|
||||||
|
|
||||||
loginPage.login(bc.getUserPassword());
|
loginPage.login(bc.getUserPassword());
|
||||||
|
appPage.assertCurrent();
|
||||||
accountFederatedIdentityPage.assertCurrent();
|
assertTrue(AccountHelper.isIdentityProviderLinked(adminClient.realm(bc.consumerRealmName()), "consumer", bc.getIDPAlias()));
|
||||||
assertTrue(accountFederatedIdentityPage.isLinked(bc.getIDPAlias()));
|
|
||||||
|
|
||||||
// Unlink my "test-user"
|
// Unlink my "test-user"
|
||||||
accountFederatedIdentityPage.clickRemoveProvider(bc.getIDPAlias());
|
AccountHelper.deleteIdentityProvider(adminClient.realm(bc.consumerRealmName()), "consumer", bc.getIDPAlias());
|
||||||
assertFalse(accountFederatedIdentityPage.isLinked(bc.getIDPAlias()));
|
assertFalse(AccountHelper.isIdentityProviderLinked(adminClient.realm(bc.consumerRealmName()), "consumer", bc.getIDPAlias()));
|
||||||
|
|
||||||
// Logout from account management
|
// Logout from account management
|
||||||
accountFederatedIdentityPage.logout();
|
AccountHelper.logout(adminClient.realm(bc.consumerRealmName()), "consumer");
|
||||||
|
AccountHelper.logout(adminClient.realm(bc.providerRealmName()), "testuser");
|
||||||
|
|
||||||
// Try to login. Previous link is not valid anymore, so now it should try to register new user
|
//Try to log in. Previous link is not valid anymore, so now it should try to register new user instead of logging into app page
|
||||||
loginPage.clickSocial(bc.getIDPAlias());
|
Assert.assertFalse(testAppHelper.login(bc.getUserLogin(), bc.getUserPassword(), bc.consumerRealmName(), "broker-app", bc.getIDPAlias()));
|
||||||
loginPage.login(bc.getUserLogin(), bc.getUserPassword());
|
|
||||||
waitForPage(driver, "update account information", false);
|
waitForPage(driver, "update account information", false);
|
||||||
updateAccountInformationPage.assertCurrent();
|
updateAccountInformationPage.assertCurrent();
|
||||||
}
|
}
|
||||||
|
@ -150,27 +156,17 @@ public abstract class AbstractAdvancedBrokerTest extends AbstractBrokerTest {
|
||||||
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testAccountManagementLinkedIdentityAlreadyExists
|
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractKeycloakIdentityProviderTest#testAccountManagementLinkedIdentityAlreadyExists
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testAccountManagementLinkedIdentityAlreadyExists() {
|
public void testAccountManagementLinkedIdentityAlreadyExists() throws URISyntaxException, IOException {
|
||||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||||
createUser(bc.consumerRealmName(), "consumer", "password", "FirstName", "LastName", "consumer@localhost.com");
|
createUser(bc.consumerRealmName(), "consumer", "password", "FirstName", "LastName", "consumer@localhost.com");
|
||||||
|
TestAppHelper testAppHelper = new TestAppHelper(oauth, loginPage, appPage);
|
||||||
|
|
||||||
driver.navigate().to(getAccountUrl(getConsumerRoot(), bc.consumerRealmName()));
|
// Link identity provider through Admin REST api
|
||||||
logInWithBroker(bc);
|
Response response = AccountHelper.addIdentityProvider(adminClient.realm(bc.consumerRealmName()), "consumer", adminClient.realm(bc.providerRealmName()), bc.getUserLogin(), bc.getIDPAlias());
|
||||||
waitForAccountManagementTitle();
|
Assert.assertEquals("status", 204, response.getStatus());
|
||||||
accountUpdateProfilePage.assertCurrent();
|
|
||||||
logoutFromRealm(getProviderRoot(), bc.providerRealmName());
|
|
||||||
logoutFromRealm(getConsumerRoot(), bc.consumerRealmName());
|
|
||||||
|
|
||||||
accountFederatedIdentityPage.realm(bc.consumerRealmName());
|
// Test we will log in immediately into app page
|
||||||
accountFederatedIdentityPage.open();
|
Assert.assertTrue(testAppHelper.login(bc.getUserLogin(), bc.getUserPassword(), bc.consumerRealmName(), "broker-app", bc.getIDPAlias()));
|
||||||
loginPage.login("consumer", "password");
|
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
|
||||||
|
|
||||||
accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias());
|
|
||||||
this.loginPage.login(bc.getUserLogin(), bc.getUserPassword());
|
|
||||||
|
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
|
||||||
assertEquals("Federated identity returned by " + bc.getIDPAlias() + " is already linked to another user.", accountFederatedIdentityPage.getError());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.keycloak.services.resources.RealmsResource;
|
||||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
|
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
|
||||||
import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
|
|
||||||
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;
|
||||||
|
@ -49,6 +48,7 @@ import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||||
import org.keycloak.testsuite.pages.ProceedPage;
|
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.pages.VerifyEmailPage;
|
||||||
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
import org.keycloak.testsuite.util.MailServer;
|
import org.keycloak.testsuite.util.MailServer;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.keycloak.testsuite.util.UserBuilder;
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
|
@ -126,10 +126,10 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest {
|
||||||
protected VerifyEmailPage verifyEmailPage;
|
protected VerifyEmailPage verifyEmailPage;
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected AccountFederatedIdentityPage accountFederatedIdentityPage;
|
protected OAuthGrantPage grantPage;
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected OAuthGrantPage grantPage;
|
protected AppPage appPage;
|
||||||
|
|
||||||
protected TimeBasedOTP totp = new TimeBasedOTP();
|
protected TimeBasedOTP totp = new TimeBasedOTP();
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ import jakarta.ws.rs.core.Response;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.admin.client.resource.UserResource;
|
import org.keycloak.admin.client.resource.UserResource;
|
||||||
import org.keycloak.admin.client.resource.UsersResource;
|
import org.keycloak.admin.client.resource.UsersResource;
|
||||||
import org.keycloak.common.Profile;
|
import org.keycloak.common.Profile;
|
||||||
import org.keycloak.common.Profile.Feature;
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -41,11 +41,10 @@ import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
import org.keycloak.testsuite.ProfileAssume;
|
import org.keycloak.testsuite.ProfileAssume;
|
||||||
import org.keycloak.testsuite.admin.ApiUtil;
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
|
|
||||||
import org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProvider;
|
import org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProvider;
|
||||||
import org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProviderFactory;
|
import org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProviderFactory;
|
||||||
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
||||||
import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
|
import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
|
||||||
|
|
||||||
|
@ -60,27 +59,27 @@ import static org.keycloak.testsuite.admin.ApiUtil.createUserAndResetPasswordWit
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
|
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
|
||||||
|
|
||||||
import org.keycloak.testsuite.runonserver.RunOnServer;
|
import org.keycloak.testsuite.runonserver.RunOnServer;
|
||||||
|
import org.keycloak.testsuite.util.AccountHelper;
|
||||||
import org.keycloak.testsuite.util.FederatedIdentityBuilder;
|
import org.keycloak.testsuite.util.FederatedIdentityBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@DisableFeature(value = Profile.Feature.ACCOUNT2, skipRestart = true) // TODO remove this (KEYCLOAK-16228)
|
|
||||||
public class AccountLinkTest extends AbstractKeycloakTest {
|
public class AccountLinkTest extends AbstractKeycloakTest {
|
||||||
public static final String CHILD_IDP = "child";
|
public static final String CHILD_IDP = "child";
|
||||||
public static final String PARENT_IDP = "parent-idp";
|
public static final String PARENT_IDP = "parent-idp";
|
||||||
public static final String PARENT_USERNAME = "parent";
|
public static final String PARENT_USERNAME = "parent";
|
||||||
|
|
||||||
@Page
|
|
||||||
protected AccountFederatedIdentityPage accountFederatedIdentityPage;
|
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected UpdateAccountInformationPage profilePage;
|
protected UpdateAccountInformationPage profilePage;
|
||||||
|
|
||||||
@Page
|
@Page
|
||||||
protected LoginPage loginPage;
|
protected LoginPage loginPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected AppPage appPage;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
RealmRepresentation realm = new RealmRepresentation();
|
RealmRepresentation realm = new RealmRepresentation();
|
||||||
|
@ -139,31 +138,27 @@ public class AccountLinkTest extends AbstractKeycloakTest {
|
||||||
@Test
|
@Test
|
||||||
public void testAccountLink() {
|
public void testAccountLink() {
|
||||||
String childUsername = "child";
|
String childUsername = "child";
|
||||||
String childPassword = "password";
|
|
||||||
String childIdp = CHILD_IDP;
|
|
||||||
|
|
||||||
testAccountLink(childUsername, childPassword, childIdp);
|
testAccountLink(childUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore // Ignore should be removed by https://github.com/keycloak/keycloak/issues/20441
|
||||||
public void testAccountLinkWithUserStorageProvider() {
|
public void testAccountLinkWithUserStorageProvider() {
|
||||||
ProfileAssume.assumeFeatureDisabled(Feature.MAP_STORAGE);
|
ProfileAssume.assumeFeatureDisabled(Profile.Feature.MAP_STORAGE);
|
||||||
|
|
||||||
String childUsername = PassThroughFederatedUserStorageProvider.PASSTHROUGH_USERNAME;
|
String childUsername = PassThroughFederatedUserStorageProvider.PASSTHROUGH_USERNAME;
|
||||||
String childPassword = PassThroughFederatedUserStorageProvider.INITIAL_PASSWORD;
|
String childPassword = PassThroughFederatedUserStorageProvider.INITIAL_PASSWORD;
|
||||||
String childIdp = CHILD_IDP;
|
String childIdp = CHILD_IDP;
|
||||||
|
|
||||||
testAccountLink(childUsername, childPassword, childIdp);
|
testAccountLink(childUsername);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteIdentityOnProviderRemoval() {
|
public void testDeleteIdentityOnProviderRemoval() {
|
||||||
String childUsername = "child";
|
String childUsername = "child";
|
||||||
String childPassword = "password";
|
|
||||||
String childIdp = CHILD_IDP;
|
|
||||||
|
|
||||||
assertFederatedIdentity(childUsername, childPassword, childIdp);
|
assertFederatedIdentity(childUsername);
|
||||||
|
|
||||||
RealmResource realm = adminClient.realm(CHILD_IDP);
|
RealmResource realm = adminClient.realm(CHILD_IDP);
|
||||||
UsersResource users = realm.users();
|
UsersResource users = realm.users();
|
||||||
|
@ -242,7 +237,7 @@ public class AccountLinkTest extends AbstractKeycloakTest {
|
||||||
assertNull(session.users().getFederatedIdentity(realm1, user, testIdpToDelete));
|
assertNull(session.users().getFederatedIdentity(realm1, user, testIdpToDelete));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkEmptyFederatedIdentities(KeycloakSession session) {
|
private static void checkEmptyFederatedIdentities(KeycloakSession session) {
|
||||||
RealmModel realm = session.getContext().getRealm();
|
RealmModel realm = session.getContext().getRealm();
|
||||||
UserModel user = session.users().getUserByUsername(realm, "child");
|
UserModel user = session.users().getUserByUsername(realm, "child");
|
||||||
|
@ -250,54 +245,25 @@ public class AccountLinkTest extends AbstractKeycloakTest {
|
||||||
assertNull(session.users().getFederatedIdentity(realm, user, PARENT_IDP));
|
assertNull(session.users().getFederatedIdentity(realm, user, PARENT_IDP));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testAccountLink(String childUsername, String childPassword, String childIdp) {
|
protected void testAccountLink(String childUsername) {
|
||||||
assertFederatedIdentity(childUsername, childPassword, childIdp);
|
assertFederatedIdentity(childUsername);
|
||||||
assertRemoveFederatedIdentity();
|
assertRemoveFederatedIdentity();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertFederatedIdentity(String childUsername, String childPassword, String childIdp) {
|
private void assertFederatedIdentity(String childUsername) {
|
||||||
accountFederatedIdentityPage.realm(childIdp);
|
//Link the identity provider through Admin REST API
|
||||||
accountFederatedIdentityPage.open();
|
Response response = AccountHelper.addIdentityProvider(adminClient.realm(CHILD_IDP), childUsername, adminClient.realm(PARENT_IDP), PARENT_USERNAME, PARENT_IDP);
|
||||||
loginPage.isCurrent();
|
Assert.assertEquals("status", 204, response.getStatus());
|
||||||
loginPage.login(childUsername, childPassword);
|
assertTrue(AccountHelper.isIdentityProviderLinked(adminClient.realm(CHILD_IDP), childUsername, PARENT_IDP));
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
|
||||||
|
|
||||||
accountFederatedIdentityPage.clickAddProvider(PARENT_IDP);
|
|
||||||
|
|
||||||
this.loginPage.isCurrent();
|
|
||||||
loginPage.login(PARENT_USERNAME, "password");
|
|
||||||
|
|
||||||
// Assert identity linked in account management
|
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
|
||||||
assertTrue(driver.getPageSource().contains("id=\"remove-link-" + PARENT_IDP + "\""));
|
|
||||||
|
|
||||||
// Logout from account management
|
|
||||||
accountFederatedIdentityPage.logout();
|
|
||||||
|
|
||||||
// Assert I am logged immediately to account management due to previously linked "test-user" identity
|
|
||||||
loginPage.isCurrent();
|
|
||||||
loginPage.clickSocial(PARENT_IDP);
|
|
||||||
loginPage.login(PARENT_USERNAME, "password");
|
|
||||||
System.out.println(driver.getCurrentUrl());
|
|
||||||
System.out.println("--------------------------------");
|
|
||||||
System.out.println(driver.getPageSource());
|
|
||||||
assertTrue(accountFederatedIdentityPage.isCurrent());
|
|
||||||
assertTrue(driver.getPageSource().contains("id=\"remove-link-" + PARENT_IDP + "\""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertRemoveFederatedIdentity() {
|
private void assertRemoveFederatedIdentity() {
|
||||||
// Unlink my "test-user"
|
// Unlink my "test-user" through Admin REST API
|
||||||
accountFederatedIdentityPage.clickRemoveProvider(PARENT_IDP);
|
AccountHelper.deleteIdentityProvider(adminClient.realm(CHILD_IDP), CHILD_IDP, PARENT_IDP);
|
||||||
assertTrue(driver.getPageSource().contains("id=\"add-link-" + PARENT_IDP + "\""));
|
assertFalse(AccountHelper.isIdentityProviderLinked(adminClient.realm(CHILD_IDP), CHILD_IDP, PARENT_IDP));
|
||||||
|
|
||||||
// Logout from account management
|
|
||||||
accountFederatedIdentityPage.logout();
|
|
||||||
|
|
||||||
this.loginPage.clickSocial(PARENT_IDP);
|
|
||||||
this.loginPage.login(PARENT_USERNAME, "password");
|
|
||||||
this.profilePage.assertCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,54 +99,6 @@ public class KcOidcBrokerWithConsentTest extends AbstractInitializedBaseBrokerTe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getConsumerRoot(), bc.consumerRealmName()));
|
|
||||||
loginPage.login("consumer", "password");
|
|
||||||
|
|
||||||
accountPage.federatedIdentity();
|
|
||||||
accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias());
|
|
||||||
|
|
||||||
this.loginPage.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.loginPage.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
|
* Referes to in old testsuite: org.keycloak.testsuite.broker.OIDCKeycloakServerBrokerWithConsentTest#testLoginCancelConsent
|
||||||
*/
|
*/
|
||||||
|
@ -162,29 +114,4 @@ public class KcOidcBrokerWithConsentTest extends AbstractInitializedBaseBrokerTe
|
||||||
|
|
||||||
assertEquals("Sign in to " + bc.consumerRealmName(), driver.getTitle());
|
assertEquals("Sign 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(getConsumerRoot(), bc.consumerRealmName()));
|
|
||||||
loginPage.login("consumer", "password");
|
|
||||||
|
|
||||||
accountPage.federatedIdentity();
|
|
||||||
|
|
||||||
accountFederatedIdentityPage.clickAddProvider(bc.getIDPAlias());
|
|
||||||
this.loginPage.login(bc.getUserLogin(), bc.getUserPassword());
|
|
||||||
|
|
||||||
// User rejected consent
|
|
||||||
grantPage.assertCurrent();
|
|
||||||
grantPage.cancel();
|
|
||||||
|
|
||||||
// Assert account error page with "consentDenied" error displayed
|
|
||||||
accountFederatedIdentityPage.assertCurrent();
|
|
||||||
Assert.assertEquals("Access denied when authenticating with kc-oidc-idp", accountFederatedIdentityPage.getError());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,10 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.keycloak.models.credential.OTPCredentialModel;
|
import org.keycloak.models.credential.OTPCredentialModel;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
|
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class AccountHelper {
|
public class AccountHelper {
|
||||||
|
@ -63,11 +65,6 @@ public class AccountHelper {
|
||||||
user.revokeConsent(clientId);
|
user.revokeConsent(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void logout(RealmResource realm, String username) {
|
|
||||||
UserResource user = getUserResource(realm, username);
|
|
||||||
user.logout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<CredentialRepresentation> getOtpCredentials(UserResource user, String userLabel) {
|
private static Optional<CredentialRepresentation> getOtpCredentials(UserResource user, String userLabel) {
|
||||||
return user.credentials().stream().filter(c -> c.getType().equals(OTPCredentialModel.TYPE)).filter(l -> l.getUserLabel().equals(userLabel)).findFirst();
|
return user.credentials().stream().filter(c -> c.getType().equals(OTPCredentialModel.TYPE)).filter(l -> l.getUserLabel().equals(userLabel)).findFirst();
|
||||||
}
|
}
|
||||||
|
@ -125,4 +122,38 @@ public class AccountHelper {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Response addIdentityProvider(RealmResource childRealm, String childUsername, RealmResource providerRealm, String providerUsername, String providerId) {
|
||||||
|
UserResource user = getUserResource(childRealm, childUsername);
|
||||||
|
|
||||||
|
FederatedIdentityRepresentation identityRepresentation = FederatedIdentityBuilder.create()
|
||||||
|
.identityProvider(providerId)
|
||||||
|
.userId(getUserResource(providerRealm, providerUsername).toRepresentation().getId())
|
||||||
|
.userName(providerUsername)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return user.addFederatedIdentity(providerId, identityRepresentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteIdentityProvider(RealmResource realm, String username, String providerId) {
|
||||||
|
UserResource user = getUserResource(realm, username);
|
||||||
|
user.removeFederatedIdentity(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isIdentityProviderLinked(RealmResource realm, String username, String providerId) {
|
||||||
|
UserResource user = getUserResource(realm, username);
|
||||||
|
|
||||||
|
for (FederatedIdentityRepresentation rep : user.getFederatedIdentity()){
|
||||||
|
if(rep.getIdentityProvider().equals(providerId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logout(RealmResource realm, String username) {
|
||||||
|
UserResource user = getUserResource(realm, username);
|
||||||
|
user.logout();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,21 @@ public class TestAppHelper {
|
||||||
return appPage.isCurrent();
|
return appPage.isCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean login(String username, String password, String realm, String clientId, String idp) throws URISyntaxException, IOException {
|
||||||
|
oauth.clientId(clientId);
|
||||||
|
loginPage.open(realm);
|
||||||
|
loginPage.clickSocial(idp);
|
||||||
|
loginPage.login(username, password);
|
||||||
|
|
||||||
|
if (loginPage.isCurrent(realm)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
completeLogin();
|
||||||
|
|
||||||
|
return appPage.isCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean logout() {
|
public boolean logout() {
|
||||||
try (CloseableHttpResponse response = oauth.doLogout(refreshToken, "password")) {
|
try (CloseableHttpResponse response = oauth.doLogout(refreshToken, "password")) {
|
||||||
return response.getStatusLine().getStatusCode() == Response.Status.NO_CONTENT.getStatusCode();
|
return response.getStatusLine().getStatusCode() == Response.Status.NO_CONTENT.getStatusCode();
|
||||||
|
|
Loading…
Reference in a new issue