Skip to content

Commit

Permalink
Merge pull request wildfly#17903 from PrarthonaPaul/WFLY-19198
Browse files Browse the repository at this point in the history
[WFLY-19198] Move the OIDC scope related tests back to the elytron-oidc-client testsuite: delete manualmode tests
  • Loading branch information
bstansberry authored Jun 12, 2024
2 parents 97a42a2 + ac97cce commit 1b758e7
Show file tree
Hide file tree
Showing 17 changed files with 314 additions and 985 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package org.wildfly.test.integration.elytron.oidc.client;

import static org.wildfly.test.integration.elytron.oidc.client.OidcBaseTest.MULTIPLE_SCOPE_APP;
import static org.wildfly.test.integration.elytron.oidc.client.OidcBaseTest.SINGLE_SCOPE_APP;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -30,7 +32,7 @@
*/
public class KeycloakConfiguration {

private static final String USER_ROLE = "user";
public static final String USER_ROLE = "user";
public static final String JBOSS_ADMIN_ROLE = "JBossAdmin";
public static final String ALICE = "alice";
public static final String ALICE_PASSWORD = "alice123+";
Expand All @@ -53,6 +55,9 @@ public class KeycloakConfiguration {
public static final String TENANT2_REALM = "tenant2";
public static final String TENANT1_ENDPOINT = "/tenant1";
public static final String TENANT2_ENDPOINT = "/tenant2";
public static final String ALICE_FIRST_NAME = "Alice";
public static final String ALICE_LAST_NAME = "Smith";
public static final boolean ALICE_EMAIL_VERIFIED = true;

public enum ClientAppType {
OIDC_CLIENT,
Expand Down Expand Up @@ -180,7 +185,7 @@ private static RealmRepresentation createRealm(String name, String clientSecret,
realm.getUsers().add(createUser(CHARLOTTE, CHARLOTTE_PASSWORD, Arrays.asList(USER_ROLE, JBOSS_ADMIN_ROLE)));
realm.getUsers().add(createUser(DAN, DAN_PASSWORD, Arrays.asList(USER_ROLE, JBOSS_ADMIN_ROLE)));
} else {
realm.getUsers().add(createUser(ALICE, ALICE_PASSWORD, Arrays.asList(USER_ROLE, JBOSS_ADMIN_ROLE)));
realm.getUsers().add(createUser(ALICE, ALICE_PASSWORD, Arrays.asList(USER_ROLE, JBOSS_ADMIN_ROLE), ALICE_FIRST_NAME, ALICE_LAST_NAME, ALICE_EMAIL_VERIFIED));
realm.getUsers().add(createUser(BOB, BOB_PASSWORD, Arrays.asList(USER_ROLE)));
realm.getUsers().add(createUser(CHARLIE, CHARLIE_PASSWORD, Arrays.asList(USER_ROLE, JBOSS_ADMIN_ROLE)));
}
Expand All @@ -205,6 +210,20 @@ private static ClientRepresentation createWebAppClient(String clientId, String c
client.setRedirectUris(Arrays.asList("http://" + clientHostName + ":" + clientPort + "/" + clientApp + "/*"));
}
client.setEnabled(true);

if (clientId.equals(MULTIPLE_SCOPE_APP) || clientId.equals(SINGLE_SCOPE_APP)) {
client.setOptionalClientScopes(new ArrayList<>());
client.setDefaultClientScopes(new ArrayList<>());
client.getDefaultClientScopes().add("web-origins");
client.getDefaultClientScopes().add("acr");
client.getOptionalClientScopes().add("address");
client.getOptionalClientScopes().add("email");
client.getOptionalClientScopes().add("profile");
client.getOptionalClientScopes().add("phone");
client.getDefaultClientScopes().add("roles");
client.getOptionalClientScopes().add("offline_access");
client.getOptionalClientScopes().add("microprofile-jwt");
}
client.setDirectAccessGrantsEnabled(directAccessGrantEnabled);
if (allowedOrigin != null) {
client.setWebOrigins(Collections.singletonList(allowedOrigin));
Expand All @@ -219,12 +238,16 @@ private static ClientRepresentation createBearerOnlyClient(String clientId) {
client.setEnabled(true);
return client;
}

private static UserRepresentation createUser(String username, String password, List<String> realmRoles) {
return createUser(username, password, realmRoles, username, username, false);
}

private static UserRepresentation createUser(String username, String password, List<String> realmRoles, String firstName, String lastName, boolean emailVerified) {
UserRepresentation user = new UserRepresentation();
user.setUsername(username);
user.setFirstName(username);
user.setLastName(username);
user.setFirstName(firstName);
user.setLastName(lastName);
user.setEmailVerified(emailVerified);
user.setEnabled(true);
user.setCredentials(new ArrayList<>());
user.setRealmRoles(realmRoles);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

package org.wildfly.test.integration.elytron.oidc.client;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SYSTEM_PROPERTY;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.wildfly.security.http.oidc.Oidc.OIDC_SCOPE;
import static org.wildfly.test.integration.elytron.oidc.client.KeycloakConfiguration.ALLOWED_ORIGIN;

import java.io.IOException;
Expand Down Expand Up @@ -39,11 +42,16 @@
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.test.http.util.TestHttpClientUtils;
import org.jboss.as.test.integration.management.ManagementOperations;
import org.jboss.as.test.integration.security.common.servlets.SimpleSecuredServlet;
import org.jboss.as.test.integration.security.common.servlets.SimpleServlet;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.jboss.as.test.shared.util.AssumeTestGroupUtil;
import org.jboss.as.version.Stability;
import org.jboss.dmr.ModelNode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
Expand All @@ -52,6 +60,7 @@
import org.keycloak.representations.idm.RealmRepresentation;
import org.wildfly.common.iteration.CodePointIterator;
import org.wildfly.security.jose.util.JsonSerialization;
import org.wildfly.test.integration.elytron.oidc.client.subsystem.SimpleServletWithScope;

import io.restassured.RestAssured;

Expand Down Expand Up @@ -88,6 +97,16 @@ public abstract class OidcBaseTest {
static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
public static final String CORS_CLIENT = "CorsClient";
public static final String OPENID_SCOPE_APP = "OpenIDScopeApp";
public static final String INVALID_SCOPE_APP = "InvalidScopeApp";
public static final String SINGLE_SCOPE_APP = "SingleScopeApp";
public static final String MULTIPLE_SCOPE_APP = "MultipleScopeApp";

private final Stability desiredStability;

public OidcBaseTest(Stability desiredStability) {
this.desiredStability = desiredStability;
}

private enum BearerAuthType {
BEARER,
Expand Down Expand Up @@ -320,6 +339,46 @@ public void testCorsRequestWithoutEnableCors() throws Exception {
SimpleServlet.RESPONSE_BODY, null, CORS_CLIENT, CLIENT_SECRET, ALLOWED_ORIGIN, false);
}

/**
* Tests that use different scope values to request access to claims values.
*/

@Test
@OperateOnDeployment(OPENID_SCOPE_APP)
public void testOpenIDScope() throws Exception {
String expectedScope = OIDC_SCOPE;
loginToApp(KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, HttpURLConnection.HTTP_OK, SimpleServlet.RESPONSE_BODY, true,
new URL("http", TestSuiteEnvironment.getHttpAddress(), TestSuiteEnvironment.getHttpPort(),
"/" + OPENID_SCOPE_APP + SimpleServletWithScope.SERVLET_PATH).toURI(), expectedScope, false);
}

@Test
@OperateOnDeployment(SINGLE_SCOPE_APP)
public void testSingleScope() throws Exception {
String expectedScope = OIDC_SCOPE + "+profile";
loginToApp(KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, HttpURLConnection.HTTP_OK, SimpleServlet.RESPONSE_BODY, true,
new URL("http", TestSuiteEnvironment.getHttpAddress(), TestSuiteEnvironment.getHttpPort(),
"/" + SINGLE_SCOPE_APP + SimpleServletWithScope.SERVLET_PATH).toURI(), expectedScope, false);
}

@Test
@OperateOnDeployment(MULTIPLE_SCOPE_APP)
public void testMultipleScope() throws Exception {
String expectedScope = OIDC_SCOPE + "+phone+profile+microprofile-jwt+email";
loginToApp(KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, HttpURLConnection.HTTP_OK, SimpleServlet.RESPONSE_BODY, true,
new URL("http", TestSuiteEnvironment.getHttpAddress(), TestSuiteEnvironment.getHttpPort(),
"/" + MULTIPLE_SCOPE_APP + SimpleServletWithScope.SERVLET_PATH).toURI(), expectedScope, false);
}

@Test
@OperateOnDeployment(INVALID_SCOPE_APP)
public void testInvalidScope() throws Exception {
String expectedScope = OIDC_SCOPE + "+INVALID_SCOPE";
loginToApp(KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, HttpURLConnection.HTTP_OK, SimpleServlet.RESPONSE_BODY, false,
new URL("http", TestSuiteEnvironment.getHttpAddress(), TestSuiteEnvironment.getHttpPort(),
"/" + INVALID_SCOPE_APP + SimpleServletWithScope.SERVLET_PATH).toURI(), expectedScope, true);
}

public static void loginToApp(String appName, String username, String password, int expectedStatusCode, String expectedText) throws Exception {
loginToApp(username, password, expectedStatusCode, expectedText, true,
new URL("http", TestSuiteEnvironment.getHttpAddress(), TestSuiteEnvironment.getHttpPort(),
Expand All @@ -336,6 +395,10 @@ public static void loginToApp(String appName, String username, String password,
}

public static void loginToApp(String username, String password, int expectedStatusCode, String expectedText, boolean loginToKeycloak, URI requestUri) throws Exception {
loginToApp(username, password, expectedStatusCode, expectedText, loginToKeycloak, requestUri, null, false);
}

public static void loginToApp(String username, String password, int expectedStatusCode, String expectedText, boolean loginToKeycloak, URI requestUri, String expectedScope, boolean checkInvalidScope) throws Exception {
CookieStore store = new BasicCookieStore();
HttpClient httpClient = TestHttpClientUtils.promiscuousCookieHttpClientBuilder()
.setDefaultCookieStore(store)
Expand All @@ -355,7 +418,22 @@ public static void loginToApp(String username, String password, int expectedStat
if (expectedText != null) {
String responseString = new BasicResponseHandler().handleResponse(afterLoginClickResponse);
assertTrue("Unexpected result " + responseString, responseString.contains(expectedText));
if (expectedScope != null) {
assertTrue(context.toString().contains("scope=" + expectedScope));
if (expectedScope.contains("profile")) {
assertTrue(responseString.contains("profile: " + KeycloakConfiguration.ALICE_FIRST_NAME + " " + KeycloakConfiguration.ALICE_LAST_NAME));
}
if (expectedScope.contains("email")) {
assertTrue(responseString.contains("email: " + KeycloakConfiguration.ALICE_EMAIL_VERIFIED));
}
if (expectedScope.contains("microprofile-jwt")) {
assertTrue(responseString.contains("microprofile-jwt: [" + KeycloakConfiguration.JBOSS_ADMIN_ROLE + ", " + KeycloakConfiguration.USER_ROLE + "]"));
}
}
}
} else if (checkInvalidScope) {
assertTrue(context.toString().contains("error_description=Invalid+scopes"));
assertTrue("Expected code == BAD REQUEST but got " + statusCode + " for request=" + requestUri, statusCode == HttpURLConnection.HTTP_BAD_REQUEST);
} else {
assertTrue("Expected code == FORBIDDEN but got " + statusCode + " for request=" + requestUri, statusCode == HttpURLConnection.HTTP_FORBIDDEN);
}
Expand Down Expand Up @@ -653,4 +731,9 @@ public enum Type {
HIDDEN, SUBMIT
}
}
protected static <T extends OidcBaseTest> void addSystemProperty(ManagementClient client, Class<T> clazz) throws Exception {
ModelNode add = Util.createAddOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, OidcBaseTest.class.getName()));
add.get(VALUE).set(clazz.getName());
ManagementOperations.executeOperation(client.getControllerClient(), add);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.jboss.as.test.integration.security.common.Utils;
import org.jboss.as.test.integration.security.common.servlets.SimpleSecuredServlet;
import org.jboss.as.test.integration.security.common.servlets.SimpleServlet;
import org.jboss.as.version.Stability;
import org.jboss.dmr.ModelNode;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
Expand All @@ -33,6 +34,8 @@
import org.wildfly.test.integration.elytron.oidc.client.OidcBaseTest;

import io.restassured.RestAssured;
import org.wildfly.test.integration.elytron.oidc.client.subsystem.SimpleServletWithScope;
import org.wildfly.test.stabilitylevel.StabilityServerSetupSnapshotRestoreTasks;

/**
* Tests for the OpenID Connect authentication mechanism.
Expand All @@ -41,7 +44,7 @@
*/
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup({ OidcWithDeploymentConfigTest.KeycloakAndSystemPropertySetup.class })
@ServerSetup({ OidcWithDeploymentConfigTest.PreviewStabilitySetupTask.class, OidcWithDeploymentConfigTest.KeycloakAndSystemPropertySetup.class })
public class OidcWithDeploymentConfigTest extends OidcBaseTest {

private static final String OIDC_PROVIDER_URL = "oidc.provider.url";
Expand All @@ -63,6 +66,10 @@ public class OidcWithDeploymentConfigTest extends OidcBaseTest {
private static final String BEARER_ONLY_WITH_PROVIDER_URL_FILE = "BearerOnlyWithProviderUrl.json";
private static final String BASIC_AUTH_WITH_PROVIDER_URL_FILE = "BasicAuthWithProviderUrl.json";
private static final String CORS_WITH_PROVIDER_URL_FILE = "CorsWithProviderUrl.json";
private static final String SINGLE_SCOPE_FILE = "OidcWithSingleScope.json";
private static final String MULTI_SCOPE_FILE = "OidcWithMultipleScopes.json";
private static final String INVALID_SCOPE_FILE = "OidcWithInvalidScope.json";
private static final String OPENID_SCOPE_FILE = "OidcWithOpenIDScope.json";

private static Map<String, KeycloakConfiguration.ClientAppType> APP_NAMES;
static {
Expand All @@ -78,6 +85,14 @@ public class OidcWithDeploymentConfigTest extends OidcBaseTest {
APP_NAMES.put(BASIC_AUTH_PROVIDER_URL_APP, KeycloakConfiguration.ClientAppType.BEARER_ONLY_CLIENT);
APP_NAMES.put(CORS_PROVIDER_URL_APP, KeycloakConfiguration.ClientAppType.BEARER_ONLY_CLIENT);
APP_NAMES.put(CORS_CLIENT, KeycloakConfiguration.ClientAppType.CORS_CLIENT);
APP_NAMES.put(SINGLE_SCOPE_APP, KeycloakConfiguration.ClientAppType.OIDC_CLIENT);
APP_NAMES.put(MULTIPLE_SCOPE_APP, KeycloakConfiguration.ClientAppType.OIDC_CLIENT);
APP_NAMES.put(INVALID_SCOPE_APP, KeycloakConfiguration.ClientAppType.OIDC_CLIENT);
APP_NAMES.put(OPENID_SCOPE_APP, KeycloakConfiguration.ClientAppType.OIDC_CLIENT);
}

public OidcWithDeploymentConfigTest() {
super(Stability.PREVIEW);
}

@ArquillianResource
Expand Down Expand Up @@ -164,6 +179,42 @@ public static WebArchive createCorsProviderUrlDeployment() {
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), CORS_WITH_PROVIDER_URL_FILE, "oidc.json");
}

@Deployment(name = SINGLE_SCOPE_APP, managed = false, testable = false)
public static WebArchive createSingleScopeDeployment() {
return ShrinkWrap.create(WebArchive.class, SINGLE_SCOPE_APP + ".war")
.addClasses(SimpleServlet.class)
.addClasses(SimpleServletWithScope.class)
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), OIDC_WITHOUT_SUBSYSTEM_CONFIG_WEB_XML, "web.xml")
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), SINGLE_SCOPE_FILE, "oidc.json");
}

@Deployment(name = MULTIPLE_SCOPE_APP, managed = false, testable = false)
public static WebArchive createMultipleScopeDeployment() {
return ShrinkWrap.create(WebArchive.class, MULTIPLE_SCOPE_APP + ".war")
.addClasses(SimpleServlet.class)
.addClasses(SimpleServletWithScope.class)
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), OIDC_WITHOUT_SUBSYSTEM_CONFIG_WEB_XML, "web.xml")
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), MULTI_SCOPE_FILE, "oidc.json");
}

@Deployment(name = INVALID_SCOPE_APP, managed = false, testable = false)
public static WebArchive createInvalidScopeDeployment() {
return ShrinkWrap.create(WebArchive.class, INVALID_SCOPE_APP + ".war")
.addClasses(SimpleServlet.class)
.addClasses(SimpleServletWithScope.class)
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), OIDC_WITHOUT_SUBSYSTEM_CONFIG_WEB_XML, "web.xml")
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), INVALID_SCOPE_FILE, "oidc.json");
}

@Deployment(name = OPENID_SCOPE_APP, managed = false, testable = false)
public static WebArchive createOpenIdScopeDeployment() {
return ShrinkWrap.create(WebArchive.class, OPENID_SCOPE_APP + ".war")
.addClasses(SimpleServlet.class)
.addClasses(SimpleServletWithScope.class)
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), OIDC_WITHOUT_SUBSYSTEM_CONFIG_WEB_XML, "web.xml")
.addAsWebInfResource(OidcWithDeploymentConfigTest.class.getPackage(), OPENID_SCOPE_FILE, "oidc.json");
}

@Test
@InSequence(1)
public void testWrongPasswordWithProviderUrl() throws Exception {
Expand Down Expand Up @@ -381,6 +432,46 @@ public void testCorsRequestWithEnableCorsWithInvalidOrigin() throws Exception {
}
}

@Test
public void testOpenIDScope() throws Exception {
try{
deployer.deploy(OPENID_SCOPE_APP);
super.testOpenIDScope();
} finally {
deployer.undeploy(OPENID_SCOPE_APP);
}
}

@Test
public void testSingleScope() throws Exception {
try {
deployer.deploy(SINGLE_SCOPE_APP);
super.testSingleScope();
} finally {
deployer.undeploy(SINGLE_SCOPE_APP);
}
}

@Test
public void testMultipleScope() throws Exception {
try {
deployer.deploy(MULTIPLE_SCOPE_APP);
super.testMultipleScope();
} finally {
deployer.undeploy(MULTIPLE_SCOPE_APP);
}
}

@Test
public void testInvalidScope() throws Exception {
try {
deployer.deploy(INVALID_SCOPE_APP);
super.testInvalidScope();
} finally {
deployer.undeploy(INVALID_SCOPE_APP);
}
}

static class KeycloakAndSystemPropertySetup extends KeycloakSetup {

@Override
Expand Down Expand Up @@ -422,4 +513,13 @@ public void tearDown(ManagementClient managementClient, String containerId) thro
Utils.applyUpdate(operation, client);
}
}

public static class PreviewStabilitySetupTask extends StabilityServerSetupSnapshotRestoreTasks.Preview {
@Override
protected void doSetup(ManagementClient managementClient) throws Exception {
// Write a system property so the model gets stored with a lower stability level.
// This is to make sure we can reload back to the higher level from the snapshot
OidcBaseTest.addSystemProperty(managementClient, OidcWithDeploymentConfigTest.class);
}
}
}
Loading

0 comments on commit 1b758e7

Please sign in to comment.