deleteClients(RealmModel realm, ClientSearchOptions searchOptions) {
// TODO Auto-generated method stub
return null;
}
@@ -128,56 +136,58 @@ public class DefaultClientService implements ClientService {
*
* Reuses API v1 logic
*/
- protected void handleServiceAccount(ClientModel model, ClientRepresentation.ServiceAccount serviceAccount) {
- if (serviceAccount != null && serviceAccount.getEnabled() != null) {
- ClientResource.updateClientServiceAccount(session, model, serviceAccount.getEnabled());
+ protected void handleServiceAccount(ClientModel model, OIDCClientRepresentation rep) {
+ boolean serviceAccountEnabled = rep.getLoginFlows().contains(OIDCClientRepresentation.Flow.SERVICE_ACCOUNT);
- if (serviceAccount.getEnabled()) {
- var clientRoleResource = clientResource.getRoleContainerResource();
- var realmRoleResource = realmAdminResource.getRoleContainerResource();
+ ClientResource.updateClientServiceAccount(session, model, serviceAccountEnabled);
- var serviceAccountUser = session.users().getServiceAccount(model);
- var serviceAccountRoleResource = realmAdminResource.users().user(clientResource.getServiceAccountUser().getId()).getRoleMappings();
+ if (!serviceAccountEnabled) {
+ return;
+ }
- Set desiredRoleNames = Optional.ofNullable(serviceAccount.getRoles()).orElse(Collections.emptySet());
- Set currentRoles = serviceAccountUser.getRoleMappingsStream().collect(Collectors.toSet());
- Set currentRoleNames = currentRoles.stream().map(RoleModel::getName).collect(Collectors.toSet());
+ var clientRoleResource = clientResource.getRoleContainerResource();
+ var realmRoleResource = realmAdminResource.getRoleContainerResource();
- // Get missing roles (in desired but not in current)
- List missingRoles = desiredRoleNames.stream()
- .filter(roleName -> !currentRoleNames.contains(roleName))
- .map(roleName -> {
- try {
- return clientRoleResource.getRole(roleName); // client role
- } catch (NotFoundException e) {
- try {
- return realmRoleResource.getRole(roleName); // realm role
- } catch (NotFoundException e2) {
- throw new ServiceException("Cannot assign role to the service account (field 'serviceAccount.roles') as it does not exist", Response.Status.BAD_REQUEST);
- }
- }
- })
- .toList();
+ var serviceAccountUser = session.users().getServiceAccount(model);
+ var serviceAccountRoleResource = realmAdminResource.users().user(clientResource.getServiceAccountUser().getId()).getRoleMappings();
- // Add missing roles (in desired but not in current)
- if (!missingRoles.isEmpty()) {
- serviceAccountRoleResource.addRealmRoleMappings(missingRoles);
- }
+ Set desiredRoleNames = Optional.ofNullable(rep.getServiceAccountRoles()).orElse(Collections.emptySet());
+ Set currentRoles = serviceAccountUser.getRoleMappingsStream().collect(Collectors.toSet());
+ Set currentRoleNames = currentRoles.stream().map(RoleModel::getName).collect(Collectors.toSet());
- // Get extra roles (in current but not in desired)
- List extraRoles = currentRoles.stream()
- .filter(role -> !desiredRoleNames.contains(role.getName()))
- .map(ModelToRepresentation::toRepresentation)
- .toList();
-
- // Remove extra roles (in current but not in desired)
- if (!extraRoles.isEmpty()) {
+ // Get missing roles (in desired but not in current)
+ List missingRoles = desiredRoleNames.stream()
+ .filter(roleName -> !currentRoleNames.contains(roleName))
+ .map(roleName -> {
try {
- serviceAccountRoleResource.deleteRealmRoleMappings(extraRoles);
+ return clientRoleResource.getRole(roleName); // client role
} catch (NotFoundException e) {
- throw new ServiceException("Cannot unassign role from the service account (field 'serviceAccount.roles') as it does not exist", Response.Status.BAD_REQUEST);
+ try {
+ return realmRoleResource.getRole(roleName); // realm role
+ } catch (NotFoundException e2) {
+ throw new ServiceException("Cannot assign role to the service account (field 'serviceAccount.roles') as it does not exist", Response.Status.BAD_REQUEST);
+ }
}
- }
+ })
+ .toList();
+
+ // Add missing roles (in desired but not in current)
+ if (!missingRoles.isEmpty()) {
+ serviceAccountRoleResource.addRealmRoleMappings(missingRoles);
+ }
+
+ // Get extra roles (in current but not in desired)
+ List extraRoles = currentRoles.stream()
+ .filter(role -> !desiredRoleNames.contains(role.getName()))
+ .map(ModelToRepresentation::toRepresentation)
+ .toList();
+
+ // Remove extra roles (in current but not in desired)
+ if (!extraRoles.isEmpty()) {
+ try {
+ serviceAccountRoleResource.deleteRealmRoleMappings(extraRoles);
+ } catch (NotFoundException e) {
+ throw new ServiceException("Cannot unassign role from the service account (field 'serviceAccount.roles') as it does not exist", Response.Status.BAD_REQUEST);
}
}
}
diff --git a/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.models.mapper.ClientModelMapperFactory b/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.models.mapper.ClientModelMapperFactory
new file mode 100644
index 00000000000..a8e6f488541
--- /dev/null
+++ b/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.models.mapper.ClientModelMapperFactory
@@ -0,0 +1 @@
+org.keycloak.models.mapper.OIDCClientModelMapperFactory
\ No newline at end of file
diff --git a/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100755
index 00000000000..84d24dcaeab
--- /dev/null
+++ b/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1 @@
+org.keycloak.models.mapper.ClientModelMapperSpi
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApi.java
index d1705bb5c7d..01bc82f9f3b 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApi.java
@@ -10,7 +10,7 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
-import org.keycloak.representations.admin.v2.ClientRepresentation;
+import org.keycloak.representations.admin.v2.BaseClientRepresentation;
import com.fasterxml.jackson.databind.JsonNode;
@@ -21,20 +21,20 @@ public interface ClientApi {
@GET
@Produces(MediaType.APPLICATION_JSON)
- ClientRepresentation getClient();
+ BaseClientRepresentation getClient();
/**
- * @return {@link ClientRepresentation} of created/updated client
+ * @return {@link BaseClientRepresentation} of created/updated client
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- Response createOrUpdateClient(@Valid ClientRepresentation client);
+ Response createOrUpdateClient(@Valid BaseClientRepresentation client);
@PATCH
@Consumes(CONTENT_TYPE_MERGE_PATCH)
@Produces(MediaType.APPLICATION_JSON)
- ClientRepresentation patchClient(JsonNode patch);
+ BaseClientRepresentation patchClient(JsonNode patch);
@DELETE
@Produces(MediaType.APPLICATION_JSON)
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApi.java
index 049250f7895..8cc8d2234bf 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApi.java
@@ -12,7 +12,7 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
-import org.keycloak.representations.admin.v2.ClientRepresentation;
+import org.keycloak.representations.admin.v2.BaseClientRepresentation;
import org.keycloak.services.resources.KeycloakOpenAPI;
import org.eclipse.microprofile.openapi.annotations.Operation;
@@ -27,16 +27,16 @@ public interface ClientsApi {
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Get all clients", description = "Returns a list of all clients in the realm")
- Stream getClients();
+ Stream getClients();
/**
- * @return {@link ClientRepresentation} of created client
+ * @return {@link BaseClientRepresentation} of created client
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Create a new client", description = "Creates a new client in the realm")
- Response createClient(@Valid ClientRepresentation client);
+ Response createClient(@Valid BaseClientRepresentation client);
@Path("{id}")
ClientApi client(@PathParam("id") String id);
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApi.java
index 4e2b49a5679..860d5c0b6bc 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApi.java
@@ -12,7 +12,7 @@ import jakarta.ws.rs.core.Response;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.representations.admin.v2.ClientRepresentation;
+import org.keycloak.representations.admin.v2.BaseClientRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ServiceException;
import org.keycloak.services.client.ClientService;
@@ -52,13 +52,13 @@ public class DefaultClientApi implements ClientApi {
}
@Override
- public ClientRepresentation getClient() {
+ public BaseClientRepresentation getClient() {
return clientService.getClient(realm, client.getClientId(), null)
.orElseThrow(() -> new NotFoundException("Cannot find the specified client"));
}
@Override
- public Response createOrUpdateClient(ClientRepresentation client) {
+ public Response createOrUpdateClient(BaseClientRepresentation client) {
try {
if (!Objects.equals(clientId, client.getClientId())) {
throw new WebApplicationException("cliendId in payload does not match the clientId in the path", Response.Status.BAD_REQUEST);
@@ -72,8 +72,8 @@ public class DefaultClientApi implements ClientApi {
}
@Override
- public ClientRepresentation patchClient(JsonNode patch) {
- ClientRepresentation client = getClient();
+ public BaseClientRepresentation patchClient(JsonNode patch) {
+ BaseClientRepresentation client = getClient();
try {
String contentType = session.getContext().getHttpRequest().getHttpHeaders().getHeaderString(HttpHeaders.CONTENT_TYPE);
MediaType mediaType = contentType == null ? null : MediaType.valueOf(contentType);
@@ -83,7 +83,7 @@ public class DefaultClientApi implements ClientApi {
}
final ObjectReader objectReader = objectMapper.readerForUpdating(client);
- ClientRepresentation updated = objectReader.readValue(patch);
+ BaseClientRepresentation updated = objectReader.readValue(patch);
validateUnknownFields(updated);
return clientService.createOrUpdate(realm, updated, true).representation();
@@ -104,8 +104,8 @@ public class DefaultClientApi implements ClientApi {
clientResource.deleteClient();
}
- static void validateUnknownFields(ClientRepresentation rep) {
- if (!rep.getAdditionalFields().isEmpty()) {
+ static void validateUnknownFields(BaseClientRepresentation rep) {
+ if (rep.getAdditionalFields().keySet().stream().anyMatch(k -> !k.equals(BaseClientRepresentation.DISCRIMINATOR_FIELD))) {
throw new WebApplicationException("Payload contains unknown fields: " + rep.getAdditionalFields().keySet(), Response.Status.BAD_REQUEST);
}
}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApi.java
index d1769101fcc..c4f4da214bd 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApi.java
@@ -11,7 +11,7 @@ import jakarta.ws.rs.core.Response;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.representations.admin.v2.ClientRepresentation;
+import org.keycloak.representations.admin.v2.BaseClientRepresentation;
import org.keycloak.representations.admin.v2.validation.CreateClientDefault;
import org.keycloak.services.ServiceException;
import org.keycloak.services.client.ClientService;
@@ -40,12 +40,12 @@ public class DefaultClientsApi implements ClientsApi {
}
@Override
- public Stream getClients() {
+ public Stream getClients() {
return clientService.getClients(realm, null, null, null);
}
@Override
- public Response createClient(@Valid ClientRepresentation client) {
+ public Response createClient(@Valid BaseClientRepresentation client) {
try {
DefaultClientApi.validateUnknownFields(client);
validator.validate(client, CreateClientDefault.class);
diff --git a/rest/admin-v2/tests/src/test/java/org/keycloak/tests/admin/client/v2/ClientApiV2Test.java b/rest/admin-v2/tests/src/test/java/org/keycloak/tests/admin/client/v2/ClientApiV2Test.java
index ed1ba9c3850..bb3eaf185d5 100644
--- a/rest/admin-v2/tests/src/test/java/org/keycloak/tests/admin/client/v2/ClientApiV2Test.java
+++ b/rest/admin-v2/tests/src/test/java/org/keycloak/tests/admin/client/v2/ClientApiV2Test.java
@@ -25,7 +25,7 @@ import jakarta.ws.rs.core.MediaType;
import org.keycloak.admin.api.client.ClientApi;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.common.Profile;
-import org.keycloak.representations.admin.v2.ClientRepresentation;
+import org.keycloak.representations.admin.v2.OIDCClientRepresentation;
import org.keycloak.services.error.ViolationExceptionResponse;
import org.keycloak.testframework.annotations.InjectAdminClient;
import org.keycloak.testframework.annotations.InjectHttpClient;
@@ -85,7 +85,7 @@ public class ClientApiV2Test {
setAuthHeader(request);
try (var response = client.execute(request)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertEquals("account", client.getClientId());
}
}
@@ -107,7 +107,7 @@ public class ClientApiV2Test {
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, ClientApi.CONTENT_TYPE_MERGE_PATCH);
- ClientRepresentation patch = new ClientRepresentation();
+ OIDCClientRepresentation patch = new OIDCClientRepresentation();
patch.setDescription("I'm also a description");
request.setEntity(new StringEntity(mapper.writeValueAsString(patch)));
@@ -115,7 +115,7 @@ public class ClientApiV2Test {
try (var response = client.execute(request)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertEquals("I'm also a description", client.getDescription());
}
}
@@ -126,7 +126,7 @@ public class ClientApiV2Test {
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = new ClientRepresentation();
+ OIDCClientRepresentation rep = new OIDCClientRepresentation();
rep.setClientId("other");
request.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
@@ -142,7 +142,7 @@ public class ClientApiV2Test {
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = new ClientRepresentation();
+ OIDCClientRepresentation rep = new OIDCClientRepresentation();
rep.setEnabled(true);
rep.setClientId("other");
rep.setDescription("I'm new");
@@ -151,7 +151,7 @@ public class ClientApiV2Test {
try (var response = client.execute(request)) {
assertEquals(201, response.getStatusLine().getStatusCode());
- ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertEquals("I'm new", client.getDescription());
}
@@ -160,7 +160,7 @@ public class ClientApiV2Test {
try (var response = client.execute(request)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertEquals("I'm updated", client.getDescription());
}
}
@@ -171,7 +171,7 @@ public class ClientApiV2Test {
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = new ClientRepresentation();
+ OIDCClientRepresentation rep = new OIDCClientRepresentation();
rep.setEnabled(true);
rep.setClientId("client-123");
rep.setDescription("I'm new");
@@ -180,7 +180,7 @@ public class ClientApiV2Test {
try (var response = client.execute(request)) {
assertThat(response.getStatusLine().getStatusCode(),is(201));
- ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(client.getEnabled(),is(true));
assertThat(client.getClientId(),is("client-123"));
assertThat(client.getDescription(),is("I'm new"));
@@ -197,7 +197,7 @@ public class ClientApiV2Test {
setAuthHeader(createRequest);
createRequest.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = new ClientRepresentation();
+ OIDCClientRepresentation rep = new OIDCClientRepresentation();
rep.setClientId("to-delete");
rep.setEnabled(true);
@@ -225,13 +225,14 @@ public class ClientApiV2Test {
}
@Test
- public void clientRepresentationValidation() throws Exception {
+ public void OIDCClientRepresentationValidation() throws Exception {
HttpPost request = new HttpPost(HOSTNAME_LOCAL_ADMIN + "/realms/master/clients");
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
request.setEntity(new StringEntity("""
{
+ "protocol": "openid-connect",
"displayName": "something",
"appUrl": "notUrl"
}
@@ -250,6 +251,7 @@ public class ClientApiV2Test {
request.setEntity(new StringEntity("""
{
+ "protocol": "openid-connect",
"clientId": "some-client",
"displayName": "something",
"appUrl": "notUrl",
@@ -285,12 +287,12 @@ public class ClientApiV2Test {
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = getTestingFullClientRep();
+ OIDCClientRepresentation rep = getTestingFullClientRep();
request.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(request)) {
assertEquals(201, response.getStatusLine().getStatusCode());
- ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(client, is(rep));
}
}
@@ -301,8 +303,8 @@ public class ClientApiV2Test {
setAuthHeader(request);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = getTestingFullClientRep();
- rep.getServiceAccount().setRoles(Set.of("non-existing", "bad-role"));
+ OIDCClientRepresentation rep = getTestingFullClientRep();
+ rep.setServiceAccountRoles(Set.of("non-existing", "bad-role"));
request.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(request)) {
@@ -318,7 +320,7 @@ public class ClientApiV2Test {
setAuthHeader(createRequest);
createRequest.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = new ClientRepresentation();
+ OIDCClientRepresentation rep = new OIDCClientRepresentation();
rep.setClientId("declarative-role-test");
rep.setEnabled(true);
rep.setRoles(Set.of("role1", "role2", "role3"));
@@ -327,7 +329,7 @@ public class ClientApiV2Test {
try (var response = client.execute(createRequest)) {
assertEquals(201, response.getStatusLine().getStatusCode());
- ClientRepresentation created = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation created = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(created.getRoles(), is(Set.of("role1", "role2", "role3")));
}
@@ -341,7 +343,7 @@ public class ClientApiV2Test {
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(updated.getRoles(), is(Set.of("new-role1", "new-role2")));
}
@@ -351,7 +353,7 @@ public class ClientApiV2Test {
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(updated.getRoles(), is(Set.of("new-role1", "add-role3", "add-role4")));
}
@@ -361,7 +363,7 @@ public class ClientApiV2Test {
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(updated.getRoles(), is(Set.of("new-role1", "add-role3", "add-role4")));
}
@@ -371,7 +373,7 @@ public class ClientApiV2Test {
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
assertThat(updated.getRoles(), is(Set.of()));
}
}
@@ -383,21 +385,19 @@ public class ClientApiV2Test {
setAuthHeader(createRequest);
createRequest.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- ClientRepresentation rep = new ClientRepresentation();
+ OIDCClientRepresentation rep = new OIDCClientRepresentation();
rep.setClientId("sa-declarative-test");
rep.setEnabled(true);
- var serviceAccount = new ClientRepresentation.ServiceAccount();
- serviceAccount.setEnabled(true);
- serviceAccount.setRoles(Set.of("default-roles-master", "offline_access"));
- rep.setServiceAccount(serviceAccount);
+ rep.setLoginFlows(Set.of(OIDCClientRepresentation.Flow.SERVICE_ACCOUNT));
+ rep.setServiceAccountRoles(Set.of("default-roles-master", "offline_access"));
createRequest.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(createRequest)) {
assertEquals(201, response.getStatusLine().getStatusCode());
- ClientRepresentation created = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
- assertThat(created.getServiceAccount().getRoles(), is(Set.of("default-roles-master", "offline_access")));
+ OIDCClientRepresentation created = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
+ assertThat(created.getServiceAccountRoles(), is(Set.of("default-roles-master", "offline_access")));
}
// 2. Update with completely new roles - should remove old ones and add new ones
@@ -405,63 +405,55 @@ public class ClientApiV2Test {
setAuthHeader(updateRequest);
updateRequest.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
- serviceAccount.setRoles(Set.of("uma_authorization", "offline_access"));
- rep.setServiceAccount(serviceAccount);
+ rep.setServiceAccountRoles(Set.of("uma_authorization", "offline_access"));
updateRequest.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
- assertThat(updated.getServiceAccount().getRoles(), is(Set.of("uma_authorization", "offline_access")));
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
+ assertThat(updated.getServiceAccountRoles(), is(Set.of("uma_authorization", "offline_access")));
}
// 3. Update with partial overlap - keep some, add some, remove some
- serviceAccount.setRoles(Set.of("offline_access", "default-roles-master"));
- rep.setServiceAccount(serviceAccount);
+ rep.setServiceAccountRoles(Set.of("offline_access", "default-roles-master"));
updateRequest.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
- assertThat(updated.getServiceAccount().getRoles(), is(Set.of("offline_access", "default-roles-master")));
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
+ assertThat(updated.getServiceAccountRoles(), is(Set.of("offline_access", "default-roles-master")));
}
// 4. Update with same roles - should be idempotent
- serviceAccount.setRoles(Set.of("offline_access", "default-roles-master"));
- rep.setServiceAccount(serviceAccount);
+ rep.setServiceAccountRoles(Set.of("offline_access", "default-roles-master"));
updateRequest.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
- assertThat(updated.getServiceAccount().getRoles(), is(Set.of("offline_access", "default-roles-master")));
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
+ assertThat(updated.getServiceAccountRoles(), is(Set.of("offline_access", "default-roles-master")));
}
// 5. Update with empty set - should remove all roles
- serviceAccount.setRoles(Set.of());
- rep.setServiceAccount(serviceAccount);
+ rep.setServiceAccountRoles(Set.of());
updateRequest.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
try (var response = client.execute(updateRequest)) {
assertEquals(200, response.getStatusLine().getStatusCode());
- ClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
- assertThat(updated.getServiceAccount().getRoles(), is(Set.of()));
+ OIDCClientRepresentation updated = mapper.createParser(response.getEntity().getContent()).readValueAs(OIDCClientRepresentation.class);
+ assertThat(updated.getServiceAccountRoles(), is(Set.of()));
}
}
- private ClientRepresentation getTestingFullClientRep() {
- var rep = new ClientRepresentation();
+ private OIDCClientRepresentation getTestingFullClientRep() {
+ var rep = new OIDCClientRepresentation();
rep.setClientId("my-client");
rep.setDisplayName("My Client");
rep.setDescription("This is My Client");
- rep.setProtocol(ClientRepresentation.OIDC);
rep.setEnabled(true);
rep.setAppUrl("http://localhost:3000");
- rep.setAppRedirectUrls(Set.of("http://localhost:3000", "http://localhost:3001"));
- // no login flows -> only flow overrides map
- // rep.setLoginFlows(Set.of("browser"));
- var auth = new ClientRepresentation.Auth();
- auth.setEnabled(true);
+ rep.setRedirectUris(Set.of("http://localhost:3000", "http://localhost:3001"));
+ var auth = new OIDCClientRepresentation.Auth();
auth.setMethod("client-jwt");
auth.setSecret("secret-1234");
// no certificate inside the old rep
@@ -469,11 +461,9 @@ public class ClientApiV2Test {
rep.setAuth(auth);
rep.setWebOrigins(Set.of("http://localhost:4000", "http://localhost:4001"));
rep.setRoles(Set.of("view-consent", "manage-account"));
- var serviceAccount = new ClientRepresentation.ServiceAccount();
- serviceAccount.setEnabled(true);
+ rep.setLoginFlows(Set.of(OIDCClientRepresentation.Flow.SERVICE_ACCOUNT));
// TODO when roles are not set and SA is enabled, the default role 'default-roles-master' for the SA is used for the master realm
- serviceAccount.setRoles(Set.of("default-roles-master"));
- rep.setServiceAccount(serviceAccount);
+ rep.setServiceAccountRoles(Set.of("default-roles-master"));
// not implemented yet
// rep.setAdditionalFields(Map.of("key1", "val1", "key2", "val2"));
return rep;