From dbd516f8e6f5152f292bedc1caffa601880f7eb9 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 29 Sep 2025 08:37:05 +0200 Subject: [PATCH] Refactor SimpleHttp to make it injectable and usable outside server (#42936) Closes #42902 Signed-off-by: stianst --- .../topics/changes/changes-26_4_0.adoc | 4 + .../keycloak/ipatuura_user_spi/Ipatuura.java | 47 +-- .../IpatuuraUserModelDelegate.java | 7 +- .../IpatuuraUserStorageProvider.java | 8 +- .../IpatuuraUserStorageProviderFactory.java | 4 +- .../broker/provider/util/SimpleHttp.java | 4 + .../org/keycloak/http/simple/SimpleHttp.java | 69 +++++ .../http/simple/SimpleHttpMethod.java | 7 + .../http/simple/SimpleHttpRequest.java | 277 ++++++++++++++++++ .../http/simple/SimpleHttpResponse.java | 149 ++++++++++ .../util => http/simple}/SimpleHttpTest.java | 13 +- .../broker/oauth/OAuth2IdentityProvider.java | 10 +- .../oidc/AbstractOAuth2IdentityProvider.java | 62 ++-- .../oidc/KeycloakOIDCIdentityProvider.java | 4 +- .../broker/oidc/OIDCIdentityProvider.java | 16 +- .../broker/saml/SAMLIdentityProvider.java | 4 +- .../email/TokenAuthEmailAuthenticator.java | 4 +- .../HttpAuthenticationChannelProvider.java | 7 +- ...channelAuthenticationCallbackEndpoint.java | 5 +- .../protocol/saml/profile/util/Soap.java | 8 +- .../IntentClientBindCheckExecutor.java | 5 +- .../bitbucket/BitbucketIdentityProvider.java | 9 +- .../facebook/FacebookIdentityProvider.java | 6 +- .../social/github/GitHubIdentityProvider.java | 14 +- .../social/gitlab/GitLabIdentityProvider.java | 8 +- .../social/google/GoogleIdentityProvider.java | 9 +- .../instagram/InstagramIdentityProvider.java | 4 +- .../LinkedInOIDCIdentityProviderFactory.java | 5 +- .../microsoft/MicrosoftIdentityProvider.java | 6 +- .../OpenshiftV4IdentityProvider.java | 4 +- .../social/paypal/PayPalIdentityProvider.java | 5 +- .../StackoverflowIdentityProvider.java | 9 +- .../CoreTestFrameworkExtension.java | 4 +- .../annotations/InjectSimpleHttp.java | 12 + .../http/SimpleHttpSupplier.java | 23 ++ .../external/SpiffeConfigTest.java | 11 +- .../org/keycloak/tests/utils/SimpleHttp.java | 32 -- .../testsuite/account/AccountRestClient.java | 4 +- .../broker/util/SimpleHttpDefault.java | 31 +- ...ountRestServiceReadOnlyAttributesTest.java | 4 +- .../account/AccountRestServiceTest.java | 75 ++--- ...AccountRestServiceWithUserProfileTest.java | 7 +- .../account/ResourcesRestServiceTest.java | 27 +- ...onUpdateEmailTestWithVerificationTest.java | 28 +- .../testsuite/broker/KcOidcBrokerTest.java | 15 +- .../KcOidcBrokerTransientSessionsTest.java | 4 +- .../error/UncaughtErrorPageTest.java | 4 +- .../ldap/LDAPAccountRestApiTest.java | 4 +- .../forms/LevelOfAssuranceFlowTest.java | 6 +- .../keycloak/testsuite/i18n/EmailTest.java | 4 +- .../testsuite/oauth/OAuthRedirectUriTest.java | 8 +- .../testsuite/oauth/TokenRevocationTest.java | 4 +- .../oidc/AbstractWellKnownProviderTest.java | 7 +- .../account/OrganizationAccountTest.java | 14 +- 54 files changed, 822 insertions(+), 299 deletions(-) create mode 100644 server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttp.java create mode 100644 server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpMethod.java create mode 100755 server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpRequest.java create mode 100644 server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpResponse.java rename server-spi-private/src/test/java/org/keycloak/{broker/provider/util => http/simple}/SimpleHttpTest.java (90%) create mode 100644 test-framework/core/src/main/java/org/keycloak/testframework/annotations/InjectSimpleHttp.java create mode 100644 test-framework/core/src/main/java/org/keycloak/testframework/http/SimpleHttpSupplier.java delete mode 100644 tests/utils/src/main/java/org/keycloak/tests/utils/SimpleHttp.java diff --git a/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc b/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc index 808d88765fa..5743d3a8ece 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc @@ -318,6 +318,10 @@ If, for whatever reason, an administrator in a common realm needs to access the The previous workaround is marked as deprecated and it can be removed in a future version of {project_name}. +=== Refactoring to `SimpleHttp` + +The `SimpleHttp` util in the `server-spi-private` module was refactored and moved to the `org.keycloak.http.simple` package. + // ------------------------ Deprecated features ------------------------ // == Deprecated features diff --git a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/Ipatuura.java b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/Ipatuura.java index 00c148d3be3..59a275a7c84 100644 --- a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/Ipatuura.java +++ b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/Ipatuura.java @@ -25,9 +25,10 @@ import java.util.ArrayList; import java.util.List; import org.keycloak.component.ComponentModel; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.KeycloakSession; -import org.keycloak.broker.provider.util.SimpleHttp; -import org.keycloak.broker.provider.util.SimpleHttp.Response; import org.keycloak.ipatuura_user_spi.schemas.SCIMSearchRequest; import org.keycloak.ipatuura_user_spi.schemas.SCIMUser; @@ -52,7 +53,7 @@ public class Ipatuura { this.session = session; } - private void parseSetCookie(Response response) throws IOException { + private void parseSetCookie(SimpleHttpResponse response) throws IOException { List setCookieHeaders = response.getHeader("Set-Cookie"); for (String h : setCookieHeaders) { @@ -73,7 +74,7 @@ public class Ipatuura { public Integer csrfAuthLogin() { - Response response; + SimpleHttpResponse response; /* Get inputs */ String server = model.getConfig().getFirst("scimurl"); @@ -84,7 +85,7 @@ public class Ipatuura { String url = String.format("https://%s%s", server, "/admin/login/"); try { - response = SimpleHttp.doGet(url, session).asResponse(); + response = SimpleHttp.create(session).doGet(url).asResponse(); parseSetCookie(response); response.close(); } catch (Exception e) { @@ -95,7 +96,7 @@ public class Ipatuura { /* Perform login POST */ try { /* Here we retrieve the Response sessionid and csrftoken cookie */ - response = SimpleHttp.doPost(url, session).header("X-CSRFToken", csrf_value).header("Cookie", csrf_cookie) + response = SimpleHttp.create(session).doPost(url).header("X-CSRFToken", csrf_value).header("Cookie", csrf_cookie) .header("referer", url).param("username", username).param("password", password).asResponse(); parseSetCookie(response); @@ -120,10 +121,10 @@ public class Ipatuura { String endpointurl = String.format("https://%s/creds/simple_pwd", server); logger.debugv("Sending POST request to {0}", endpointurl); - SimpleHttp simpleHttp = SimpleHttp.doPost(endpointurl, session).header("X-CSRFToken", this.csrf_value) + SimpleHttpRequest simpleHttp = SimpleHttp.create(session).doPost(endpointurl).header("X-CSRFToken", this.csrf_value) .header("Cookie", this.csrf_cookie).header("SessionId", sessionid_cookie).header("referer", endpointurl) .param("username", username).param("password", password); - try (Response response = simpleHttp.asResponse()){ + try (SimpleHttpResponse response = simpleHttp.asResponse()){ JsonNode result = response.asJson(); return (result.get("result").get("validated").asBoolean()); } catch (Exception e) { @@ -139,9 +140,9 @@ public class Ipatuura { String endpointurl = String.format("https://%s/bridge/login_kerberos/", server); logger.debugv("Sending POST request to {0}", endpointurl); - SimpleHttp simpleHttp = SimpleHttp.doPost(endpointurl, session).header("Authorization", "Negotiate " + spnegoToken) + SimpleHttpRequest simpleHttp = SimpleHttp.create(session).doPost(endpointurl).header("Authorization", "Negotiate " + spnegoToken) .param("username", ""); - try (Response response = simpleHttp.asResponse()) { + try (SimpleHttpResponse response = simpleHttp.asResponse()) { logger.debugv("Response status is {0}", response.getStatus()); return response.getFirstHeader("Remote-User"); } catch (Exception e) { @@ -150,8 +151,8 @@ public class Ipatuura { } } - public Response clientRequest(String endpoint, String method, T entity) throws Exception { - Response response = null; + public SimpleHttpResponse clientRequest(String endpoint, String method, T entity) throws Exception { + SimpleHttpResponse response = null; if (!this.logged_in) { this.csrfAuthLogin(); @@ -171,22 +172,22 @@ public class Ipatuura { try { switch (method) { case "GET": - response = SimpleHttp.doGet(endpointurl, session).header("X-CSRFToken", csrf_value) + response = SimpleHttp.create(session).doGet(endpointurl).header("X-CSRFToken", csrf_value) .header("Cookie", csrf_cookie).header("SessionId", sessionid_cookie).asResponse(); break; case "DELETE": - response = SimpleHttp.doDelete(endpointurl, session).header("X-CSRFToken", csrf_value) + response = SimpleHttp.create(session).doDelete(endpointurl).header("X-CSRFToken", csrf_value) .header("Cookie", csrf_cookie).header("SessionId", sessionid_cookie).header("referer", endpointurl) .asResponse(); break; case "POST": /* Header is needed for domains endpoint only, but use it here anyway */ - response = SimpleHttp.doPost(endpointurl, session).header("X-CSRFToken", this.csrf_value) + response = SimpleHttp.create(session).doPost(endpointurl).header("X-CSRFToken", this.csrf_value) .header("Cookie", this.csrf_cookie).header("SessionId", sessionid_cookie) .header("referer", endpointurl).json(entity).asResponse(); break; case "PUT": - response = SimpleHttp.doPut(endpointurl, session).header("X-CSRFToken", this.csrf_value) + response = SimpleHttp.create(session).doPut(endpointurl).header("X-CSRFToken", this.csrf_value) .header("SessionId", sessionid_cookie).header("Cookie", this.csrf_cookie).json(entity).asResponse(); break; default: @@ -223,7 +224,7 @@ public class Ipatuura { String usersSearchUrl = "Users/.search"; SCIMUser user = null; - Response response; + SimpleHttpResponse response; try { response = clientRequest(usersSearchUrl, "POST", newSearch); user = response.asJson(SCIMUser.class); @@ -256,13 +257,13 @@ public class Ipatuura { return getUserByAttr(username, attribute); } - public Response deleteUser(String username) { + public SimpleHttpResponse deleteUser(String username) { SCIMUser userobj = getUserByUsername(username); SCIMUser.Resource user = userobj.getResources().get(0); String userIdUrl = String.format("Users/%s", user.getId()); - Response response; + SimpleHttpResponse response; try { response = clientRequest(userIdUrl, "DELETE", null); } catch (Exception e) { @@ -305,12 +306,12 @@ public class Ipatuura { return user; } - public Response createUser(String username) { + public SimpleHttpResponse createUser(String username) { String usersUrl = "Users"; SCIMUser.Resource newUser = setupUser(username); - Response response; + SimpleHttpResponse response; try { response = clientRequest(usersUrl, "POST", newUser); } catch (Exception e) { @@ -349,7 +350,7 @@ public class Ipatuura { } } - public Response updateUser(Ipatuura ipatuura, String username, String attr, List values) { + public SimpleHttpResponse updateUser(Ipatuura ipatuura, String username, String attr, List values) { logger.debug(String.format("Updating %s attribute for %s", attr, username)); /* Get existing user */ if (ipatuura.csrfAuthLogin() == null) { @@ -365,7 +366,7 @@ public class Ipatuura { /* Update user in SCIM */ String modifyUrl = String.format("Users/%s", user.getId()); - Response response; + SimpleHttpResponse response; try { response = clientRequest(modifyUrl, "PUT", user); } catch (Exception e) { diff --git a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserModelDelegate.java b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserModelDelegate.java index 1c5ac232bc1..b3e832e3b37 100644 --- a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserModelDelegate.java +++ b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserModelDelegate.java @@ -17,17 +17,16 @@ package org.keycloak.ipatuura_user_spi; +import org.apache.http.HttpStatus; import org.jboss.logging.Logger; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.component.ComponentModel; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.UserModel; import org.keycloak.models.utils.UserModelDelegate; import java.io.IOException; import java.util.List; -import org.apache.http.HttpStatus; - public class IpatuuraUserModelDelegate extends UserModelDelegate { private static final Logger logger = Logger.getLogger(IpatuuraUserModelDelegate.class); @@ -44,7 +43,7 @@ public class IpatuuraUserModelDelegate extends UserModelDelegate { @Override public void setAttribute(String attr, List values) { - SimpleHttp.Response resp = this.ipatuura.updateUser(ipatuura, this.getUsername(), attr, values); + SimpleHttpResponse resp = this.ipatuura.updateUser(ipatuura, this.getUsername(), attr, values); try { if (resp.getStatus() != HttpStatus.SC_OK && resp.getStatus() != HttpStatus.SC_NO_CONTENT) { logger.warn("Unexpected PUT status code returned"); diff --git a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProvider.java b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProvider.java index 9b24f0e99ff..8a9c5b23325 100755 --- a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProvider.java +++ b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProvider.java @@ -24,6 +24,7 @@ import org.keycloak.credential.CredentialAuthentication; import org.keycloak.credential.CredentialInput; import org.keycloak.credential.CredentialInputValidator; import org.keycloak.credential.UserCredentialManager; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.CredentialValidationOutput; import org.keycloak.models.GroupModel; import org.keycloak.models.KeycloakSession; @@ -37,7 +38,6 @@ import org.keycloak.storage.UserStoragePrivateUtil; import org.keycloak.storage.user.ImportedUserValidation; import org.keycloak.storage.user.UserLookupProvider; import org.keycloak.storage.user.UserRegistrationProvider; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.ipatuura_user_spi.authenticator.IpatuuraAuthenticator; import org.keycloak.ipatuura_user_spi.schemas.SCIMError; @@ -201,7 +201,7 @@ public class IpatuuraUserStorageProvider implements UserStorageProvider, UserLoo public UserModel addUser(RealmModel realm, String username) { Ipatuura ipatuura = this.ipatuura; - SimpleHttp.Response resp = ipatuura.createUser(username); + SimpleHttpResponse resp = ipatuura.createUser(username); try { if (resp.getStatus() != HttpStatus.SC_CREATED) { @@ -225,7 +225,7 @@ public class IpatuuraUserStorageProvider implements UserStorageProvider, UserLoo logger.debugv("Removing user: {0}", user.getUsername()); Ipatuura ipatuura = this.ipatuura; - SimpleHttp.Response resp = ipatuura.deleteUser(user.getUsername()); + SimpleHttpResponse resp = ipatuura.deleteUser(user.getUsername()); Boolean status = false; try { status = resp.getStatus() == HttpStatus.SC_NO_CONTENT; @@ -267,7 +267,7 @@ public class IpatuuraUserStorageProvider implements UserStorageProvider, UserLoo Ipatuura ipatuura = this.ipatuura; SCIMUser user = null; - SimpleHttp.Response response; + SimpleHttpResponse response; try { response = ipatuura.clientRequest("/Users", "GET", null); user = response.asJson(SCIMUser.class); diff --git a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProviderFactory.java b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProviderFactory.java index 22006f187f8..705f3153b65 100755 --- a/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProviderFactory.java +++ b/federation/ipatuura/src/main/java/org/keycloak/ipatuura_user_spi/IpatuuraUserStorageProviderFactory.java @@ -19,9 +19,9 @@ package org.keycloak.ipatuura_user_spi; import org.jboss.logging.Logger; import org.keycloak.Config; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.Profile; import org.keycloak.component.ComponentModel; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.component.ComponentValidationException; @@ -75,7 +75,7 @@ public class IpatuuraUserStorageProviderFactory implements UserStorageProviderFa throws ComponentValidationException { Ipatuura ipatuura = new Ipatuura(session, config); - SimpleHttp.Response response; + SimpleHttpResponse response; try { response = ipatuura.clientRequest("", "GET", null); diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java index 511de51d5bb..2d4699ee4a6 100755 --- a/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java +++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java @@ -68,7 +68,11 @@ import java.util.zip.GZIPInputStream; * @author Stian Thorgersen * @author Vlastimil Elias (velias at redhat dot com) * @author David Klassen (daviddd.kl@gmail.com) + * + * @deprecated An updated version of SimpleHttp is available in {@link org.keycloak.http.simple.SimpleHttp}. This + * version will be deleted in Keycloak 27.0 */ +@Deprecated public class SimpleHttp { private static final ObjectMapper mapper = new ObjectMapper(); diff --git a/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttp.java b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttp.java new file mode 100644 index 00000000000..d13b44c1ec4 --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttp.java @@ -0,0 +1,69 @@ +package org.keycloak.http.simple; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.keycloak.connections.httpclient.HttpClientProvider; +import org.keycloak.models.KeycloakSession; + +public class SimpleHttp { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final HttpClient client; + private long maxConsumedResponseSize; + private RequestConfig requestConfig; + + private SimpleHttp(HttpClient client, long maxConsumedResponseSize) { + this.client = client; + this.maxConsumedResponseSize = maxConsumedResponseSize; + } + + public static SimpleHttp create(KeycloakSession session) { + HttpClientProvider provider = session.getProvider(HttpClientProvider.class); + return new SimpleHttp(provider.getHttpClient(), provider.getMaxConsumedResponseSize()); + } + + public static SimpleHttp create(HttpClient httpClient) { + return new SimpleHttp(httpClient, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); + } + + public SimpleHttp withRequestConfig(RequestConfig requestConfig) { + this.requestConfig = requestConfig; + return this; + } + + public SimpleHttp withMaxConsumedResponseSize(long maxConsumedResponseSize) { + this.maxConsumedResponseSize = maxConsumedResponseSize; + return this; + } + + private SimpleHttpRequest doRequest(String url, SimpleHttpMethod method) { + return new SimpleHttpRequest(url, method, client, requestConfig, maxConsumedResponseSize, objectMapper); + } + + public SimpleHttpRequest doGet(String url) { + return doRequest(url, SimpleHttpMethod.GET); + } + + public SimpleHttpRequest doPost(String url) { + return doRequest(url, SimpleHttpMethod.POST); + } + + public SimpleHttpRequest doPut(String url) { + return doRequest(url, SimpleHttpMethod.PUT); + } + + public SimpleHttpRequest doDelete(String url) { + return doRequest(url, SimpleHttpMethod.DELETE); + } + + public SimpleHttpRequest doHead(String url) { + return doRequest(url, SimpleHttpMethod.HEAD); + } + + public SimpleHttpRequest doPatch(String url) { + return doRequest(url, SimpleHttpMethod.PATCH); + } + +} diff --git a/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpMethod.java b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpMethod.java new file mode 100644 index 00000000000..1d5f12c2298 --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpMethod.java @@ -0,0 +1,7 @@ +package org.keycloak.http.simple; + +enum SimpleHttpMethod { + + GET, DELETE, HEAD, PUT, PATCH, POST + +} diff --git a/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpRequest.java b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpRequest.java new file mode 100755 index 00000000000..160c15fa614 --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpRequest.java @@ -0,0 +1,277 @@ +/* + * 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.http.simple; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHeaders; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpPatch; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.message.BasicNameValuePair; +import org.keycloak.common.util.Base64; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Stian Thorgersen + * @author Vlastimil Elias (velias at redhat dot com) + * @author David Klassen (daviddd.kl@gmail.com) + */ +public class SimpleHttpRequest { + + private final HttpClient client; + private final RequestConfig requestConfig; + + private final ObjectMapper objectMapper; + + private final String url; + private final SimpleHttpMethod method; + private Map headers; + private Map params; + private Object entity; + + private final long maxConsumedResponseSize; + + SimpleHttpRequest(String url, SimpleHttpMethod method, HttpClient client, RequestConfig requestConfig, long maxConsumedResponseSize, ObjectMapper objectMapper) { + this.client = client; + this.requestConfig = requestConfig; + this.url = url; + this.method = method; + this.maxConsumedResponseSize = maxConsumedResponseSize; + this.objectMapper = objectMapper; + } + + public SimpleHttpRequest header(String name, String value) { + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(name, value); + return this; + } + + public String getHeader(String name) { + if (headers != null) { + return headers.get(name); + } + return null; + } + + public Map getHeaders() { + if (headers == null) { + return null; + } + return Collections.unmodifiableMap(headers); + } + + public String getParam(String name) { + if (params == null) { + return null; + } + return params.get(name); + } + + public Map getParams() { + if (params == null) { + return null; + } + return Collections.unmodifiableMap(params); + } + + public Object getEntity() { + return entity; + } + + public SimpleHttpRequest json(Object entity) { + this.entity = entity; + return this; + } + + public SimpleHttpRequest entity(HttpEntity entity) { + this.entity = entity; + return this; + } + + public SimpleHttpRequest params(Map params) { + this.params = params; + return this; + } + + public SimpleHttpRequest param(String name, String value) { + if (params == null) { + params = new HashMap<>(); + } + params.put(name, value); + return this; + } + + public SimpleHttpRequest auth(String token) { + header("Authorization", "Bearer " + token); + return this; + } + + public SimpleHttpRequest authBasic(final String username, final String password) { + final String basicCredentials = String.format("%s:%s", username, password); + header("Authorization", "Basic " + Base64.encodeBytes(basicCredentials.getBytes())); + return this; + } + + public SimpleHttpRequest acceptJson() { + if (headers == null || !headers.containsKey("Accept")) { + header("Accept", "application/json"); + } + return this; + } + + public JsonNode asJson() throws IOException { + if (headers == null || !headers.containsKey("Accept")) { + header("Accept", "application/json"); + } + return objectMapper.readTree(asString()); + } + + public T asJson(Class type) throws IOException { + if (headers == null || !headers.containsKey("Accept")) { + header("Accept", "application/json"); + } + return objectMapper.readValue(asString(), type); + } + + public T asJson(TypeReference type) throws IOException { + if (headers == null || !headers.containsKey("Accept")) { + header("Accept", "application/json"); + } + return objectMapper.readValue(asString(), type); + } + + public String asString() throws IOException { + return asResponse().asString(); + } + + public int asStatus() throws IOException { + return asResponse().getStatus(); + } + + public SimpleHttpResponse asResponse() throws IOException { + return makeRequest(); + } + + private HttpRequestBase createHttpRequest() { + return switch (method) { + case GET -> new HttpGet(appendParameterToUrl(url)); + case DELETE -> new HttpDelete(appendParameterToUrl(url)); + case HEAD -> new HttpHead(appendParameterToUrl(url)); + case PUT -> new HttpPut(appendParameterToUrl(url)); + case PATCH -> new HttpPatch(appendParameterToUrl(url)); + case POST -> new HttpPost(url); + }; + } + + /** + * @return the URL without params + */ + public String getUrl() { + return url; + } + + private SimpleHttpResponse makeRequest() throws IOException { + HttpRequestBase httpRequest = createHttpRequest(); + + if (httpRequest instanceof HttpPost || httpRequest instanceof HttpPut || httpRequest instanceof HttpPatch) { + if (params != null) { + ((HttpEntityEnclosingRequestBase) httpRequest).setEntity(getFormEntityFromParameter()); + } else if (entity instanceof HttpEntity) { + ((HttpEntityEnclosingRequestBase) httpRequest).setEntity((HttpEntity) entity); + } else if (entity != null) { + if (headers == null || !headers.containsKey(HttpHeaders.CONTENT_TYPE)) { + header(HttpHeaders.CONTENT_TYPE, "application/json"); + } + ((HttpEntityEnclosingRequestBase) httpRequest).setEntity(getJsonEntity()); + } else { + throw new IllegalStateException("No content set"); + } + } + + if (headers != null) { + for (Map.Entry h : headers.entrySet()) { + httpRequest.setHeader(h.getKey(), h.getValue()); + } + } + + if (requestConfig != null) { + httpRequest.setConfig(requestConfig); + } + + return new SimpleHttpResponse(client.execute(httpRequest), maxConsumedResponseSize, objectMapper); + } + + private URI appendParameterToUrl(String url) { + try { + URIBuilder uriBuilder = new URIBuilder(url); + + if (params != null) { + for (Map.Entry p : params.entrySet()) { + uriBuilder.setParameter(p.getKey(), p.getValue()); + } + } + + return uriBuilder.build(); + } catch (URISyntaxException ignored) { + return null; + } + } + + private StringEntity getJsonEntity() throws IOException { + return new StringEntity(objectMapper.writeValueAsString(entity), ContentType.getByMimeType(headers.get(HttpHeaders.CONTENT_TYPE))); + } + + private UrlEncodedFormEntity getFormEntityFromParameter() { + List urlParameters = new ArrayList<>(); + + if (params != null) { + for (Map.Entry p : params.entrySet()) { + urlParameters. add(new BasicNameValuePair(p.getKey(), p.getValue())); + } + } + + return new UrlEncodedFormEntity(urlParameters, StandardCharsets.UTF_8); + } + +} diff --git a/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpResponse.java b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpResponse.java new file mode 100644 index 00000000000..59223ceee7c --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpResponse.java @@ -0,0 +1,149 @@ +package org.keycloak.http.simple; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.Header; +import org.apache.http.HeaderIterator; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.entity.ContentType; +import org.keycloak.connections.httpclient.SafeInputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.GZIPInputStream; + +public class SimpleHttpResponse implements AutoCloseable { + + private final HttpResponse response; + private final long maxConsumedResponseSize; + private final ObjectMapper objectMapper; + private int statusCode = -1; + private String responseString; + private ContentType contentType; + + public SimpleHttpResponse(HttpResponse response, long maxConsumedResponseSize, ObjectMapper objectMapper) { + this.response = response; + this.maxConsumedResponseSize = maxConsumedResponseSize; + this.objectMapper = objectMapper; + } + + private void readResponse() throws IOException { + if (statusCode == -1) { + statusCode = response.getStatusLine().getStatusCode(); + + InputStream is; + HttpEntity entity = response.getEntity(); + if (entity != null) { + is = entity.getContent(); + contentType = ContentType.getOrDefault(entity); + Charset charset = contentType.getCharset(); + try { + HeaderIterator it = response.headerIterator(); + while (it.hasNext()) { + Header header = it.nextHeader(); + if (header.getName().equals("Content-Encoding") && header.getValue().equals("gzip")) { + is = new GZIPInputStream(is); + } + } + + is = new SafeInputStream(is, maxConsumedResponseSize); + + try (InputStreamReader reader = charset == null ? new InputStreamReader(is, StandardCharsets.UTF_8) : + new InputStreamReader(is, charset)) { + + StringWriter writer = new StringWriter(); + + char[] buffer = new char[1024 * 4]; + for (int n = reader.read(buffer); n != -1; n = reader.read(buffer)) { + writer.write(buffer, 0, n); + } + + responseString = writer.toString(); + } + } finally { + if (is != null) { + is.close(); + } + } + } + } + } + + public int getStatus() throws IOException { + readResponse(); + return response.getStatusLine().getStatusCode(); + } + + public JsonNode asJson() throws IOException { + return objectMapper.readTree(asString()); + } + + public T asJson(Class type) throws IOException { + return objectMapper.readValue(asString(), type); + } + + public T asJson(TypeReference type) throws IOException { + return objectMapper.readValue(asString(), type); + } + + public String asString() throws IOException { + readResponse(); + return responseString; + } + + public String getFirstHeader(String name) throws IOException { + readResponse(); + Header[] headers = response.getHeaders(name); + + if (headers != null && headers.length > 0) { + return headers[0].getValue(); + } + + return null; + } + + public List getHeader(String name) throws IOException { + readResponse(); + Header[] headers = response.getHeaders(name); + + if (headers != null && headers.length > 0) { + return Stream.of(headers).map(Header::getValue).collect(Collectors.toList()); + } + + return null; + } + + public Header[] getAllHeaders() throws IOException { + readResponse(); + return response.getAllHeaders(); + } + + public ContentType getContentType() throws IOException { + readResponse(); + return contentType; + } + + public Charset getContentTypeCharset() throws IOException { + readResponse(); + if (contentType != null) { + Charset charset = contentType.getCharset(); + if (charset != null) { + return charset; + } + } + return StandardCharsets.UTF_8; + } + + public void close() throws IOException { + readResponse(); + } +} diff --git a/server-spi-private/src/test/java/org/keycloak/broker/provider/util/SimpleHttpTest.java b/server-spi-private/src/test/java/org/keycloak/http/simple/SimpleHttpTest.java similarity index 90% rename from server-spi-private/src/test/java/org/keycloak/broker/provider/util/SimpleHttpTest.java rename to server-spi-private/src/test/java/org/keycloak/http/simple/SimpleHttpTest.java index 619ec914098..6f4dbbb708d 100644 --- a/server-spi-private/src/test/java/org/keycloak/broker/provider/util/SimpleHttpTest.java +++ b/server-spi-private/src/test/java/org/keycloak/http/simple/SimpleHttpTest.java @@ -1,5 +1,6 @@ -package org.keycloak.broker.provider.util; +package org.keycloak.http.simple; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; @@ -70,7 +71,7 @@ public final class SimpleHttpTest { @Test public void withCharset() throws IOException { HttpResponse httpResponse = createBasicResponse(entity); - SimpleHttp.Response response = new SimpleHttp.Response(httpResponse, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); + SimpleHttpResponse response = new SimpleHttpResponse(httpResponse, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE, new ObjectMapper()); if (success) { assertEquals(original, response.asString()); } else { @@ -110,10 +111,10 @@ public final class SimpleHttpTest { String expectedResponse = "{\"value\":\"" + value + "\"}"; HttpClientMock client = new HttpClientMock(); if (expectedResponse.getBytes(StandardCharsets.UTF_8).length < 1024) { - SimpleHttp.Response response = SimpleHttp.doPost("", client, 1024).json(new DummyEntity(value)).asResponse(); + SimpleHttpResponse response = SimpleHttp.create(client).withMaxConsumedResponseSize(1024).doPost("").json(new DummyEntity(value)).asResponse(); assertEquals(expectedResponse, response.asString()); } else { - IOException e = assertThrows(IOException.class, () -> SimpleHttp.doPost("", client, 1024).json(new DummyEntity(value)).asResponse().asString()); + IOException e = assertThrows(IOException.class, () -> SimpleHttp.create(client).withMaxConsumedResponseSize(1024).doPost("").json(new DummyEntity(value)).asResponse().asString()); assertThat(e.getMessage(), startsWith("Response is at least")); } } @@ -123,10 +124,10 @@ public final class SimpleHttpTest { String expectedResponse = "dummy=" + URLEncoder.encode(value, StandardCharsets.UTF_8); HttpClientMock client = new HttpClientMock(); if (expectedResponse.getBytes(StandardCharsets.UTF_8).length < 1024) { - SimpleHttp.Response response = SimpleHttp.doPost("", client, 1024).param("dummy", value).asResponse(); + SimpleHttpResponse response = SimpleHttp.create(client).withMaxConsumedResponseSize(1024).doPost("").param("dummy", value).asResponse(); assertEquals(expectedResponse, response.asString()); } else { - IOException e = assertThrows(IOException.class, () -> SimpleHttp.doPost("", client, 1024).json(new DummyEntity(value)).asResponse().asString()); + IOException e = assertThrows(IOException.class, () -> SimpleHttp.create(client).withMaxConsumedResponseSize(1024).doPost("").json(new DummyEntity(value)).asResponse().asString()); assertThat(e.getMessage(), startsWith("Response is at least")); } } diff --git a/services/src/main/java/org/keycloak/broker/oauth/OAuth2IdentityProvider.java b/services/src/main/java/org/keycloak/broker/oauth/OAuth2IdentityProvider.java index f2ce8cf672a..4b66c10e83b 100755 --- a/services/src/main/java/org/keycloak/broker/oauth/OAuth2IdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oauth/OAuth2IdentityProvider.java @@ -25,7 +25,9 @@ import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.IdentityBrokerException; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.KeycloakSession; import org.keycloak.protocol.oidc.TokenExchangeContext; @@ -103,7 +105,7 @@ public class OAuth2IdentityProvider extends AbstractOAuth2IdentityProvider= 200 && status < 400; response = simpleResponse.asString(); @@ -775,10 +777,10 @@ public abstract class AbstractOAuth2IdentityProvider= 200 && status < 400; if (!success) { logger.warn("Failed backchannel broker logout to: " + url); @@ -359,8 +361,8 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider=200 && status < 400; diff --git a/services/src/main/java/org/keycloak/email/TokenAuthEmailAuthenticator.java b/services/src/main/java/org/keycloak/email/TokenAuthEmailAuthenticator.java index 297af519d38..1e7c52bb47e 100644 --- a/services/src/main/java/org/keycloak/email/TokenAuthEmailAuthenticator.java +++ b/services/src/main/java/org/keycloak/email/TokenAuthEmailAuthenticator.java @@ -5,7 +5,7 @@ import jakarta.mail.AuthenticationFailedException; import jakarta.mail.MessagingException; import jakarta.mail.Transport; import org.jboss.logging.Logger; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttp; import org.keycloak.models.KeycloakSession; import org.keycloak.utils.KeycloakSessionUtil; import org.keycloak.vault.VaultStringSecret; @@ -122,7 +122,7 @@ public class TokenAuthEmailAuthenticator implements EmailAuthenticator { } private JsonNode fetchTokenViaHTTP(KeycloakSession session, String authTokenUrl, String authTokenScope, String authTokenClientId, String authTokenClientSecret) throws IOException { - return SimpleHttp.doPost(authTokenUrl, session) + return SimpleHttp.create(session).doPost(authTokenUrl) .param("client_id", authTokenClientId) .param("client_secret", authTokenClientSecret) .param("scope", authTokenScope) diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/channel/HttpAuthenticationChannelProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/channel/HttpAuthenticationChannelProvider.java index 93bd9f78b88..f3743b822a3 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/channel/HttpAuthenticationChannelProvider.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/channel/HttpAuthenticationChannelProvider.java @@ -24,7 +24,8 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response.Status; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -78,7 +79,7 @@ public class HttpAuthenticationChannelProvider implements AuthenticationChannelP channelRequest.setAcrValues(request.getAcrValues()); channelRequest.setAdditionalParameters(request.getOtherClaims()); - SimpleHttp simpleHttp = SimpleHttp.doPost(httpAuthenticationChannelUri, session) + SimpleHttpRequest simpleHttp = SimpleHttp.create(session).doPost(httpAuthenticationChannelUri) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) .json(channelRequest) .auth(createBearerToken(request, client)); @@ -122,7 +123,7 @@ public class HttpAuthenticationChannelProvider implements AuthenticationChannelP /** * Extension point to allow subclass to override this method in order to add data to post to decoupled server. */ - protected SimpleHttp completeDecoupledAuthnRequest(SimpleHttp simpleHttp, AuthenticationChannelRequest channelRequest) { + protected SimpleHttpRequest completeDecoupledAuthnRequest(SimpleHttpRequest simpleHttp, AuthenticationChannelRequest channelRequest) { return simpleHttp; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/endpoints/BackchannelAuthenticationCallbackEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/endpoints/BackchannelAuthenticationCallbackEndpoint.java index df1893d8e5d..440ab34a333 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/endpoints/BackchannelAuthenticationCallbackEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/endpoints/BackchannelAuthenticationCallbackEndpoint.java @@ -21,10 +21,11 @@ import org.jboss.resteasy.reactive.NoCache; import org.keycloak.http.HttpRequest; import org.keycloak.OAuthErrorException; import org.keycloak.TokenVerifier; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; import org.keycloak.models.CibaConfig; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; @@ -221,7 +222,7 @@ public class BackchannelAuthenticationCallbackEndpoint extends AbstractCibaEndpo ClientNotificationEndpointRequest clientNotificationRequest = new ClientNotificationEndpointRequest(); clientNotificationRequest.setAuthReqId(deviceModel.getAuthReqId()); - SimpleHttp simpleHttp = SimpleHttp.doPost(clientNotificationEndpoint, session) + SimpleHttpRequest simpleHttp = SimpleHttp.create(session).doPost(clientNotificationEndpoint) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) .json(clientNotificationRequest) .auth(deviceModel.getClientNotificationToken()); diff --git a/services/src/main/java/org/keycloak/protocol/saml/profile/util/Soap.java b/services/src/main/java/org/keycloak/protocol/saml/profile/util/Soap.java index 25646991de9..f8866f51cd4 100755 --- a/services/src/main/java/org/keycloak/protocol/saml/profile/util/Soap.java +++ b/services/src/main/java/org/keycloak/protocol/saml/profile/util/Soap.java @@ -22,7 +22,9 @@ import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.KeycloakSession; import org.keycloak.saml.processing.core.saml.v2.util.DocumentUtil; import org.keycloak.saml.processing.web.util.PostBindingUtil; @@ -262,7 +264,7 @@ public final class Soap { message.saveChanges(); } // use SimpleHttp from the session - SimpleHttp simpleHttp = SimpleHttp.doPost(url, session); + SimpleHttpRequest simpleHttp = SimpleHttp.create(session).doPost(url); // add all the headers as HTTP headers except the ones needed for the HttpEntity Iterator reqHeaders = message.getMimeHeaders().getAllHeaders(); ContentType contentType = null; @@ -291,7 +293,7 @@ public final class Soap { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { message.writeTo(out); simpleHttp.entity(new ByteArrayEntity(out.toByteArray(), 0, length, contentType)); - try (SimpleHttp.Response res = simpleHttp.asResponse()) { + try (SimpleHttpResponse res = simpleHttp.asResponse()) { // HTTP_INTERNAL_ERROR (500) and HTTP_BAD_REQUEST (400) should be processed as SOAP faults if (res.getStatus() == HttpStatus.SC_INTERNAL_SERVER_ERROR || res.getStatus() == HttpStatus.SC_BAD_REQUEST diff --git a/services/src/main/java/org/keycloak/services/clientpolicy/executor/IntentClientBindCheckExecutor.java b/services/src/main/java/org/keycloak/services/clientpolicy/executor/IntentClientBindCheckExecutor.java index 30515eff93f..cddfcd6c5d4 100644 --- a/services/src/main/java/org/keycloak/services/clientpolicy/executor/IntentClientBindCheckExecutor.java +++ b/services/src/main/java/org/keycloak/services/clientpolicy/executor/IntentClientBindCheckExecutor.java @@ -26,7 +26,8 @@ import jakarta.ws.rs.core.MediaType; import org.jboss.logging.Logger; import org.keycloak.OAuthErrorException; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest; @@ -119,7 +120,7 @@ public class IntentClientBindCheckExecutor implements ClientPolicyExecutorProvid IntentBindCheckRequest request = new IntentBindCheckRequest(); request.setClientId(clientId); request.setIntentId(intentId); - SimpleHttp simpleHttp = SimpleHttp.doPost(configuration.getIntentClientBindCheckEndpoint(), session) + SimpleHttpRequest simpleHttp = SimpleHttp.create(session).doPost(configuration.getIntentClientBindCheckEndpoint()) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) .json(request); IntentBindCheckResponse response = null; diff --git a/services/src/main/java/org/keycloak/social/bitbucket/BitbucketIdentityProvider.java b/services/src/main/java/org/keycloak/social/bitbucket/BitbucketIdentityProvider.java index 964363b7840..86b5bae32a0 100755 --- a/services/src/main/java/org/keycloak/social/bitbucket/BitbucketIdentityProvider.java +++ b/services/src/main/java/org/keycloak/social/bitbucket/BitbucketIdentityProvider.java @@ -24,11 +24,12 @@ import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.IdentityBrokerException; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.broker.social.SocialIdentityProvider; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.KeycloakSession; import org.keycloak.services.ErrorResponseException; @@ -72,7 +73,7 @@ public class BitbucketIdentityProvider extends AbstractOAuth2IdentityProvider im @Override protected BrokeredIdentityContext validateExternalTokenThroughUserInfo(EventBuilder event, String subjectToken, String subjectTokenType) { event.detail("validation_method", "user info"); - SimpleHttp.Response response = null; + SimpleHttpResponse response = null; int status = 0; try { String userInfoUrl = getProfileEndpointForValidation(event); @@ -141,7 +142,7 @@ public class BitbucketIdentityProvider extends AbstractOAuth2IdentityProvider im AbstractJsonUserAttributeMapper.storeUserProfileForMapper(user, profile, getConfig().getAlias()); try { - JsonNode emails = SimpleHttp.doGet(USER_EMAIL_URL, session).header("Authorization", "Bearer " + subjectToken).asJson(); + JsonNode emails = SimpleHttp.create(session).doGet(USER_EMAIL_URL).header("Authorization", "Bearer " + subjectToken).asJson(); // {"pagelen":10,"values":[{"is_primary":true,"is_confirmed":true,"type":"email","email":"bburke@redhat.com","links":{"self":{"href":"https://api.bitbucket.org/2.0/user/emails/bburke@redhat.com"}}}],"page":1,"size":1} JsonNode emailJson = emails.get("values"); @@ -164,7 +165,7 @@ public class BitbucketIdentityProvider extends AbstractOAuth2IdentityProvider im @Override protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { try { - JsonNode profile = SimpleHttp.doGet(USER_URL, session).header("Authorization", "Bearer " + accessToken).asJson(); + JsonNode profile = SimpleHttp.create(session).doGet(USER_URL).header("Authorization", "Bearer " + accessToken).asJson(); String type = getJsonProperty(profile, "type"); if (type == null) { diff --git a/services/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java b/services/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java index fc26c1a4514..318e735ee5a 100755 --- a/services/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java +++ b/services/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java @@ -27,9 +27,9 @@ import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.IdentityBrokerException; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.broker.social.SocialIdentityProvider; import org.keycloak.events.EventBuilder; +import org.keycloak.http.simple.SimpleHttp; import org.keycloak.models.KeycloakSession; import org.keycloak.protocol.oidc.TokenExchangeContext; import org.keycloak.saml.common.util.StringUtil; @@ -62,7 +62,7 @@ public class FacebookIdentityProvider extends AbstractOAuth2IdentityProvider { + + @Override + public SimpleHttp getValue(InstanceContext instanceContext) { + HttpClient httpClient = instanceContext.getDependency(HttpClient.class); + return SimpleHttp.create(httpClient); + } + + @Override + public boolean compatible(InstanceContext a, RequestedInstance b) { + return true; + } + +} diff --git a/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java b/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java index d5df86956ed..06a01b718b6 100644 --- a/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java @@ -2,7 +2,6 @@ package org.keycloak.tests.client.authentication.external; import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.core.Response; -import org.apache.http.client.HttpClient; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; @@ -10,12 +9,13 @@ import org.junit.jupiter.api.TestMethodOrder; import org.keycloak.admin.client.resource.IdentityProvidersResource; import org.keycloak.broker.spiffe.SpiffeIdentityProviderConfig; import org.keycloak.broker.spiffe.SpiffeIdentityProviderFactory; +import org.keycloak.http.simple.SimpleHttp; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.IdentityProviderShowInAccountConsole; import org.keycloak.models.IdentityProviderStorageProvider; import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.testframework.annotations.InjectHttpClient; import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.annotations.InjectSimpleHttp; import org.keycloak.testframework.annotations.InjectUser; import org.keycloak.testframework.annotations.KeycloakIntegrationTest; import org.keycloak.testframework.oauth.OAuthClient; @@ -27,7 +27,6 @@ import org.keycloak.testframework.remote.runonserver.RunOnServerClient; import org.keycloak.testframework.ui.annotations.InjectPage; import org.keycloak.testframework.ui.page.LoginPage; import org.keycloak.tests.common.BasicUserConfig; -import org.keycloak.tests.utils.SimpleHttp; import org.keycloak.testsuite.util.IdentityProviderBuilder; import org.openqa.selenium.NoSuchElementException; @@ -46,8 +45,8 @@ public class SpiffeConfigTest { @InjectRunOnServer RunOnServerClient runOnServer; - @InjectHttpClient - HttpClient httpClient; + @InjectSimpleHttp + SimpleHttp simpleHttp; @InjectOAuthClient OAuthClient oAuthClient; @@ -90,7 +89,7 @@ public class SpiffeConfigTest { private void checkNoIdpsInAccountConsole() throws IOException { String accessToken = oAuthClient.passwordGrantRequest(user.getUsername(), user.getPassword()).send().getAccessToken(); String accountUrl = realm.getBaseUrl() + "/account//linked-accounts"; - JsonNode json = SimpleHttp.doGet(accountUrl, httpClient).auth(accessToken).asJson(); + JsonNode json = simpleHttp.doGet(accountUrl).auth(accessToken).asJson(); Assertions.assertEquals(0, json.size()); } diff --git a/tests/utils/src/main/java/org/keycloak/tests/utils/SimpleHttp.java b/tests/utils/src/main/java/org/keycloak/tests/utils/SimpleHttp.java deleted file mode 100644 index 3faf4ed08ad..00000000000 --- a/tests/utils/src/main/java/org/keycloak/tests/utils/SimpleHttp.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.keycloak.tests.utils; - -import org.apache.http.client.HttpClient; -import org.keycloak.connections.httpclient.HttpClientProvider; - -public class SimpleHttp extends org.keycloak.broker.provider.util.SimpleHttp { - - protected SimpleHttp(String url, String method, HttpClient client, long maxConsumedResponseSize) { - super(url, method, client, maxConsumedResponseSize); - } - - public static org.keycloak.broker.provider.util.SimpleHttp doDelete(String url, HttpClient client) { - return org.keycloak.broker.provider.util.SimpleHttp.doDelete(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); - } - - public static org.keycloak.broker.provider.util.SimpleHttp doPost(String url, HttpClient client) { - return org.keycloak.broker.provider.util.SimpleHttp.doPost(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); - } - - public static org.keycloak.broker.provider.util.SimpleHttp doPut(String url, HttpClient client) { - return org.keycloak.broker.provider.util.SimpleHttp.doPut(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); - } - - public static org.keycloak.broker.provider.util.SimpleHttp doGet(String url, HttpClient client) { - return org.keycloak.broker.provider.util.SimpleHttp.doGet(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); - } - - public static org.keycloak.broker.provider.util.SimpleHttp doHead(String url, HttpClient client) { - return org.keycloak.broker.provider.util.SimpleHttp.doHead(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); - } - -} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/account/AccountRestClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/account/AccountRestClient.java index 1caa2b15fab..7bf600ceb8b 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/account/AccountRestClient.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/account/AccountRestClient.java @@ -26,7 +26,7 @@ import java.util.function.Supplier; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.representations.account.CredentialMetadataRepresentation; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.resources.account.AccountCredentialResource; @@ -74,7 +74,7 @@ public class AccountRestClient implements AutoCloseable { .orElse(null); } - public SimpleHttp.Response removeCredential(String credentialId) { + public SimpleHttpResponse removeCredential(String credentialId) { try { return SimpleHttpDefault .doDelete(getAccountUrl("credentials/" + credentialId), httpClient) diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/broker/util/SimpleHttpDefault.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/broker/util/SimpleHttpDefault.java index 84db53e602b..eb6a835276b 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/broker/util/SimpleHttpDefault.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/broker/util/SimpleHttpDefault.java @@ -18,39 +18,34 @@ package org.keycloak.testsuite.broker.util; import org.apache.http.client.HttpClient; -import org.keycloak.broker.provider.util.SimpleHttp; -import org.keycloak.connections.httpclient.HttpClientProvider; +import org.keycloak.http.simple.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpRequest; /** * This class provides additional builders used in tests to create instances of SimpleHttpTest with a default length response size set. * * @author Alexander Schwartz */ -public abstract class SimpleHttpDefault extends SimpleHttp { +public abstract class SimpleHttpDefault { - protected SimpleHttpDefault(String url, String method, HttpClient client, long maxConsumedResponseSize) { - // dummy constructor, only needed to make the compiler happy - super(url, method, client, maxConsumedResponseSize); + public static SimpleHttpRequest doDelete(String url, HttpClient client) { + return SimpleHttp.create(client).doDelete(url); } - public static SimpleHttp doDelete(String url, HttpClient client) { - return SimpleHttp.doDelete(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); + public static SimpleHttpRequest doPost(String url, HttpClient client) { + return SimpleHttp.create(client).doPost(url); } - public static SimpleHttp doPost(String url, HttpClient client) { - return SimpleHttp.doPost(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); + public static SimpleHttpRequest doPut(String url, HttpClient client) { + return SimpleHttp.create(client).doPut(url); } - public static SimpleHttp doPut(String url, HttpClient client) { - return SimpleHttp.doPut(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); + public static SimpleHttpRequest doGet(String url, HttpClient client) { + return SimpleHttp.create(client).doGet(url); } - public static SimpleHttp doGet(String url, HttpClient client) { - return SimpleHttp.doGet(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); - } - - public static SimpleHttp doHead(String url, HttpClient client) { - return SimpleHttp.doHead(url, client, HttpClientProvider.DEFAULT_MAX_CONSUMED_RESPONSE_SIZE); + public static SimpleHttpRequest doHead(String url, HttpClient client) { + return SimpleHttp.create(client).doHead(url); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceReadOnlyAttributesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceReadOnlyAttributesTest.java index 7f5cfa8f273..a196e577a7a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceReadOnlyAttributesTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceReadOnlyAttributesTest.java @@ -32,7 +32,7 @@ import org.junit.Before; import org.junit.Test; import org.keycloak.admin.client.resource.UserProfileResource; import org.keycloak.admin.client.resource.UserResource; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.representations.account.UserRepresentation; import org.keycloak.representations.idm.ErrorRepresentation; import org.keycloak.representations.userprofile.config.UPAttribute; @@ -265,7 +265,7 @@ public class AccountRestServiceReadOnlyAttributesTest extends AbstractRestServic private void updateError(UserRepresentation user, int expectedStatus, String expectedMessage) throws IOException { - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); assertEquals(expectedStatus, response.getStatus()); assertEquals(expectedMessage, response.asJson(ErrorRepresentation.class).getErrorMessage()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java index 4024943b5ea..1e5725c9799 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java @@ -17,8 +17,10 @@ package org.keycloak.testsuite.account; import com.fasterxml.jackson.core.type.TypeReference; +import jakarta.ws.rs.ClientErrorException; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import org.apache.http.Header; import org.apache.http.impl.client.CloseableHttpClient; import org.hamcrest.Matchers; @@ -34,12 +36,13 @@ import org.keycloak.authentication.authenticators.browser.WebAuthnPasswordlessAu import org.keycloak.authentication.requiredactions.DeleteCredentialAction; import org.keycloak.authentication.requiredactions.WebAuthnPasswordlessRegisterFactory; import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.enums.AccountRestApiVersion; import org.keycloak.common.util.ObjectUtil; import org.keycloak.credential.CredentialTypeMetadata; import org.keycloak.events.Details; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttpRequest; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.ClientScopeModel; import org.keycloak.models.UserModel; @@ -53,7 +56,6 @@ import org.keycloak.representations.account.ClientRepresentation; import org.keycloak.representations.account.ConsentRepresentation; import org.keycloak.representations.account.ConsentScopeRepresentation; import org.keycloak.representations.account.SessionRepresentation; -import org.keycloak.representations.idm.UserProfileAttributeMetadata; import org.keycloak.representations.account.UserRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionRepresentation; @@ -66,22 +68,21 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RequiredActionProviderRepresentation; import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation; +import org.keycloak.representations.idm.UserProfileAttributeMetadata; import org.keycloak.services.cors.Cors; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.account.AccountCredentialResource; import org.keycloak.services.util.ResolveRelative; +import org.keycloak.testsuite.AbstractAuthenticationTest; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.AbstractAuthenticationTest; import org.keycloak.testsuite.broker.util.SimpleHttpDefault; -import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.TokenUtil; import org.keycloak.testsuite.util.UserBuilder; +import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.userprofile.UserProfileUtil; import org.keycloak.userprofile.UserProfileContext; -import jakarta.ws.rs.ClientErrorException; -import jakarta.ws.rs.core.Response; import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -305,7 +306,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { user.setFirstName(originalFirstName); user.setLastName(originalLastName); user.setEmail(originalEmail); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); System.out.println(response.asString()); assertEquals(204, response.getStatus()); } @@ -353,7 +354,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { adminClient.realm("test").update(realmRep); user.setEmail(originalEmail); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); System.out.println(response.asString()); assertEquals(204, response.getStatus()); } @@ -413,7 +414,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { user.setFirstName(originalFirstName); user.setLastName(originalLastName); user.setEmail(originalEmail); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); System.out.println(response.asString()); assertEquals(204, response.getStatus()); } @@ -520,7 +521,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { user.setFirstName(originalFirstName); user.setLastName(originalLastName); user.setEmail(originalEmail); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); System.out.println(response.asString()); assertEquals(204, response.getStatus()); } @@ -570,7 +571,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { user.setUsername(originalUsername); user.setAttributes(originalAttributes); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); System.out.println(response.asString()); assertEquals(204, response.getStatus()); } @@ -602,11 +603,11 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { @Test public void testCors() throws IOException { String accountUrl = getAccountUrl(null); - SimpleHttp a = SimpleHttpDefault.doGet(accountUrl + "/linked-accounts", httpClient).auth(tokenUtil.getToken()) + SimpleHttpRequest a = SimpleHttpDefault.doGet(accountUrl + "/linked-accounts", httpClient).auth(tokenUtil.getToken()) .header("Origin", "http://localtest.me:8180") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); - try (SimpleHttp.Response response = a.asResponse()) { + try (SimpleHttpResponse response = a.asResponse()) { Set expected = new HashSet<>(); Header[] actual = response.getAllHeaders(); @@ -629,7 +630,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { } protected static UserRepresentation getUser(String accountUrl, CloseableHttpClient httpClient, TokenUtil tokenUtil) throws IOException { - SimpleHttp a = SimpleHttpDefault.doGet(accountUrl, httpClient).auth(tokenUtil.getToken()); + SimpleHttpRequest a = SimpleHttpDefault.doGet(accountUrl, httpClient).auth(tokenUtil.getToken()); try { return a.asJson(UserRepresentation.class); @@ -640,7 +641,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { } protected UserRepresentation updateAndGet(UserRepresentation user) throws IOException { - SimpleHttp a = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user); + SimpleHttpRequest a = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user); try { assertEquals(204, a.asStatus()); } catch (AssertionError e) { @@ -652,7 +653,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { protected void updateError(UserRepresentation user, int expectedStatus, String expectedMessage) throws IOException { - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); assertEquals(expectedStatus, response.getStatus()); ErrorRepresentation errorRep = response.asJson(ErrorRepresentation.class); List errors = errorRep.getErrors(); @@ -795,7 +796,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { .get(); // Test that current user can't update the credential, which belongs to the different user - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doPut(getAccountUrl("credentials/" + otpCredential.getId() + "/label"), httpClient) .auth(tokenUtil.getToken()) .json("new-label") @@ -874,7 +875,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { .filter(credentialRep -> OTPCredentialModel.TYPE.equals(credentialRep.getType())) .findFirst() .get(); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("credentials/" + otpCredential.getId()), httpClient) .acceptJson() .auth(tokenUtil.getToken()) @@ -980,7 +981,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { String otpCredentialId = otpCredential.getUserCredentialMetadatas().get(0).getCredential().getId(); // remove credential using account console as otp is removable - try (SimpleHttp.Response response = SimpleHttpDefault + try (SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("credentials/" + otpCredentialId), httpClient) .acceptJson() .auth(tokenUtil.getToken()) @@ -1041,7 +1042,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { assertCredentialContainerExpected(password, PasswordCredentialModel.TYPE, CredentialTypeMetadata.Category.BASIC_AUTHENTICATION.toString(), "password-display-name", "password-help-text", "kcAuthenticatorPasswordClass", null, UserModel.RequiredAction.UPDATE_PASSWORD.toString(), false, 1); - try (SimpleHttp.Response response = SimpleHttpDefault + try (SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("credentials/" + password.getUserCredentialMetadatas().get(0).getCredential().getId()), httpClient) .acceptJson() .auth(tokenUtil.getToken()) @@ -1305,7 +1306,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { @Test public void listApplicationsWithoutPermission() throws IOException { TokenUtil token = new TokenUtil("no-account-access", "password"); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doGet(getAccountUrl("applications"), httpClient) .header("Accept", "application/json") .auth(token.getToken()) @@ -1317,7 +1318,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void getNotExistingApplication() throws IOException { TokenUtil token = new TokenUtil("view-applications-access", "password"); String appId = "not-existing"; - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doGet(getAccountUrl("applications/" + appId), httpClient) .header("Accept", "application/json") .auth(token.getToken()) @@ -1427,7 +1428,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { List requestedScopes = testRealm().clientScopes().findAll().subList(0,1); ConsentRepresentation requestedConsent = createRequestedConsent(requestedScopes); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doPost(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .json(requestedConsent) @@ -1445,7 +1446,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { List requestedScopes = testRealm().clientScopes().findAll().subList(0,1); ConsentRepresentation requestedConsent = createRequestedConsent(requestedScopes); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doPost(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .json(requestedConsent) @@ -1548,7 +1549,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { List requestedScopes = testRealm().clientScopes().findAll().subList(0,1); ConsentRepresentation requestedConsent = createRequestedConsent(requestedScopes); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doPut(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .json(requestedConsent) @@ -1566,7 +1567,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { List requestedScopes = testRealm().clientScopes().findAll().subList(0,1); ConsentRepresentation requestedConsent = createRequestedConsent(requestedScopes); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doPut(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .json(requestedConsent) @@ -1609,7 +1610,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void getConsentForNotExistingClient() throws IOException { tokenUtil = new TokenUtil("view-consent-access", "password"); String appId = "not-existing"; - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doGet(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1621,7 +1622,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void getNotExistingConsentForClient() throws IOException { tokenUtil = new TokenUtil("view-consent-access", "password"); String appId = "security-admin-console"; - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doGet(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1633,7 +1634,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void getConsentWithoutPermission() throws IOException { tokenUtil = new TokenUtil("no-account-access", "password"); String appId = "security-admin-console"; - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doGet(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1660,7 +1661,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { assertEquals(1, consentRepresentation.getGrantedScopes().size()); assertEquals(requestedScopes.get(0).getId(), consentRepresentation.getGrantedScopes().get(0).getId()); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1687,7 +1688,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void deleteConsentForNotExistingClient() throws IOException { tokenUtil = new TokenUtil("manage-consent-access", "password"); String appId = "not-existing"; - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1699,7 +1700,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void deleteConsentWithoutPermission() throws IOException { tokenUtil = new TokenUtil("view-consent-access", "password"); String appId = "security-admin-console"; - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("applications/" + appId + "/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1717,7 +1718,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { tokenUtil = new TokenUtil("view-applications-access", "password"); - SimpleHttp.Response response = SimpleHttpDefault + SimpleHttpResponse response = SimpleHttpDefault .doDelete(getAccountUrl("applications/offline-client/consent"), httpClient) .header("Accept", "application/json") .auth(tokenUtil.getToken()) @@ -1751,7 +1752,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void testInvalidApiVersion() throws IOException { apiVersion = "v2-foo"; - SimpleHttp.Response response = SimpleHttpDefault.doGet(getAccountUrl("credentials"), httpClient).auth(tokenUtil.getToken()).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doGet(getAccountUrl("credentials"), httpClient).auth(tokenUtil.getToken()).asResponse(); assertEquals("API version not found", response.asJson().get("error").textValue()); assertEquals(404, response.getStatus()); } @@ -1762,7 +1763,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { AccessTokenResponse tokenResponse = oauth.doPasswordGrantRequest("test-user@localhost", "password"); assertNull(tokenResponse.getErrorDescription()); - SimpleHttp.Response response = SimpleHttpDefault.doGet(getAccountUrl(null), httpClient) + SimpleHttpResponse response = SimpleHttpDefault.doGet(getAccountUrl(null), httpClient) .auth(tokenResponse.getAccessToken()) .header("Accept", "application/json") .asResponse(); @@ -1808,7 +1809,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { realmRep.setAccountTheme("custom-account-provider"); adminClient.realm("test").update(realmRep); - SimpleHttp.Response response = SimpleHttpDefault.doGet(getAccountUrl(null), httpClient) + SimpleHttpResponse response = SimpleHttpDefault.doGet(getAccountUrl(null), httpClient) .header("Accept", "text/html") .asResponse(); assertEquals(200, response.getStatus()); @@ -1826,7 +1827,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { public void testUpdateProfileUnrecognizedPropertyInRepresentation() throws IOException { final UserRepresentation user = getUser(); final Map invalidRep = Map.of("id", user.getId(), "username", user.getUsername(), "invalid", "something"); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient) + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient) .auth(tokenUtil.getToken()) .json(invalidRep) .asResponse(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceWithUserProfileTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceWithUserProfileTest.java index 327c8594dd4..430ea758745 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceWithUserProfileTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceWithUserProfileTest.java @@ -42,9 +42,10 @@ import java.util.Set; import org.junit.Before; import org.junit.Test; import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.events.Details; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttpRequest; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.representations.idm.UserProfileAttributeMetadata; @@ -366,7 +367,7 @@ public class AccountRestServiceWithUserProfileTest extends AbstractRestServiceTe user.setLastName(originalLastName); user.setEmail(originalEmail); user.setAttributes(originalAttributes); - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); System.out.println(response.asString()); assertEquals(204, response.getStatus()); } @@ -425,7 +426,7 @@ public class AccountRestServiceWithUserProfileTest extends AbstractRestServiceTe } protected UserRepresentation updateAndGet(UserRepresentation user) throws IOException { - SimpleHttp a = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user); + SimpleHttpRequest a = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user); try { assertEquals(204, a.asStatus()); } catch (AssertionError e) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResourcesRestServiceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResourcesRestServiceTest.java index 13eb8009938..07cb3335ed6 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResourcesRestServiceTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ResourcesRestServiceTest.java @@ -24,9 +24,10 @@ import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.authorization.client.AuthzClient; import org.keycloak.authorization.client.Configuration; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.Profile; import org.keycloak.common.util.KeycloakUriBuilder; +import org.keycloak.http.simple.SimpleHttpRequest; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.jose.jws.JWSInput; import org.keycloak.models.AccountRoles; import org.keycloak.representations.AccessToken; @@ -387,7 +388,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { permissions.add(new Permission(users.get(users.size() - 1), "Scope A", "Scope B", "Scope C", "Scope D")); String resourceId = sharedResource.getId(); - SimpleHttp.Response response = SimpleHttpDefault.doPut(getAccountUrl("resources/" + encodePathAsIs(resourceId) + "/permissions"), httpClient) + SimpleHttpResponse response = SimpleHttpDefault.doPut(getAccountUrl("resources/" + encodePathAsIs(resourceId) + "/permissions"), httpClient) .auth(tokenUtil.getToken()) .json(permissions).asResponse(); @@ -411,7 +412,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { public void failShareResourceInvalidPermissions() throws Exception { List permissions = new ArrayList<>(); - SimpleHttp.Response response = SimpleHttpDefault.doPut(getAccountUrl("resources/" + encodePathAsIs(getMyResources().get(0).getId()) + "/permissions"), httpClient) + SimpleHttpResponse response = SimpleHttpDefault.doPut(getAccountUrl("resources/" + encodePathAsIs(getMyResources().get(0).getId()) + "/permissions"), httpClient) .auth(tokenUtil.getToken()) .json(permissions).asResponse(); @@ -476,7 +477,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { permissions.add(new Permission(users.get(users.size() - 1), "Scope B", "Scope D")); String resourceId = sharedResource.getId(); - SimpleHttp.Response response = SimpleHttpDefault.doPut(getAccountUrl("resources/" + encodePathAsIs(resourceId) + "/permissions"), httpClient) + SimpleHttpResponse response = SimpleHttpDefault.doPut(getAccountUrl("resources/" + encodePathAsIs(resourceId) + "/permissions"), httpClient) .auth(tokenUtil.getToken()) .json(permissions).asResponse(); @@ -643,7 +644,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { return getSharedWithMe(userName, null, -1, -1, null); } - private List getSharedWithMe(String userName, String name, int first, int max, Consumer responseHandler) { + private List getSharedWithMe(String userName, String name, int first, int max, Consumer responseHandler) { KeycloakUriBuilder uri = KeycloakUriBuilder.fromUri("/shared-with-me"); if (name != null) { @@ -663,7 +664,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { return doGet(resource, tokenUtil.getToken(), typeReference); } - private R doGet(String resource, TypeReference typeReference, Consumer response) { + private R doGet(String resource, TypeReference typeReference, Consumer response) { return doGet(resource, tokenUtil.getToken(), typeReference, response); } @@ -679,12 +680,12 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { } } - private R doGet(String resource, String token, TypeReference typeReference, Consumer responseHandler) { + private R doGet(String resource, String token, TypeReference typeReference, Consumer responseHandler) { try { - SimpleHttp http = get(resource, token); + SimpleHttpRequest http = get(resource, token); http.header("Accept", "application/json"); - SimpleHttp.Response response = http.asResponse(); + SimpleHttpResponse response = http.asResponse(); if (responseHandler != null) { responseHandler.accept(response); @@ -706,7 +707,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { } } - private SimpleHttp get(String resource, String token) { + private SimpleHttpRequest get(String resource, String token) { return SimpleHttpDefault.doGet(getAccountUrl("resources" + resource), httpClient).auth(token); } @@ -757,7 +758,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { return doGet(uri.build().toString(), new TypeReference>() {}); } - private List getMyResources(int first, int max, Consumer response) { + private List getMyResources(int first, int max, Consumer response) { String query = ""; if (first > -1 && max > -1) { query = "?first=" + first + "&max=" + max; @@ -815,7 +816,7 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { } } - private void assertNextPageLink(SimpleHttp.Response response, String uri, int nextPage, int previousPage, int max) { + private void assertNextPageLink(SimpleHttpResponse response, String uri, int nextPage, int previousPage, int max) { try { List links = response.getHeader("Link"); @@ -839,4 +840,4 @@ public class ResourcesRestServiceTest extends AbstractRestServiceTest { fail("Fail to get link header"); } } -} \ No newline at end of file +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateEmailTestWithVerificationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateEmailTestWithVerificationTest.java index 69e56ccfd99..66e339c196d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateEmailTestWithVerificationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateEmailTestWithVerificationTest.java @@ -16,21 +16,10 @@ */ package org.keycloak.testsuite.actions; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot; - import jakarta.mail.Address; import jakarta.mail.Message; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; -import java.io.IOException; -import java.util.List; -import java.util.UUID; - import jakarta.ws.rs.core.Response.Status; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; @@ -42,9 +31,9 @@ import org.keycloak.admin.client.resource.AuthenticationManagementResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.authentication.actiontoken.updateemail.UpdateEmailActionToken; import org.keycloak.authentication.requiredactions.UpdateEmail; -import org.keycloak.broker.provider.util.SimpleHttp.Response; import org.keycloak.events.Details; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.representations.idm.EventRepresentation; @@ -60,8 +49,19 @@ import org.keycloak.testsuite.pages.InfoPage; import org.keycloak.testsuite.util.GreenMailRule; import org.keycloak.testsuite.util.MailUtils; import org.keycloak.testsuite.util.UserBuilder; -import org.keycloak.testsuite.util.oauth.OAuthClient; import org.keycloak.testsuite.util.WaitUtils; +import org.keycloak.testsuite.util.oauth.OAuthClient; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot; public class RequiredActionUpdateEmailTestWithVerificationTest extends AbstractRequiredActionUpdateEmailTest { @@ -193,7 +193,7 @@ public class RequiredActionUpdateEmailTestWithVerificationTest extends AbstractR String confirmationLink = fetchEmailConfirmationLink("new@localhost"); try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { - try (Response response = SimpleHttpDefault.doHead(confirmationLink, httpClient).asResponse()) { + try (SimpleHttpResponse response = SimpleHttpDefault.doHead(confirmationLink, httpClient).asResponse()) { assertEquals(Status.OK.getStatusCode(), response.getStatus()); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java index 2113da8ae39..9b26f521205 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java @@ -3,14 +3,15 @@ package org.keycloak.testsuite.broker; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import jakarta.ws.rs.core.Response; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.admin.client.resource.ClientScopeResource; +import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.admin.client.resource.IdentityProviderResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; @@ -18,8 +19,8 @@ import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.broker.oidc.OIDCIdentityProviderConfig; import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper; import org.keycloak.broker.oidc.mappers.UserAttributeMapper; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.crypto.Algorithm; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.ClientModel; import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderMapperSyncMode; @@ -48,10 +49,8 @@ import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.broker.util.SimpleHttpDefault; import org.keycloak.testsuite.util.AccountHelper; -import org.keycloak.testsuite.util.oauth.OAuthClient; import org.keycloak.testsuite.util.WaitUtils; - -import jakarta.ws.rs.core.Response; +import org.keycloak.testsuite.util.oauth.OAuthClient; import java.io.IOException; import java.util.ArrayList; @@ -70,10 +69,10 @@ import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertEquals; import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS; import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; -import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; -import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim; import static org.keycloak.testsuite.broker.BrokerTestTools.getConsumerRoot; import static org.keycloak.testsuite.broker.BrokerTestTools.getProviderRoot; +import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; +import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim; /** * Final class as it's not intended to be overriden. Feel free to remove "final" if you really know what you are doing. @@ -377,7 +376,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest { assertThat(errorPage.getError(), is("Page not found")); try (CloseableHttpClient client = HttpClientBuilder.create().build()) { - SimpleHttp.Response simple = SimpleHttpDefault.doGet(LINK, client).asResponse(); + SimpleHttpResponse simple = SimpleHttpDefault.doGet(LINK, client).asResponse(); assertThat(simple, notNullValue()); assertThat(simple.getStatus(), is(Response.Status.NOT_FOUND.getStatusCode())); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java index f9660e6fbed..7e51709fa42 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java @@ -20,12 +20,12 @@ import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper; import org.keycloak.broker.oidc.mappers.UserAttributeMapper; import org.keycloak.broker.provider.ConfigConstants; import org.keycloak.broker.provider.HardcodedRoleMapper; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.Profile; import org.keycloak.crypto.Algorithm; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.Constants; import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderMapperSyncMode; @@ -370,7 +370,7 @@ public final class KcOidcBrokerTransientSessionsTest extends AbstractAdvancedBro assertThat(errorPage.getError(), is("Page not found")); try (CloseableHttpClient client = HttpClientBuilder.create().build()) { - SimpleHttp.Response simple = SimpleHttpDefault.doGet(LINK, client).asResponse(); + SimpleHttpResponse simple = SimpleHttpDefault.doGet(LINK, client).asResponse(); assertThat(simple, notNullValue()); assertThat(simple.getStatus(), is(Response.Status.NOT_FOUND.getStatusCode())); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java index 818c311c132..9773e6f0f77 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java @@ -14,8 +14,8 @@ import org.junit.Assert; import org.junit.Test; import org.keycloak.OAuthErrorException; import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.util.StreamUtil; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.BrowserSecurityHeaders; import org.keycloak.representations.idm.OAuth2ErrorRepresentation; import org.keycloak.representations.idm.RealmRepresentation; @@ -169,7 +169,7 @@ public class UncaughtErrorPageTest extends AbstractKeycloakTest { URI uri = suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/realms/master/testing/uncaught-error").build(); try (CloseableHttpClient client = HttpClientBuilder.create().build()) { - SimpleHttp.Response response = SimpleHttpDefault.doGet(uri.toString(), client).header("Accept", MediaType.TEXT_HTML_UTF_8).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doGet(uri.toString(), client).header("Accept", MediaType.TEXT_HTML_UTF_8).asResponse(); for (BrowserSecurityHeaders header : BrowserSecurityHeaders.values()) { String expectedValue = header.getDefaultValue(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPAccountRestApiTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPAccountRestApiTest.java index b772a2c516e..0ae063838a3 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPAccountRestApiTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPAccountRestApiTest.java @@ -33,9 +33,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runners.MethodSorters; import org.keycloak.admin.client.resource.UserProfileResource; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.federation.kerberos.KerberosFederationProvider; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.models.credential.PasswordCredentialModel; @@ -343,7 +343,7 @@ public class LDAPAccountRestApiTest extends AbstractLDAPTest { } private void updateProfileExpectError(UserRepresentation user, int expectedStatus, String expectedMessage) throws IOException { - SimpleHttp.Response response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse(); assertEquals(expectedStatus, response.getStatus()); assertEquals(expectedMessage, response.asJson(ErrorRepresentation.class).getErrorMessage()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LevelOfAssuranceFlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LevelOfAssuranceFlowTest.java index 32f63c49e5e..0a1197f6c75 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LevelOfAssuranceFlowTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LevelOfAssuranceFlowTest.java @@ -41,11 +41,11 @@ import org.keycloak.authentication.authenticators.browser.RecoveryAuthnCodesForm import org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory; import org.keycloak.authentication.authenticators.conditional.ConditionalLoaAuthenticator; import org.keycloak.authentication.authenticators.conditional.ConditionalLoaAuthenticatorFactory; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.Profile; import org.keycloak.cookie.CookieType; import org.keycloak.events.Details; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.AuthenticationExecutionModel.Requirement; import org.keycloak.models.AuthenticationFlowBindings; import org.keycloak.models.Constants; @@ -821,7 +821,7 @@ public class LevelOfAssuranceFlowTest extends AbstractChangeImportedUserPassword .accessToken(token1.accessToken) .build()) { otpCredentialId = accountRestClient.getCredentialByUserLabel("totp2-label").getId(); - try (SimpleHttp.Response response = accountRestClient.removeCredential(otpCredentialId)) { + try (SimpleHttpResponse response = accountRestClient.removeCredential(otpCredentialId)) { Assert.assertEquals(403, response.getStatus()); } } @@ -832,7 +832,7 @@ public class LevelOfAssuranceFlowTest extends AbstractChangeImportedUserPassword .accessToken(token2.accessToken) .build()) { otpCredentialId = accountRestClient.getCredentialByUserLabel("totp2-label").getId(); - try (SimpleHttp.Response response = accountRestClient.removeCredential(otpCredentialId)) { + try (SimpleHttpResponse response = accountRestClient.removeCredential(otpCredentialId)) { Assert.assertEquals(204, response.getStatus()); } Assert.assertNull(accountRestClient.getCredentialByUserLabel("totp2-label")); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java index 0f589d83aa8..30d201b81bb 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java @@ -47,7 +47,7 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.keycloak.admin.client.resource.UserResource; -import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.UserModel; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.admin.ApiUtil; @@ -153,7 +153,7 @@ public class EmailTest extends AbstractI18NTest { try { UserResource testUser = ApiUtil.findUserByUsernameId(testRealm(), "login-test"); CloseableHttpClient httpClient = HttpClientBuilder.create().build(); - SimpleHttp.Response responseGet = SimpleHttpDefault.doPut(getAuthServerRoot() + "admin/realms/test/users/" + testUser.toRepresentation().getId() + "/execute-actions-email", httpClient) + SimpleHttpResponse responseGet = SimpleHttpDefault.doPut(getAuthServerRoot() + "admin/realms/test/users/" + testUser.toRepresentation().getId() + "/execute-actions-email", httpClient) .auth(adminClient.tokenManager().getAccessTokenString()) .header("Accept-Language", "de") .json(Arrays.asList(UserModel.RequiredAction.UPDATE_PASSWORD.toString())) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java index acd66c97171..cc0a8ead42a 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java @@ -32,9 +32,9 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.keycloak.OAuth2Constants; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.util.Encode; import org.keycloak.common.util.KeycloakUriBuilder; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.models.Constants; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; @@ -44,10 +44,10 @@ import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.util.ClientBuilder; import org.keycloak.testsuite.util.ClientManager; +import org.keycloak.testsuite.util.RealmBuilder; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse; import org.keycloak.testsuite.util.oauth.OAuthClient; -import org.keycloak.testsuite.util.RealmBuilder; import java.io.IOException; import java.io.OutputStream; @@ -55,8 +55,8 @@ import java.net.InetSocketAddress; import java.net.URL; import java.util.List; -import static org.junit.Assert.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; import static org.keycloak.testsuite.AbstractAdminTest.loadJson; import static org.keycloak.testsuite.util.oauth.OAuthClient.APP_ROOT; @@ -307,7 +307,7 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest { String loginPage = SimpleHttpDefault.doGet(loginUrl, client).asString(); String formAction = loginPage.split("action=\"")[1].split("\"")[0].replaceAll("&", "&"); - SimpleHttp.Response response = SimpleHttpDefault.doPost(formAction, client).param("username", "test-user@localhost").param("password", "password").asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doPost(formAction, client).param("username", "test-user@localhost").param("password", "password").asResponse(); response.getStatus(); assertThat(response.getFirstHeader("Location"), Matchers.startsWith("android-app://org.keycloak.examples.cordova/https/keycloak-cordova-example.github.io/login")); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenRevocationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenRevocationTest.java index b316662495b..2b064044bbe 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenRevocationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenRevocationTest.java @@ -53,9 +53,9 @@ import org.keycloak.OAuthErrorException; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; -import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.events.Details; import org.keycloak.events.EventType; +import org.keycloak.http.simple.SimpleHttpRequest; import org.keycloak.representations.idm.OAuth2ErrorRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserSessionRepresentation; @@ -367,7 +367,7 @@ public class TokenRevocationTest extends AbstractKeycloakTest { // Test account REST not possible String accountUrl = OAuthClient.AUTH_SERVER_ROOT + "/realms/test/account"; - SimpleHttp accountRequest = SimpleHttpDefault.doGet(accountUrl, restHttpClient) + SimpleHttpRequest accountRequest = SimpleHttpDefault.doGet(accountUrl, restHttpClient) .auth(accessTokenString) .acceptJson(); assertEquals(Status.UNAUTHORIZED.getStatusCode(), accountRequest.asStatus()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AbstractWellKnownProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AbstractWellKnownProviderTest.java index 55b83b14667..977236ab7ba 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AbstractWellKnownProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AbstractWellKnownProviderTest.java @@ -31,10 +31,9 @@ import org.junit.Test; import org.junit.runners.MethodSorters; import org.keycloak.OAuth2Constants; import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.broker.provider.util.SimpleHttp; -import org.keycloak.common.Profile; import org.keycloak.common.constants.ServiceAccountConstants; import org.keycloak.crypto.Algorithm; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.jose.jwe.JWEConstants; import org.keycloak.jose.jwk.JSONWebKeySet; import org.keycloak.models.Constants; @@ -301,11 +300,11 @@ public abstract class AbstractWellKnownProviderTest extends AbstractKeycloakTest OIDCConfigurationRepresentation representation = SimpleHttpDefault.doGet(getAuthServerRoot().toString() + "realms/test/.well-known/openid-configuration", client).asJson(OIDCConfigurationRepresentation.class); String jwksUri = representation.getJwksUri(); - SimpleHttp.Response response = SimpleHttpDefault.doGet(jwksUri, client).header(ACCEPT, APPLICATION_JWKS).asResponse(); + SimpleHttpResponse response = SimpleHttpDefault.doGet(jwksUri, client).header(ACCEPT, APPLICATION_JWKS).asResponse(); assertEquals(APPLICATION_JWKS, response.getFirstHeader(CONTENT_TYPE)); // Test HEAD method works (Issue 41537) - SimpleHttp.Response responseHead = SimpleHttpDefault.doHead(jwksUri, client).header(ACCEPT, APPLICATION_JWKS).asResponse(); + SimpleHttpResponse responseHead = SimpleHttpDefault.doHead(jwksUri, client).header(ACCEPT, APPLICATION_JWKS).asResponse(); assertEquals(Response.Status.OK.getStatusCode(), responseHead.getStatus()); assertEquals(APPLICATION_JWKS, responseHead.getFirstHeader(CONTENT_TYPE)); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/account/OrganizationAccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/account/OrganizationAccountTest.java index 2ad715d7fd5..3fb0784aa16 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/account/OrganizationAccountTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/account/OrganizationAccountTest.java @@ -17,10 +17,6 @@ package org.keycloak.testsuite.organization.account; -import java.io.IOException; -import java.util.List; -import java.util.SortedSet; - import com.fasterxml.jackson.core.type.TypeReference; import jakarta.ws.rs.core.Response.Status; import org.apache.http.impl.client.CloseableHttpClient; @@ -31,7 +27,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.keycloak.admin.client.resource.OrganizationResource; -import org.keycloak.broker.provider.util.SimpleHttp.Response; +import org.keycloak.http.simple.SimpleHttpResponse; import org.keycloak.representations.account.LinkedAccountRepresentation; import org.keycloak.representations.account.OrganizationRepresentation; import org.keycloak.representations.idm.ErrorRepresentation; @@ -43,6 +39,10 @@ import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest; import org.keycloak.testsuite.util.TokenUtil; import org.keycloak.testsuite.util.UserBuilder; +import java.io.IOException; +import java.util.List; +import java.util.SortedSet; + public class OrganizationAccountTest extends AbstractOrganizationTest { @Rule @@ -75,7 +75,7 @@ public class OrganizationAccountTest extends AbstractOrganizationTest { LinkedAccountRepresentation link = findLinkedAccount(bc.getIDPAlias()); Assert.assertNotNull(link); - try (Response response = SimpleHttpDefault.doDelete(getAccountUrl("linked-accounts/" + link.getProviderAlias()), client).auth(tokenUtil.getToken()).acceptJson().asResponse()) { + try (SimpleHttpResponse response = SimpleHttpDefault.doDelete(getAccountUrl("linked-accounts/" + link.getProviderAlias()), client).auth(tokenUtil.getToken()).acceptJson().asResponse()) { Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus()); ErrorRepresentation error = response.asJson(ErrorRepresentation.class); Assert.assertEquals("You cannot remove the link to an identity provider associated with an organization.", error.getErrorMessage()); @@ -83,7 +83,7 @@ public class OrganizationAccountTest extends AbstractOrganizationTest { // broker no longer linked to the organization organization.identityProviders().get(bc.getIDPAlias()).delete().close(); - try (Response response = SimpleHttpDefault.doDelete(getAccountUrl("linked-accounts/" + link.getProviderAlias()), client).auth(tokenUtil.getToken()).acceptJson().asResponse()) { + try (SimpleHttpResponse response = SimpleHttpDefault.doDelete(getAccountUrl("linked-accounts/" + link.getProviderAlias()), client).auth(tokenUtil.getToken()).acceptJson().asResponse()) { Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus()); } }