diff --git a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java index b848902187..bdfdd98c24 100644 --- a/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java +++ b/http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcRequestAuthenticator.java @@ -169,7 +169,7 @@ protected String getRedirectUri(String state) { for (String paramName : forwardableQueryParams) { String paramValue = getQueryParamValue(facade, paramName); if (SCOPE.equals(paramName)) { - paramValue = removeInvalidScopeValue(addOidcScopeIfNeeded(deployment.getScope())); + paramValue = addOidcScopeIfNeeded(deployment.getScope()); } if (paramValue != null && !paramValue.isEmpty()) { forwardedQueryParams.add(new BasicNameValuePair(paramName, paramValue)); @@ -405,13 +405,6 @@ private static String addOidcScopeIfNeeded(String scope) { } } - private static String removeInvalidScopeValue(String scope){ - List requestedScopeValues = new ArrayList<>(Arrays.asList(scope.split(" "))); - List validScopeValues = new ArrayList<>(Arrays.asList("profile", "email", "phone", "address", "offline_access", OIDC_SCOPE)); - requestedScopeValues.removeIf(value -> !validScopeValues.contains(value)); - return String.join(" ", requestedScopeValues); - } - private static boolean hasScope(String scopeParam, String targetScope) { if (scopeParam == null || targetScope == null) { return false; diff --git a/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcTest.java b/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcTest.java index e041fa61b3..169b6dc482 100644 --- a/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcTest.java +++ b/http/oidc/src/test/java/org/wildfly/security/http/oidc/OidcTest.java @@ -30,8 +30,10 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.List; import java.util.Map; +import com.gargoylesoftware.htmlunit.WebClient; import org.apache.http.HttpStatus; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -45,6 +47,7 @@ import io.restassured.RestAssured; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.QueueDispatcher; +import org.wildfly.security.http.HttpServerCookie; /** * Tests for the OpenID Connect authentication mechanism. @@ -165,12 +168,10 @@ public void testTokenSignatureAlgorithm() throws Exception { performAuthentication(getOidcConfigurationInputStreamWithTokenSignatureAlgorithm(), KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, true, HttpStatus.SC_MOVED_TEMPORARILY, getClientUrl(), CLIENT_PAGE_TEXT); } - @Test public void testInvalidScope() throws Exception { - performAuthentication(getoidcConfigurationInputStreamWithScope(CLIENT_SECRET, "INVALID_SCOPE"), KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, - true, HttpStatus.SC_MOVED_TEMPORARILY, getClientUrl(), CLIENT_PAGE_TEXT); - checkScopeValuesInHTTPServerResponse(OIDC_SCOPE); + checkInvalidScopeError(getoidcConfigurationInputStreamWithScope(CLIENT_SECRET, "INVALID_SCOPE"), KeycloakConfiguration.ALICE, KeycloakConfiguration.ALICE_PASSWORD, + true, HttpStatus.SC_MOVED_TEMPORARILY, getClientUrl(), "error=invalid_scope", OIDC_SCOPE + "+INVALID_SCOPE"); } @Test @@ -241,6 +242,42 @@ private void checkScopeValuesInHTTPServerResponse(String expectedScope) throws H assert(response.getFirstResponseHeaderValue("Location").contains("scope=" + expectedScope)); } + private void checkInvalidScopeError(InputStream oidcConfig, String username, String password, boolean loginToKeycloak, + int expectedDispatcherStatusCode, String expectedLocation, String clientPageText, String expectedScope) throws Exception { + try { + Map props = new HashMap<>(); + OidcClientConfiguration oidcClientConfiguration = OidcClientConfigurationBuilder.build(oidcConfig); + assertEquals(OidcClientConfiguration.RelativeUrlsUsed.NEVER, oidcClientConfiguration.getRelativeUrls()); + + OidcClientContext oidcClientContext = new OidcClientContext(oidcClientConfiguration); + oidcFactory = new OidcMechanismFactory(oidcClientContext); + HttpServerAuthenticationMechanism mechanism = oidcFactory.createAuthenticationMechanism(OIDC_NAME, props, getCallbackHandler()); + + URI requestUri = new URI(getClientUrl()); + TestingHttpServerRequest request = new TestingHttpServerRequest(null, requestUri); + mechanism.evaluateRequest(request); + TestingHttpServerResponse response = request.getResponse(); + assert(response.getFirstResponseHeaderValue("Location").contains("scope=" + expectedScope)); + assertEquals(loginToKeycloak ? HttpStatus.SC_MOVED_TEMPORARILY : HttpStatus.SC_FORBIDDEN, response.getStatusCode()); + assertEquals(Status.NO_AUTH, request.getResult()); + + if (loginToKeycloak) { + client.setDispatcher(createAppResponse(mechanism, expectedDispatcherStatusCode, expectedLocation, clientPageText)); + WebClient webClient = getWebClient(); + List cookies = response.getCookies(); + if (cookies != null) { + for (HttpServerCookie cookie : cookies) { + webClient.addCookie(getCookieString(cookie), requestUri.toURL(), null); + } + } + TextPage keycloakLoginPage = webClient.getPage(response.getLocation()); + assertTrue(keycloakLoginPage.getWebResponse().getWebRequest().toString().contains("error_description=Invalid+scopes")); + } + } finally { + client.setDispatcher(new QueueDispatcher()); + } + } + private InputStream getOidcConfigurationInputStream(String clientSecret, String authServerUrl) { String oidcConfig = "{\n" + " \"realm\" : \"" + TEST_REALM + "\",\n" +