diff --git a/server-spi-private/src/main/java/org/keycloak/services/cors/Cors.java b/server-spi-private/src/main/java/org/keycloak/services/cors/Cors.java
index 424bd67e128d..7acb0e9adee6 100755
--- a/server-spi-private/src/main/java/org/keycloak/services/cors/Cors.java
+++ b/server-spi-private/src/main/java/org/keycloak/services/cors/Cors.java
@@ -18,13 +18,11 @@
package org.keycloak.services.cors;
import java.util.concurrent.TimeUnit;
-import java.util.function.BiConsumer;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.ResponseBuilder;
-import org.keycloak.http.HttpRequest;
-import org.keycloak.http.HttpResponse;
+import org.keycloak.common.util.Resteasy;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.Provider;
@@ -36,59 +34,67 @@
*/
public interface Cors extends Provider {
- public static final long DEFAULT_MAX_AGE = TimeUnit.HOURS.toSeconds(1);
- public static final String DEFAULT_ALLOW_METHODS = "GET, HEAD, OPTIONS";
- public static final String DEFAULT_ALLOW_HEADERS = "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, DPoP";
+ long DEFAULT_MAX_AGE = TimeUnit.HOURS.toSeconds(1);
+ String DEFAULT_ALLOW_METHODS = "GET, HEAD, OPTIONS";
+ String DEFAULT_ALLOW_HEADERS = "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, DPoP";
- public static final String ORIGIN_HEADER = "Origin";
- public static final String AUTHORIZATION_HEADER = "Authorization";
+ String ORIGIN_HEADER = "Origin";
+ String AUTHORIZATION_HEADER = "Authorization";
- public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
- public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
- public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
- public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
- public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
- public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
+ String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
+ String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
+ String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
+ String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
+ String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
+ String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
- public static final String ACCESS_CONTROL_ALLOW_ORIGIN_WILDCARD = "*";
- public static final String INCLUDE_REDIRECTS = "+";
+ String ACCESS_CONTROL_ALLOW_ORIGIN_WILDCARD = "*";
- public static Cors add(HttpRequest request, ResponseBuilder response) {
+ static Cors builder() {
KeycloakSession session = KeycloakSessionUtil.getKeycloakSession();
- return session.getProvider(Cors.class).request(request).builder(response);
+ return session.getProvider(Cors.class);
}
- public static Cors add(HttpRequest request) {
- KeycloakSession session = KeycloakSessionUtil.getKeycloakSession();
- return session.getProvider(Cors.class).request(request);
- }
-
- public Cors request(HttpRequest request);
+ Cors builder(ResponseBuilder builder);
- public Cors builder(ResponseBuilder builder);
+ Cors preflight();
- public Cors preflight();
+ Cors auth();
- public Cors auth();
+ Cors allowAllOrigins();
- public Cors allowAllOrigins();
+ Cors allowedOrigins(KeycloakSession session, ClientModel client);
- public Cors allowedOrigins(KeycloakSession session, ClientModel client);
+ Cors allowedOrigins(AccessToken token);
- public Cors allowedOrigins(AccessToken token);
+ Cors allowedOrigins(String... allowedOrigins);
- public Cors allowedOrigins(String... allowedOrigins);
+ Cors allowedMethods(String... allowedMethods);
- public Cors allowedMethods(String... allowedMethods);
+ Cors exposedHeaders(String... exposedHeaders);
- public Cors exposedHeaders(String... exposedHeaders);
+ /**
+ * Add the CORS headers to the current {@link org.keycloak.http.HttpResponse}.
+ */
+ void add();
- public Cors addExposedHeaders(String... exposedHeaders);
+ /**
+ *
Add the CORS headers to the current server {@link org.keycloak.http.HttpResponse} and returns a {@link Response} based
+ * on the given {@code builder}.
+ *
+ *
This is a convenient method to make it easier to return a {@link Response} from methods while at the same time
+ * adding the corresponding CORS headers to the underlying server response.
+ *
+ * @param builder the response builder
+ * @return the response built from the response builder
+ */
+ default Response add(ResponseBuilder builder) {
+ if (builder == null) {
+ throw new IllegalStateException("builder is not set");
+ }
- public Response build();
-
- public boolean build(HttpResponse response);
-
- public boolean build(BiConsumer addHeader);
+ add();
+ return builder.build();
+ }
}
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index 7f914533acf8..e4a92a97a0ec 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -273,10 +273,11 @@ public Response authorize(KeycloakAuthorizationRequest request) {
}
private Response createSuccessfulResponse(Object response, KeycloakAuthorizationRequest request) {
- return Cors.add(request.getHttpRequest(), Response.status(Status.OK).type(MediaType.APPLICATION_JSON_TYPE).entity(response))
+ return Cors.builder()
.allowedOrigins(request.getKeycloakSession(), request.getKeycloakSession().getContext().getClient())
.allowedMethods(HttpMethod.POST)
- .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
+ .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS)
+ .add(Response.status(Status.OK).type(MediaType.APPLICATION_JSON_TYPE).entity(response));
}
private boolean isPublicClientRequestingEntitlementWithClaims(KeycloakAuthorizationRequest request) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/DefaultTokenExchangeProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/DefaultTokenExchangeProvider.java
index 1ee995bef1fa..cf78f0c281e9 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/DefaultTokenExchangeProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/DefaultTokenExchangeProvider.java
@@ -279,7 +279,7 @@ protected Response exchangeToIdentityProvider(UserModel targetUser, UserSessionM
throw new CorsErrorResponseException(cors, OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN);
}
Response response = ((ExchangeTokenToIdentityProviderToken)provider).exchangeFromToken(session.getContext().getUri(), event, client, targetUserSession, targetUser, formParams);
- return cors.builder(Response.fromResponse(response)).build();
+ return cors.add(Response.fromResponse(response));
}
@@ -451,7 +451,7 @@ protected Response exchangeClientToOIDCClient(UserModel targetUser, UserSessionM
event.success();
- return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(res, MediaType.APPLICATION_JSON_TYPE));
}
protected Response exchangeClientToSAML2Client(UserModel targetUser, UserSessionModel targetUserSession, String requestedTokenType, ClientModel targetClient) {
@@ -501,7 +501,7 @@ protected Response exchangeClientToSAML2Client(UserModel targetUser, UserSession
event.success();
- return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(res, MediaType.APPLICATION_JSON_TYPE));
}
protected Response exchangeExternalToken(String issuer, String subjectToken) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index 48625265662a..0d7eb735d4ba 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -199,7 +199,7 @@ public Object thirdPartyCookiesCheck() {
@Path("certs")
@Produces(MediaType.APPLICATION_JSON)
public Response getVersionPreflight() {
- return Cors.add(request, Response.ok()).allowedMethods("GET").preflight().auth().build();
+ return Cors.builder().allowedMethods("GET").preflight().auth().add(Response.ok());
}
@GET
@@ -232,7 +232,7 @@ public Response certs() {
keySet.setKeys(jwks);
Response.ResponseBuilder responseBuilder = Response.ok(keySet).cacheControl(CacheControlUtil.getDefaultCacheControl());
- return Cors.add(request, responseBuilder).allowedOrigins("*").auth().build();
+ return Cors.builder().allowedOrigins("*").auth().add(responseBuilder);
}
@Path("userinfo")
@@ -276,7 +276,7 @@ public Object resolveExtension(@PathParam("extension") String extension) {
private void checkSsl() {
if (!session.getContext().getUri().getBaseUri().getScheme().equals("https")
&& realm.getSslRequired().isRequired(clientConnection)) {
- Cors cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ Cors cors = Cors.builder().auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
throw new CorsErrorResponseException(cors.allowAllOrigins(), OAuthErrorException.INVALID_REQUEST, "HTTPS required",
Response.Status.FORBIDDEN);
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
index 6323205491cf..a6c1e32885e3 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
@@ -130,7 +130,7 @@ public LogoutEndpoint(KeycloakSession session, TokenManager tokenManager, EventB
@Path("/")
@OPTIONS
public Response issueUserInfoPreflight() {
- return Cors.add(this.request, Response.ok()).auth().preflight().build();
+ return Cors.builder().auth().preflight().add(Response.ok());
}
/**
@@ -496,7 +496,7 @@ private Response doBrowserLogout(AuthenticationSessionModel logoutSession) {
* @return
*/
private Response logoutToken() {
- cors = Cors.add(request).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ cors = Cors.builder().auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
MultivaluedMap form = request.getDecodedFormParameters();
checkSsl();
@@ -550,7 +550,7 @@ private Response logoutToken() {
}
}
- return cors.builder(Response.noContent()).build();
+ return cors.add(Response.noContent());
}
/**
@@ -618,18 +618,16 @@ public Response backchannelLogout() {
session.getProvider(SecurityHeadersProvider.class).options().allowEmptyContentType();
if (oneOrMoreDownstreamLogoutsFailed(backchannelLogoutResponse)) {
- return Cors.add(request)
+ return Cors.builder()
.auth()
- .builder(Response.status(Response.Status.GATEWAY_TIMEOUT)
- .type(MediaType.APPLICATION_JSON_TYPE))
- .build();
+ .add(Response.status(Response.Status.GATEWAY_TIMEOUT)
+ .type(MediaType.APPLICATION_JSON_TYPE));
}
- return Cors.add(request)
+ return Cors.builder()
.auth()
- .builder(Response.ok()
- .type(MediaType.APPLICATION_JSON_TYPE))
- .build();
+ .add(Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE));
}
private BackchannelLogoutResponse backchannelLogoutWithSessionId(String sessionId,
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index 2a36487b2754..5c8268e592d0 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -108,7 +108,7 @@ public TokenEndpoint(KeycloakSession session, TokenManager tokenManager, EventBu
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@POST
public Response processGrantRequest() {
- cors = Cors.add(request).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ cors = Cors.builder().auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
MultivaluedMap formParameters = request.getDecodedFormParameters();
@@ -150,7 +150,7 @@ public Response preflight() {
if (logger.isDebugEnabled()) {
logger.debugv("CORS preflight from: {0}", headers.getRequestHeaders().getFirst("Origin"));
}
- return Cors.add(request, Response.ok()).auth().preflight().allowedMethods("POST", "OPTIONS").build();
+ return Cors.builder().auth().preflight().allowedMethods("POST", "OPTIONS").add(Response.ok());
}
private void checkSsl() {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java
index 4d4dae73e089..ee8c322f0737 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java
@@ -91,7 +91,7 @@ public TokenRevocationEndpoint(KeycloakSession session, EventBuilder event) {
public Response revoke() {
event.event(EventType.REVOKE_GRANT);
- cors = Cors.add(request).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ cors = Cors.builder().auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
checkSsl();
checkRealm();
@@ -130,12 +130,12 @@ public Response revoke() {
}
session.getProvider(SecurityHeadersProvider.class).options().allowEmptyContentType();
- return cors.builder(Response.ok()).build();
+ return cors.add(Response.ok());
}
@OPTIONS
public Response preflight() {
- return Cors.add(request, Response.ok()).auth().preflight().allowedMethods("POST", "OPTIONS").build();
+ return Cors.builder().auth().preflight().allowedMethods("POST", "OPTIONS").add(Response.ok());
}
private void checkSsl() {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 332eb57605e1..fafdbe4f48a0 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -112,7 +112,7 @@ public UserInfoEndpoint(KeycloakSession session, org.keycloak.protocol.oidc.Toke
@Path("/")
@OPTIONS
public Response issueUserInfoPreflight() {
- return Cors.add(this.request, Response.ok()).auth().preflight().build();
+ return Cors.builder().auth().preflight().add(Response.ok());
}
@Path("/")
@@ -322,7 +322,7 @@ private Response issueUserInfo() {
event.success();
- return cors.builder(responseBuilder).build();
+ return cors.add(responseBuilder);
}
private String jweFromContent(String content, String jweContentType) {
@@ -363,7 +363,7 @@ private void checkAccessTokenDuplicated(MultivaluedMap formParam
}
private void setupCors() {
- cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ cors = Cors.builder().auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
error.cors(cors);
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/ClientCredentialsGrantType.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/ClientCredentialsGrantType.java
index 17543ad7af82..9cdc26a09ec8 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/grants/ClientCredentialsGrantType.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/ClientCredentialsGrantType.java
@@ -180,7 +180,7 @@ public Response process(Context context) {
}
event.success();
- return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(res, MediaType.APPLICATION_JSON_TYPE));
}
@Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/OAuth2GrantTypeBase.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/OAuth2GrantTypeBase.java
index 5fe0fe0378a4..19b2e9a9ef81 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/grants/OAuth2GrantTypeBase.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/OAuth2GrantTypeBase.java
@@ -159,7 +159,7 @@ protected Response createTokenResponse(UserModel user, UserSessionModel userSess
event.success();
- return cors.builder(Response.ok(res).type(MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(res).type(MediaType.APPLICATION_JSON_TYPE));
}
protected void checkAndBindMtlsHoKToken(TokenManager.AccessTokenResponseBuilder responseBuilder, boolean useRefreshToken) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/PreAuthorizedCodeGrantType.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/PreAuthorizedCodeGrantType.java
index 2a0f510f0656..60534a08f1a5 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/grants/PreAuthorizedCodeGrantType.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/PreAuthorizedCodeGrantType.java
@@ -96,7 +96,7 @@ public Response process(Context context) {
event.success();
- return cors.allowAllOrigins().builder(Response.ok(tokenResponse).type(MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.allowAllOrigins().add(Response.ok(tokenResponse).type(MediaType.APPLICATION_JSON_TYPE));
}
@Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/RefreshTokenGrantType.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/RefreshTokenGrantType.java
index efafc320cecb..608da8481434 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/grants/RefreshTokenGrantType.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/RefreshTokenGrantType.java
@@ -108,7 +108,7 @@ public Response process(Context context) {
event.success();
- return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(res, MediaType.APPLICATION_JSON_TYPE));
}
@Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/ResourceOwnerPasswordCredentialsGrantType.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/ResourceOwnerPasswordCredentialsGrantType.java
index 81b36bf09ac5..e3fce2e6c129 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/grants/ResourceOwnerPasswordCredentialsGrantType.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/ResourceOwnerPasswordCredentialsGrantType.java
@@ -31,7 +31,6 @@
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.ClientSessionContext;
-import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.AuthenticationFlowResolver;
@@ -113,7 +112,7 @@ public Response process(Context context) {
if (challenge != null) {
// Remove authentication session as "Resource Owner Password Credentials Grant" is single-request scoped authentication
new AuthenticationSessionManager(session).removeAuthenticationSession(realm, authSession, false);
- cors.build(response);
+ cors.add();
return challenge;
}
processor.evaluateRequiredActionTriggers();
@@ -161,7 +160,7 @@ public Response process(Context context) {
event.success();
AuthenticationManager.logSuccess(session, authSession);
- return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(res, MediaType.APPLICATION_JSON_TYPE));
}
@Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/device/endpoints/DeviceEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/device/endpoints/DeviceEndpoint.java
index 0f21197ce0bb..42b7a046b749 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/grants/device/endpoints/DeviceEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/device/endpoints/DeviceEndpoint.java
@@ -101,7 +101,7 @@ public DeviceEndpoint(KeycloakSession session, EventBuilder event) {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response handleDeviceRequest() {
- cors = Cors.add(request).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ cors = Cors.builder().auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
logger.trace("Processing @POST request");
event.event(EventType.OAUTH2_DEVICE_AUTH);
@@ -186,7 +186,7 @@ public Response handleDeviceRequest() {
response.setVerificationUri(deviceUrl);
response.setVerificationUriComplete(deviceUrl + "?user_code=" + response.getUserCode());
- return cors.builder(Response.ok(JsonSerialization.writeValueAsBytes(response)).type(MediaType.APPLICATION_JSON_TYPE)).build();
+ return cors.add(Response.ok(JsonSerialization.writeValueAsBytes(response)).type(MediaType.APPLICATION_JSON_TYPE));
} catch (Exception e) {
throw new RuntimeException("Error creating OAuth 2.0 Device Authorization Response.", e);
}
@@ -197,7 +197,7 @@ public Response preflight() {
if (logger.isDebugEnabled()) {
logger.debugv("CORS preflight from: {0}", headers.getRequestHeaders().getFirst("Origin"));
}
- return Cors.add(request, Response.ok()).auth().preflight().allowedMethods("POST", "OPTIONS").build();
+ return Cors.builder().auth().preflight().allowedMethods("POST", "OPTIONS").add(Response.ok());
}
/**
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/par/endpoints/ParEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/par/endpoints/ParEndpoint.java
index e94639fb8145..188aad9e3f66 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/par/endpoints/ParEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/par/endpoints/ParEndpoint.java
@@ -80,7 +80,7 @@ public Response request() {
ProfileHelper.requireFeature(Profile.Feature.PAR);
- cors = Cors.add(httpRequest).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ cors = Cors.builder().auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
event.event(EventType.PUSHED_AUTHORIZATION_REQUEST);
@@ -163,10 +163,9 @@ public Response request() {
ParResponse parResponse = new ParResponse(requestUri, expiresIn);
session.getProvider(SecurityHeadersProvider.class).options().allowEmptyContentType();
- return cors.builder(Response.status(Response.Status.CREATED)
- .entity(parResponse)
- .type(MediaType.APPLICATION_JSON_TYPE))
- .build();
+ return cors.add(Response.status(Response.Status.CREATED)
+ .entity(parResponse)
+ .type(MediaType.APPLICATION_JSON_TYPE));
}
}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
index f7063d14e9e2..3a75254af113 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
@@ -18,7 +18,6 @@
package org.keycloak.protocol.oidc.utils;
import org.jboss.logging.Logger;
-import org.keycloak.http.HttpResponse;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.ClientAuthenticator;
import org.keycloak.authentication.ClientAuthenticatorFactory;
@@ -51,8 +50,7 @@ public static ClientAuthResult authorizeClient(KeycloakSession session, EventBui
if (response != null) {
if (cors != null) {
cors.allowAllOrigins();
- HttpResponse httpResponse = session.getContext().getHttpResponse();
- cors.build(httpResponse);
+ cors.add();
}
throw new WebApplicationException(response);
}
diff --git a/services/src/main/java/org/keycloak/services/CorsErrorResponseException.java b/services/src/main/java/org/keycloak/services/CorsErrorResponseException.java
index e2d903c2da9e..f2ed7848513a 100644
--- a/services/src/main/java/org/keycloak/services/CorsErrorResponseException.java
+++ b/services/src/main/java/org/keycloak/services/CorsErrorResponseException.java
@@ -49,7 +49,7 @@ public String getErrorDescription() {
public Response getResponse() {
OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
Response.ResponseBuilder builder = Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE);
- return cors.builder(builder).build();
+ return cors.add(builder);
}
}
diff --git a/services/src/main/java/org/keycloak/services/cors/DefaultCors.java b/services/src/main/java/org/keycloak/services/cors/DefaultCors.java
index 45b3dd869a2f..d33488ab71bf 100755
--- a/services/src/main/java/org/keycloak/services/cors/DefaultCors.java
+++ b/services/src/main/java/org/keycloak/services/cors/DefaultCors.java
@@ -21,9 +21,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import java.util.function.BiConsumer;
-import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.ResponseBuilder;
import org.jboss.logging.Logger;
@@ -42,7 +40,8 @@ public class DefaultCors implements Cors {
private static final Logger logger = Logger.getLogger(DefaultCors.class);
- private HttpRequest request;
+ private final HttpRequest request;
+ private final HttpResponse response;
private ResponseBuilder builder;
private Set allowedOrigins;
private Set allowedMethods;
@@ -51,14 +50,9 @@ public class DefaultCors implements Cors {
private boolean preflight;
private boolean auth;
- DefaultCors(HttpRequest request) {
- this.request = request;
- }
-
- @Override
- public Cors request(HttpRequest request) {
- this.request = request;
- return this;
+ DefaultCors(KeycloakSession session) {
+ this.request = session.getContext().getHttpRequest();
+ this.response = session.getContext().getHttpResponse();
}
@Override
@@ -117,89 +111,65 @@ public Cors allowedMethods(String... allowedMethods) {
@Override
public Cors exposedHeaders(String... exposedHeaders) {
- this.exposedHeaders = new HashSet<>(Arrays.asList(exposedHeaders));
- return this;
- }
-
- @Override
- public Cors addExposedHeaders(String... exposedHeaders) {
if (this.exposedHeaders == null) {
- this.exposedHeaders(exposedHeaders);
- } else {
- this.exposedHeaders.addAll(Arrays.asList(exposedHeaders));
+ this.exposedHeaders = new HashSet<>();
}
- return this;
- }
- @Override
- public Response build() {
- if (builder == null) {
- throw new IllegalStateException("builder is not set");
- }
+ this.exposedHeaders.addAll(Arrays.asList(exposedHeaders));
- if (build(builder::header)) {
- logger.debug("Added CORS headers to response");
- }
- return builder.build();
- }
-
- @Override
- public boolean build(HttpResponse response) {
- if (build(response::addHeader)) {
- logger.debug("Added CORS headers to response");
- return true;
- }
- return false;
+ return this;
}
@Override
- public boolean build(BiConsumer addHeader) {
+ public void add() {
if (request == null) {
throw new IllegalStateException("request is not set");
}
+ if (response == null) {
+ throw new IllegalStateException("response is not set");
+ }
+
String origin = request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN_HEADER);
if (origin == null) {
logger.trace("No Origin header, ignoring");
- return false;
+ return;
}
if (!preflight && (allowedOrigins == null || (!allowedOrigins.contains(origin) && !allowedOrigins.contains(ACCESS_CONTROL_ALLOW_ORIGIN_WILDCARD)))) {
if (logger.isDebugEnabled()) {
logger.debugv("Invalid CORS request: origin {0} not in allowed origins {1}", origin, allowedOrigins);
}
- return false;
+ return;
}
- addHeader.accept(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
+ response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
if (preflight) {
if (allowedMethods != null) {
- addHeader.accept(ACCESS_CONTROL_ALLOW_METHODS, CollectionUtil.join(allowedMethods));
+ response.setHeader(ACCESS_CONTROL_ALLOW_METHODS, CollectionUtil.join(allowedMethods));
} else {
- addHeader.accept(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
+ response.setHeader(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
}
}
if (!preflight && exposedHeaders != null) {
- addHeader.accept(ACCESS_CONTROL_EXPOSE_HEADERS, CollectionUtil.join(exposedHeaders));
+ response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS, CollectionUtil.join(exposedHeaders));
}
- addHeader.accept(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
+ response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
if (preflight) {
if (auth) {
- addHeader.accept(ACCESS_CONTROL_ALLOW_HEADERS, String.format("%s, %s", DEFAULT_ALLOW_HEADERS, AUTHORIZATION_HEADER));
+ response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS, String.format("%s, %s", DEFAULT_ALLOW_HEADERS, AUTHORIZATION_HEADER));
} else {
- addHeader.accept(ACCESS_CONTROL_ALLOW_HEADERS, DEFAULT_ALLOW_HEADERS);
+ response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS, DEFAULT_ALLOW_HEADERS);
}
}
if (preflight) {
- addHeader.accept(ACCESS_CONTROL_MAX_AGE, String.valueOf(DEFAULT_MAX_AGE));
+ response.setHeader(ACCESS_CONTROL_MAX_AGE, String.valueOf(DEFAULT_MAX_AGE));
}
-
- return true;
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/cors/DefaultCorsFactory.java b/services/src/main/java/org/keycloak/services/cors/DefaultCorsFactory.java
index de301f557118..17877512aa37 100644
--- a/services/src/main/java/org/keycloak/services/cors/DefaultCorsFactory.java
+++ b/services/src/main/java/org/keycloak/services/cors/DefaultCorsFactory.java
@@ -30,7 +30,7 @@ public class DefaultCorsFactory implements CorsFactory {
@Override
public Cors create(KeycloakSession session) {
- return new DefaultCors(session.getContext().getHttpRequest());
+ return new DefaultCors(session);
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 537471f44672..7a1bc7e29fad 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -448,7 +448,7 @@ public Object getEndpoint(@PathParam("provider_alias") String providerAlias) {
@Path("{provider_alias}/token")
@OPTIONS
public Response retrieveTokenPreflight() {
- return Cors.add(this.request, Response.ok()).auth().preflight().build();
+ return Cors.builder().auth().preflight().add(Response.ok());
}
@GET
@@ -1346,7 +1346,7 @@ private IdentityProviderModel getIdentityProviderConfig(String providerAlias) {
}
private Response corsResponse(Response response, ClientModel clientModel) {
- return Cors.add(this.request, Response.fromResponse(response)).auth().allowedOrigins(session, clientModel).build();
+ return Cors.builder().auth().allowedOrigins(session, clientModel).add(Response.fromResponse(response));
}
private void fireErrorEvent(String message, Throwable throwable) {
diff --git a/services/src/main/java/org/keycloak/services/resources/JsResource.java b/services/src/main/java/org/keycloak/services/resources/JsResource.java
index 0ead07a1a2fb..fd46429fd363 100755
--- a/services/src/main/java/org/keycloak/services/resources/JsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/JsResource.java
@@ -127,7 +127,7 @@ private Response getJs(String name, String version) {
}
String contentType = "text/javascript";
- Cors cors = Cors.add(session.getContext().getHttpRequest()).allowAllOrigins();
+ Cors cors = Cors.builder().allowAllOrigins();
ResourceEncodingProvider encodingProvider = ResourceEncodingHelper.getResourceEncodingProvider(session, contentType);
@@ -143,9 +143,9 @@ private Response getJs(String name, String version) {
if (encodingProvider != null) {
rb.encoding(encodingProvider.getEncoding());
}
- return cors.builder(rb).build();
+ return cors.add(rb);
} else {
- return cors.builder(Response.status(Response.Status.NOT_FOUND)).build();
+ return cors.add(Response.status(Response.Status.NOT_FOUND));
}
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
index 39de90191a55..a1b182e5b748 100755
--- a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
@@ -68,7 +68,7 @@ public PublicRealmResource(KeycloakSession session) {
@Path("/")
@OPTIONS
public Response accountPreflight() {
- return Cors.add(request, Response.ok()).auth().preflight().build();
+ return Cors.builder().auth().preflight().add(Response.ok());
}
/**
@@ -80,7 +80,7 @@ public Response accountPreflight() {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public PublishedRealmRepresentation getRealm() {
- Cors.add(request).allowedOrigins(Cors.ACCESS_CONTROL_ALLOW_ORIGIN_WILDCARD).auth().build(response);
+ Cors.builder().allowedOrigins(Cors.ACCESS_CONTROL_ALLOW_ORIGIN_WILDCARD).auth().add();
return realmRep(session, realm, session.getContext().getUri());
}
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index 99fc6d6f3c6e..7542f27133c1 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -217,7 +217,7 @@ public IdentityBrokerService getBrokerService(final @PathParam("realm") String n
@Produces(MediaType.APPLICATION_JSON)
public Response getVersionPreflight(final @PathParam("realm") String name,
final @PathParam("provider") String providerName) {
- return Cors.add(session.getContext().getHttpRequest(), Response.ok()).allowedMethods("GET").preflight().auth().build();
+ return Cors.builder().allowedMethods("GET").preflight().auth().add(Response.ok());
}
@GET
@@ -240,7 +240,7 @@ public Response getWellKnown(final @PathParam("realm") String name,
if (wellKnown != null) {
ResponseBuilder responseBuilder = Response.ok(wellKnown.getConfig()).cacheControl(CacheControlUtil.noCache());
- return Cors.add(session.getContext().getHttpRequest(), responseBuilder).allowedOrigins("*").auth().build();
+ return Cors.builder().allowedOrigins("*").auth().add(responseBuilder);
}
throw new NotFoundException();
@@ -279,7 +279,7 @@ private void checkSsl(RealmModel realm) {
if (!"https".equals(session.getContext().getUri().getBaseUri().getScheme())
&& realm.getSslRequired().isRequired(session.getContext().getConnection())) {
HttpRequest request = session.getContext().getHttpRequest();
- Cors cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
+ Cors cors = Cors.builder().auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
throw new CorsErrorResponseException(cors.allowAllOrigins(), OAuthErrorException.INVALID_REQUEST, "HTTPS required",
Response.Status.FORBIDDEN);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/ThemeResource.java b/services/src/main/java/org/keycloak/services/resources/ThemeResource.java
index e676aeb9f394..a8ce7363c442 100644
--- a/services/src/main/java/org/keycloak/services/resources/ThemeResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/ThemeResource.java
@@ -109,7 +109,7 @@ public Response getResource(@PathParam("version") String version, @PathParam("th
@Path("/{realm}/{themeType}/{locale}")
@OPTIONS
public Response localizationTextPreflight() {
- return Cors.add(session.getContext().getHttpRequest(), Response.ok()).auth().preflight().build();
+ return Cors.builder().auth().preflight().add(Response.ok());
}
@GET
@@ -151,8 +151,7 @@ public Response getLocalizationTexts(@PathParam("realm") String realmName, @Quer
new KeySource((String) e.getKey(), (String) e.getValue())).collect(toList());
}
- Response.ResponseBuilder responseBuilder = Response.ok(result);
- return Cors.add(session.getContext().getHttpRequest(), responseBuilder).allowedOrigins("*").auth().build();
+ return Cors.builder().allowedOrigins("*").auth().add(Response.ok(result));
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/account/AccountLoader.java b/services/src/main/java/org/keycloak/services/resources/account/AccountLoader.java
index 250e19e0115d..50b9144eff6e 100644
--- a/services/src/main/java/org/keycloak/services/resources/account/AccountLoader.java
+++ b/services/src/main/java/org/keycloak/services/resources/account/AccountLoader.java
@@ -86,7 +86,7 @@ public Object getAccountService() {
AccountResourceProvider accountResourceProvider = getAccountResourceProvider(theme);
if (request.getHttpMethod().equals(HttpMethod.OPTIONS)) {
- return new CorsPreflightService(request);
+ return new CorsPreflightService();
} else if ((accepts.contains(MediaType.APPLICATION_JSON_TYPE) || MediaType.APPLICATION_JSON_TYPE.equals(content)) && !uriInfo.getPath().endsWith("keycloak.json")) {
return getAccountRestService(client, null);
} else if (accountResourceProvider != null) {
@@ -100,7 +100,7 @@ public Object getAccountService() {
@Produces(MediaType.APPLICATION_JSON)
public Object getVersionedAccountRestService(final @PathParam("version") String version) {
if (request.getHttpMethod().equals(HttpMethod.OPTIONS)) {
- return new CorsPreflightService(request);
+ return new CorsPreflightService();
}
return getAccountRestService(getAccountManagementClient(session.getContext().getRealm()), version);
}
@@ -137,7 +137,7 @@ private AccountRestService getAccountRestService(ClientModel client, String vers
Auth auth = new Auth(session.getContext().getRealm(), accessToken, authResult.getUser(), client, authResult.getSession(), false);
- Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response);
+ Cors.builder().allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().add();
if (authResult.getUser().getServiceAccountClientLink() != null) {
throw new NotAuthorizedException("Service accounts are not allowed to access this service");
diff --git a/services/src/main/java/org/keycloak/services/resources/account/CorsPreflightService.java b/services/src/main/java/org/keycloak/services/resources/account/CorsPreflightService.java
index c205caab8f79..a1da7b3d4539 100644
--- a/services/src/main/java/org/keycloak/services/resources/account/CorsPreflightService.java
+++ b/services/src/main/java/org/keycloak/services/resources/account/CorsPreflightService.java
@@ -1,6 +1,5 @@
package org.keycloak.services.resources.account;
-import org.keycloak.http.HttpRequest;
import org.keycloak.services.cors.Cors;
import jakarta.ws.rs.OPTIONS;
@@ -12,12 +11,6 @@
*/
public class CorsPreflightService {
- private final HttpRequest request;
-
- public CorsPreflightService(HttpRequest request) {
- this.request = request;
- }
-
/**
* CORS preflight
*
@@ -26,8 +19,8 @@ public CorsPreflightService(HttpRequest request) {
@Path("{any:.*}")
@OPTIONS
public Response preflight() {
- Cors cors = Cors.add(request, Response.ok()).auth().allowedMethods("GET", "POST", "DELETE", "PUT", "HEAD", "OPTIONS").preflight();
- return cors.build();
+ return Cors.builder().auth().allowedMethods("GET", "POST", "DELETE", "PUT", "HEAD", "OPTIONS").preflight()
+ .add(Response.ok());
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java b/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java
index dcf796c5e68a..215c073baa24 100644
--- a/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java
@@ -99,7 +99,7 @@ public LinkedAccountsResource(KeycloakSession session,
public Response linkedAccounts() {
auth.requireOneOf(AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_PROFILE);
SortedSet linkedAccounts = getLinkedAccounts(this.session, this.realm, this.user);
- return Cors.add(request, Response.ok(linkedAccounts)).auth().allowedOrigins(auth.getToken()).build();
+ return Cors.builder().auth().allowedOrigins(auth.getToken()).add(Response.ok(linkedAccounts));
}
private Set findSocialIds() {
@@ -183,7 +183,7 @@ public Response buildLinkedAccountURI(@PathParam("providerAlias") String provide
rep.setHash(hash);
rep.setNonce(nonce);
- return Cors.add(request, Response.ok(rep)).auth().allowedOrigins(auth.getToken()).build();
+ return Cors.builder().auth().allowedOrigins(auth.getToken()).add(Response.ok(rep));
} catch (Exception spe) {
spe.printStackTrace();
throw ErrorResponse.error(Messages.FAILED_TO_PROCESS_RESPONSE, Response.Status.INTERNAL_SERVER_ERROR);
@@ -221,7 +221,7 @@ public Response removeLinkedAccount(@PathParam("providerAlias") String providerA
.detail(Details.IDENTITY_PROVIDER_USERNAME, link.getUserName())
.success();
- return Cors.add(request, Response.noContent()).auth().allowedOrigins(auth.getToken()).build();
+ return Cors.builder().auth().allowedOrigins(auth.getToken()).add(Response.noContent());
}
private String checkCommonPreconditions(String providerAlias) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
index aa62abd2f8ad..499c5a263497 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
@@ -185,7 +185,7 @@ public ClientManager.InstallationAdapterConfig config() {
@Path("whoami")
@OPTIONS
public Response whoAmIPreFlight() {
- return new AdminCorsPreflightService(request).preflight();
+ return new AdminCorsPreflightService().preflight();
}
/**
@@ -239,10 +239,11 @@ public Response whoAmI(@QueryParam("currentRealm") String currentRealm) {
Locale locale = session.getContext().resolveLocale(user);
- Cors.add(request).allowedOrigins(authResult.getToken()).allowedMethods("GET").auth()
- .build(response);
-
- return Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess, locale)).build();
+ return Cors.builder()
+ .allowedOrigins(authResult.getToken())
+ .allowedMethods("GET")
+ .auth()
+ .add(Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess, locale)));
}
private void addRealmAccess(RealmModel realm, UserModel user, Map> realmAdminAccess) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminCorsPreflightService.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminCorsPreflightService.java
index 57ac4676377a..de223994bc13 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminCorsPreflightService.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminCorsPreflightService.java
@@ -1,6 +1,5 @@
package org.keycloak.services.resources.admin;
-import org.keycloak.http.HttpRequest;
import org.keycloak.services.cors.Cors;
import jakarta.ws.rs.OPTIONS;
@@ -12,12 +11,6 @@
*/
public class AdminCorsPreflightService {
- private HttpRequest request;
-
- public AdminCorsPreflightService(HttpRequest request) {
- this.request = request;
- }
-
/**
* CORS preflight
*
@@ -26,7 +19,7 @@ public AdminCorsPreflightService(HttpRequest request) {
@Path("{any:.*}")
@OPTIONS
public Response preflight() {
- return Cors.add(request, Response.ok()).preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
+ return Cors.builder().preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().add(Response.ok());
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
index 1aff7d960050..d5262d491703 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
@@ -224,10 +224,7 @@ public RealmsAdminResource getRealmsAdmin() {
logger.debug("authenticated admin access for: " + auth.getUser().getUsername());
}
- HttpResponse response = getHttpResponse();
-
- Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").exposedHeaders("Location").auth().build(
- response);
+ Cors.builder().allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").exposedHeaders("Location").auth().add();
return new RealmsAdminResource(session, auth, tokenManager);
}
@@ -236,13 +233,11 @@ public RealmsAdminResource getRealmsAdmin() {
@OPTIONS
@Operation(hidden = true)
public Object preFlight() {
- HttpRequest request = getHttpRequest();
-
if (!isAdminApiEnabled()) {
throw new NotFoundException();
}
- return new AdminCorsPreflightService(request);
+ return new AdminCorsPreflightService();
}
/**
@@ -261,7 +256,7 @@ public Object getServerInfo() {
HttpRequest request = getHttpRequest();
if (request.getHttpMethod().equals(HttpMethod.OPTIONS)) {
- return new AdminCorsPreflightService(request);
+ return new AdminCorsPreflightService();
}
AdminAuth auth = authenticateRealmAdminRequest(session.getContext().getRequestHeaders());
@@ -273,8 +268,7 @@ public Object getServerInfo() {
logger.debug("authenticated admin access for: " + auth.getUser().getUsername());
}
- Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(
- getHttpResponse());
+ Cors.builder().allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().add();
return new ServerInfoAdminResource(session);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResourcePreflight.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResourcePreflight.java
index 79e8c26b9dc5..646a05c6fc47 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResourcePreflight.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResourcePreflight.java
@@ -41,7 +41,7 @@ public RealmsAdminResourcePreflight(KeycloakSession session, AdminAuth auth, Tok
@Path("{any:.*}")
@OPTIONS
public Response preFlight() {
- return Cors.add(request, Response.ok()).preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
+ return Cors.builder().preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().add(Response.ok());
}
}
diff --git a/services/src/main/java/org/keycloak/utils/OAuth2Error.java b/services/src/main/java/org/keycloak/utils/OAuth2Error.java
index 71fd1cbf8b62..f59cb7e16d4d 100644
--- a/services/src/main/java/org/keycloak/utils/OAuth2Error.java
+++ b/services/src/main/java/org/keycloak/utils/OAuth2Error.java
@@ -136,10 +136,10 @@ public WebApplicationException build() {
bearer.setErrorDescription(errorDescription);
WWWAuthenticate wwwAuthenticate = new WWWAuthenticate(bearer);
wwwAuthenticate.build(builder::header);
- cors.ifPresent(_cors -> _cors.addExposedHeaders(WWW_AUTHENTICATE));
+ cors.ifPresent(_cors -> _cors.exposedHeaders(WWW_AUTHENTICATE));
builder.entity("").type(MediaType.TEXT_PLAIN_UTF_8_TYPE);
}
- cors.ifPresent(_cors -> { _cors.build(builder::header); });
+ cors.ifPresent(Cors::add);
return constructor.newInstance(builder.build());
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
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 91da63421ab7..86090b97350e 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,6 +17,9 @@
package org.keycloak.testsuite.account;
import com.fasterxml.jackson.core.type.TypeReference;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import org.apache.http.Header;
import org.apache.http.impl.client.CloseableHttpClient;
import org.hamcrest.Matchers;
import org.junit.Assert;
@@ -62,6 +65,7 @@
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
+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;
@@ -81,9 +85,11 @@
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
import static org.hamcrest.CoreMatchers.is;
@@ -592,6 +598,26 @@ public void testUpdateProfileWithRegistrationEmailAsUsername() throws IOExceptio
}
}
+ @Test
+ public void testCors() throws IOException {
+ String accountUrl = getAccountUrl(null);
+ SimpleHttp 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()) {
+ Set expected = new HashSet<>();
+ Header[] actual = response.getAllHeaders();
+
+ for (Header header : actual) {
+ assertTrue(expected.add(header.getName()));
+ }
+
+ assertThat(expected, Matchers.hasItems(Cors.ACCESS_CONTROL_ALLOW_ORIGIN, Cors.ACCESS_CONTROL_ALLOW_CREDENTIALS));
+ }
+
+ }
+
protected UserRepresentation getUser() throws IOException {
return getUser(true);
}