mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Migrate tests from org/keycloak/tests/admin/authentication to new framework (#37003)
* Migrate tests from org/keycloak/tests/admin/authentication to new framework Part of #34494 Signed-off-by: stianst <stianst@gmail.com> * Update tests/MIGRATING_TESTS.md Signed-off-by: Stian Thorgersen <stian@redhat.com> --------- Signed-off-by: stianst <stianst@gmail.com> Signed-off-by: Stian Thorgersen <stian@redhat.com>
This commit is contained in:
parent
b9442b1690
commit
19cabe8238
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -342,7 +342,7 @@ jobs:
|
||||
run: ./mvnw install -e -pl testsuite/integration-arquillian/servers/auth-server/quarkus
|
||||
|
||||
- name: Run new base tests
|
||||
run: ./mvnw test -f tests/pom.xml -Dtest=JDKTestSuite
|
||||
run: ./mvnw package -f tests/pom.xml -Dtest=JDKTestSuite
|
||||
|
||||
- name: Run base tests
|
||||
run: |
|
||||
@ -681,7 +681,7 @@ jobs:
|
||||
|
||||
- name: Run new base tests
|
||||
run: |
|
||||
KC_TEST_DATABASE=${{ matrix.db }} KC_TEST_DATABASE_REUSE=true TESTCONTAINERS_REUSE_ENABLE=true ./mvnw test -f tests/pom.xml -Dtest=DatabaseTestSuite
|
||||
KC_TEST_DATABASE=${{ matrix.db }} KC_TEST_DATABASE_REUSE=true TESTCONTAINERS_REUSE_ENABLE=true ./mvnw package -f tests/pom.xml -Dtest=DatabaseTestSuite
|
||||
|
||||
- name: Database container port
|
||||
run: |
|
||||
@ -1083,7 +1083,7 @@ jobs:
|
||||
uses: ./.github/actions/integration-test-setup
|
||||
|
||||
- name: Run tests
|
||||
run: ./mvnw test -f tests/pom.xml
|
||||
run: ./mvnw package -f tests/pom.xml
|
||||
|
||||
check:
|
||||
name: Status Check - Keycloak CI
|
||||
|
||||
@ -77,7 +77,14 @@ public abstract class AbstractEvents<R> {
|
||||
}
|
||||
|
||||
public void skipAll() {
|
||||
try {
|
||||
Thread.sleep(1); // Wait 1 ms to make sure time passes
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
testStarted = getCurrentTime();
|
||||
lastFetch = -1;
|
||||
events.clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -101,7 +108,7 @@ public abstract class AbstractEvents<R> {
|
||||
|
||||
protected abstract Logger getLogger();
|
||||
|
||||
protected long getCurrentTime() {
|
||||
public long getCurrentTime() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,21 @@ public class AdminEventAssertion {
|
||||
return new AdminEventAssertion(event, false).assertValidOperationType();
|
||||
}
|
||||
|
||||
public static AdminEventAssertion assertEvent(AdminEventRepresentation event, OperationType operationType, String resourcePath, Object representation, ResourceType resourceType) {
|
||||
return assertSuccess(event)
|
||||
.operationType(operationType)
|
||||
.resourcePath(resourcePath)
|
||||
.representation(representation)
|
||||
.resourceType(resourceType);
|
||||
}
|
||||
|
||||
public static AdminEventAssertion assertEvent(AdminEventRepresentation event, OperationType operationType, String resourcePath, ResourceType resourceType) {
|
||||
return assertSuccess(event)
|
||||
.operationType(operationType)
|
||||
.resourcePath(resourcePath)
|
||||
.resourceType(resourceType);
|
||||
}
|
||||
|
||||
public AdminEventAssertion operationType(OperationType operationType) {
|
||||
Assertions.assertEquals(operationType.name(), getOperationType());
|
||||
return this;
|
||||
|
||||
69
tests/MIGRATING_TESTS.md
Normal file
69
tests/MIGRATING_TESTS.md
Normal file
@ -0,0 +1,69 @@
|
||||
### Basics
|
||||
|
||||
When migrating tests use the remote server mode as this will make it much quicker to run tests than having to start/stop
|
||||
Keycloak when you run the test from the IDE.
|
||||
|
||||
Add `@KeycloakIntegrationTest` to the class.
|
||||
|
||||
Change `import org.junit.Test;` to `import org.junit.jupiter.api.Test;`
|
||||
|
||||
Remove extends `AbstractKeycloakTest` as the new test framework provides injection of resources needed by the test there
|
||||
is no need for the `AbstractKeycloakTest` and tests should instead inject what they need.
|
||||
|
||||
One thing your test is most likely going to need is a realm, this is now done with:
|
||||
|
||||
```
|
||||
@InjectRealm
|
||||
ManagedRealm realm;
|
||||
```
|
||||
|
||||
### Changed packages/classes
|
||||
|
||||
| Old | New |
|
||||
|---------------------------------------------|------------------------------------------------|
|
||||
| org.junit.Assert | org.junit.jupiter.api.Assertions |
|
||||
| org.junit.Test | org.junit.jupiter.api.Test |
|
||||
| org.keycloak.testsuite.admin.ApiUtil | org.keycloak.tests.utils.admin.ApiUtil |
|
||||
| org.keycloak.testsuite.util.AdminEventPaths | org.keycloak.tests.utils.admin.AdminEventPaths |
|
||||
|
||||
### Assertions
|
||||
|
||||
Change `import org.junit.Assert;` to `import org.junit.jupiter.api.Assertions;`, and replace `Assert.` with `Assertions.` throughout.
|
||||
|
||||
If the assert passes a message (for example `Assert.assertEquals("Message", expected, actual)`) the message in `Assertions`
|
||||
is now the last parameter (for example `Assertions.assertEquals(expected, actual, "Message")`).
|
||||
|
||||
### Admin events
|
||||
|
||||
Admin events are handled slightly differently in the new test framework.
|
||||
|
||||
An example for the old testsuite:
|
||||
|
||||
```
|
||||
@Rule
|
||||
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
|
||||
|
||||
public void myTest() {
|
||||
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, ...);
|
||||
}
|
||||
```
|
||||
|
||||
Converted to the new test framework:
|
||||
|
||||
```
|
||||
@InjectAdminEvents
|
||||
public AdminEvents adminEvents;
|
||||
|
||||
public void myTest() {
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, ...);
|
||||
}
|
||||
```
|
||||
|
||||
Notice that there is no need to pass `realmId` when asserting an event, that is because the `AdminEvents` will only
|
||||
receive events for the current realm.
|
||||
|
||||
For better readability `AdminEventAssertion` provides a method chaining approach to assert various fields in the event
|
||||
(the example above could be change to `AdminEventAssertion.assertSuccess(adminEvents.poll()).operationType(OperationType.CREATE)...`).
|
||||
|
||||
There is also improved support for skipping events using skip methods, that allows skipping one event (`.skip()`),
|
||||
multiple events (`.skip(5)`), or skipping all previous events (`.skipAll()`).
|
||||
@ -86,6 +86,11 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.tests</groupId>
|
||||
<artifactId>keycloak-tests-custom-providers</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-suite</artifactId>
|
||||
|
||||
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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.tests.admin.authentication;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectAdminEvents;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.testframework.events.AdminEvents;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
import org.keycloak.tests.utils.admin.ApiUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
public abstract class AbstractAuthenticationTest {
|
||||
|
||||
static final String REQUIRED = "REQUIRED";
|
||||
static final String CONDITIONAL = "CONDITIONAL";
|
||||
static final String DISABLED = "DISABLED";
|
||||
static final String ALTERNATIVE = "ALTERNATIVE";
|
||||
|
||||
@InjectRealm
|
||||
ManagedRealm managedRealm;
|
||||
|
||||
RealmResource realmResource;
|
||||
AuthenticationManagementResource authMgmtResource;
|
||||
protected String testRealmId;
|
||||
|
||||
@InjectAdminEvents
|
||||
public AdminEvents adminEvents;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
realmResource = managedRealm.admin();
|
||||
authMgmtResource = realmResource.flows();
|
||||
testRealmId = managedRealm.getId();
|
||||
}
|
||||
|
||||
public static AuthenticationExecutionInfoRepresentation findExecutionByProvider(String provider, List<AuthenticationExecutionInfoRepresentation> executions) {
|
||||
for (AuthenticationExecutionInfoRepresentation exec : executions) {
|
||||
if (provider.equals(exec.getProviderId())) {
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for an execution located before the provided execution on the same level of
|
||||
* an authentication flow.
|
||||
*
|
||||
* @param execution execution to find a neighbor for
|
||||
* @param executions list of executions to search in
|
||||
* @return execution, or null if not found
|
||||
*/
|
||||
public static AuthenticationExecutionInfoRepresentation findPreviousExecution(AuthenticationExecutionInfoRepresentation execution, List<AuthenticationExecutionInfoRepresentation> executions) {
|
||||
for (AuthenticationExecutionInfoRepresentation exec : executions) {
|
||||
if (exec.getLevel() != execution.getLevel()) {
|
||||
continue;
|
||||
}
|
||||
if (exec.getIndex() == execution.getIndex() - 1) {
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static AuthenticationFlowRepresentation findFlowByAlias(String alias, List<AuthenticationFlowRepresentation> flows) {
|
||||
for (AuthenticationFlowRepresentation flow : flows) {
|
||||
if (alias.equals(flow.getAlias())) {
|
||||
return flow;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void compareExecution(AuthenticationExecutionInfoRepresentation expected, AuthenticationExecutionInfoRepresentation actual) {
|
||||
Assertions.assertEquals(expected.getRequirement(), actual.getRequirement(), "Execution requirement - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getDisplayName(), actual.getDisplayName(), "Execution display name - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getConfigurable(), actual.getConfigurable(), "Execution configurable - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getProviderId(), actual.getProviderId(), "Execution provider id - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getLevel(), actual.getLevel(), "Execution level - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getIndex(), actual.getIndex(), "Execution index - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getPriority(), actual.getPriority(), "Execution priority - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getAuthenticationFlow(), actual.getAuthenticationFlow(), "Execution authentication flow - " + actual.getProviderId());
|
||||
Assertions.assertEquals(expected.getRequirementChoices(), actual.getRequirementChoices(), "Execution requirement choices - " + actual.getProviderId());
|
||||
}
|
||||
|
||||
void compareExecution(AuthenticationExecutionExportRepresentation expected, AuthenticationExecutionExportRepresentation actual) {
|
||||
Assertions.assertEquals(expected.getFlowAlias(), actual.getFlowAlias(), "Execution flowAlias - " + actual.getFlowAlias());
|
||||
Assertions.assertEquals(expected.getAuthenticator(), actual.getAuthenticator(), "Execution authenticator - " + actual.getAuthenticator());
|
||||
Assertions.assertEquals(expected.isUserSetupAllowed(), actual.isUserSetupAllowed(), "Execution userSetupAllowed - " + actual.getAuthenticator());
|
||||
Assertions.assertEquals(expected.isAuthenticatorFlow(), actual.isAuthenticatorFlow(), "Execution authenticatorFlow - " + actual.getAuthenticator());
|
||||
Assertions.assertEquals(expected.getAuthenticatorConfig(), actual.getAuthenticatorConfig(), "Execution authenticatorConfig - " + actual.getAuthenticatorConfig());
|
||||
Assertions.assertEquals(expected.getPriority(), actual.getPriority(), "Execution priority - " + actual.getAuthenticator());
|
||||
Assertions.assertEquals(expected.getRequirement(), actual.getRequirement(), "Execution requirement - " + actual.getAuthenticator());
|
||||
}
|
||||
|
||||
void compareExecutions(List<AuthenticationExecutionExportRepresentation> expected, List<AuthenticationExecutionExportRepresentation> actual) {
|
||||
Assertions.assertNotNull(actual, "Executions should not be null");
|
||||
Assertions.assertEquals(expected.size(), actual.size(), "Size");
|
||||
|
||||
for (int i = 0; i < expected.size(); i++) {
|
||||
compareExecution(expected.get(i), actual.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
void compareFlows(AuthenticationFlowRepresentation expected, AuthenticationFlowRepresentation actual) {
|
||||
Assertions.assertEquals(expected.getAlias(), actual.getAlias(), "Flow alias");
|
||||
Assertions.assertEquals(expected.getDescription(), actual.getDescription(), "Flow description");
|
||||
Assertions.assertEquals(expected.getProviderId(), actual.getProviderId(), "Flow providerId");
|
||||
Assertions.assertEquals(expected.isTopLevel(), actual.isTopLevel(), "Flow top level");
|
||||
Assertions.assertEquals(expected.isBuiltIn(), actual.isBuiltIn(), "Flow built-in");
|
||||
|
||||
List<AuthenticationExecutionExportRepresentation> expectedExecs = expected.getAuthenticationExecutions();
|
||||
List<AuthenticationExecutionExportRepresentation> actualExecs = actual.getAuthenticationExecutions();
|
||||
|
||||
if (expectedExecs == null) {
|
||||
Assertions.assertTrue(actualExecs == null || actualExecs.size() == 0, "Executions should be null or empty");
|
||||
} else {
|
||||
compareExecutions(expectedExecs, actualExecs);
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticationFlowRepresentation newFlow(String alias, String description,
|
||||
String providerId, boolean topLevel, boolean builtIn) {
|
||||
AuthenticationFlowRepresentation flow = new AuthenticationFlowRepresentation();
|
||||
flow.setAlias(alias);
|
||||
flow.setDescription(description);
|
||||
flow.setProviderId(providerId);
|
||||
flow.setTopLevel(topLevel);
|
||||
flow.setBuiltIn(builtIn);
|
||||
return flow;
|
||||
}
|
||||
|
||||
AuthenticationExecutionInfoRepresentation newExecInfo(String displayName, String providerId, Boolean configurable,
|
||||
int level, int index, String requirement, Boolean authFlow, String[] choices,
|
||||
int priority) {
|
||||
|
||||
AuthenticationExecutionInfoRepresentation execution = new AuthenticationExecutionInfoRepresentation();
|
||||
execution.setRequirement(requirement);
|
||||
execution.setDisplayName(displayName);
|
||||
execution.setConfigurable(configurable);
|
||||
execution.setProviderId(providerId);
|
||||
execution.setLevel(level);
|
||||
execution.setIndex(index);
|
||||
execution.setAuthenticationFlow(authFlow);
|
||||
execution.setPriority(priority);
|
||||
if (choices != null) {
|
||||
execution.setRequirementChoices(Arrays.asList(choices));
|
||||
}
|
||||
return execution;
|
||||
}
|
||||
|
||||
void addExecInfo(List<AuthenticationExecutionInfoRepresentation> target, String displayName, String providerId, Boolean configurable,
|
||||
int level, int index, String requirement, Boolean authFlow, String[] choices, int priority) {
|
||||
|
||||
AuthenticationExecutionInfoRepresentation exec = newExecInfo(displayName, providerId, configurable, level, index, requirement, authFlow, choices, priority);
|
||||
target.add(exec);
|
||||
}
|
||||
|
||||
AuthenticatorConfigRepresentation newConfig(String alias, String[] keyvalues) {
|
||||
AuthenticatorConfigRepresentation config = new AuthenticatorConfigRepresentation();
|
||||
config.setAlias(alias);
|
||||
|
||||
if (keyvalues == null) {
|
||||
throw new IllegalArgumentException("keyvalues == null");
|
||||
}
|
||||
if (keyvalues.length % 2 != 0) {
|
||||
throw new IllegalArgumentException("keyvalues should have even number of elements");
|
||||
}
|
||||
|
||||
LinkedHashMap<String, String> params = new LinkedHashMap<>();
|
||||
for (int i = 0; i < keyvalues.length; i += 2) {
|
||||
params.put(keyvalues[i], keyvalues[i + 1]);
|
||||
}
|
||||
config.setConfig(params);
|
||||
return config;
|
||||
}
|
||||
|
||||
String createFlow(AuthenticationFlowRepresentation flowRep) {
|
||||
return createFlow(flowRep, true);
|
||||
}
|
||||
|
||||
String createFlow(AuthenticationFlowRepresentation flowRep, boolean autoDelete) {
|
||||
Response response = authMgmtResource.createFlow(flowRep);
|
||||
Assertions.assertEquals(201, response.getStatus());
|
||||
response.close();
|
||||
String flowId = ApiUtil.getCreatedId(response);
|
||||
if (autoDelete) {
|
||||
managedRealm.cleanup().add(r -> r.flows().deleteFlow(flowId));
|
||||
}
|
||||
AdminEventAssertion.assertSuccess(adminEvents.poll())
|
||||
.operationType(OperationType.CREATE)
|
||||
.resourcePath(AdminEventPaths.authFlowPath(flowId))
|
||||
.representation(flowRep)
|
||||
.resourceType(ResourceType.AUTH_FLOW);
|
||||
return flowId;
|
||||
}
|
||||
}
|
||||
@ -15,10 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.authentication.AuthenticationFlow;
|
||||
import org.keycloak.authentication.authenticators.browser.UsernameFormFactory;
|
||||
import org.keycloak.authentication.authenticators.browser.WebAuthnAuthenticatorFactory;
|
||||
@ -29,23 +32,22 @@ import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentatio
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
import org.keycloak.testsuite.util.AssertAdminEvents;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.tests.utils.admin.ApiUtil;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
|
||||
// KEYCLOAK-7975
|
||||
@ -55,9 +57,9 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("newName", "new-browser-flow");
|
||||
Response response = authMgmtResource.copy("browser", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
try {
|
||||
Assert.assertEquals("Copy flow", 201, response.getStatus());
|
||||
Assertions.assertEquals(201, response.getStatus(), "Copy flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -65,7 +67,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// create Conditional OTP Form execution
|
||||
params.put("provider", "auth-conditional-otp-form");
|
||||
authMgmtResource.addExecution("new-browser-flow", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-browser-flow"), params, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-browser-flow"), params, ResourceType.AUTH_EXECUTION);
|
||||
|
||||
List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("new-browser-flow");
|
||||
AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider("auth-conditional-otp-form", executionReps);
|
||||
@ -108,7 +110,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
params.put("provider", "idp-review-profile");
|
||||
try {
|
||||
authMgmtResource.addExecution("browser", params);
|
||||
Assert.fail("add execution to built-in flow should fail");
|
||||
Assertions.fail("add execution to built-in flow should fail");
|
||||
} catch (BadRequestException expected) {
|
||||
// Expected
|
||||
}
|
||||
@ -116,7 +118,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// try add execution to not-existent flow
|
||||
try {
|
||||
authMgmtResource.addExecution("not-existent", params);
|
||||
Assert.fail("add execution to not-existent flow should fail");
|
||||
Assertions.fail("add execution to not-existent flow should fail");
|
||||
} catch (BadRequestException expected) {
|
||||
// Expected
|
||||
}
|
||||
@ -124,9 +126,9 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// copy built-in flow so we get a new editable flow
|
||||
params.put("newName", "Copy-of-browser");
|
||||
Response response = authMgmtResource.copy("browser", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
try {
|
||||
Assert.assertEquals("Copy flow", 201, response.getStatus());
|
||||
Assertions.assertEquals(201, response.getStatus(), "Copy flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -135,7 +137,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
params.put("provider", "test-execution");
|
||||
try {
|
||||
authMgmtResource.addExecution("CopyOfBrowser", params);
|
||||
Assert.fail("add execution with inexistent provider should fail");
|
||||
Assertions.fail("add execution with inexistent provider should fail");
|
||||
} catch(BadRequestException expected) {
|
||||
// Expected
|
||||
}
|
||||
@ -143,34 +145,34 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// add execution - should succeed
|
||||
params.put("provider", "idp-review-profile");
|
||||
authMgmtResource.addExecution("Copy-of-browser", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("Copy-of-browser"), params, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionPath("Copy-of-browser"), params, ResourceType.AUTH_EXECUTION);
|
||||
|
||||
// check execution was added
|
||||
List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("Copy-of-browser");
|
||||
AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider("idp-review-profile", executionReps);
|
||||
Assert.assertNotNull("idp-review-profile added", exec);
|
||||
Assertions.assertNotNull(exec, "idp-review-profile added");
|
||||
|
||||
// we'll need auth-cookie later
|
||||
AuthenticationExecutionInfoRepresentation authCookieExec = findExecutionByProvider("auth-cookie", executionReps);
|
||||
|
||||
AuthenticationExecutionInfoRepresentation previousExecution = findPreviousExecution(exec, executionReps);
|
||||
Assert.assertNotNull(previousExecution);
|
||||
Assertions.assertNotNull(previousExecution);
|
||||
compareExecution(newExecInfo("Review Profile", "idp-review-profile", true, 0, 5, DISABLED, null, new String[]{REQUIRED, ALTERNATIVE,DISABLED}, previousExecution.getPriority() + 1), exec);
|
||||
|
||||
// remove execution
|
||||
authMgmtResource.removeExecution(exec.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()), ResourceType.AUTH_EXECUTION);
|
||||
|
||||
// check execution was removed
|
||||
executionReps = authMgmtResource.getExecutions("Copy-of-browser");
|
||||
exec = findExecutionByProvider("idp-review-profile", executionReps);
|
||||
Assert.assertNull("idp-review-profile removed", exec);
|
||||
Assertions.assertNull(exec, "idp-review-profile removed");
|
||||
|
||||
// now add the execution again using a different method and representation
|
||||
|
||||
// delete auth-cookie
|
||||
authMgmtResource.removeExecution(authCookieExec.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authExecutionPath(authCookieExec.getId()), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authExecutionPath(authCookieExec.getId()), ResourceType.AUTH_EXECUTION);
|
||||
|
||||
AuthenticationExecutionRepresentation rep = new AuthenticationExecutionRepresentation();
|
||||
rep.setPriority(10);
|
||||
@ -180,7 +182,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// Should fail - missing parent flow
|
||||
response = authMgmtResource.addExecution(rep);
|
||||
try {
|
||||
Assert.assertEquals("added execution missing parent flow", 400, response.getStatus());
|
||||
Assertions.assertEquals(400, response.getStatus(), "added execution missing parent flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -189,7 +191,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
rep.setParentFlow("not-existent-id");
|
||||
response = authMgmtResource.addExecution(rep);
|
||||
try {
|
||||
Assert.assertEquals("added execution missing parent flow", 400, response.getStatus());
|
||||
Assertions.assertEquals(400, response.getStatus(), "added execution missing parent flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -199,7 +201,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
rep.setParentFlow(browserFlow.getId());
|
||||
response = authMgmtResource.addExecution(rep);
|
||||
try {
|
||||
Assert.assertEquals("added execution to builtin flow", 400, response.getStatus());
|
||||
Assertions.assertEquals(400, response.getStatus(), "added execution to builtin flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -210,18 +212,17 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
rep.setParentFlow(flow.getId());
|
||||
|
||||
// add execution - should succeed
|
||||
response = authMgmtResource.addExecution(rep);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authMgmtBasePath() + "/executions"), rep, ResourceType.AUTH_EXECUTION);
|
||||
try {
|
||||
Assert.assertEquals("added execution", 201, response.getStatus());
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
String createdId = ApiUtil.getCreatedId(authMgmtResource.addExecution(rep));
|
||||
AdminEventAssertion.assertSuccess(adminEvents.poll())
|
||||
.operationType(OperationType.CREATE)
|
||||
.resourcePath(AdminEventPaths.authMgmtBasePath(), "executions", createdId)
|
||||
.representation(rep)
|
||||
.resourceType(ResourceType.AUTH_EXECUTION);
|
||||
|
||||
// check execution was added
|
||||
List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions("Copy-of-browser");
|
||||
exec = findExecutionByProvider("auth-cookie", executions);
|
||||
Assert.assertNotNull("auth-cookie added", exec);
|
||||
Assertions.assertNotNull(exec, "auth-cookie added");
|
||||
|
||||
// Note: there is no checking in addExecution if requirement is one of requirementChoices
|
||||
// Thus we can have OPTIONAL which is neither ALTERNATIVE, nor DISABLED
|
||||
@ -235,14 +236,14 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("browser");
|
||||
AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider("auth-cookie", executionReps);
|
||||
|
||||
Assert.assertEquals("auth-cookie set to ALTERNATIVE", ALTERNATIVE, exec.getRequirement());
|
||||
Assert.assertEquals("auth-cookie is first in the flow", exec.getIndex(), 0);
|
||||
Assertions.assertEquals(ALTERNATIVE, exec.getRequirement(), "auth-cookie set to ALTERNATIVE");
|
||||
Assertions.assertEquals(exec.getIndex(), 0, "auth-cookie is first in the flow");
|
||||
|
||||
// switch from DISABLED to ALTERNATIVE
|
||||
exec.setRequirement(DISABLED);
|
||||
exec.setPriority(Integer.MAX_VALUE);
|
||||
authMgmtResource.updateExecutions("browser", exec);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), exec, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), exec, ResourceType.AUTH_EXECUTION);
|
||||
|
||||
// make sure the change is visible
|
||||
executionReps = authMgmtResource.getExecutions("browser");
|
||||
@ -269,12 +270,12 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
Map<String, Object> executionData = new HashMap<>();
|
||||
executionData.put("provider", ClientIdAndSecretAuthenticator.PROVIDER_ID);
|
||||
authMgmtResource.addExecution("new-client-flow", executionData);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-client-flow"), executionData, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-client-flow"), executionData, ResourceType.AUTH_EXECUTION);
|
||||
|
||||
// Check executions of not-existent flow - SHOULD FAIL
|
||||
try {
|
||||
authMgmtResource.getExecutions("not-existent");
|
||||
Assert.fail("Not expected to find executions");
|
||||
Assertions.fail("Not expected to find executions");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -282,12 +283,12 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// Check existent executions
|
||||
List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions("new-client-flow");
|
||||
AuthenticationExecutionInfoRepresentation executionRep = findExecutionByProvider(ClientIdAndSecretAuthenticator.PROVIDER_ID, executions);
|
||||
Assert.assertNotNull(executionRep);
|
||||
Assertions.assertNotNull(executionRep);
|
||||
|
||||
// Update execution with not-existent flow - SHOULD FAIL
|
||||
try {
|
||||
authMgmtResource.updateExecutions("not-existent", executionRep);
|
||||
Assert.fail("Not expected to update execution with not-existent flow");
|
||||
Assertions.fail("Not expected to update execution with not-existent flow");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -297,7 +298,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
executionRep2.setId("not-existent");
|
||||
try {
|
||||
authMgmtResource.updateExecutions("new-client-flow", executionRep2);
|
||||
Assert.fail("Not expected to update not-existent execution");
|
||||
Assertions.fail("Not expected to update not-existent execution");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -305,27 +306,23 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
// Update success
|
||||
executionRep.setRequirement(ALTERNATIVE);
|
||||
authMgmtResource.updateExecutions("new-client-flow", executionRep);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("new-client-flow"), executionRep, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("new-client-flow"), executionRep, ResourceType.AUTH_EXECUTION);
|
||||
|
||||
// Check updated
|
||||
executionRep = findExecutionByProvider(ClientIdAndSecretAuthenticator.PROVIDER_ID, authMgmtResource.getExecutions("new-client-flow"));
|
||||
Assert.assertEquals(ALTERNATIVE, executionRep.getRequirement());
|
||||
Assertions.assertEquals(ALTERNATIVE, executionRep.getRequirement());
|
||||
|
||||
// Remove execution with not-existent ID
|
||||
try {
|
||||
authMgmtResource.removeExecution("not-existent");
|
||||
Assert.fail("Didn't expect to find execution");
|
||||
Assertions.fail("Didn't expect to find execution");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Successfuly remove execution and flow
|
||||
authMgmtResource.removeExecution(executionRep.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authExecutionPath(executionRep.getId()), ResourceType.AUTH_EXECUTION);
|
||||
|
||||
AuthenticationFlowRepresentation rep = findFlowByAlias("new-client-flow", authMgmtResource.getFlows());
|
||||
authMgmtResource.deleteFlow(rep.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authFlowPath(rep.getId()), ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authExecutionPath(executionRep.getId()), ResourceType.AUTH_EXECUTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -335,31 +332,31 @@ public class ExecutionTest extends AbstractAuthenticationTest {
|
||||
|
||||
params.put("newName", newBrowserFlow);
|
||||
try (Response response = authMgmtResource.copy("browser", params)) {
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
Assert.assertEquals("Copy flow", 201, response.getStatus());
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
Assertions.assertEquals(201, response.getStatus(), "Copy flow");
|
||||
}
|
||||
|
||||
addExecutionCheckReq(newBrowserFlow, UsernameFormFactory.PROVIDER_ID, params, REQUIRED);
|
||||
addExecutionCheckReq(newBrowserFlow, WebAuthnAuthenticatorFactory.PROVIDER_ID, params, DISABLED);
|
||||
|
||||
AuthenticationFlowRepresentation rep = findFlowByAlias(newBrowserFlow, authMgmtResource.getFlows());
|
||||
Assert.assertNotNull(rep);
|
||||
Assertions.assertNotNull(rep);
|
||||
authMgmtResource.deleteFlow(rep.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authFlowPath(rep.getId()), ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authFlowPath(rep.getId()), ResourceType.AUTH_FLOW);
|
||||
}
|
||||
|
||||
private void addExecutionCheckReq(String flow, String providerID, HashMap<String, Object> params, String expectedRequirement) {
|
||||
params.put("provider", providerID);
|
||||
authMgmtResource.addExecution(flow, params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionPath(flow), params, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionPath(flow), params, ResourceType.AUTH_EXECUTION);
|
||||
|
||||
List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions(flow);
|
||||
AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider(providerID, executionReps);
|
||||
|
||||
Assert.assertNotNull(exec);
|
||||
Assert.assertEquals(expectedRequirement, exec.getRequirement());
|
||||
Assertions.assertNotNull(exec);
|
||||
Assertions.assertEquals(expectedRequirement, exec.getRequirement());
|
||||
|
||||
authMgmtResource.removeExecution(exec.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()), ResourceType.AUTH_EXECUTION);
|
||||
}
|
||||
}
|
||||
@ -15,29 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.CreatedResponseUtil;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticatorFactory;
|
||||
import org.keycloak.common.util.StreamUtil;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
import org.keycloak.testsuite.util.ContainerAssume;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.ClientErrorException;
|
||||
@ -46,6 +24,31 @@ import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.CreatedResponseUtil;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticatorFactory;
|
||||
import org.keycloak.common.util.StreamUtil;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.representations.idm.AdminEventRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
import org.keycloak.tests.utils.admin.ApiUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -56,7 +59,6 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -67,27 +69,29 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.keycloak.testsuite.util.Matchers.body;
|
||||
import static org.keycloak.testsuite.util.Matchers.statusCodeIs;
|
||||
import static org.keycloak.tests.utils.matchers.Matchers.body;
|
||||
import static org.keycloak.tests.utils.matchers.Matchers.statusCodeIs;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class FlowTest extends AbstractAuthenticationTest {
|
||||
|
||||
// KEYCLOAK-3681: Delete top flow doesn't delete all subflows
|
||||
@Test
|
||||
public void testRemoveSubflows() {
|
||||
createFlow(newFlow("Foo", "Foo flow", "generic", true, false));
|
||||
createFlow(newFlow("Foo", "Foo flow", "generic", true, false), false);
|
||||
addFlowToParent("Foo", "child");
|
||||
addFlowToParent("child", "grandchild");
|
||||
|
||||
List<AuthenticationFlowRepresentation> flows = authMgmtResource.getFlows();
|
||||
AuthenticationFlowRepresentation found = findFlowByAlias("Foo", flows);
|
||||
authMgmtResource.deleteFlow(found.getId());
|
||||
assertAdminEvents.clear();
|
||||
|
||||
createFlow(newFlow("Foo", "Foo flow", "generic", true, false));
|
||||
adminEvents.skipAll();
|
||||
|
||||
createFlow(newFlow("Foo", "Foo flow", "generic", true, false), false);
|
||||
addFlowToParent("Foo", "child");
|
||||
|
||||
// Under the old code, this would throw an error because "grandchild"
|
||||
@ -109,13 +113,11 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
.filter(r -> "child".equals(r.getDisplayName()) && r.getLevel() == 0).findAny().orElse(null);
|
||||
assertNotNull(childExececution);
|
||||
authMgmtResource.removeExecution(childExececution.getId());
|
||||
assertAdminEvents.clear();
|
||||
adminEvents.skip();
|
||||
|
||||
// check subflows were removed and can be re-created
|
||||
addFlowToParent("Foo", "child");
|
||||
addFlowToParent("child", "grandchild");
|
||||
|
||||
authMgmtResource.deleteFlow(findFlowByAlias("Foo", authMgmtResource.getFlows()).getId());
|
||||
}
|
||||
|
||||
private void addFlowToParent(String parentAlias, String childAlias) {
|
||||
@ -129,13 +131,13 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
@Test
|
||||
public void testAddFlowWithRestrictedCharInAlias() {
|
||||
Response resp = authMgmtResource.createFlow(newFlow("fo]o", "Browser flow", "basic-flow", true, false));
|
||||
Assert.assertEquals(400, resp.getStatus());
|
||||
Assertions.assertEquals(400, resp.getStatus());
|
||||
|
||||
try {
|
||||
CreatedResponseUtil.getCreatedId(resp);
|
||||
Assert.fail("Not expected getCreatedId to success");
|
||||
Assertions.fail("Not expected getCreatedId to success");
|
||||
} catch (WebApplicationException wae) {
|
||||
Assert.assertThat(wae.getMessage(), endsWith("Error: Character ']' not allowed."));
|
||||
MatcherAssert.assertThat(wae.getMessage(), endsWith("Error: Character ']' not allowed."));
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,19 +147,19 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
// test that built-in flow cannot be deleted
|
||||
List<AuthenticationFlowRepresentation> flows = authMgmtResource.getFlows();
|
||||
AuthenticationFlowRepresentation builtInFlow = flows.stream().filter(AuthenticationFlowRepresentation::isBuiltIn).findAny().orElse(null);
|
||||
Assert.assertNotNull("No built in flow in the realm", builtInFlow);
|
||||
Assertions.assertNotNull(builtInFlow, "No built in flow in the realm");
|
||||
try {
|
||||
authMgmtResource.deleteFlow(builtInFlow.getId());
|
||||
Assert.fail("deleteFlow should fail for built in flow");
|
||||
Assertions.fail("deleteFlow should fail for built in flow");
|
||||
} catch (BadRequestException e) {
|
||||
OAuth2ErrorRepresentation error = e.getResponse().readEntity(OAuth2ErrorRepresentation.class);
|
||||
Assert.assertEquals("Can't delete built in flow", error.getError());
|
||||
Assertions.assertEquals("Can't delete built in flow", error.getError());
|
||||
}
|
||||
|
||||
// try create new flow using alias of already existing flow
|
||||
Response response = authMgmtResource.createFlow(newFlow("browser", "Browser flow", "basic-flow", true, false));
|
||||
try {
|
||||
Assert.assertEquals("createFlow using the alias of existing flow should fail", 409, response.getStatus());
|
||||
Assertions.assertEquals(409, response.getStatus(), "createFlow using the alias of existing flow should fail");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -165,7 +167,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
// try create flow without alias
|
||||
response = authMgmtResource.createFlow(newFlow(null, "Browser flow", "basic-flow", true, false));
|
||||
try {
|
||||
Assert.assertEquals("createFlow using the alias of existing flow should fail", 409, response.getStatus());
|
||||
Assertions.assertEquals(409, response.getStatus(), "createFlow using the alias of existing flow should fail");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -173,26 +175,26 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
|
||||
// create new flow that should succeed
|
||||
AuthenticationFlowRepresentation newFlow = newFlow("browser-2", "Browser flow", "basic-flow", true, false);
|
||||
createFlow(newFlow);
|
||||
createFlow(newFlow, false);
|
||||
|
||||
// check that new flow is returned in a children list
|
||||
flows = authMgmtResource.getFlows();
|
||||
AuthenticationFlowRepresentation found = findFlowByAlias("browser-2", flows);
|
||||
|
||||
Assert.assertNotNull("created flow visible in parent", found);
|
||||
Assertions.assertNotNull(found, "created flow visible in parent");
|
||||
compareFlows(newFlow, found);
|
||||
|
||||
// check lookup flow with unexistent ID
|
||||
try {
|
||||
authMgmtResource.getFlow("id-123-notExistent");
|
||||
Assert.fail("Not expected to find unexistent flow");
|
||||
Assertions.fail("Not expected to find unexistent flow");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// check that new flow is returned individually
|
||||
AuthenticationFlowRepresentation found2 = authMgmtResource.getFlow(found.getId());
|
||||
Assert.assertNotNull("created flow visible directly", found2);
|
||||
Assertions.assertNotNull(found2, "created flow visible directly");
|
||||
compareFlows(newFlow, found2);
|
||||
|
||||
|
||||
@ -214,7 +216,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
// inexistent parent flow - should fail
|
||||
try {
|
||||
authMgmtResource.addExecutionFlow("inexistent-parent-flow-alias", data);
|
||||
Assert.fail("addExecutionFlow for inexistent parent should have failed");
|
||||
Assertions.fail("addExecutionFlow for inexistent parent should have failed");
|
||||
} catch (Exception expected) {
|
||||
// Expected
|
||||
}
|
||||
@ -223,7 +225,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
try {
|
||||
data.put("alias", "browser");
|
||||
authMgmtResource.addExecutionFlow("browser-2", data);
|
||||
Assert.fail("addExecutionFlow should have failed as browser flow already exists");
|
||||
Assertions.fail("addExecutionFlow should have failed as browser flow already exists");
|
||||
} catch (Exception expected) {
|
||||
// Expected
|
||||
}
|
||||
@ -232,17 +234,17 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
data.put("alias", "SomeFlow");
|
||||
authMgmtResource.addExecutionFlow("browser-2", data);
|
||||
authMgmtResource.addExecutionFlow("browser-2", data2);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data2, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data2, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
// check that new flow is returned in a children list
|
||||
flows = authMgmtResource.getFlows();
|
||||
found2 = findFlowByAlias("browser-2", flows);
|
||||
Assert.assertNotNull("created flow visible in parent", found2);
|
||||
Assertions.assertNotNull(found2, "created flow visible in parent");
|
||||
|
||||
List<AuthenticationExecutionExportRepresentation> execs = found2.getAuthenticationExecutions();
|
||||
Assert.assertNotNull(execs);
|
||||
Assert.assertEquals("Size two", 2, execs.size());
|
||||
Assertions.assertNotNull(execs);
|
||||
Assertions.assertEquals(2, execs.size(), "Size two");
|
||||
|
||||
AuthenticationExecutionExportRepresentation expected = new AuthenticationExecutionExportRepresentation();
|
||||
expected.setFlowAlias("SomeFlow");
|
||||
@ -263,17 +265,17 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
|
||||
// delete non-built-in flow
|
||||
authMgmtResource.deleteFlow(found.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authFlowPath(found.getId()), ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authFlowPath(found.getId()), ResourceType.AUTH_FLOW);
|
||||
|
||||
// check the deleted flow is no longer returned
|
||||
flows = authMgmtResource.getFlows();
|
||||
found = findFlowByAlias("browser-2", flows);
|
||||
Assert.assertNull("flow deleted", found);
|
||||
Assertions.assertNull(found, "flow deleted");
|
||||
|
||||
// Check deleting flow second time will fail
|
||||
try {
|
||||
authMgmtResource.deleteFlow("id-123-notExistent");
|
||||
Assert.fail("Not expected to delete flow, which doesn't exist");
|
||||
Assertions.fail("Not expected to delete flow, which doesn't exist");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -287,10 +289,10 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
Runnable assertRemoveFail = () -> {
|
||||
try {
|
||||
authMgmtResource.deleteFlow(flowId);
|
||||
Assert.fail("Not expected to delete flow that is in use.");
|
||||
Assertions.fail("Not expected to delete flow that is in use.");
|
||||
} catch (WebApplicationException e) {
|
||||
OAuth2ErrorRepresentation error = e.getResponse().readEntity(OAuth2ErrorRepresentation.class);
|
||||
Assert.assertEquals("For more on this error consult the server log.", error.getErrorDescription());
|
||||
Assertions.assertEquals("For more on this error consult the server log.", error.getErrorDescription());
|
||||
}
|
||||
};
|
||||
|
||||
@ -347,9 +349,9 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
idp.setProviderId("oidc");
|
||||
|
||||
Response response = realmResource.identityProviders().create(idp);
|
||||
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||
Assertions.assertNotNull(ApiUtil.getCreatedId(response));
|
||||
response.close();
|
||||
getCleanup().addIdentityProviderAlias(idp.getAlias());
|
||||
managedRealm.cleanup().add(r -> r.identityProviders().get(idp.getAlias()).remove());
|
||||
|
||||
IdentityProviderResource idpResource = realmResource.identityProviders().get("idp");
|
||||
BiConsumer<Supplier<String>, Consumer<String>> assertRemoveFailByIdp =
|
||||
@ -399,7 +401,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
// copy that should succeed
|
||||
params.put("newName", "Copy of browser");
|
||||
response = authMgmtResource.copy("browser", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
try {
|
||||
assertThat("Copy flow", response, statusCodeIs(Status.CREATED));
|
||||
} finally {
|
||||
@ -411,8 +413,8 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
AuthenticationFlowRepresentation browser = findFlowByAlias("browser", flows);
|
||||
AuthenticationFlowRepresentation copyOfBrowser = findFlowByAlias("Copy of browser", flows);
|
||||
|
||||
Assert.assertNotNull(browser);
|
||||
Assert.assertNotNull(copyOfBrowser);
|
||||
Assertions.assertNotNull(browser);
|
||||
Assertions.assertNotNull(copyOfBrowser);
|
||||
|
||||
// adjust expected values before comparing
|
||||
browser.setAlias("Copy of browser");
|
||||
@ -423,7 +425,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
|
||||
// get new flow directly and compare
|
||||
copyOfBrowser = authMgmtResource.getFlow(copyOfBrowser.getId());
|
||||
Assert.assertNotNull(copyOfBrowser);
|
||||
Assertions.assertNotNull(copyOfBrowser);
|
||||
compareFlows(browser, copyOfBrowser);
|
||||
authMgmtResource.deleteFlow(copyOfBrowser.getId());
|
||||
}
|
||||
@ -434,9 +436,9 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("newName", "parent");
|
||||
Response response = authMgmtResource.copy("browser", params);
|
||||
Assert.assertEquals(201, response.getStatus());
|
||||
Assertions.assertEquals(201, response.getStatus());
|
||||
response.close();
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
|
||||
params = new HashMap<>();
|
||||
params.put("alias", "child");
|
||||
@ -445,7 +447,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
params.put("type", "basic-flow");
|
||||
|
||||
authMgmtResource.addExecutionFlow("parent", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("parent"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("parent"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
authMgmtResource.deleteFlow(findFlowByAlias("parent", authMgmtResource.getFlows()).getId());
|
||||
}
|
||||
@ -460,9 +462,9 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("newName", "Copy of browser");
|
||||
Response response = authMgmtResource.copy("browser", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
try {
|
||||
Assert.assertEquals("Copy flow", 201, response.getStatus());
|
||||
Assertions.assertEquals(201, response.getStatus(), "Copy flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -473,9 +475,9 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
//Set a new unique name. Should succeed
|
||||
testFlow.setAlias("Copy of browser2");
|
||||
authMgmtResource.updateFlow(testFlow.getId(), testFlow);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authEditFlowPath(testFlow.getId()), ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authEditFlowPath(testFlow.getId()), ResourceType.AUTH_FLOW);
|
||||
flows = authMgmtResource.getFlows();
|
||||
Assert.assertEquals("Copy of browser2", findFlowByAlias("Copy of browser2", flows).getAlias());
|
||||
Assertions.assertEquals("Copy of browser2", findFlowByAlias("Copy of browser2", flows).getAlias());
|
||||
|
||||
//Create new flow and edit the old one to have the new ones name
|
||||
AuthenticationFlowRepresentation newFlow = newFlow("New Flow", "Test description", "basic-flow", true, false);
|
||||
@ -484,7 +486,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
flows = authMgmtResource.getFlows();
|
||||
AuthenticationFlowRepresentation found = findFlowByAlias("New Flow", flows);
|
||||
|
||||
Assert.assertNotNull("created flow visible in parent", found);
|
||||
Assertions.assertNotNull(found, "created flow visible in parent");
|
||||
compareFlows(newFlow, found);
|
||||
|
||||
//try to update old flow with alias that already exists
|
||||
@ -506,15 +508,15 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
flows = authMgmtResource.getFlows();
|
||||
|
||||
//name should be the same for the old Flow
|
||||
Assert.assertEquals("Copy of browser2", findFlowByAlias("Copy of browser2", flows).getAlias());
|
||||
Assertions.assertEquals("Copy of browser2", findFlowByAlias("Copy of browser2", flows).getAlias());
|
||||
|
||||
//Only update the description
|
||||
found.setDescription("New description");
|
||||
authMgmtResource.updateFlow(found.getId(), found);
|
||||
flows = authMgmtResource.getFlows();
|
||||
|
||||
Assert.assertEquals("New description", findFlowByAlias("New Flow", flows).getDescription());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authEditFlowPath(found.getId()), ResourceType.AUTH_FLOW);
|
||||
Assertions.assertEquals("New description", findFlowByAlias("New Flow", flows).getDescription());
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authEditFlowPath(found.getId()), ResourceType.AUTH_FLOW);
|
||||
|
||||
//Update name and description
|
||||
found.setAlias("New Flow2");
|
||||
@ -522,13 +524,12 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
authMgmtResource.updateFlow(found.getId(), found);
|
||||
flows = authMgmtResource.getFlows();
|
||||
|
||||
Assert.assertEquals("New Flow2", findFlowByAlias("New Flow2", flows).getAlias());
|
||||
Assert.assertEquals("New description2", findFlowByAlias("New Flow2", flows).getDescription());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authEditFlowPath(found.getId()), ResourceType.AUTH_FLOW);
|
||||
Assert.assertNull(findFlowByAlias("New Flow", flows));
|
||||
Assertions.assertEquals("New Flow2", findFlowByAlias("New Flow2", flows).getAlias());
|
||||
Assertions.assertEquals("New description2", findFlowByAlias("New Flow2", flows).getDescription());
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authEditFlowPath(found.getId()), ResourceType.AUTH_FLOW);
|
||||
Assertions.assertNull(findFlowByAlias("New Flow", flows));
|
||||
|
||||
authMgmtResource.deleteFlow(testFlow.getId());
|
||||
authMgmtResource.deleteFlow(found.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -546,7 +547,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
params.put("type", "basic-flow");
|
||||
|
||||
authMgmtResource.addExecutionFlow("Parent-Flow", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
executionReps = authMgmtResource.getExecutions("Parent-Flow");
|
||||
|
||||
@ -559,7 +560,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
|
||||
try {
|
||||
authMgmtResource.addExecutionFlow("Parent-Flow", params);
|
||||
Assert.fail("addExecutionFlow the alias already exist");
|
||||
Assertions.fail("addExecutionFlow the alias already exist");
|
||||
} catch (Exception expected) {
|
||||
// Expected
|
||||
}
|
||||
@ -578,19 +579,19 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
found.setDescription("This is another child flow2");
|
||||
|
||||
authMgmtResource.updateExecutions("Parent-Flow", found);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("Parent-Flow"), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("Parent-Flow"), ResourceType.AUTH_EXECUTION);
|
||||
executionReps = authMgmtResource.getExecutions("Parent-Flow");
|
||||
Assert.assertEquals("Child-Flow2", executionReps.get(0).getDisplayName());
|
||||
Assert.assertEquals("This is another child flow2", executionReps.get(0).getDescription());
|
||||
Assertions.assertEquals("Child-Flow2", executionReps.get(0).getDisplayName());
|
||||
Assertions.assertEquals("This is another child flow2", executionReps.get(0).getDescription());
|
||||
|
||||
//edit only description
|
||||
found.setDescription("This is another child flow3");
|
||||
authMgmtResource.updateExecutions("Parent-Flow", found);
|
||||
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("Parent-Flow"), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("Parent-Flow"), ResourceType.AUTH_EXECUTION);
|
||||
executionReps = authMgmtResource.getExecutions("Parent-Flow");
|
||||
Assert.assertEquals("Child-Flow2", executionReps.get(0).getDisplayName());
|
||||
Assert.assertEquals("This is another child flow3", executionReps.get(0).getDescription());
|
||||
Assertions.assertEquals("Child-Flow2", executionReps.get(0).getDisplayName());
|
||||
Assertions.assertEquals("This is another child flow3", executionReps.get(0).getDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -607,7 +608,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
params.put("priority", 50);
|
||||
|
||||
authMgmtResource.addExecutionFlow("Parent-Flow", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
params.clear();
|
||||
params.put("alias", "Child-Flow2");
|
||||
@ -617,7 +618,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
params.put("priority", 10);
|
||||
|
||||
authMgmtResource.addExecutionFlow("Parent-Flow", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
params.clear();
|
||||
params.put("alias", "Child-Flow3");
|
||||
@ -627,16 +628,16 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
params.put("priority", 20);
|
||||
|
||||
authMgmtResource.addExecutionFlow("Parent-Flow", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("Parent-Flow"), params, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("Parent-Flow");
|
||||
// Verify the initial order and priority value
|
||||
Assert.assertEquals("Child-Flow2", executionReps.get(0).getDisplayName());
|
||||
Assert.assertEquals(10, executionReps.get(0).getPriority());
|
||||
Assert.assertEquals("Child-Flow3", executionReps.get(1).getDisplayName());
|
||||
Assert.assertEquals(20, executionReps.get(1).getPriority());
|
||||
Assert.assertEquals("Child-Flow1", executionReps.get(2).getDisplayName());
|
||||
Assert.assertEquals(50, executionReps.get(2).getPriority());
|
||||
Assertions.assertEquals("Child-Flow2", executionReps.get(0).getDisplayName());
|
||||
Assertions.assertEquals(10, executionReps.get(0).getPriority());
|
||||
Assertions.assertEquals("Child-Flow3", executionReps.get(1).getDisplayName());
|
||||
Assertions.assertEquals(20, executionReps.get(1).getPriority());
|
||||
Assertions.assertEquals("Child-Flow1", executionReps.get(2).getDisplayName());
|
||||
Assertions.assertEquals(50, executionReps.get(2).getPriority());
|
||||
|
||||
// Move last execution to the beginning
|
||||
AuthenticationExecutionInfoRepresentation lastToFirst = executionReps.get(2);
|
||||
@ -645,24 +646,18 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
executionReps = authMgmtResource.getExecutions("Parent-Flow");
|
||||
|
||||
// Verify new order and priority
|
||||
Assert.assertEquals("Child-Flow1", executionReps.get(0).getDisplayName());
|
||||
Assert.assertEquals(5, executionReps.get(0).getPriority());
|
||||
Assert.assertEquals("Child-Flow2", executionReps.get(1).getDisplayName());
|
||||
Assert.assertEquals(10, executionReps.get(1).getPriority());
|
||||
Assert.assertEquals("Child-Flow3", executionReps.get(2).getDisplayName());
|
||||
Assert.assertEquals(20, executionReps.get(2).getPriority());
|
||||
Assertions.assertEquals("Child-Flow1", executionReps.get(0).getDisplayName());
|
||||
Assertions.assertEquals(5, executionReps.get(0).getPriority());
|
||||
Assertions.assertEquals("Child-Flow2", executionReps.get(1).getDisplayName());
|
||||
Assertions.assertEquals(10, executionReps.get(1).getPriority());
|
||||
Assertions.assertEquals("Child-Flow3", executionReps.get(2).getDisplayName());
|
||||
Assertions.assertEquals(20, executionReps.get(2).getPriority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failWithLongDescription() throws IOException {
|
||||
ContainerAssume.assumeAuthServerQuarkus();
|
||||
AuthenticationFlowRepresentation rep = authMgmtResource.getFlows().stream()
|
||||
.filter(new Predicate<AuthenticationFlowRepresentation>() {
|
||||
@Override
|
||||
public boolean test(AuthenticationFlowRepresentation rep) {
|
||||
return "docker auth".equals(rep.getAlias());
|
||||
}
|
||||
}).findAny().orElse(null);
|
||||
.filter(rep1 -> "docker auth".equals(rep1.getAlias())).findAny().orElse(null);
|
||||
|
||||
assertNotNull(rep);
|
||||
|
||||
@ -692,27 +687,27 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
// get a built in flow
|
||||
List<AuthenticationFlowRepresentation> flows = authMgmtResource.getFlows();
|
||||
AuthenticationFlowRepresentation flow = flows.stream().filter(AuthenticationFlowRepresentation::isBuiltIn).findFirst().orElse(null);
|
||||
Assert.assertNotNull("There is no builtin flow", flow);
|
||||
Assertions.assertNotNull(flow, "There is no builtin flow");
|
||||
|
||||
// adding an execution should fail
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("provider", "allow-access-authenticator");
|
||||
BadRequestException e = Assert.assertThrows(BadRequestException.class, () -> authMgmtResource.addExecution(flow.getAlias(), data));
|
||||
BadRequestException e = Assertions.assertThrows(BadRequestException.class, () -> authMgmtResource.addExecution(flow.getAlias(), data));
|
||||
OAuth2ErrorRepresentation error = e.getResponse().readEntity(OAuth2ErrorRepresentation.class);
|
||||
Assert.assertEquals("It is illegal to add execution to a built in flow", error.getError());
|
||||
Assertions.assertEquals("It is illegal to add execution to a built in flow", error.getError());
|
||||
|
||||
// adding a sub-flow should fail as well
|
||||
e = Assert.assertThrows(BadRequestException.class, () -> addFlowToParent(flow.getAlias(), "child"));
|
||||
e = Assertions.assertThrows(BadRequestException.class, () -> addFlowToParent(flow.getAlias(), "child"));
|
||||
error = e.getResponse().readEntity(OAuth2ErrorRepresentation.class);
|
||||
Assert.assertEquals("It is illegal to add sub-flow to a built in flow", error.getError());
|
||||
Assertions.assertEquals("It is illegal to add sub-flow to a built in flow", error.getError());
|
||||
|
||||
// removing any execution (execution or flow) should fail too
|
||||
List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions(flow.getAlias());
|
||||
Assert.assertNotNull("The builtin flow has no executions", executions);
|
||||
Assert.assertFalse("The builtin flow has no executions", executions.isEmpty());
|
||||
e = Assert.assertThrows(BadRequestException.class, () -> authMgmtResource.removeExecution(executions.get(0).getId()));
|
||||
Assertions.assertNotNull(executions, "The builtin flow has no executions");
|
||||
Assertions.assertFalse(executions.isEmpty(), "The builtin flow has no executions");
|
||||
e = Assertions.assertThrows(BadRequestException.class, () -> authMgmtResource.removeExecution(executions.get(0).getId()));
|
||||
error = e.getResponse().readEntity(OAuth2ErrorRepresentation.class);
|
||||
Assert.assertEquals("It is illegal to remove execution from a built in flow", error.getError());
|
||||
Assertions.assertEquals("It is illegal to remove execution from a built in flow", error.getError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -725,7 +720,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertNotNull(existingFlow);
|
||||
Assertions.assertNotNull(existingFlow);
|
||||
|
||||
List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions(existingFlow.getAlias());
|
||||
AuthenticationExecutionInfoRepresentation executionWithConfig = null;
|
||||
@ -736,7 +731,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertNotNull(executionWithConfig);
|
||||
Assertions.assertNotNull(executionWithConfig);
|
||||
|
||||
AuthenticatorConfigRepresentation executionConfig = new AuthenticatorConfigRepresentation();
|
||||
|
||||
@ -744,14 +739,14 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
executionConfig.setConfig(Map.of("key", "value"));
|
||||
|
||||
try (Response response = authMgmtResource.newExecutionConfig(executionWithConfig.getId(), executionConfig)) {
|
||||
getCleanup().addAuthenticationConfigId(ApiUtil.getCreatedId(response));
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionConfigPath(executionWithConfig.getId()), executionConfig, ResourceType.AUTHENTICATOR_CONFIG);
|
||||
managedRealm.cleanup().add(r -> r.flows().removeAuthenticatorConfig(ApiUtil.getCreatedId(response)));
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionConfigPath(executionWithConfig.getId()), executionConfig, ResourceType.AUTHENTICATOR_CONFIG);
|
||||
}
|
||||
|
||||
String newFlowName = "Duplicated of " + DefaultAuthenticationFlows.BROWSER_FLOW;
|
||||
Map<String, Object> copyFlowParams = Map.of("newName", newFlowName);
|
||||
authMgmtResource.copy(existingFlow.getAlias(), copyFlowParams).close();
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), copyFlowParams, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), copyFlowParams, ResourceType.AUTH_FLOW);
|
||||
|
||||
AuthenticationFlowRepresentation newFlow = null;
|
||||
|
||||
@ -776,7 +771,7 @@ public class FlowTest extends AbstractAuthenticationTest {
|
||||
assertFalse(newExecutionConfigIds.isEmpty());
|
||||
|
||||
for (String executionConfigId : newExecutionConfigIds) {
|
||||
Assert.assertFalse("Execution config not duplicated", existingExecutionConfigIds.contains(executionConfigId));
|
||||
Assertions.assertFalse(existingExecutionConfigIds.contains(executionConfigId), "Execution config not duplicated");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,15 +15,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.testsuite.util.KerberosUtils;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.tests.utils.KerberosUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -35,6 +36,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class InitialFlowsTest extends AbstractAuthenticationTest {
|
||||
|
||||
private HashMap<String, AuthenticatorConfigRepresentation> configs = new HashMap<>();
|
||||
@ -85,7 +87,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
|
||||
|
||||
|
||||
private void compareExecutionsInfo(List<AuthenticationExecutionInfoRepresentation> expected, List<AuthenticationExecutionInfoRepresentation> actual) {
|
||||
Assert.assertEquals("Executions count", expected.size(), actual.size());
|
||||
Assertions.assertEquals(expected.size(), actual.size(), "Executions count");
|
||||
Iterator<AuthenticationExecutionInfoRepresentation> it1 = expected.iterator();
|
||||
Iterator<AuthenticationExecutionInfoRepresentation> it2 = actual.iterator();
|
||||
while (it1.hasNext()) {
|
||||
@ -108,8 +110,8 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
|
||||
if (cfg1 == null && cfg2 == null) {
|
||||
return;
|
||||
}
|
||||
Assert.assertEquals("Execution configuration alias", cfg1.getAlias(), cfg2.getAlias());
|
||||
Assert.assertEquals("Execution configuration params", cfg1.getConfig(), cfg2.getConfig());
|
||||
Assertions.assertEquals(cfg1.getAlias(), cfg2.getAlias(), "Execution configuration alias");
|
||||
Assertions.assertEquals(cfg1.getConfig(), cfg2.getConfig(), "Execution configuration params");
|
||||
}
|
||||
|
||||
private List<FlowExecutions> orderAlphabetically(List<FlowExecutions> result) {
|
||||
@ -15,20 +15,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import org.junit.Test;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
|
||||
import org.keycloak.authentication.forms.RegistrationRecaptcha;
|
||||
import org.keycloak.authentication.forms.RegistrationRecaptchaEnterprise;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigInfoRepresentation;
|
||||
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.ProfileAssume;
|
||||
import org.keycloak.testsuite.util.KerberosUtils;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.tests.utils.Assert;
|
||||
import org.keycloak.tests.utils.KerberosUtils;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@ -37,25 +37,26 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
|
||||
@Test
|
||||
public void testFormProviders() {
|
||||
List<Map<String, Object>> result = authMgmtResource.getFormProviders();
|
||||
|
||||
Assert.assertNotNull("null result", result);
|
||||
Assert.assertEquals("size", 1, result.size());
|
||||
Assertions.assertNotNull(result, "null result");
|
||||
Assertions.assertEquals(1, result.size(), "size");
|
||||
Map<String, Object> item = result.get(0);
|
||||
|
||||
Assert.assertEquals("id", "registration-page-form", item.get("id"));
|
||||
Assert.assertEquals("displayName", "Registration Page", item.get("displayName"));
|
||||
Assert.assertEquals("description", "This is the controller for the registration page", item.get("description"));
|
||||
Assertions.assertEquals("registration-page-form", item.get("id"), "id");
|
||||
Assertions.assertEquals("Registration Page", item.get("displayName"), "displayName");
|
||||
Assertions.assertEquals("This is the controller for the registration page", item.get("description"), "description");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -85,12 +86,6 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
"Validates client based on signed JWT issued by client and signed with the Client private key", false);
|
||||
addClientAuthenticatorProviderInfo(expected, "client-secret", "Client Id and Secret", "Validates client based on 'client_id' and " +
|
||||
"'client_secret' sent either in request parameters or in 'Authorization: Basic' header", true);
|
||||
addClientAuthenticatorProviderInfo(expected, "testsuite-client-id-required", "Signed Jwt", "Validates client based on signed JWT issued by client " +
|
||||
"and signed with the Client private key", false);
|
||||
addClientAuthenticatorProviderInfo(expected, "testsuite-client-passthrough", "Testsuite Dummy Client Validation", "Testsuite dummy authenticator, " +
|
||||
"which automatically authenticates hardcoded client (like 'test-app' )", false);
|
||||
addClientAuthenticatorProviderInfo(expected, "testsuite-client-dummy", "Testsuite ClientId Dummy",
|
||||
"Dummy client authenticator, which authenticates the client with clientId only", false);
|
||||
addClientAuthenticatorProviderInfo(expected, "client-x509", "X509 Certificate",
|
||||
"Validates client based on a X509 Certificate", false);
|
||||
addClientAuthenticatorProviderInfo(expected, "client-secret-jwt", "Signed Jwt with Client Secret",
|
||||
@ -102,16 +97,10 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
@Test
|
||||
public void testPerClientConfigDescriptions() {
|
||||
Map<String, List<ConfigPropertyRepresentation>> configs = authMgmtResource.getPerClientConfigDescription();
|
||||
Assert.assertTrue(configs.containsKey("client-jwt"));
|
||||
Assert.assertTrue(configs.containsKey("client-secret"));
|
||||
Assert.assertTrue(configs.containsKey("testsuite-client-passthrough"));
|
||||
Assert.assertTrue(configs.get("client-jwt").isEmpty());
|
||||
Assert.assertTrue(configs.get("client-secret").isEmpty());
|
||||
List<ConfigPropertyRepresentation> cfg = configs.get("testsuite-client-passthrough");
|
||||
Assert.assertProviderConfigProperty(cfg.get(0), "passthroughauth.foo", "Foo Property", null,
|
||||
"Foo Property of this authenticator, which does nothing", "String");
|
||||
Assert.assertProviderConfigProperty(cfg.get(1), "passthroughauth.bar", "Bar Property", null,
|
||||
"Bar Property of this authenticator, which does nothing", "boolean");
|
||||
Assertions.assertTrue(configs.containsKey("client-jwt"));
|
||||
Assertions.assertTrue(configs.containsKey("client-secret"));
|
||||
Assertions.assertTrue(configs.get("client-jwt").isEmpty());
|
||||
Assertions.assertTrue(configs.get("client-secret").isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -119,16 +108,16 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
// Try some not-existent provider
|
||||
try {
|
||||
authMgmtResource.getAuthenticatorConfigDescription("not-existent");
|
||||
Assert.fail("Don't expected to find provider 'not-existent'");
|
||||
Assertions.fail("Don't expected to find provider 'not-existent'");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
AuthenticatorConfigInfoRepresentation infoRep = authMgmtResource.getAuthenticatorConfigDescription(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID);
|
||||
Assert.assertEquals("Create User If Unique", infoRep.getName());
|
||||
Assert.assertEquals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, infoRep.getProviderId());
|
||||
Assert.assertEquals("Detect if there is existing Keycloak account with same email like identity provider. If no, create new user", infoRep.getHelpText());
|
||||
Assert.assertEquals(1, infoRep.getProperties().size());
|
||||
Assertions.assertEquals("Create User If Unique", infoRep.getName());
|
||||
Assertions.assertEquals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, infoRep.getProviderId());
|
||||
Assertions.assertEquals("Detect if there is existing Keycloak account with same email like identity provider. If no, create new user", infoRep.getHelpText());
|
||||
Assertions.assertEquals(1, infoRep.getProperties().size());
|
||||
Assert.assertProviderConfigProperty(infoRep.getProperties().get(0), "require.password.update.after.registration", "Require Password Update After Registration",
|
||||
null, "If this option is true and new user is successfully imported from Identity Provider to Keycloak (there is no duplicated email or username detected in Keycloak DB), then this user is required to update his password",
|
||||
"boolean");
|
||||
@ -147,9 +136,6 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
"Validates a OTP on a separate OTP form. Only shown if required based on the configured conditions.");
|
||||
addProviderInfo(result, "auth-cookie", "Cookie", "Validates the SSO cookie set by the auth server.");
|
||||
addProviderInfo(result, "auth-otp-form", "OTP Form", "Validates a OTP on a separate OTP form.");
|
||||
if (ProfileAssume.isFeatureEnabled(Profile.Feature.SCRIPTS)) {
|
||||
addProviderInfo(result, "auth-script-based", "Script", "Script based authentication. Allows to define custom authentication logic via JavaScript.");
|
||||
}
|
||||
String kerberosHelpMessage = (KerberosUtils.isKerberosSupportExpected())
|
||||
? "Initiates the SPNEGO protocol. Most often used with Kerberos."
|
||||
: "DISABLED. Please enable Kerberos feature and make sure Kerberos available in your platform. Initiates the SPNEGO protocol. Most often used with Kerberos.";
|
||||
@ -166,8 +152,6 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
addProviderInfo(result, "direct-grant-validate-username", "Username Validation",
|
||||
"Validates the username supplied as a 'username' form parameter in direct grant request");
|
||||
addProviderInfo(result, "docker-http-basic-authenticator", "Docker Authenticator", "Uses HTTP Basic authentication to validate docker users, returning a docker error token on auth failure");
|
||||
addProviderInfo(result, "expected-param-authenticator", "TEST: Expected Parameter",
|
||||
"You will be approved if you send query string parameter 'foo' with expected value.");
|
||||
addProviderInfo(result, "http-basic-authenticator", "HTTP Basic Authentication", "Validates username and password from Authorization HTTP header");
|
||||
addProviderInfo(result, "identity-provider-redirector", "Identity Provider Redirector", "Redirects to default Identity Provider or Identity Provider specified with kc_idp_hint query parameter");
|
||||
addProviderInfo(result, "idp-auto-link", "Automatically set existing user", "Automatically set existing user to authentication context without any verification");
|
||||
@ -182,24 +166,11 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
"User reviews and updates profile data retrieved from Identity Provider in the displayed form");
|
||||
addProviderInfo(result, "idp-username-password-form", "Username Password Form for identity provider reauthentication",
|
||||
"Validates a password from login form. Username may be already known from identity provider authentication");
|
||||
addProviderInfo(result, "push-button-authenticator", "TEST: Button Login",
|
||||
"Just press the button to login.");
|
||||
addProviderInfo(result, "reset-credential-email", "Send Reset Email", "Send email to user and wait for response.");
|
||||
addProviderInfo(result, "reset-credentials-choose-user", "Choose User", "Choose a user to reset credentials for");
|
||||
addProviderInfo(result, "reset-otp", "Reset OTP", "Removes existing OTP configurations (if chosen) and sets the 'Configure OTP' required action.");
|
||||
addProviderInfo(result, "reset-password", "Reset Password", "Sets the Update Password required action if execution is REQUIRED. " +
|
||||
"Will also set it if execution is OPTIONAL and the password is currently configured for it.");
|
||||
addProviderInfo(result, "testsuite-dummy-click-through", "Testsuite Dummy Click Thru",
|
||||
"Testsuite Dummy authenticator. User needs to click through the page to continue.");
|
||||
addProviderInfo(result, "testsuite-dummy-passthrough", "Testsuite Dummy Pass Thru",
|
||||
"Testsuite Dummy authenticator. Just passes through and is hardcoded to a specific user");
|
||||
addProviderInfo(result, "testsuite-dummy-registration", "Testsuite Dummy Pass Thru",
|
||||
"Testsuite Dummy authenticator. Just passes through and is hardcoded to a specific user");
|
||||
addProviderInfo(result, "set-client-note-authenticator", "Set Client Note Authenticator", "Set client note of specified name with the specified value to the authenticationSession.");
|
||||
addProviderInfo(result, "testsuite-username", "Testsuite Username Only",
|
||||
"Testsuite Username authenticator. Username parameter sets username");
|
||||
addProviderInfo(result, "test-suite-fire-error-event", "Fire Error Event",
|
||||
"Testsuite Error event firer authenticator.");
|
||||
addProviderInfo(result, "webauthn-authenticator", "WebAuthn Authenticator", "Authenticator for WebAuthn. Usually used for WebAuthn two-factor authentication");
|
||||
addProviderInfo(result, "webauthn-authenticator-passwordless", "WebAuthn Passwordless Authenticator", "Authenticator for Passwordless WebAuthn authentication");
|
||||
|
||||
@ -213,8 +184,6 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
"Executes the current flow only if authenticators are configured");
|
||||
addProviderInfo(result, "conditional-user-attribute", "Condition - user attribute",
|
||||
"Flow is executed only if the user attribute exists and has the expected value");
|
||||
addProviderInfo(result, "set-attribute", "Set user attribute",
|
||||
"Set a user attribute");
|
||||
addProviderInfo(result, "idp-detect-existing-broker-user", "Detect existing broker user",
|
||||
"Detect if there is an existing Keycloak account with same email like identity provider. If no, throw an error.");
|
||||
|
||||
@ -229,9 +198,6 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
addProviderInfo(result, "user-session-limits", "User session count limiter",
|
||||
"Configures how many concurrent sessions a single user is allowed to create for this realm and/or client");
|
||||
|
||||
addProviderInfo(result, "custom-callback-authenticator", "Custom callback Factory",
|
||||
"Used for testing purposes of Callback factory");
|
||||
|
||||
addProviderInfo(result, "idp-add-organization-member", "Organization Member Onboard", "Adds a federated user as a member of an organization");
|
||||
addProviderInfo(result, "organization", "Organization Identity-First Login", "If organizations are enabled, automatically redirects users to the corresponding identity provider.");
|
||||
addProviderInfo(result, "conditional-sub-flow-executed", "Condition - sub-flow executed", "Condition to evaluate if a sub-flow was executed successfully during the authentication process");
|
||||
@ -247,7 +213,7 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
||||
}
|
||||
|
||||
private void compareProviders(List<Map<String, Object>> expected, List<Map<String, Object>> actual) {
|
||||
Assert.assertEquals("Providers count", expected.size(), actual.size());
|
||||
Assertions.assertEquals(expected.size(), actual.size(), "Providers count");
|
||||
// compare ignoring list and map impl types
|
||||
assertThat(normalizeResults(actual), is(normalizeResults(expected)));
|
||||
}
|
||||
@ -15,22 +15,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class RegistrationFlowTest extends AbstractAuthenticationTest {
|
||||
|
||||
@Test
|
||||
@ -46,20 +49,20 @@ public class RegistrationFlowTest extends AbstractAuthenticationTest {
|
||||
data.put("description", "registrationForm2 flow");
|
||||
data.put("provider", "registration-page-form");
|
||||
authMgmtResource.addExecutionFlow("registration2", data);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("registration2"), data, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("registration2"), data, ResourceType.AUTH_EXECUTION_FLOW);
|
||||
|
||||
// Should fail to add execution under top level flow
|
||||
Map<String, Object> data2 = new HashMap<>();
|
||||
data2.put("provider", "registration-password-action");
|
||||
try {
|
||||
authMgmtResource.addExecution("registration2", data2);
|
||||
Assert.fail("Not expected to add execution of type 'registration-password-action' under top flow");
|
||||
Assertions.fail("Not expected to add execution of type 'registration-password-action' under top flow");
|
||||
} catch (BadRequestException bre) {
|
||||
}
|
||||
|
||||
// Should success to add execution under form flow
|
||||
authMgmtResource.addExecution("registrationForm2", data2);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("registrationForm2"), data2, ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authAddExecutionPath("registrationForm2"), data2, ResourceType.AUTH_EXECUTION);
|
||||
}
|
||||
|
||||
// TODO: More type-safety instead of passing generic maps
|
||||
@ -15,19 +15,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.representations.idm.RequiredActionConfigInfoRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectAdminEvents;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.testframework.events.AdminEvents;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfig;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfigBuilder;
|
||||
import org.keycloak.testsuite.actions.DummyConfigurableRequiredActionFactory;
|
||||
import org.keycloak.testsuite.actions.DummyRequiredActionFactory;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
|
||||
import jakarta.ws.rs.ClientErrorException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
@ -41,13 +49,14 @@ import java.util.Map;
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest(config = RequiredActionsTest.CustomProvidersServerConfig.class)
|
||||
public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
|
||||
@Override
|
||||
protected boolean removeVerifyProfileAtImport() {
|
||||
// do not remove verify profile action for this test
|
||||
return false;
|
||||
}
|
||||
@InjectRealm
|
||||
ManagedRealm managedRealm;
|
||||
|
||||
@InjectAdminEvents
|
||||
AdminEvents adminEvents;
|
||||
|
||||
@Test
|
||||
public void testRequiredActions() {
|
||||
@ -70,22 +79,22 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
|
||||
RequiredActionProviderRepresentation forUpdate = newRequiredAction("VERIFY_EMAIL", "Verify Email", false, false, null);
|
||||
authMgmtResource.updateRequiredAction(forUpdate.getAlias(), forUpdate);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
|
||||
result = authMgmtResource.getRequiredActions();
|
||||
RequiredActionProviderRepresentation updated = findRequiredActionByAlias(forUpdate.getAlias(), result);
|
||||
|
||||
Assert.assertNotNull("Required Action still there", updated);
|
||||
Assertions.assertNotNull(updated, "Required Action still there");
|
||||
compareRequiredAction(forUpdate, updated);
|
||||
|
||||
forUpdate.setConfig(Collections.<String, String>emptyMap());
|
||||
authMgmtResource.updateRequiredAction(forUpdate.getAlias(), forUpdate);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
|
||||
result = authMgmtResource.getRequiredActions();
|
||||
updated = findRequiredActionByAlias(forUpdate.getAlias(), result);
|
||||
|
||||
Assert.assertNotNull("Required Action still there", updated);
|
||||
Assertions.assertNotNull(updated, "Required Action still there");
|
||||
compareRequiredAction(forUpdate, updated);
|
||||
}
|
||||
|
||||
@ -95,16 +104,16 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
|
||||
// Dummy RequiredAction is not registered in the realm and WebAuthn actions
|
||||
List<RequiredActionProviderSimpleRepresentation> result = authMgmtResource.getUnregisteredRequiredActions();
|
||||
Assert.assertEquals(2, result.size());
|
||||
Assertions.assertEquals(2, result.size());
|
||||
RequiredActionProviderSimpleRepresentation action = result.stream().filter(
|
||||
a -> a.getProviderId().equals(DummyRequiredActionFactory.PROVIDER_ID)
|
||||
).findFirst().get();
|
||||
Assert.assertEquals(DummyRequiredActionFactory.PROVIDER_ID, action.getProviderId());
|
||||
Assert.assertEquals("Dummy Action", action.getName());
|
||||
Assertions.assertEquals(DummyRequiredActionFactory.PROVIDER_ID, action.getProviderId());
|
||||
Assertions.assertEquals("Dummy Action", action.getName());
|
||||
|
||||
// Register it
|
||||
authMgmtResource.registerRequiredAction(action);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action, ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action, ResourceType.REQUIRED_ACTION);
|
||||
|
||||
// Try to register 2nd time
|
||||
try {
|
||||
@ -119,7 +128,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
requiredAction.setProviderId("not-existent");
|
||||
try {
|
||||
authMgmtResource.registerRequiredAction(requiredAction);
|
||||
Assert.fail("Didn't expect to register requiredAction with providerId: 'not-existent'");
|
||||
Assertions.fail("Didn't expect to register requiredAction with providerId: 'not-existent'");
|
||||
} catch (Exception ex) {
|
||||
// Expected
|
||||
}
|
||||
@ -127,7 +136,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
// Try to find not-existent action - should fail
|
||||
try {
|
||||
authMgmtResource.getRequiredAction("not-existent");
|
||||
Assert.fail("Didn't expect to find requiredAction of alias 'not-existent'");
|
||||
Assertions.fail("Didn't expect to find requiredAction of alias 'not-existent'");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -138,12 +147,12 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
true, false, Collections.<String, String>emptyMap()));
|
||||
|
||||
// Confirm the registered priority - should be N + 1
|
||||
Assert.assertEquals(lastPriority + 1, rep.getPriority());
|
||||
Assertions.assertEquals(lastPriority + 1, rep.getPriority());
|
||||
|
||||
// Update not-existent - should fail
|
||||
try {
|
||||
authMgmtResource.updateRequiredAction("not-existent", rep);
|
||||
Assert.fail("Not expected to update not-existent requiredAction");
|
||||
Assertions.fail("Not expected to update not-existent requiredAction");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -151,21 +160,21 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
// Update (set it as defaultAction)
|
||||
rep.setDefaultAction(true);
|
||||
authMgmtResource.updateRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, rep);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), rep, ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), rep, ResourceType.REQUIRED_ACTION);
|
||||
compareRequiredAction(rep, newRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, "Dummy Action",
|
||||
true, true, Collections.<String, String>emptyMap()));
|
||||
|
||||
// Remove unexistent - should fail
|
||||
try {
|
||||
authMgmtResource.removeRequiredAction("not-existent");
|
||||
Assert.fail("Not expected to remove not-existent requiredAction");
|
||||
Assertions.fail("Not expected to remove not-existent requiredAction");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Remove success
|
||||
authMgmtResource.removeRequiredAction(DummyRequiredActionFactory.PROVIDER_ID);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
|
||||
}
|
||||
|
||||
@ -176,9 +185,9 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
|
||||
// query configurable properties
|
||||
RequiredActionConfigInfoRepresentation requiredActionConfigDescription = authMgmtResource.getRequiredActionConfigDescription(providerId);
|
||||
Assert.assertNotNull(requiredActionConfigDescription);
|
||||
Assert.assertNotNull(requiredActionConfigDescription.getProperties());
|
||||
Assert.assertTrue(requiredActionConfigDescription.getProperties().size() == 2);
|
||||
Assertions.assertNotNull(requiredActionConfigDescription);
|
||||
Assertions.assertNotNull(requiredActionConfigDescription.getProperties());
|
||||
Assertions.assertTrue(requiredActionConfigDescription.getProperties().size() == 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -187,45 +196,45 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
|
||||
// Dummy RequiredAction is not registered in the realm and WebAuthn actions
|
||||
List<RequiredActionProviderSimpleRepresentation> result = authMgmtResource.getUnregisteredRequiredActions();
|
||||
Assert.assertEquals(2, result.size());
|
||||
Assertions.assertEquals(2, result.size());
|
||||
String providerId = DummyConfigurableRequiredActionFactory.PROVIDER_ID;
|
||||
RequiredActionProviderSimpleRepresentation action = result.stream().filter(
|
||||
a -> providerId.equals(a.getProviderId())
|
||||
).findFirst().get();
|
||||
Assert.assertEquals(providerId, action.getProviderId());
|
||||
Assert.assertEquals("Configurable Test Action", action.getName());
|
||||
Assertions.assertEquals(providerId, action.getProviderId());
|
||||
Assertions.assertEquals("Configurable Test Action", action.getName());
|
||||
|
||||
// Register it
|
||||
authMgmtResource.registerRequiredAction(action);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action, ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action, ResourceType.REQUIRED_ACTION);
|
||||
|
||||
RequiredActionConfigRepresentation requiredActionConfigRep = new RequiredActionConfigRepresentation();
|
||||
Map<String, String> newActionConfig = Map.ofEntries(Map.entry("setting1", "value1"), Map.entry("setting2", "false"));
|
||||
requiredActionConfigRep.setConfig(newActionConfig);
|
||||
|
||||
authMgmtResource.updateRequiredActionConfig(providerId, requiredActionConfigRep);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionConfigPath(providerId), ResourceType.REQUIRED_ACTION_CONFIG);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authRequiredActionConfigPath(providerId), ResourceType.REQUIRED_ACTION_CONFIG);
|
||||
|
||||
RequiredActionConfigRepresentation savedRequiredActionConfigRep = authMgmtResource.getRequiredActionConfig(providerId);
|
||||
Assert.assertNotNull(savedRequiredActionConfigRep);
|
||||
Assert.assertNotNull(savedRequiredActionConfigRep.getConfig());
|
||||
Assert.assertTrue(savedRequiredActionConfigRep.getConfig().entrySet().containsAll(newActionConfig.entrySet()));
|
||||
Assertions.assertNotNull(savedRequiredActionConfigRep);
|
||||
Assertions.assertNotNull(savedRequiredActionConfigRep.getConfig());
|
||||
Assertions.assertTrue(savedRequiredActionConfigRep.getConfig().entrySet().containsAll(newActionConfig.entrySet()));
|
||||
|
||||
// delete config
|
||||
authMgmtResource.removeRequiredActionConfig(providerId);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authRequiredActionConfigPath(providerId), ResourceType.REQUIRED_ACTION_CONFIG);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authRequiredActionConfigPath(providerId), ResourceType.REQUIRED_ACTION_CONFIG);
|
||||
|
||||
RequiredActionProviderRepresentation rep = authMgmtResource.getRequiredAction(providerId);
|
||||
|
||||
// Remove success
|
||||
authMgmtResource.removeRequiredAction(providerId);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
|
||||
// Retrieval after deletion should throw a NotFound exception
|
||||
try {
|
||||
authMgmtResource.getRequiredActionConfig(providerId);
|
||||
} catch (Exception ex) {
|
||||
Assert.assertTrue(NotFoundException.class.isInstance(ex));
|
||||
Assertions.assertTrue(NotFoundException.class.isInstance(ex));
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,8 +254,8 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
}
|
||||
|
||||
private void compareRequiredActions(List<RequiredActionProviderRepresentation> expected, List<RequiredActionProviderRepresentation> actual) {
|
||||
Assert.assertNotNull("Actual null", actual);
|
||||
Assert.assertEquals("Required actions count", expected.size(), actual.size());
|
||||
Assertions.assertNotNull(actual, "Actual null");
|
||||
Assertions.assertEquals(expected.size(), actual.size(), "Required actions count");
|
||||
|
||||
Iterator<RequiredActionProviderRepresentation> ite = expected.iterator();
|
||||
Iterator<RequiredActionProviderRepresentation> ita = actual.iterator();
|
||||
@ -256,11 +265,11 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
}
|
||||
|
||||
private void compareRequiredAction(RequiredActionProviderRepresentation expected, RequiredActionProviderRepresentation actual) {
|
||||
Assert.assertEquals("alias - " + expected.getAlias(), expected.getAlias(), actual.getAlias());
|
||||
Assert.assertEquals("name - " + expected.getAlias(), expected.getName(), actual.getName());
|
||||
Assert.assertEquals("enabled - " + expected.getAlias(), expected.isEnabled(), actual.isEnabled());
|
||||
Assert.assertEquals("defaultAction - " + expected.getAlias(), expected.isDefaultAction(), actual.isDefaultAction());
|
||||
Assert.assertEquals("config - " + expected.getAlias(), expected.getConfig() != null ? expected.getConfig() : Collections.<String, String>emptyMap(), actual.getConfig());
|
||||
Assertions.assertEquals(expected.getAlias(), actual.getAlias(), "alias - " + expected.getAlias());
|
||||
Assertions.assertEquals(expected.getName(), actual.getName(), "name - " + expected.getAlias());
|
||||
Assertions.assertEquals(expected.isEnabled(), actual.isEnabled(), "enabled - " + expected.getAlias());
|
||||
Assertions.assertEquals(expected.isDefaultAction(), actual.isDefaultAction(), "defaultAction - " + expected.getAlias());
|
||||
Assertions.assertEquals(expected.getConfig() != null ? expected.getConfig() : Collections.<String, String>emptyMap(), actual.getConfig(), "config - " + expected.getAlias());
|
||||
}
|
||||
|
||||
private void addRequiredAction(List<RequiredActionProviderRepresentation> target, String alias, String name, boolean enabled, boolean defaultAction, Map<String, String> conf) {
|
||||
@ -283,4 +292,14 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
return o1.getAlias().compareTo(o2.getAlias());
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomProvidersServerConfig implements KeycloakServerConfig {
|
||||
|
||||
@Override
|
||||
public KeycloakServerConfigBuilder configure(KeycloakServerConfigBuilder config) {
|
||||
return config.dependency("org.keycloak.tests", "keycloak-tests-custom-providers");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,36 +15,38 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class ShiftExecutionTest extends AbstractAuthenticationTest {
|
||||
|
||||
@Test
|
||||
public void testShiftExecution() {
|
||||
|
||||
// copy built-in flow so we get a new editable flow
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("newName", "Copy of browser");
|
||||
Response response = authMgmtResource.copy("browser", params);
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
|
||||
try {
|
||||
Assert.assertEquals("Copy flow", 201, response.getStatus());
|
||||
Assertions.assertEquals(201, response.getStatus(), "Copy flow");
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
@ -58,42 +60,42 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
|
||||
// Not possible to raisePriority of not-existent flow
|
||||
try {
|
||||
authMgmtResource.raisePriority("not-existent");
|
||||
Assert.fail("Not expected to raise priority of not existent flow");
|
||||
Assertions.fail("Not expected to raise priority of not existent flow");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// shift last execution up
|
||||
authMgmtResource.raisePriority(last.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authRaiseExecutionPath(last.getId()), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authRaiseExecutionPath(last.getId()), ResourceType.AUTH_EXECUTION);
|
||||
|
||||
List<AuthenticationExecutionInfoRepresentation> executions2 = authMgmtResource.getExecutions("Copy of browser");
|
||||
|
||||
AuthenticationExecutionInfoRepresentation last2 = executions2.get(executions.size() - 1);
|
||||
AuthenticationExecutionInfoRepresentation oneButLast2 = executions2.get(executions.size() - 2);
|
||||
|
||||
Assert.assertEquals("Execution shifted up - N", last.getId(), oneButLast2.getId());
|
||||
Assert.assertEquals("Execution shifted up - N-1", oneButLast.getId(), last2.getId());
|
||||
Assertions.assertEquals(last.getId(), oneButLast2.getId(), "Execution shifted up - N");
|
||||
Assertions.assertEquals(oneButLast.getId(), last2.getId(), "Execution shifted up - N-1");
|
||||
|
||||
// Not possible to lowerPriority of not-existent flow
|
||||
try {
|
||||
authMgmtResource.lowerPriority("not-existent");
|
||||
Assert.fail("Not expected to raise priority of not existent flow");
|
||||
Assertions.fail("Not expected to raise priority of not existent flow");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// shift one before last down
|
||||
authMgmtResource.lowerPriority(oneButLast2.getId());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authLowerExecutionPath(oneButLast2.getId()), ResourceType.AUTH_EXECUTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authLowerExecutionPath(oneButLast2.getId()), ResourceType.AUTH_EXECUTION);
|
||||
|
||||
executions2 = authMgmtResource.getExecutions("Copy of browser");
|
||||
|
||||
last2 = executions2.get(executions.size() - 1);
|
||||
oneButLast2 = executions2.get(executions.size() - 2);
|
||||
|
||||
Assert.assertEquals("Execution shifted down - N", last.getId(), last2.getId());
|
||||
Assert.assertEquals("Execution shifted down - N-1", oneButLast.getId(), oneButLast2.getId());
|
||||
Assertions.assertEquals(last.getId(), last2.getId(), "Execution shifted down - N");
|
||||
Assertions.assertEquals(oneButLast.getId(), oneButLast2.getId(), "Execution shifted down - N-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -106,7 +108,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
|
||||
// Not possible to raise - It's builtin flow
|
||||
try {
|
||||
authMgmtResource.raisePriority(last.getId());
|
||||
Assert.fail("Not expected to raise priority of builtin flow");
|
||||
Assertions.fail("Not expected to raise priority of builtin flow");
|
||||
} catch (BadRequestException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -114,7 +116,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
|
||||
// Not possible to lower - It's builtin flow
|
||||
try {
|
||||
authMgmtResource.lowerPriority(oneButLast.getId());
|
||||
Assert.fail("Not expected to lower priority of builtin flow");
|
||||
Assertions.fail("Not expected to lower priority of builtin flow");
|
||||
} catch (BadRequestException nfe) {
|
||||
// Expected
|
||||
}
|
||||
@ -15,22 +15,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.authentication;
|
||||
|
||||
import java.util.List;
|
||||
package org.keycloak.tests.admin.authentication;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:wadahiro@gmail.com">Hiroyuki Wada</a>
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class ShiftRequiredActionTest extends AbstractAuthenticationTest {
|
||||
|
||||
@Test
|
||||
@ -45,41 +47,41 @@ public class ShiftRequiredActionTest extends AbstractAuthenticationTest {
|
||||
// Not possible to raisePriority of not-existent required action
|
||||
try {
|
||||
authMgmtResource.raisePriority("not-existent");
|
||||
Assert.fail("Not expected to raise priority of not existent required action");
|
||||
Assertions.fail("Not expected to raise priority of not existent required action");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// shift last required action up
|
||||
authMgmtResource.raiseRequiredActionPriority(last.getAlias());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authRaiseRequiredActionPath(last.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authRaiseRequiredActionPath(last.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
|
||||
List<RequiredActionProviderRepresentation> actions2 = authMgmtResource.getRequiredActions();
|
||||
|
||||
RequiredActionProviderRepresentation last2 = actions2.get(actions.size() - 1);
|
||||
RequiredActionProviderRepresentation oneButLast2 = actions2.get(actions.size() - 2);
|
||||
|
||||
Assert.assertEquals("Required action shifted up - N", last.getAlias(), oneButLast2.getAlias());
|
||||
Assert.assertEquals("Required action up - N-1", oneButLast.getAlias(), last2.getAlias());
|
||||
Assertions.assertEquals(last.getAlias(), oneButLast2.getAlias(), "Required action shifted up - N");
|
||||
Assertions.assertEquals(oneButLast.getAlias(), last2.getAlias(), "Required action up - N-1");
|
||||
|
||||
// Not possible to lowerPriority of not-existent required action
|
||||
try {
|
||||
authMgmtResource.lowerRequiredActionPriority("not-existent");
|
||||
Assert.fail("Not expected to raise priority of not existent required action");
|
||||
Assertions.fail("Not expected to raise priority of not existent required action");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// shift one before last down
|
||||
authMgmtResource.lowerRequiredActionPriority(oneButLast2.getAlias());
|
||||
assertAdminEvents.assertEvent(testRealmId, OperationType.UPDATE, AdminEventPaths.authLowerRequiredActionPath(oneButLast2.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.UPDATE, AdminEventPaths.authLowerRequiredActionPath(oneButLast2.getAlias()), ResourceType.REQUIRED_ACTION);
|
||||
|
||||
actions2 = authMgmtResource.getRequiredActions();
|
||||
|
||||
last2 = actions2.get(actions.size() - 1);
|
||||
oneButLast2 = actions2.get(actions.size() - 2);
|
||||
|
||||
Assert.assertEquals("Required action shifted down - N", last.getAlias(), last2.getAlias());
|
||||
Assert.assertEquals("Required action shifted down - N-1", oneButLast.getAlias(), oneButLast2.getAlias());
|
||||
Assertions.assertEquals(last.getAlias(), last2.getAlias(), "Required action shifted down - N");
|
||||
Assertions.assertEquals(oneButLast.getAlias(), oneButLast2.getAlias(), "Required action shifted down - N-1");
|
||||
}
|
||||
}
|
||||
48
tests/custom-providers/pom.xml
Executable file
48
tests/custom-providers/pom.xml
Executable file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-tests-parent</artifactId>
|
||||
<groupId>org.keycloak.tests</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-tests-custom-providers</artifactId>
|
||||
<name>Keycloak Testsuite Custom Providers</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Keycloak Testsuite Custom Providers</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi-private</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2024 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.actions;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RequiredActionConfigModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DummyConfigurableRequiredActionFactory implements RequiredActionFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "configurable-test-action";
|
||||
|
||||
public static final String SETTING_1 = "setting1";
|
||||
|
||||
public static final String SETTING_2 = "setting2";
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Configurable Test Action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiredActionProvider create(KeycloakSession session) {
|
||||
return new RequiredActionProvider() {
|
||||
@Override
|
||||
public void evaluateTriggers(RequiredActionContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requiredActionChallenge(RequiredActionContext context) {
|
||||
|
||||
// users can access the given Required Action configuration via RequiredActionContext#getContext()
|
||||
RequiredActionConfigModel configModel = context.getConfig();
|
||||
Map<String, String> config = configModel.getConfig();
|
||||
|
||||
String setting1Value = configModel.getConfigValue(SETTING_1);
|
||||
|
||||
context.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = ProviderConfigurationBuilder.create() //
|
||||
.property() //
|
||||
.name(SETTING_1) //
|
||||
.label("Setting 1") //
|
||||
.helpText("Setting 1 Help Text") //
|
||||
.type(ProviderConfigProperty.STRING_TYPE) //
|
||||
.defaultValue("setting1Default") //
|
||||
.add() //
|
||||
|
||||
.property() //
|
||||
.name(SETTING_2) //
|
||||
.label("Setting 2") //
|
||||
.helpText("Setting 2 Help Text") //
|
||||
.type(ProviderConfigProperty.BOOLEAN_TYPE) //
|
||||
.defaultValue("true") //
|
||||
.add() //
|
||||
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigMetadata() {
|
||||
return CONFIG_PROPERTIES;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.actions;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class DummyRequiredActionFactory implements RequiredActionFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "dummy-action";
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Dummy Action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiredActionProvider create(KeycloakSession session) {
|
||||
return new RequiredActionProvider() {
|
||||
@Override
|
||||
public void evaluateTriggers(RequiredActionContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requiredActionChallenge(RequiredActionContext context) {
|
||||
context.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
#
|
||||
# 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.actions.DummyRequiredActionFactory
|
||||
org.keycloak.testsuite.actions.DummyConfigurableRequiredActionFactory
|
||||
@ -35,6 +35,7 @@
|
||||
<modules>
|
||||
<module>base</module>
|
||||
<module>utils</module>
|
||||
<module>custom-providers</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2023 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.tests.utils;
|
||||
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class KerberosUtils {
|
||||
|
||||
// TODO Figure out if we need to be able to disable Kerberos support for some tests; if so find a better way
|
||||
public static boolean isKerberosSupportExpected() {
|
||||
String kerberosSupported = System.getProperty("auth.server.kerberos.supported");
|
||||
// Supported by default. It is considered unsupported just if explicitly disabled
|
||||
return !"false".equals(kerberosSupported);
|
||||
}
|
||||
|
||||
public static void assumeKerberosSupportExpected() {
|
||||
Assumptions.assumeTrue(isKerberosSupportExpected(), "Kerberos feature is not expected to be supported by auth server");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* 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.tests.utils.admin;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import org.keycloak.admin.client.resource.AttackDetectionResource;
|
||||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||
import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
|
||||
import org.keycloak.admin.client.resource.ClientInitialAccessResource;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.ClientScopeResource;
|
||||
import org.keycloak.admin.client.resource.ClientScopesResource;
|
||||
import org.keycloak.admin.client.resource.ClientsResource;
|
||||
import org.keycloak.admin.client.resource.ComponentsResource;
|
||||
import org.keycloak.admin.client.resource.GroupResource;
|
||||
import org.keycloak.admin.client.resource.GroupsResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProvidersResource;
|
||||
import org.keycloak.admin.client.resource.ProtocolMappersResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.RoleByIdResource;
|
||||
import org.keycloak.admin.client.resource.RoleMappingResource;
|
||||
import org.keycloak.admin.client.resource.RoleResource;
|
||||
import org.keycloak.admin.client.resource.RolesResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AdminEventPaths {
|
||||
|
||||
// REALM
|
||||
|
||||
public static String deleteSessionPath(String userSessionId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "deleteSession").build(userSessionId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String defaultGroupPath(String groupId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "addDefaultGroup").build(groupId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String defaultDefaultClientScopePath(String clientScopeId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "addDefaultDefaultClientScope").build(clientScopeId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String defaultOptionalClientScopePath(String clientScopeId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "addDefaultOptionalClientScope").build(clientScopeId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String userProfilePath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "users")
|
||||
.path(UsersResource.class, "userProfile")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// CLIENT RESOURCE
|
||||
|
||||
public static String clientResourcePath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clients").path(ClientsResource.class, "get").build(clientDbId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientRolesResourcePath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "roles").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientRoleResourcePath(String clientDbId, String roleName) {
|
||||
URI uri = UriBuilder.fromUri(clientRolesResourcePath(clientDbId)).path(RolesResource.class, "get").build(roleName);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientRoleResourceCompositesPath(String clientDbId, String roleName) {
|
||||
URI uri = UriBuilder.fromUri(clientRoleResourcePath(clientDbId, roleName))
|
||||
.path(RoleResource.class, "getRoleComposites").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientProtocolMappersPath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId))
|
||||
.path(ClientResource.class, "getProtocolMappers")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String clientProtocolMapperPath(String clientDbId, String protocolMapperId) {
|
||||
URI uri = UriBuilder.fromUri(clientProtocolMappersPath(clientDbId))
|
||||
.path(ProtocolMappersResource.class, "getMapperById")
|
||||
.build(protocolMapperId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientPushRevocationPath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "pushRevocation").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientNodesPath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "registerNode").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientNodePath(String clientDbId, String node) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "unregisterNode").build(node);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientTestNodesAvailablePath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "testNodesAvailable").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientGenerateSecretPath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "generateNewSecret").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientRegenerateRegistrationAccessTokenPath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "regenerateRegistrationAccessToken").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientCertificateGenerateSecretPath(String clientDbId, String certificateAttribute) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId))
|
||||
.path(ClientResource.class, "getCertficateResource")
|
||||
.path(ClientAttributeCertificateResource.class, "generate")
|
||||
.build(certificateAttribute);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String clientScopeMappingsRealmLevelPath(String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "getScopeMappings")
|
||||
.path(RoleMappingResource.class, "realmLevel")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientScopeMappingsClientLevelPath(String clientDbId, String clientOwningRoleId) {
|
||||
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "getScopeMappings")
|
||||
.path(RoleMappingResource.class, "clientLevel")
|
||||
.build(clientOwningRoleId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CLIENT SCOPES
|
||||
|
||||
public static String clientScopeResourcePath(String clientScopeId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clientScopes").path(ClientScopesResource.class, "get").build(clientScopeId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientScopeGenerateAudienceClientScopePath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clientScopes").path(ClientScopesResource.class, "generateAudienceClientScope").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientScopeRoleMappingsRealmLevelPath(String clientScopeDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientScopeResourcePath(clientScopeDbId)).path(ClientScopeResource.class, "getScopeMappings")
|
||||
.path(RoleMappingResource.class, "realmLevel")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientScopeRoleMappingsClientLevelPath(String clientScopeDbId, String clientOwningRoleId) {
|
||||
URI uri = UriBuilder.fromUri(clientScopeResourcePath(clientScopeDbId)).path(ClientScopeResource.class, "getScopeMappings")
|
||||
.path(RoleMappingResource.class, "clientLevel")
|
||||
.build(clientOwningRoleId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String clientScopeProtocolMappersPath(String clientScopeDbId) {
|
||||
URI uri = UriBuilder.fromUri(clientScopeResourcePath(clientScopeDbId))
|
||||
.path(ClientScopeResource.class, "getProtocolMappers")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String clientScopeProtocolMapperPath(String clientScopeDbId, String protocolMapperId) {
|
||||
URI uri = UriBuilder.fromUri(clientScopeProtocolMappersPath(clientScopeDbId))
|
||||
.path(ProtocolMappersResource.class, "getMapperById")
|
||||
.build(protocolMapperId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// ROLES
|
||||
|
||||
public static String rolesResourcePath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "roles").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String roleResourcePath(String roleName) {
|
||||
URI uri = UriBuilder.fromUri(rolesResourcePath()).path(RolesResource.class, "get").build(roleName);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String roleResourceCompositesPath(String roleName) {
|
||||
URI uri = UriBuilder.fromUri(roleResourcePath(roleName)).path(RoleResource.class, "getRoleComposites").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String rolesByIdResourcePath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "rolesById").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String roleByIdResourcePath(String roleId) {
|
||||
URI uri = UriBuilder.fromUri(rolesByIdResourcePath()).path(RoleByIdResource.class, "getRole").build(roleId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String roleByIdResourceCompositesPath(String roleId) {
|
||||
URI uri = UriBuilder.fromUri(rolesByIdResourcePath()).path(RoleByIdResource.class, "getRoleComposites").build(roleId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// USERS
|
||||
|
||||
public static String userResourcePath(String userId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "users").path(UsersResource.class, "get").build(userId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String userResetPasswordPath(String userId) {
|
||||
URI uri = UriBuilder.fromUri(userResourcePath(userId)).path(UserResource.class, "resetPassword").build(userId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String userRealmRoleMappingsPath(String userId) {
|
||||
URI uri = UriBuilder.fromUri(userResourcePath(userId))
|
||||
.path(UserResource.class, "roles")
|
||||
.path(RoleMappingResource.class, "realmLevel").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String userClientRoleMappingsPath(String userId, String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(userResourcePath(userId))
|
||||
.path(UserResource.class, "roles")
|
||||
.path(RoleMappingResource.class, "clientLevel").build(clientDbId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String userFederatedIdentityLink(String userId, String idpAlias) {
|
||||
URI uri = UriBuilder.fromUri(userResourcePath(userId))
|
||||
.path(UserResource.class, "addFederatedIdentity")
|
||||
.build(idpAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String userGroupPath(String userId, String groupId) {
|
||||
URI uri = UriBuilder.fromUri(userResourcePath(userId))
|
||||
.path(UserResource.class, "joinGroup")
|
||||
.build(groupId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// IDENTITY PROVIDERS
|
||||
|
||||
public static String identityProvidersPath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "identityProviders").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String identityProviderCreatePath() {
|
||||
URI uri = UriBuilder.fromUri(identityProvidersPath()).path(IdentityProvidersResource.class, "create").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String identityProviderPath(String idpAlias) {
|
||||
URI uri = UriBuilder.fromUri(identityProvidersPath()).path(IdentityProvidersResource.class, "get").build(idpAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String identityProviderMapperPath(String idpAlias, String idpMapperId) {
|
||||
URI uri = UriBuilder.fromUri(identityProviderPath(idpAlias)).path(IdentityProviderResource.class, "getMapperById").build(idpMapperId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// COMPONENTS
|
||||
public static String componentsPath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "components").build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String componentPath(String componentId) {
|
||||
URI uri = UriBuilder.fromUri(componentsPath()).path(ComponentsResource.class, "component").build(componentId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// CLIENT INITIAL ACCESS
|
||||
|
||||
public static String clientInitialAccessPath(String clientInitialAccessId) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clientInitialAccess")
|
||||
.path(ClientInitialAccessResource.class, "delete")
|
||||
.build(clientInitialAccessId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// GROUPS
|
||||
|
||||
public static String groupsPath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "groups")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String groupPath(String groupId) {
|
||||
URI uri = UriBuilder.fromUri(groupsPath()).path(GroupsResource.class, "group")
|
||||
.build(groupId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String groupRolesPath(String groupId) {
|
||||
URI uri = UriBuilder.fromUri(groupPath(groupId))
|
||||
.path(GroupResource.class, "roles")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String groupRolesRealmRolesPath(String groupId) {
|
||||
URI uri = UriBuilder.fromUri(groupRolesPath(groupId))
|
||||
.path(RoleMappingResource.class, "realmLevel")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String groupRolesClientRolesPath(String groupId, String clientDbId) {
|
||||
URI uri = UriBuilder.fromUri(groupRolesPath(groupId))
|
||||
.path(RoleMappingResource.class, "clientLevel")
|
||||
.build(clientDbId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String groupSubgroupsPath(String groupId) {
|
||||
URI uri = UriBuilder.fromUri(groupPath(groupId))
|
||||
.path(GroupResource.class, "subGroup")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
// AUTHENTICATION FLOWS
|
||||
|
||||
public static String authMgmtBasePath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "flows")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authFlowsPath() {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getFlows")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authFlowPath(String flowId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getFlow")
|
||||
.build(flowId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authCopyFlowPath(String flowAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "copy")
|
||||
.build(flowAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authEditFlowPath(String flowId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "updateFlow")
|
||||
.build(flowId);
|
||||
return uri.toString();
|
||||
}
|
||||
public static String authAddExecutionFlowPath(String flowAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "addExecutionFlow")
|
||||
.build(flowAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authAddExecutionPath(String flowAlias) {
|
||||
return authFlowPath(flowAlias) + "/executions/execution";
|
||||
}
|
||||
|
||||
public static String authUpdateExecutionPath(String flowAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "updateExecutions")
|
||||
.build(flowAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authExecutionPath(String executionId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "removeExecution")
|
||||
.build(executionId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authAddExecutionConfigPath(String executionId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "newExecutionConfig")
|
||||
.build(executionId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authExecutionConfigPath(String configId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getAuthenticatorConfig")
|
||||
.build(configId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authRaiseExecutionPath(String executionId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "raisePriority")
|
||||
.build(executionId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authLowerExecutionPath(String executionId) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "lowerPriority")
|
||||
.build(executionId);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authRequiredActionPath(String requiredActionAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getRequiredAction")
|
||||
.build(requiredActionAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authRequiredActionConfigPath(String requiredActionAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getRequiredActionConfig")
|
||||
.build(requiredActionAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authRaiseRequiredActionPath(String requiredActionAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "raiseRequiredActionPriority")
|
||||
.build(requiredActionAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String authLowerRequiredActionPath(String requiredActionAlias) {
|
||||
URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "lowerRequiredActionPriority")
|
||||
.build(requiredActionAlias);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
// ATTACK DETECTION
|
||||
|
||||
public static String attackDetectionClearBruteForceForUserPath(String username) {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "attackDetection")
|
||||
.path(AttackDetectionResource.class, "clearBruteForceForUser")
|
||||
.build(username);
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public static String attackDetectionClearAllBruteForcePath() {
|
||||
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "attackDetection")
|
||||
.path(AttackDetectionResource.class, "clearAllBruteForce")
|
||||
.build();
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.tests.utils.matchers;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Matcher for matching status code of {@link Response} instance.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class HttpResponseBodyMatcher extends BaseMatcher<HttpResponse> {
|
||||
|
||||
private final Matcher<String> matcher;
|
||||
|
||||
private ThreadLocal<String> lastEntity = new ThreadLocal<>();
|
||||
|
||||
public HttpResponseBodyMatcher(Matcher<String> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
lastEntity.remove();
|
||||
try {
|
||||
lastEntity.set(EntityUtils.toString(((HttpResponse) item).getEntity()));
|
||||
return (item instanceof HttpResponse) && this.matcher.matches(lastEntity.get());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
Description d = description.appendText("was ").appendValue(item);
|
||||
if (lastEntity.get() != null) {
|
||||
d.appendText(" with entity ").appendText(lastEntity.get());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("response body matches ").appendDescriptionOf(this.matcher);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.tests.utils.matchers;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Matcher for matching status code of {@link Response} instance.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class HttpResponseStatusCodeMatcher extends BaseMatcher<HttpResponse> {
|
||||
|
||||
private final Matcher<? extends Number> matcher;
|
||||
|
||||
public HttpResponseStatusCodeMatcher(Matcher<? extends Number> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
return (item instanceof HttpResponse) && this.matcher.matches(((HttpResponse) item).getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
Description d = description.appendText("was ").appendValue(item)
|
||||
.appendText(" with entity ");
|
||||
try {
|
||||
d.appendText(EntityUtils.toString(((HttpResponse) item).getEntity()));
|
||||
} catch (IOException e) {
|
||||
d.appendText("<Cannot decode entity: " + e.getMessage() + ">");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("response status code matches ").appendDescriptionOf(this.matcher);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.tests.utils.matchers;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.keycloak.dom.saml.v2.SAML2Object;
|
||||
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
|
||||
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
|
||||
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
||||
import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
* Additional hamcrest matchers
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class Matchers {
|
||||
|
||||
/**
|
||||
* Matcher on HTTP status code of a {@link Response} instance.
|
||||
* @param matcher
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<Response> body(Matcher<String> matcher) {
|
||||
return new ResponseBodyMatcher(matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher on HTTP body of a {@link Response} instance.
|
||||
* @param matcher
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<HttpResponse> bodyHC(Matcher<String> matcher) {
|
||||
return new HttpResponseBodyMatcher(matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher on HTTP status code of a {@link Response} instance.
|
||||
* @param matcher
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<Response> statusCode(Matcher<? extends Number> matcher) {
|
||||
return new ResponseStatusCodeMatcher(matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher on HTTP status code of a {@link Response} instance (HttpClient variant).
|
||||
* @param matcher
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<HttpResponse> statusCodeHC(Matcher<? extends Number> matcher) {
|
||||
return new HttpResponseStatusCodeMatcher(matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the HTTP status code of a {@link Response} instance is equal to the given code.
|
||||
* @param expectedStatusCode
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<Response> statusCodeIs(Response.Status expectedStatusCode) {
|
||||
return new ResponseStatusCodeMatcher(org.hamcrest.Matchers.is(expectedStatusCode.getStatusCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the HTTP status code of a {@link Response} instance is equal to the given code (HttpClient variant).
|
||||
* @param expectedStatusCode
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<HttpResponse> statusCodeIsHC(Response.Status expectedStatusCode) {
|
||||
return new HttpResponseStatusCodeMatcher(org.hamcrest.Matchers.is(expectedStatusCode.getStatusCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the HTTP status code of a {@link Response} instance is equal to the given code.
|
||||
* @param expectedStatusCode
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<Response> statusCodeIs(int expectedStatusCode) {
|
||||
return new ResponseStatusCodeMatcher(org.hamcrest.Matchers.is(expectedStatusCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the HTTP status code of a {@link Response} instance is equal to the given code (HttpClient variant).
|
||||
* @param expectedStatusCode
|
||||
* @return
|
||||
*/
|
||||
public static Matcher<HttpResponse> statusCodeIsHC(int expectedStatusCode) {
|
||||
return new HttpResponseStatusCodeMatcher(org.hamcrest.Matchers.is(expectedStatusCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the HTTP status code of a {@link Response} instance is equal to the given code.
|
||||
* @param matcher
|
||||
* @return
|
||||
*/
|
||||
public static <T> Matcher<Response> header(Matcher<Map<String, T>> matcher) {
|
||||
return new ResponseHeaderMatcher<>(matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the SAML status code of a {@link ResponseType} instance is equal to the given code.
|
||||
* @param expectedStatus
|
||||
* @return
|
||||
*/
|
||||
public static <T> Matcher<SAML2Object> isSamlResponse(JBossSAMLURIConstants expectedStatus) {
|
||||
return allOf(
|
||||
instanceOf(ResponseType.class),
|
||||
new SamlResponseTypeMatcher(is(expectedStatus.getUri()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the destination of a SAML {@link LogoutRequestType} instance is equal to the given destination.
|
||||
* @param destination
|
||||
* @return
|
||||
*/
|
||||
public static <T> Matcher<SAML2Object> isSamlLogoutRequest(String destination) {
|
||||
return allOf(
|
||||
instanceOf(LogoutRequestType.class),
|
||||
new SamlLogoutRequestTypeMatcher(URI.create(destination))
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Matches when the type of a SAML object is instance of {@link AuthnRequestType}.
|
||||
* @return
|
||||
*/
|
||||
public static <T> Matcher<SAML2Object> isSamlAuthnRequest() {
|
||||
return instanceOf(AuthnRequestType.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches when the SAML status of a {@link StatusResponseType} instance is equal to the given code.
|
||||
* @param expectedStatus
|
||||
* @return
|
||||
*/
|
||||
public static <T> Matcher<SAML2Object> isSamlStatusResponse(JBossSAMLURIConstants... expectedStatus) {
|
||||
return allOf(
|
||||
instanceOf(StatusResponseType.class),
|
||||
new SamlStatusResponseTypeMatcher(Arrays.stream(expectedStatus).map(JBossSAMLURIConstants::getUri).toArray(i -> new URI[i]))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.tests.utils.matchers;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
/**
|
||||
* Matcher for matching status code of {@link Response} instance.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class ResponseBodyMatcher extends BaseMatcher<Response> {
|
||||
|
||||
private final Matcher<String> matcher;
|
||||
|
||||
public ResponseBodyMatcher(Matcher<String> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
if (item instanceof Response) {
|
||||
final Response rItem = (Response) item;
|
||||
rItem.bufferEntity();
|
||||
return this.matcher.matches(rItem.readEntity(String.class));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("response body matches ").appendDescriptionOf(this.matcher);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.tests.utils.matchers;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Matcher for matching status code of {@link Response} instance.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class ResponseHeaderMatcher<T> extends BaseMatcher<Response> {
|
||||
|
||||
private final Matcher<Map<String, T>> matcher;
|
||||
|
||||
public ResponseHeaderMatcher(Matcher<Map<String, T>> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
return (item instanceof Response) && this.matcher.matches(((Response) item).getHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("response headers match ").appendDescriptionOf(this.matcher);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.tests.utils.matchers;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
/**
|
||||
* Matcher for matching status code of {@link Response} instance.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class ResponseStatusCodeMatcher extends BaseMatcher<Response> {
|
||||
|
||||
private final Matcher<? extends Number> matcher;
|
||||
|
||||
public ResponseStatusCodeMatcher(Matcher<? extends Number> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
return (item instanceof Response) && this.matcher.matches(((Response) item).getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("response status code matches ").appendDescriptionOf(this.matcher);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.keycloak.tests.utils.matchers;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.keycloak.dom.saml.v2.SAML2Object;
|
||||
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class SamlLogoutRequestTypeMatcher extends BaseMatcher<SAML2Object> {
|
||||
|
||||
private final Matcher<URI> destinationMatcher;
|
||||
|
||||
public SamlLogoutRequestTypeMatcher(URI destination) {
|
||||
this.destinationMatcher = is(destination);
|
||||
}
|
||||
|
||||
public SamlLogoutRequestTypeMatcher(Matcher<URI> destinationMatcher) {
|
||||
this.destinationMatcher = destinationMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
return destinationMatcher.matches(((LogoutRequestType) item).getDestination());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
description.appendText("was ").appendValue(((LogoutRequestType) item).getDestination());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("SAML logout request destination matches ").appendDescriptionOf(this.destinationMatcher);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.keycloak.tests.utils.matchers;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.keycloak.dom.saml.v2.SAML2Object;
|
||||
import org.keycloak.dom.saml.v2.protocol.ResponseType;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class SamlResponseTypeMatcher extends BaseMatcher<SAML2Object> {
|
||||
|
||||
private final Matcher<URI> statusMatcher;
|
||||
|
||||
public SamlResponseTypeMatcher(JBossSAMLURIConstants expectedStatus) {
|
||||
this.statusMatcher = is(expectedStatus.getUri());
|
||||
}
|
||||
|
||||
public SamlResponseTypeMatcher(Matcher<URI> statusMatcher) {
|
||||
this.statusMatcher = statusMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
return statusMatcher.matches(((ResponseType) item).getStatus().getStatusCode().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
description.appendText("was ").appendValue(((ResponseType) item).getStatus().getStatusCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("SAML response status code matches ").appendDescriptionOf(this.statusMatcher);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.keycloak.tests.utils.matchers;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.keycloak.dom.saml.v2.SAML2Object;
|
||||
import org.keycloak.dom.saml.v2.protocol.StatusCodeType;
|
||||
import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class SamlStatusResponseTypeMatcher extends BaseMatcher<SAML2Object> {
|
||||
|
||||
private final List<Matcher<URI>> statusMatchers;
|
||||
|
||||
public SamlStatusResponseTypeMatcher(URI... statusMatchers) {
|
||||
this.statusMatchers = new ArrayList(statusMatchers.length);
|
||||
for (URI uri : statusMatchers) {
|
||||
this.statusMatchers.add(is(uri));
|
||||
}
|
||||
}
|
||||
|
||||
public SamlStatusResponseTypeMatcher(List<Matcher<URI>> statusMatchers) {
|
||||
this.statusMatchers = statusMatchers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
StatusCodeType statusCode = ((StatusResponseType) item).getStatus().getStatusCode();
|
||||
for (Matcher<URI> statusMatcher : statusMatchers) {
|
||||
if (! statusMatcher.matches(statusCode.getValue())) {
|
||||
return false;
|
||||
}
|
||||
statusCode = statusCode.getStatusCode();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
StatusCodeType statusCode = ((StatusResponseType) item).getStatus().getStatusCode();
|
||||
description.appendText("was ");
|
||||
while (statusCode != null) {
|
||||
description.appendText("/").appendValue(statusCode.getValue());
|
||||
statusCode = statusCode.getStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("SAML status response status matches ");
|
||||
for (Matcher<URI> statusMatcher : statusMatchers) {
|
||||
description.appendText("/").appendDescriptionOf(statusMatcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user