diff --git a/pom.xml b/pom.xml
index c8c0e0dd0f9..4a478968c40 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1145,11 +1145,6 @@
keycloak-admin-v2-api
${project.version}
-
- org.keycloak
- keycloak-admin-v2-providers
- ${project.version}
-
org.keycloak
keycloak-admin-v2-rest
diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml
index 0dbe29b6a04..9a6a7dbfb76 100644
--- a/quarkus/runtime/pom.xml
+++ b/quarkus/runtime/pom.xml
@@ -424,17 +424,6 @@
-
- org.keycloak
- keycloak-admin-v2-providers
-
-
- *
- *
-
-
-
-
org.keycloak
keycloak-admin-v2-rest
diff --git a/rest/admin-v2/api/pom.xml b/rest/admin-v2/api/pom.xml
index 11d876a215d..46b1ad13bbd 100644
--- a/rest/admin-v2/api/pom.xml
+++ b/rest/admin-v2/api/pom.xml
@@ -20,6 +20,11 @@
+
+ org.keycloak
+ keycloak-services
+ provided
+
org.keycloak
keycloak-server-spi
@@ -40,5 +45,34 @@
jakarta.ws.rs
jakarta.ws.rs-api
+
+ org.mapstruct
+ mapstruct
+
+
+ jakarta.enterprise
+ jakarta.enterprise.cdi-api
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ -AgeneratedTranslationFilesPath=${project.build.directory}/generated-translation-files
+
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${org.mapstruct.version}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructClientModelMapper.java b/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/MapStructClientModelMapper.java
similarity index 100%
rename from rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructClientModelMapper.java
rename to rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/MapStructClientModelMapper.java
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructModelMapper.java b/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/MapStructModelMapper.java
similarity index 100%
rename from rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructModelMapper.java
rename to rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/MapStructModelMapper.java
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapper.java b/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapper.java
index 1c4f5d1019e..510b70b7787 100644
--- a/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapper.java
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapper.java
@@ -1,11 +1,7 @@
package org.keycloak.models.mapper;
-import org.keycloak.provider.Provider;
-
-public interface ModelMapper extends Provider {
+public interface ModelMapper {
ClientModelMapper clients();
- default void close() {
- }
}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapperFactory.java b/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapperFactory.java
deleted file mode 100644
index 2393d4a9eee..00000000000
--- a/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapperFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.models.mapper;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface ModelMapperFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapperSpi.java b/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapperSpi.java
deleted file mode 100644
index 41fedc931de..00000000000
--- a/rest/admin-v2/api/src/main/java/org/keycloak/models/mapper/ModelMapperSpi.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.keycloak.models.mapper;
-
-import org.keycloak.common.Profile;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-public class ModelMapperSpi implements Spi {
- public static final String NAME = "model-mapper";
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Class extends ModelMapper> getProviderClass() {
- return ModelMapper.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return ModelMapperFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- // Currently used only by Client Admin API v2
- return Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2);
- }
-}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/representations/admin/v2/ClientRepresentation.java b/rest/admin-v2/api/src/main/java/org/keycloak/representations/admin/v2/ClientRepresentation.java
index f2ee3cd63ab..345dee6e5d9 100644
--- a/rest/admin-v2/api/src/main/java/org/keycloak/representations/admin/v2/ClientRepresentation.java
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/representations/admin/v2/ClientRepresentation.java
@@ -5,7 +5,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.constraints.URL;
import org.keycloak.representations.admin.v2.validation.CreateClient;
@@ -167,7 +166,6 @@ public class ClientRepresentation extends BaseRepresentation {
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public static class Auth {
- @NotNull
@JsonPropertyDescription("Whether authentication is enabled for this client")
private Boolean enabled;
@@ -216,7 +214,6 @@ public class ClientRepresentation extends BaseRepresentation {
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public static class ServiceAccount {
- @NotNull
@JsonPropertyDescription("Whether the service account is enabled")
private Boolean enabled;
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/services/Service.java b/rest/admin-v2/api/src/main/java/org/keycloak/services/Service.java
index 7e46c4a0c8c..d6bcb813a67 100644
--- a/rest/admin-v2/api/src/main/java/org/keycloak/services/Service.java
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/services/Service.java
@@ -1,9 +1,7 @@
package org.keycloak.services;
-import org.keycloak.provider.Provider;
-
/**
* Service handling business logic for various user interfaces (REST API, GraphQL, GitOps,...)
*/
-public interface Service extends Provider {
+public interface Service {
}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientService.java b/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientService.java
index df90ee0301a..5405c249b02 100644
--- a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientService.java
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientService.java
@@ -7,6 +7,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.representations.admin.v2.ClientRepresentation;
import org.keycloak.services.Service;
import org.keycloak.services.ServiceException;
+import org.keycloak.services.resources.admin.ClientResource;
+import org.keycloak.services.resources.admin.ClientsResource;
public interface ClientService extends Service {
@@ -27,14 +29,14 @@ public interface ClientService extends Service {
record CreateOrUpdateResult(ClientRepresentation representation, boolean created) {}
- Optional getClient(RealmModel realm, String clientId, ClientProjectionOptions projectionOptions);
+ Optional getClient(ClientResource clientResource, RealmModel realm, String clientId, ClientProjectionOptions projectionOptions);
- Stream getClients(RealmModel realm, ClientProjectionOptions projectionOptions, ClientSearchOptions searchOptions, ClientSortAndSliceOptions sortAndSliceOptions);
+ Stream getClients(ClientsResource clientsResource, RealmModel realm, ClientProjectionOptions projectionOptions, ClientSearchOptions searchOptions, ClientSortAndSliceOptions sortAndSliceOptions);
ClientRepresentation deleteClient(RealmModel realm, String clientId);
Stream deleteClients(RealmModel realm, ClientSearchOptions searchOptions);
- CreateOrUpdateResult createOrUpdate(RealmModel realm, ClientRepresentation client, boolean allowUpdate) throws ServiceException;
+ CreateOrUpdateResult createOrUpdate(ClientsResource clientsResource, ClientResource clientResource, RealmModel realm, ClientRepresentation client, boolean allowUpdate) throws ServiceException;
}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientServiceFactory.java b/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientServiceFactory.java
deleted file mode 100644
index 7d247fc41a9..00000000000
--- a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientServiceFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.services.client;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface ClientServiceFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientServiceSpi.java b/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientServiceSpi.java
deleted file mode 100644
index 4fcbaabfcd3..00000000000
--- a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/ClientServiceSpi.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.services.client;
-
-import org.keycloak.common.Profile;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-public class ClientServiceSpi implements Spi {
- public static final String NAME = "client-service";
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Class extends ClientService> getProviderClass() {
- return ClientService.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return ClientServiceFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2);
- }
-}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/services/client/DefaultClientService.java b/rest/admin-v2/api/src/main/java/org/keycloak/services/client/DefaultClientService.java
new file mode 100644
index 00000000000..3a35f573045
--- /dev/null
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/services/client/DefaultClientService.java
@@ -0,0 +1,91 @@
+package org.keycloak.services.client;
+
+import jakarta.ws.rs.core.Response;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.mapper.ClientModelMapper;
+import org.keycloak.models.mapper.MapStructModelMapper;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.admin.v2.ClientRepresentation;
+import org.keycloak.representations.admin.v2.validation.CreateClientDefault;
+import org.keycloak.services.ServiceException;
+import org.keycloak.services.resources.admin.ClientResource;
+import org.keycloak.services.resources.admin.ClientsResource;
+import org.keycloak.validation.jakarta.HibernateValidatorProvider;
+import org.keycloak.validation.jakarta.JakartaValidatorProvider;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+// TODO
+public class DefaultClientService implements ClientService {
+ private final KeycloakSession session;
+ private final ClientModelMapper mapper;
+ private final JakartaValidatorProvider validator;
+
+ public DefaultClientService(KeycloakSession session) {
+ this.session = session;
+ this.mapper = new MapStructModelMapper().clients();
+ this.validator = new HibernateValidatorProvider();
+ }
+
+ @Override
+ public Optional getClient(ClientResource clientResource, RealmModel realm, String clientId,
+ ClientProjectionOptions projectionOptions) {
+ // TODO: is the access map on the representation needed
+ return Optional.ofNullable(clientResource).map(ClientResource::viewClientModel).map(mapper::fromModel);
+ }
+
+ @Override
+ public Stream getClients(ClientsResource clientsResource, RealmModel realm,
+ ClientProjectionOptions projectionOptions, ClientSearchOptions searchOptions,
+ ClientSortAndSliceOptions sortAndSliceOptions) {
+ // TODO: is the access map on the representation needed
+ return clientsResource.getClientModels(null, true, false, null, null, null).map(mapper::fromModel);
+ }
+
+ @Override
+ public CreateOrUpdateResult createOrUpdate(ClientsResource clientsResource, ClientResource clientResource,
+ RealmModel realm, ClientRepresentation client, boolean allowUpdate) throws ServiceException {
+ boolean created = false;
+ ClientModel model = null;
+ if (clientResource != null) {
+ if (!allowUpdate) {
+ throw new ServiceException("Client already exists", Response.Status.CONFLICT);
+ }
+ model = clientResource.viewClientModel();
+ mapper.toModel(model, client, realm);
+ var rep = ModelToRepresentation.toRepresentation(model, session);
+ clientResource.update(rep);
+ } else {
+ created = true;
+ validator.validate(client, CreateClientDefault.class); // TODO improve it to avoid second validation when we know it is create and not update
+
+ // dummy add/remove to obtain a detached model
+ model = realm.addClient(client.getClientId());
+ realm.removeClient(model.getId());
+
+ mapper.toModel(model, client, realm);
+ var rep = ModelToRepresentation.toRepresentation(model, session);
+ model = clientsResource.createClientModel(rep);
+ }
+
+ var updated = mapper.fromModel(model);
+
+ return new CreateOrUpdateResult(updated, created);
+ }
+
+ @Override
+ public ClientRepresentation deleteClient(RealmModel realm, String clientId) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Stream deleteClients(RealmModel realm, ClientSearchOptions searchOptions) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/services/error/ValidationExceptionHandler.java b/rest/admin-v2/api/src/main/java/org/keycloak/services/error/ValidationExceptionHandler.java
similarity index 100%
rename from rest/admin-v2/providers/src/main/java/org/keycloak/services/error/ValidationExceptionHandler.java
rename to rest/admin-v2/api/src/main/java/org/keycloak/services/error/ValidationExceptionHandler.java
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProvider.java b/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProvider.java
similarity index 84%
rename from rest/admin-v2/providers/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProvider.java
rename to rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProvider.java
index 027ab764a16..5897c20c10e 100644
--- a/rest/admin-v2/providers/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProvider.java
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProvider.java
@@ -1,5 +1,6 @@
package org.keycloak.validation.jakarta;
+import jakarta.enterprise.inject.spi.CDI;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
@@ -8,10 +9,10 @@ import java.util.Set;
import java.util.function.Function;
public class HibernateValidatorProvider implements JakartaValidatorProvider {
- private final Validator validator;
- public HibernateValidatorProvider(Validator validator) {
- this.validator = validator;
+ private final Validator validator = CDI.current().select(Validator.class).get();
+
+ public HibernateValidatorProvider() {
}
@Override
@@ -35,8 +36,4 @@ public class HibernateValidatorProvider implements JakartaValidatorProvider {
return validator;
}
- @Override
- public void close() {
-
- }
}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProvider.java b/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProvider.java
index 2a7a4b3f032..0d22fe0ebd0 100644
--- a/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProvider.java
+++ b/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProvider.java
@@ -3,12 +3,11 @@ package org.keycloak.validation.jakarta;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
-import org.keycloak.provider.Provider;
import java.util.Set;
import java.util.function.Function;
-public interface JakartaValidatorProvider extends Provider {
+public interface JakartaValidatorProvider {
void validate(T object, Class>... groups) throws ConstraintViolationException;
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProviderFactory.java b/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProviderFactory.java
deleted file mode 100644
index 3c2365ea9dd..00000000000
--- a/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorProviderFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.validation.jakarta;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface JakartaValidatorProviderFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorSpi.java b/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorSpi.java
deleted file mode 100644
index ebf314b99dc..00000000000
--- a/rest/admin-v2/api/src/main/java/org/keycloak/validation/jakarta/JakartaValidatorSpi.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.validation.jakarta;
-
-import org.keycloak.common.Profile;
-import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-public class JakartaValidatorSpi implements Spi {
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public String getName() {
- return "jakarta-validator";
- }
-
- @Override
- public Class extends Provider> getProviderClass() {
- return JakartaValidatorProvider.class;
- }
-
- @Override
- public Class extends ProviderFactory>> getProviderFactoryClass() {
- return JakartaValidatorProviderFactory.class;
- }
-
- @Override
- public boolean isEnabled() {
- // Currently used only by Client Admin API v2
- return Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2);
- }
-}
diff --git a/rest/admin-v2/providers/src/main/resources/META-INF/beans.xml b/rest/admin-v2/api/src/main/resources/META-INF/beans.xml
similarity index 100%
rename from rest/admin-v2/providers/src/main/resources/META-INF/beans.xml
rename to rest/admin-v2/api/src/main/resources/META-INF/beans.xml
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
deleted file mode 100644
index ed56a9f2837..00000000000
--- a/rest/admin-v2/api/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ /dev/null
@@ -1,3 +0,0 @@
-org.keycloak.services.client.ClientServiceSpi
-org.keycloak.models.mapper.ModelMapperSpi
-org.keycloak.validation.jakarta.JakartaValidatorSpi
\ No newline at end of file
diff --git a/rest/admin-v2/pom.xml b/rest/admin-v2/pom.xml
index e29537fb897..89ac6da1413 100644
--- a/rest/admin-v2/pom.xml
+++ b/rest/admin-v2/pom.xml
@@ -16,7 +16,6 @@
rest
api
- providers
tests
\ No newline at end of file
diff --git a/rest/admin-v2/providers/pom.xml b/rest/admin-v2/providers/pom.xml
deleted file mode 100644
index 386af0ce4a6..00000000000
--- a/rest/admin-v2/providers/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
- 4.0.0
-
- org.keycloak
- keycloak-admin-v2-parent
- 999.0.0-SNAPSHOT
-
-
- keycloak-admin-v2-providers
- Keycloak Admin API v2 Providers
-
-
- 17
- 17
- 17
- UTF-8
-
-
-
-
- org.keycloak
- keycloak-admin-v2-api
-
-
- org.mapstruct
- mapstruct
-
-
- org.hibernate.validator
- hibernate-validator
-
-
- jakarta.enterprise
- jakarta.enterprise.cdi-api
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
-
- -AgeneratedTranslationFilesPath=${project.build.directory}/generated-translation-files
-
-
-
- org.mapstruct
- mapstruct-processor
- ${org.mapstruct.version}
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructModelMapperFactory.java b/rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructModelMapperFactory.java
deleted file mode 100644
index 9c6468d21fa..00000000000
--- a/rest/admin-v2/providers/src/main/java/org/keycloak/models/mapper/MapStructModelMapperFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.keycloak.models.mapper;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class MapStructModelMapperFactory implements ModelMapperFactory {
- public static final String PROVIDER_ID = "default";
- private static ModelMapper SINGLETON;
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public ModelMapper create(KeycloakSession session) {
- if (SINGLETON == null) {
- SINGLETON = new MapStructModelMapper();
- }
- return SINGLETON;
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/services/client/DefaultClientService.java b/rest/admin-v2/providers/src/main/java/org/keycloak/services/client/DefaultClientService.java
deleted file mode 100644
index ac9d6001e21..00000000000
--- a/rest/admin-v2/providers/src/main/java/org/keycloak/services/client/DefaultClientService.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.keycloak.services.client;
-
-import jakarta.ws.rs.core.Response;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.mapper.ClientModelMapper;
-import org.keycloak.models.mapper.ModelMapper;
-import org.keycloak.representations.admin.v2.ClientRepresentation;
-import org.keycloak.representations.admin.v2.validation.CreateClientDefault;
-import org.keycloak.services.ServiceException;
-import org.keycloak.validation.jakarta.JakartaValidatorProvider;
-
-import java.util.Optional;
-import java.util.stream.Stream;
-
-// TODO
-public class DefaultClientService implements ClientService {
- private final KeycloakSession session;
- private final ClientModelMapper mapper;
- private final JakartaValidatorProvider validator;
-
- public DefaultClientService(KeycloakSession session) {
- this.session = session;
- this.mapper = session.getProvider(ModelMapper.class).clients();
- this.validator = session.getProvider(JakartaValidatorProvider.class);
- }
-
- @Override
- public Optional getClient(RealmModel realm, String clientId,
- ClientProjectionOptions projectionOptions) {
- return Optional.ofNullable(realm.getClientByClientId(clientId)).map(mapper::fromModel);
- }
-
- @Override
- public Stream getClients(RealmModel realm, ClientProjectionOptions projectionOptions,
- ClientSearchOptions searchOptions, ClientSortAndSliceOptions sortAndSliceOptions) {
- return realm.getClientsStream().map(mapper::fromModel);
- }
-
- @Override
- public CreateOrUpdateResult createOrUpdate(RealmModel realm, ClientRepresentation client, boolean allowUpdate)
- throws ServiceException {
- boolean created = false;
- ClientModel model = realm.getClientByClientId(client.getClientId());
- if (model != null) {
- if (!allowUpdate) {
- throw new ServiceException("Client already exists", Response.Status.CONFLICT);
- }
- } else {
- validator.validate(client, CreateClientDefault.class); // TODO improve it to avoid second validation when we know it is create and not update
- model = realm.addClient(client.getClientId());
- created = true;
- }
-
- // TODO: defaulting, validation, canonicalization
-
- mapper.toModel(model, client, realm);
-
- var updated = mapper.fromModel(model);
-
- return new CreateOrUpdateResult(updated, created);
- }
-
- @Override
- public ClientRepresentation deleteClient(RealmModel realm, String clientId) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Stream deleteClients(RealmModel realm, ClientSearchOptions searchOptions) {
- // TODO Auto-generated method stub
- return null;
- }
-
-
- @Override
- public void close() {
-
- }
-
-}
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/services/client/DefaultClientServiceFactory.java b/rest/admin-v2/providers/src/main/java/org/keycloak/services/client/DefaultClientServiceFactory.java
deleted file mode 100644
index 7dec08bf0c2..00000000000
--- a/rest/admin-v2/providers/src/main/java/org/keycloak/services/client/DefaultClientServiceFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.services.client;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class DefaultClientServiceFactory implements ClientServiceFactory {
- public static final String PROVIDER_ID = "default";
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public ClientService create(KeycloakSession session) {
- return new DefaultClientService(session);
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/rest/admin-v2/providers/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProviderFactory.java b/rest/admin-v2/providers/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProviderFactory.java
deleted file mode 100644
index e50f9c5dbba..00000000000
--- a/rest/admin-v2/providers/src/main/java/org/keycloak/validation/jakarta/HibernateValidatorProviderFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.keycloak.validation.jakarta;
-
-import jakarta.enterprise.inject.spi.CDI;
-import jakarta.validation.Validator;
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class HibernateValidatorProviderFactory implements JakartaValidatorProviderFactory {
- public static final String PROVIDER_ID = "default";
- private static HibernateValidatorProvider SINGLETON;
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public JakartaValidatorProvider create(KeycloakSession session) {
- if (SINGLETON == null) {
- SINGLETON = new HibernateValidatorProvider(CDI.current().select(Validator.class).get());
- }
- return SINGLETON;
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.models.mapper.ModelMapperFactory b/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.models.mapper.ModelMapperFactory
deleted file mode 100644
index 1746852e27c..00000000000
--- a/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.models.mapper.ModelMapperFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.models.mapper.MapStructModelMapperFactory
\ No newline at end of file
diff --git a/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.services.client.ClientServiceFactory b/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.services.client.ClientServiceFactory
deleted file mode 100644
index 9ef09d55c3f..00000000000
--- a/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.services.client.ClientServiceFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.services.client.DefaultClientServiceFactory
\ No newline at end of file
diff --git a/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.validation.jakarta.JakartaValidatorProviderFactory b/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.validation.jakarta.JakartaValidatorProviderFactory
deleted file mode 100644
index c40b9ff7d96..00000000000
--- a/rest/admin-v2/providers/src/main/resources/META-INF/services/org.keycloak.validation.jakarta.JakartaValidatorProviderFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.validation.jakarta.HibernateValidatorProviderFactory
\ No newline at end of file
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApi.java
index b0b55f2cdd8..fc39ec26aa5 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApi.java
@@ -2,9 +2,8 @@ package org.keycloak.admin.api;
import jakarta.ws.rs.Path;
import org.keycloak.admin.api.realm.RealmsApi;
-import org.keycloak.provider.Provider;
-public interface AdminApi extends Provider {
+public interface AdminApi {
@Path("realms")
RealmsApi realms();
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApiFactory.java
deleted file mode 100644
index c0e44d01504..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApiFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.admin.api;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface AdminApiFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApiSpi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApiSpi.java
deleted file mode 100644
index 154b5949803..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminApiSpi.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.keycloak.admin.api;
-
-import org.keycloak.common.Profile;
-import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-public class AdminApiSpi implements Spi {
- public static final String PROVIDER_ID = "admin-api-root";
-
- @Override
- public String getName() {
- return PROVIDER_ID;
- }
-
- @Override
- public Class extends Provider> getProviderClass() {
- return AdminApi.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return AdminApiFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2); // There's currently only Client API for the new Admin API v2
- }
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminRootV2.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminRootV2.java
index cafbb09782e..bb5dc27ecf7 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminRootV2.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/AdminRootV2.java
@@ -17,17 +17,10 @@ public class AdminRootV2 {
@Context
protected KeycloakSession session;
- @Path("")
- public AdminApi latestAdminApi() {
- checkApiEnabled();
- // we could return the latest Admin API if no version is specified
- return session.getProvider(AdminApi.class);
- }
-
@Path("v2")
public AdminApi adminApi() {
checkApiEnabled();
- return session.getProvider(AdminApi.class);
+ return new DefaultAdminApi(session);
}
@Path("{any:.*}")
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApi.java
index e79450077c4..3085988c1af 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApi.java
@@ -7,11 +7,14 @@ import org.keycloak.admin.api.realm.DefaultRealmsApi;
import org.keycloak.admin.api.realm.RealmsApi;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.services.resources.admin.AdminAuth;
import org.keycloak.services.resources.admin.AdminRoot;
+import org.keycloak.services.resources.admin.RealmsAdminResource;
public class DefaultAdminApi implements AdminApi {
private final KeycloakSession session;
+ private final RealmsAdminResource realmsAdminResource;
private final AdminAuth auth;
public DefaultAdminApi(KeycloakSession session) {
@@ -22,16 +25,13 @@ public class DefaultAdminApi implements AdminApi {
if (!auth.getRealm().getName().equals(Config.getAdminRealm()) || !auth.hasRealmRole(AdminRoles.ADMIN)) {
throw new NotAuthorizedException("Wrong permissions");
}
+ this.realmsAdminResource = new RealmsAdminResource(session, auth, new TokenManager());
}
@Path("realms")
@Override
public RealmsApi realms() {
- return new DefaultRealmsApi(session);
+ return new DefaultRealmsApi(session, realmsAdminResource);
}
- @Override
- public void close() {
-
- }
}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApiFactory.java
deleted file mode 100644
index 137dffcfa58..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/DefaultAdminApiFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.admin.api;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class DefaultAdminApiFactory implements AdminApiFactory {
- public static final String PROVIDER_ID = "default";
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public AdminApi create(KeycloakSession session) {
- return new DefaultAdminApi(session);
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
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 ebfd825c590..116386802bf 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,12 +10,11 @@ import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import org.keycloak.admin.api.FieldValidation;
-import org.keycloak.provider.Provider;
import org.keycloak.representations.admin.v2.ClientRepresentation;
import com.fasterxml.jackson.databind.JsonNode;
-public interface ClientApi extends Provider {
+public interface ClientApi {
// TODO move these
String CONTENT_TYPE_MERGE_PATCH = "application/merge-patch+json";
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApiFactory.java
deleted file mode 100644
index eb95f913aae..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApiFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.admin.api.client;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface ClientApiFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApiSpi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApiSpi.java
deleted file mode 100644
index b246e00dbef..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientApiSpi.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.keycloak.admin.api.client;
-
-import org.keycloak.common.Profile;
-import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-public class ClientApiSpi implements Spi {
- public static final String NAME = "admin-api-client";
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Class extends Provider> getProviderClass() {
- return ClientApi.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return ClientApiFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2);
- }
-}
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 d56e7701895..290927912ad 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
@@ -8,7 +8,6 @@ import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.keycloak.admin.api.FieldValidation;
-import org.keycloak.provider.Provider;
import org.keycloak.representations.admin.v2.ClientRepresentation;
import jakarta.ws.rs.Consumes;
@@ -22,7 +21,7 @@ import org.keycloak.services.resources.KeycloakOpenAPI;
@Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS_V2)
@Extension(name = KeycloakOpenAPI.Profiles.ADMIN, value = "")
-public interface ClientsApi extends Provider {
+public interface ClientsApi {
@GET
@Produces(MediaType.APPLICATION_JSON)
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApiFactory.java
deleted file mode 100644
index da3a180474a..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApiFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.admin.api.client;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface ClientsApiFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApiSpi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApiSpi.java
deleted file mode 100644
index 23cf437c135..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/ClientsApiSpi.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.keycloak.admin.api.client;
-
-import org.keycloak.common.Profile;
-import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-public class ClientsApiSpi implements Spi {
- public static final String NAME = "admin-api-clients";
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Class extends Provider> getProviderClass() {
- return ClientsApi.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return ClientsApiFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return Profile.isFeatureEnabled(Profile.Feature.CLIENT_ADMIN_API_V2);
- }
-}
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 d3d8f1e2ab9..e7ca291674b 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,6 +12,9 @@ import org.keycloak.representations.admin.v2.ClientRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ServiceException;
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 com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
@@ -33,24 +36,35 @@ public class DefaultClientApi implements ClientApi {
private final ClientService clientService;
private HttpResponse response;
- public DefaultClientApi(KeycloakSession session) {
+ private final ClientResource clientResource;
+ private final ClientsResource clientsResource;
+ private final String clientId;
+
+ public DefaultClientApi(KeycloakSession session, ClientsResource clientsResource, ClientResource clientResource, String clientId) {
this.session = session;
this.realm = Objects.requireNonNull(session.getContext().getRealm());
this.client = Objects.requireNonNull(session.getContext().getClient());
- this.clientService = session.getProvider(ClientService.class);
+ this.clientService = new DefaultClientService(session);
this.response = session.getContext().getHttpResponse();
+ this.clientsResource = clientsResource;
+ this.clientResource = clientResource;
+ this.clientId = clientId;
}
@Override
public ClientRepresentation getClient() {
- return clientService.getClient(realm, client.getClientId(), null)
+ return clientService.getClient(clientResource, realm, client.getClientId(), null)
.orElseThrow(() -> new NotFoundException("Cannot find the specified client"));
}
@Override
public ClientRepresentation createOrUpdateClient(ClientRepresentation client, FieldValidation fieldValidation) {
try {
- var result = clientService.createOrUpdate(realm, client, true);
+ if (!Objects.equals(clientId, client.getClientId())) {
+ throw new WebApplicationException("cliendId in payload does not match the clientId in the path", Response.Status.BAD_REQUEST);
+ }
+ validateUnknownFields(fieldValidation, client, response);
+ var result = clientService.createOrUpdate(clientsResource, clientResource, realm, client, true);
if (result.created()) {
response.setStatus(Response.Status.CREATED.getStatusCode());
}
@@ -79,16 +93,8 @@ public class DefaultClientApi implements ClientApi {
updated = objectReader.readValue(patch);
}
- // TODO: reuse in the other methods
- if (!updated.getAdditionalFields().isEmpty()) {
- if (fieldValidation == null || fieldValidation == FieldValidation.Strict) {
- // validation failed
- throw new WebApplicationException("Payload contains unknown fields: " + updated.getAdditionalFields().keySet(), Response.Status.BAD_REQUEST);
- } else if (fieldValidation == FieldValidation.Warn) {
- response.addHeader("WARNING", "Payload contains unknown fields: " + updated.getAdditionalFields().keySet());
- }
- }
- return clientService.createOrUpdate(realm, updated, true).representation();
+ validateUnknownFields(fieldValidation, 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);
@@ -99,8 +105,15 @@ public class DefaultClientApi implements ClientApi {
}
}
- @Override
- public void close() {
-
+ static void validateUnknownFields(FieldValidation fieldValidation, ClientRepresentation rep, HttpResponse response) {
+ if (!rep.getAdditionalFields().isEmpty()) {
+ if (fieldValidation == null || fieldValidation == FieldValidation.Strict) {
+ // validation failed
+ throw new WebApplicationException("Payload contains unknown fields: " + rep.getAdditionalFields().keySet(), Response.Status.BAD_REQUEST);
+ } else if (fieldValidation == FieldValidation.Warn) {
+ response.addHeader("WARNING", "Payload contains unknown fields: " + rep.getAdditionalFields().keySet());
+ }
+ }
}
+
}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApiFactory.java
deleted file mode 100644
index baf95861c28..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientApiFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.admin.api.client;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class DefaultClientApiFactory implements ClientApiFactory {
- public static final String PROVIDER_ID = "default";
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public ClientApi create(KeycloakSession session) {
- return new DefaultClientApi(session);
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
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 e8e4b7cc3f5..39a76fc598d 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
@@ -5,7 +5,6 @@ import java.util.Optional;
import java.util.stream.Stream;
import jakarta.validation.Valid;
-import jakarta.ws.rs.NotFoundException;
import org.keycloak.admin.api.FieldValidation;
import org.keycloak.http.HttpResponse;
import org.keycloak.models.KeycloakSession;
@@ -14,10 +13,14 @@ import org.keycloak.representations.admin.v2.ClientRepresentation;
import org.keycloak.representations.admin.v2.validation.CreateClientDefault;
import org.keycloak.services.ServiceException;
import org.keycloak.services.client.ClientService;
+import org.keycloak.services.client.DefaultClientService;
+import org.keycloak.services.resources.admin.ClientsResource;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
+
+import org.keycloak.validation.jakarta.HibernateValidatorProvider;
import org.keycloak.validation.jakarta.JakartaValidatorProvider;
public class DefaultClientsApi implements ClientsApi {
@@ -26,26 +29,29 @@ public class DefaultClientsApi implements ClientsApi {
private final HttpResponse response;
private final ClientService clientService;
private final JakartaValidatorProvider validator;
+ private final ClientsResource clientsResource;
- public DefaultClientsApi(KeycloakSession session) {
+ public DefaultClientsApi(KeycloakSession session, ClientsResource clientsResource) {
this.session = session;
this.realm = Objects.requireNonNull(session.getContext().getRealm());
- this.clientService = session.getProvider(ClientService.class);
+ this.clientService = new DefaultClientService(session);
this.response = session.getContext().getHttpResponse();
- this.validator = session.getProvider(JakartaValidatorProvider.class);
+ this.validator = new HibernateValidatorProvider();
+ this.clientsResource = clientsResource;
}
@Override
public Stream getClients() {
- return clientService.getClients(realm, null, null, null);
+ return clientService.getClients(clientsResource, realm, null, null, null);
}
@Override
public ClientRepresentation createClient(@Valid ClientRepresentation client, FieldValidation fieldValidation) {
try {
+ DefaultClientApi.validateUnknownFields(fieldValidation, client, response);
validator.validate(client, CreateClientDefault.class);
response.setStatus(Response.Status.CREATED.getStatusCode());
- return clientService.createOrUpdate(realm, client, false).representation();
+ return clientService.createOrUpdate(clientsResource, null, realm, client, false).representation();
} catch (ServiceException e) {
throw new WebApplicationException(e.getMessage(), e.getSuggestedResponseStatus().orElse(Response.Status.BAD_REQUEST));
}
@@ -53,13 +59,8 @@ public class DefaultClientsApi implements ClientsApi {
@Override
public ClientApi client(@PathParam("id") String clientId) {
- var client = Optional.ofNullable(session.clients().getClientByClientId(realm, clientId)).orElseThrow(() -> new NotFoundException("Client cannot be found"));
- session.getContext().setClient(client);
- return session.getProvider(ClientApi.class);
+ var client = Optional.ofNullable(session.clients().getClientByClientId(realm, clientId));
+ return new DefaultClientApi(session, clientsResource, client.map(c -> clientsResource.getClient(c.getId())).orElse(null), clientId);
}
- @Override
- public void close() {
-
- }
}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApiFactory.java
deleted file mode 100644
index 931fe3af6ba..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/client/DefaultClientsApiFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.admin.api.client;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class DefaultClientsApiFactory implements ClientsApiFactory {
- public static final String PROVIDER_ID = "default";
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public ClientsApi create(KeycloakSession session) {
- return new DefaultClientsApi(session);
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApi.java
index 00b3181f7ab..edf6b5b8855 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApi.java
@@ -2,26 +2,23 @@ package org.keycloak.admin.api.realm;
import jakarta.ws.rs.Path;
import org.keycloak.admin.api.client.ClientsApi;
+import org.keycloak.admin.api.client.DefaultClientsApi;
import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-
-import java.util.Objects;
+import org.keycloak.services.resources.admin.RealmAdminResource;
public class DefaultRealmApi implements RealmApi {
private final KeycloakSession session;
- private final RealmModel realm;
+ private final RealmAdminResource realmAdminResource;
- public DefaultRealmApi(KeycloakSession session) {
+ public DefaultRealmApi(KeycloakSession session, RealmAdminResource realmAdmin) {
this.session = session;
- this.realm = Objects.requireNonNull(session.getContext().getRealm());
+ this.realmAdminResource = realmAdmin;
}
@Path("clients")
@Override
public ClientsApi clients() {
- return session.getProvider(ClientsApi.class);
+ return new DefaultClientsApi(session, realmAdminResource.getClients());
}
- @Override
- public void close() {}
}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApiFactory.java
deleted file mode 100644
index a231426c480..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmApiFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.admin.api.realm;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class DefaultRealmApiFactory implements RealmApiFactory {
- public static final String PROVIDER_ID = "default";
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public RealmApi create(KeycloakSession session) {
- return new DefaultRealmApi(session);
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApi.java
index d673e9b8fcd..32514308f99 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApi.java
@@ -1,29 +1,24 @@
package org.keycloak.admin.api.realm;
-import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import org.keycloak.models.KeycloakSession;
-
-import java.util.Optional;
+import org.keycloak.services.resources.admin.RealmsAdminResource;
public class DefaultRealmsApi implements RealmsApi {
private final KeycloakSession session;
+ private final RealmsAdminResource realmsAdminResource;
- public DefaultRealmsApi(KeycloakSession session) {
+ public DefaultRealmsApi(KeycloakSession session, RealmsAdminResource realmsAdminResource) {
this.session = session;
+ this.realmsAdminResource = realmsAdminResource;
}
@Path("{name}")
@Override
public RealmApi realm(@PathParam("name") String name) {
- var realm = Optional.ofNullable(session.realms().getRealmByName(name)).orElseThrow(() -> new NotFoundException("Realm cannot be found"));
- session.getContext().setRealm(realm);
- return session.getProvider(RealmApi.class);
+ var realmAdmin = realmsAdminResource.getRealmAdmin(name);
+ return new DefaultRealmApi(session, realmAdmin);
}
- @Override
- public void close() {
-
- }
}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApiFactory.java
deleted file mode 100644
index c8a1a7370c1..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/DefaultRealmsApiFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.keycloak.admin.api.realm;
-
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-
-public class DefaultRealmsApiFactory implements RealmsApiFactory {
- public static final String PROVIDER_ID = "default";
-
- @Override
- public String getId() {
- return PROVIDER_ID;
- }
-
- @Override
- public RealmsApi create(KeycloakSession session) {
- return new DefaultRealmsApi(session);
- }
-
- @Override
- public void init(Config.Scope config) {
-
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApi.java
index 0074acad205..3a69618f44d 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApi.java
@@ -2,9 +2,8 @@ package org.keycloak.admin.api.realm;
import jakarta.ws.rs.Path;
import org.keycloak.admin.api.client.ClientsApi;
-import org.keycloak.provider.Provider;
-public interface RealmApi extends Provider {
+public interface RealmApi {
@Path("clients")
ClientsApi clients();
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApiFactory.java
deleted file mode 100644
index 54a4835530d..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApiFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.admin.api.realm;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface RealmApiFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApiSpi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApiSpi.java
deleted file mode 100644
index 6c692bc39fa..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmApiSpi.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.keycloak.admin.api.realm;
-
-import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-import static org.keycloak.admin.api.AdminRootV2.isAdminApiV2Enabled;
-
-public class RealmApiSpi implements Spi {
- public static final String NAME = "admin-api-realm";
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Class extends Provider> getProviderClass() {
- return RealmApi.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return RealmApiFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return isAdminApiV2Enabled();
- }
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApi.java
index 92a26a5b2d0..f3df56c23c7 100644
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApi.java
+++ b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApi.java
@@ -1,11 +1,9 @@
package org.keycloak.admin.api.realm;
-
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
-import org.keycloak.provider.Provider;
-public interface RealmsApi extends Provider {
+public interface RealmsApi {
@Path("{name}")
RealmApi realm(@PathParam("name") String name);
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApiFactory.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApiFactory.java
deleted file mode 100644
index aff3c8a2fd2..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApiFactory.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.keycloak.admin.api.realm;
-
-import org.keycloak.provider.ProviderFactory;
-
-public interface RealmsApiFactory extends ProviderFactory {
-}
diff --git a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApiSpi.java b/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApiSpi.java
deleted file mode 100644
index b26cce77cc3..00000000000
--- a/rest/admin-v2/rest/src/main/java/org/keycloak/admin/api/realm/RealmsApiSpi.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.keycloak.admin.api.realm;
-
-import org.keycloak.provider.Provider;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.Spi;
-
-import static org.keycloak.admin.api.AdminRootV2.isAdminApiV2Enabled;
-
-public class RealmsApiSpi implements Spi {
- public static final String NAME = "admin-api-realms";
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Class extends Provider> getProviderClass() {
- return RealmsApi.class;
- }
-
- @Override
- public Class extends ProviderFactory> getProviderFactoryClass() {
- return RealmsApiFactory.class;
- }
-
- @Override
- public boolean isInternal() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return isAdminApiV2Enabled();
- }
-}
diff --git a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.AdminApiFactory b/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.AdminApiFactory
deleted file mode 100644
index 14f064e7d7e..00000000000
--- a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.AdminApiFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.admin.api.DefaultAdminApiFactory
\ No newline at end of file
diff --git a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.client.ClientApiFactory b/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.client.ClientApiFactory
deleted file mode 100644
index 310fd11a655..00000000000
--- a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.client.ClientApiFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.admin.api.client.DefaultClientApiFactory
\ No newline at end of file
diff --git a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.client.ClientsApiFactory b/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.client.ClientsApiFactory
deleted file mode 100644
index 9a5198083ae..00000000000
--- a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.client.ClientsApiFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.admin.api.client.DefaultClientsApiFactory
\ No newline at end of file
diff --git a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.realm.RealmApiFactory b/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.realm.RealmApiFactory
deleted file mode 100644
index 31e0a0ea889..00000000000
--- a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.realm.RealmApiFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.admin.api.realm.DefaultRealmApiFactory
\ No newline at end of file
diff --git a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.realm.RealmsApiFactory b/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.realm.RealmsApiFactory
deleted file mode 100644
index d37d3d5a413..00000000000
--- a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.admin.api.realm.RealmsApiFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.keycloak.admin.api.realm.DefaultRealmsApiFactory
\ No newline at end of file
diff --git a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.provider.Spi
deleted file mode 100644
index d84d8e9be37..00000000000
--- a/rest/admin-v2/rest/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ /dev/null
@@ -1,5 +0,0 @@
-org.keycloak.admin.api.AdminApiSpi
-org.keycloak.admin.api.realm.RealmsApiSpi
-org.keycloak.admin.api.realm.RealmApiSpi
-org.keycloak.admin.api.client.ClientsApiSpi
-org.keycloak.admin.api.client.ClientApiSpi
\ No newline at end of file
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 694097b9d68..28d75eb7798 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
@@ -24,6 +24,7 @@ import org.apache.http.HttpMessage;
import org.apache.http.client.methods.HttpGet;
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.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
@@ -126,6 +127,51 @@ public class ClientApiV2Test {
}
}
+ @Test
+ public void putFailsWithDifferentClientId() throws Exception {
+ HttpPut request = new HttpPut(HOSTNAME_LOCAL_ADMIN + "/realms/master/clients/account");
+ setAuthHeader(request);
+ request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
+
+ ClientRepresentation rep = new ClientRepresentation();
+ rep.setClientId("other");
+
+ request.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
+
+ try (var response = client.execute(request)) {
+ assertEquals(400, response.getStatusLine().getStatusCode());
+ }
+ }
+
+ @Test
+ public void putCreateOrUpdates() throws Exception {
+ HttpPut request = new HttpPut(HOSTNAME_LOCAL_ADMIN + "/realms/master/clients/other");
+ setAuthHeader(request);
+ request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
+
+ ClientRepresentation rep = new ClientRepresentation();
+ rep.setEnabled(true);
+ rep.setClientId("other");
+ rep.setDescription("I'm new");
+
+ request.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
+
+ try (var response = client.execute(request)) {
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ assertEquals("I'm new", client.getDescription());
+ }
+
+ rep.setDescription("I'm updated");
+ request.setEntity(new StringEntity(mapper.writeValueAsString(rep)));
+
+ try (var response = client.execute(request)) {
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ ClientRepresentation client = mapper.createParser(response.getEntity().getContent()).readValueAs(ClientRepresentation.class);
+ assertEquals("I'm updated", client.getDescription());
+ }
+ }
+
@Test
public void clientRepresentationValidation() throws Exception {
HttpPost request = new HttpPost(HOSTNAME_LOCAL_ADMIN + "/realms/master/clients");
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 58341c9b487..571af77b0c3 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -194,6 +194,16 @@ public class ClientResource {
@Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS)
@Operation( summary = "Get representation of the client")
public ClientRepresentation getClient() {
+ viewClientModel();
+
+ ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session);
+
+ representation.setAccess(auth.clients().getAccess(client));
+
+ return representation;
+ }
+
+ public ClientModel viewClientModel() {
try {
session.clientPolicy().triggerOnEvent(new AdminClientViewContext(client, auth.adminAuth()));
} catch (ClientPolicyException cpe) {
@@ -201,12 +211,7 @@ public class ClientResource {
}
auth.clients().requireView(client);
-
- ClientRepresentation representation = ModelToRepresentation.toRepresentation(client, session);
-
- representation.setAccess(auth.clients().getAccess(client));
-
- return representation;
+ return client;
}
/**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index 00042f1dfe3..9108ab20770 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -119,6 +119,20 @@ public class ClientsResource {
@QueryParam("q") String searchQuery,
@Parameter(description = "the first result") @QueryParam("first") Integer firstResult,
@Parameter(description = "the max results to return") @QueryParam("max") Integer maxResults) {
+ return ModelToRepresentation.filterValidRepresentations(
+ getClientModels(clientId, viewableOnly, search, searchQuery, firstResult, maxResults), c -> {
+ ClientRepresentation representation = ModelToRepresentation.toRepresentation(c, session);
+ representation.setAccess(auth.clients().getAccess(c));
+ return representation;
+ });
+ }
+
+ public Stream getClientModels(String clientId,
+ boolean viewableOnly,
+ boolean search,
+ String searchQuery,
+ Integer firstResult,
+ Integer maxResults) {
auth.clients().requireList();
boolean canView = AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(realm) || auth.clients().canView();
@@ -152,21 +166,7 @@ public class ClientsResource {
throw new ErrorResponseException(Errors.INVALID_REQUEST, e.getMessage(), Response.Status.BAD_REQUEST);
}
- Stream s = ModelToRepresentation.filterValidRepresentations(clientModels,
- c -> {
- ClientRepresentation representation = null;
- if (canView || auth.clients().canView(c)) {
- representation = ModelToRepresentation.toRepresentation(c, session);
- representation.setAccess(auth.clients().getAccess(c));
- } else if (!viewableOnly && auth.clients().canView(c)) {
- representation = new ClientRepresentation();
- representation.setId(c.getId());
- representation.setClientId(c.getClientId());
- representation.setDescription(c.getDescription());
- }
-
- return representation;
- });
+ Stream s = clientModels.filter(m -> canView || auth.clients().canView(m));
if (!canView) {
s = paginatedStream(s, firstResult, maxResults);
@@ -196,6 +196,11 @@ public class ClientsResource {
@APIResponse(responseCode = "409", description = "Conflict")
})
public Response createClient(final ClientRepresentation rep) {
+ var created = createClientModel(rep);
+ return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(created.getId()).build()).build();
+ }
+
+ public ClientModel createClientModel(final ClientRepresentation rep) {
auth.clients().requireManage();
try {
@@ -232,7 +237,7 @@ public class ClientsResource {
session.getContext().setClient(clientModel);
session.clientPolicy().triggerOnEvent(new AdminClientRegisteredContext(clientModel, auth.adminAuth()));
- return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
+ return clientModel;
} catch (ModelDuplicateException e) {
throw ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
} catch (ClientPolicyException cpe) {