mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Remove JSON Patch support from the Client API v2 MVP (#44120)
Closes: #43572 Signed-off-by: Peter Zaoral <pzaoral@redhat.com>
This commit is contained in:
parent
a4c583246d
commit
b9d94d325b
@ -436,10 +436,6 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Keycloak Dependencies-->
|
||||
<dependency>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>zjsonpatch</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>commons-logging-jboss-logging</artifactId>
|
||||
|
||||
@ -40,9 +40,5 @@
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>zjsonpatch</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -27,7 +27,7 @@ public interface ClientApi {
|
||||
ClientRepresentation createOrUpdateClient(@Valid ClientRepresentation client);
|
||||
|
||||
@PATCH
|
||||
@Consumes({MediaType.APPLICATION_JSON_PATCH_JSON, CONTENT_TYPE_MERGE_PATCH})
|
||||
@Consumes(CONTENT_TYPE_MERGE_PATCH)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
ClientRepresentation patchClient(JsonNode patch);
|
||||
|
||||
|
||||
@ -20,13 +20,12 @@ import org.keycloak.services.client.ClientService;
|
||||
import org.keycloak.services.client.DefaultClientService;
|
||||
import org.keycloak.services.resources.admin.ClientResource;
|
||||
import org.keycloak.services.resources.admin.ClientsResource;
|
||||
import org.keycloak.services.util.ObjectMapperResolver;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import io.fabric8.zjsonpatch.JsonPatch;
|
||||
import io.fabric8.zjsonpatch.JsonPatchException;
|
||||
|
||||
public class DefaultClientApi implements ClientApi {
|
||||
|
||||
@ -39,6 +38,9 @@ public class DefaultClientApi implements ClientApi {
|
||||
private final ClientResource clientResource;
|
||||
private final ClientsResource clientsResource;
|
||||
private final String clientId;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapperResolver().getContext(null);
|
||||
|
||||
public DefaultClientApi(KeycloakSession session, ClientsResource clientsResource, ClientResource clientResource, String clientId) {
|
||||
this.session = session;
|
||||
@ -49,6 +51,7 @@ public class DefaultClientApi implements ClientApi {
|
||||
this.clientsResource = clientsResource;
|
||||
this.clientResource = clientResource;
|
||||
this.clientId = clientId;
|
||||
this.objectMapper = MAPPER;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,28 +79,22 @@ public class DefaultClientApi implements ClientApi {
|
||||
|
||||
@Override
|
||||
public ClientRepresentation patchClient(JsonNode patch) {
|
||||
// patches don't yet allow for creating
|
||||
ClientRepresentation client = getClient();
|
||||
try {
|
||||
String contentType = session.getContext().getHttpRequest().getHttpHeaders().getHeaderString(HttpHeaders.CONTENT_TYPE);
|
||||
|
||||
ClientRepresentation updated = null;
|
||||
|
||||
// TODO: there should be a more centralized objectmapper
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
if (MediaType.valueOf(contentType).getSubtype().equals(MediaType.APPLICATION_JSON_PATCH_JSON_TYPE.getSubtype())) {
|
||||
JsonNode patchedNode = JsonPatch.apply(patch, objectMapper.convertValue(client, JsonNode.class));
|
||||
updated = objectMapper.convertValue(patchedNode, ClientRepresentation.class);
|
||||
} else { // must be merge patch
|
||||
final ObjectReader objectReader = objectMapper.readerForUpdating(client);
|
||||
updated = objectReader.readValue(patch);
|
||||
MediaType mediaType = contentType == null ? null : MediaType.valueOf(contentType);
|
||||
MediaType mergePatch = MediaType.valueOf(ClientApi.CONTENT_TYPE_MERGE_PATCH);
|
||||
if (mediaType == null || !mediaType.isCompatible(mergePatch)) {
|
||||
throw new WebApplicationException("Unsupported media type", Response.Status.UNSUPPORTED_MEDIA_TYPE);
|
||||
}
|
||||
|
||||
final ObjectReader objectReader = objectMapper.readerForUpdating(client);
|
||||
ClientRepresentation updated = objectReader.readValue(patch);
|
||||
|
||||
validateUnknownFields(updated, response);
|
||||
return clientService.createOrUpdate(clientsResource, clientResource, realm, updated, true).representation();
|
||||
} catch (JsonPatchException e) {
|
||||
// TODO: kubernetes uses 422 instead
|
||||
throw new WebApplicationException(e.getMessage(), Response.Status.BAD_REQUEST);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new WebApplicationException("Unsupported media type", Response.Status.UNSUPPORTED_MEDIA_TYPE);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new WebApplicationException(e.getMessage(), Response.Status.BAD_REQUEST);
|
||||
} catch (IOException e) {
|
||||
|
||||
@ -90,23 +90,10 @@ public class ClientApiV2Test {
|
||||
public void jsonPatchClient() throws Exception {
|
||||
HttpPatch request = new HttpPatch(HOSTNAME_LOCAL_ADMIN + "/realms/master/clients/account");
|
||||
setAuthHeader(request);
|
||||
request.setEntity(new StringEntity("not json"));
|
||||
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_PATCH_JSON);
|
||||
try (var response = client.execute(request)) {
|
||||
EntityUtils.consumeQuietly(response.getEntity());
|
||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
request.setEntity(new StringEntity(
|
||||
"""
|
||||
[{"op": "add", "path": "/description", "value": "I'm a description"}]
|
||||
"""));
|
||||
|
||||
try (var response = client.execute(request)) {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
|
||||
ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
|
||||
assertEquals("I'm a description", client.getDescription());
|
||||
assertEquals(415, response.getStatusLine().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user