Properly execute AuthenticationFlowCallbackProviderTest with Map storage
Closes #10268, Closes #10225
This commit is contained in:
parent
a7c8aa1dd3
commit
8a0f1ccb34
4 changed files with 113 additions and 21 deletions
|
@ -1,12 +1,17 @@
|
|||
package org.keycloak.testsuite.pages;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
public class PageUtils {
|
||||
|
||||
public static String getPageTitle(WebDriver driver) {
|
||||
return driver.findElement(By.id("kc-page-title")).getText();
|
||||
try {
|
||||
return driver.findElement(By.id("kc-page-title")).getText();
|
||||
} catch (NoSuchElementException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -81,9 +81,9 @@ import java.util.Scanner;
|
|||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_HOST;
|
||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_PORT;
|
||||
|
@ -188,12 +188,29 @@ public abstract class AbstractKeycloakTest {
|
|||
adminClient = testContext.getAdminClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed before test realms import
|
||||
* <p>
|
||||
* In @Before block
|
||||
*/
|
||||
protected void beforeAbstractKeycloakTestRealmImport() throws Exception {
|
||||
}
|
||||
protected void postAfterAbstractKeycloak() throws Exception {
|
||||
|
||||
/**
|
||||
* Executed after test realms import
|
||||
* <p>
|
||||
* In @Before block
|
||||
*/
|
||||
protected void afterAbstractKeycloakTestRealmImport() {
|
||||
}
|
||||
|
||||
protected void afterAbstractKeycloakTestRealmImport() {}
|
||||
/**
|
||||
* Executed as the last task of each test case
|
||||
* <p>
|
||||
* In @After block
|
||||
*/
|
||||
protected void postAfterAbstractKeycloak() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterAbstractKeycloakTest() throws Exception {
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
package org.keycloak.testsuite.forms;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.authentication.authenticators.access.AllowAccessAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory;
|
||||
import org.keycloak.authentication.authenticators.conditional.ConditionalLoaAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.conditional.ConditionalLoaAuthenticatorFactory;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
|
@ -36,7 +37,6 @@ import org.keycloak.testsuite.util.FlowUtil;
|
|||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assume.assumeThat;
|
||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||
|
||||
/**
|
||||
|
@ -45,6 +45,8 @@ import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerEx
|
|||
@AuthServerContainerExclude(REMOTE)
|
||||
public class AuthenticationFlowCallbackProviderTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
protected static final String DEFAULT_FLOW = "newCallbackFlow";
|
||||
|
||||
@Page
|
||||
protected LoginPage loginPage;
|
||||
|
||||
|
@ -55,9 +57,18 @@ public class AuthenticationFlowCallbackProviderTest extends AbstractTestRealmKey
|
|||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpFlow() {
|
||||
setBrowserFlow();
|
||||
}
|
||||
|
||||
@After
|
||||
public void revertFlow() {
|
||||
BrowserFlowTest.revertFlows(testRealm(), DEFAULT_FLOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loaEssentialNonExisting() {
|
||||
setBrowserFlow();
|
||||
LevelOfAssuranceFlowTest.openLoginFormWithAcrClaim(oauth, true, "4");
|
||||
|
||||
loginPage.assertCurrent();
|
||||
|
@ -69,10 +80,6 @@ public class AuthenticationFlowCallbackProviderTest extends AbstractTestRealmKey
|
|||
|
||||
@Test
|
||||
public void errorWithCustomProvider() {
|
||||
// Ignore test case for Map Storage - GitHub Issue #10225
|
||||
assumeThat("This test case does not work properly with Map Storage", Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE), is(false));
|
||||
|
||||
setBrowserFlow();
|
||||
LevelOfAssuranceFlowTest.openLoginFormWithAcrClaim(oauth, true, "1");
|
||||
|
||||
loginPage.assertCurrent();
|
||||
|
@ -83,9 +90,9 @@ public class AuthenticationFlowCallbackProviderTest extends AbstractTestRealmKey
|
|||
}
|
||||
|
||||
protected void setBrowserFlow() {
|
||||
testingClient.server("test").run(session -> FlowUtil.inCurrentRealm(session).copyBrowserFlow("newFlow"));
|
||||
testingClient.server("test").run(session -> FlowUtil.inCurrentRealm(session)
|
||||
.selectFlow("newFlow")
|
||||
testingClient.server(TEST_REALM_NAME).run(session -> FlowUtil.inCurrentRealm(session).copyBrowserFlow(DEFAULT_FLOW));
|
||||
testingClient.server(TEST_REALM_NAME).run(session -> FlowUtil.inCurrentRealm(session)
|
||||
.selectFlow(DEFAULT_FLOW)
|
||||
.inForms(forms -> forms
|
||||
.clear()
|
||||
.addSubFlowExecution(AuthenticationExecutionModel.Requirement.CONDITIONAL, subflow -> subflow
|
||||
|
|
|
@ -8,16 +8,24 @@ import org.keycloak.models.AuthenticatorConfigModel;
|
|||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.services.resources.admin.AuthenticationManagementResource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.models.utils.DefaultAuthenticationFlows.BROWSER_FLOW;
|
||||
import static org.keycloak.models.utils.DefaultAuthenticationFlows.DIRECT_GRANT_FLOW;
|
||||
import static org.keycloak.models.utils.DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW;
|
||||
import static org.keycloak.models.utils.DefaultAuthenticationFlows.REGISTRATION_FLOW;
|
||||
import static org.keycloak.models.utils.DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW;
|
||||
|
||||
public class FlowUtil {
|
||||
private RealmModel realm;
|
||||
private AuthenticationFlowModel currentFlow;
|
||||
|
@ -67,23 +75,27 @@ public class FlowUtil {
|
|||
}
|
||||
|
||||
public FlowUtil copyBrowserFlow(String newFlowAlias) {
|
||||
return copyFlow(DefaultAuthenticationFlows.BROWSER_FLOW, newFlowAlias);
|
||||
checkAndRestoreDefaultFlow(realm::getBrowserFlow, realm::setBrowserFlow, newFlowAlias, BROWSER_FLOW);
|
||||
return copyFlow(BROWSER_FLOW, newFlowAlias);
|
||||
}
|
||||
|
||||
public FlowUtil copyResetCredentialsFlow(String newFlowAlias) {
|
||||
return copyFlow(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW, newFlowAlias);
|
||||
checkAndRestoreDefaultFlow(realm::getResetCredentialsFlow, realm::setResetCredentialsFlow, newFlowAlias, RESET_CREDENTIALS_FLOW);
|
||||
return copyFlow(RESET_CREDENTIALS_FLOW, newFlowAlias);
|
||||
}
|
||||
|
||||
public FlowUtil copyFirstBrokerLoginFlow(String newFlowAlias) {
|
||||
return copyFlow(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, newFlowAlias);
|
||||
return copyFlow(FIRST_BROKER_LOGIN_FLOW, newFlowAlias);
|
||||
}
|
||||
|
||||
public FlowUtil copyRegistrationFlow(String newFlowAlias) {
|
||||
return copyFlow(DefaultAuthenticationFlows.REGISTRATION_FLOW, newFlowAlias);
|
||||
checkAndRestoreDefaultFlow(realm::getRegistrationFlow, realm::setRegistrationFlow, newFlowAlias, REGISTRATION_FLOW);
|
||||
return copyFlow(REGISTRATION_FLOW, newFlowAlias);
|
||||
}
|
||||
|
||||
public FlowUtil copyDirectGrantFlow(String newFlowAlias) {
|
||||
return copyFlow(DefaultAuthenticationFlows.DIRECT_GRANT_FLOW, newFlowAlias);
|
||||
checkAndRestoreDefaultFlow(realm::getDirectGrantFlow, realm::setDirectGrantFlow, newFlowAlias, DIRECT_GRANT_FLOW);
|
||||
return copyFlow(DIRECT_GRANT_FLOW, newFlowAlias);
|
||||
}
|
||||
|
||||
public FlowUtil copyFlow(String original, String newFlowAlias) {
|
||||
|
@ -92,6 +104,14 @@ public class FlowUtil {
|
|||
if (existingBrowserFlow == null) {
|
||||
throw new FlowUtilException("Can't copy flow: " + original + " does not exist");
|
||||
}
|
||||
|
||||
// remove new authentication flow with 'newFlowAlias' alias if present
|
||||
AuthenticationFlowModel foundFlow = realm.getFlowByAlias(newFlowAlias);
|
||||
if (foundFlow != null) {
|
||||
clearAuthenticationFlow(foundFlow.getId());
|
||||
realm.removeAuthenticationFlow(foundFlow);
|
||||
}
|
||||
|
||||
currentFlow = AuthenticationManagementResource.copyFlow(realm, existingBrowserFlow, newFlowAlias);
|
||||
|
||||
return this;
|
||||
|
@ -119,7 +139,7 @@ public class FlowUtil {
|
|||
}
|
||||
|
||||
public FlowUtil clear() {
|
||||
realm.getAuthenticationExecutionsStream(currentFlow.getId()).forEachOrdered(realm::removeAuthenticatorExecution);
|
||||
clearAuthenticationFlow(currentFlow.getId());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -264,4 +284,47 @@ public class FlowUtil {
|
|||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove authentication flows and executions included in the specified flow
|
||||
*
|
||||
* @param flowId id of flow, which content will be removed
|
||||
*/
|
||||
private void clearAuthenticationFlow(String flowId) {
|
||||
realm.getAuthenticationExecutionsStream(flowId)
|
||||
.filter(Objects::nonNull)
|
||||
.forEachOrdered(f -> {
|
||||
if (f.isAuthenticatorFlow() && f.getFlowId() != null) {
|
||||
clearAuthenticationFlow(f.getFlowId());
|
||||
realm.removeAuthenticationFlow(realm.getAuthenticationFlowById(f.getFlowId()));
|
||||
}
|
||||
realm.removeAuthenticatorExecution(f);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the new flow is set as default one
|
||||
* If yes, restore the default one
|
||||
* <p>
|
||||
* Usable for removing flow, which must not be used as the default flow
|
||||
*
|
||||
* @param getFlow getter for obtaining the default flow
|
||||
* @param setFlow setter for the setting of the default flow
|
||||
* @param newFlowAlias alias of tested flow
|
||||
* @param defaultFlowAlias default flow alias
|
||||
*/
|
||||
private void checkAndRestoreDefaultFlow(Supplier<AuthenticationFlowModel> getFlow,
|
||||
Consumer<AuthenticationFlowModel> setFlow,
|
||||
String newFlowAlias,
|
||||
String defaultFlowAlias) {
|
||||
if (getFlow == null || setFlow == null || newFlowAlias == null || defaultFlowAlias == null) return;
|
||||
|
||||
final String alias = Optional.ofNullable(getFlow.get())
|
||||
.map(AuthenticationFlowModel::getAlias)
|
||||
.orElse(null);
|
||||
|
||||
if (alias != null && alias.equals(newFlowAlias)) {
|
||||
setFlow.accept(realm.getFlowByAlias(defaultFlowAlias));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue