mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-07 23:50:03 -05:00
fix: creating a cleaner module for use by java clients (#47874)
* fix: minimizing the dependencies for the rest module closes: #48114 Signed-off-by: Steve Hawkins <shawkins@redhat.com> * renaming the modules also remove jsonnode logic from the oas filter and the databind dependency Signed-off-by: Steve Hawkins <shawkins@redhat.com> * addressing review comments Signed-off-by: Steve Hawkins <shawkins@redhat.com> --------- Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2023 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.common.constants;
|
||||
|
||||
/**
|
||||
* Class of constants relating to the OpenAPI annotations in Keycloak and the Keycloak Admin REST API
|
||||
*/
|
||||
public class KeycloakOpenAPI {
|
||||
|
||||
protected KeycloakOpenAPI() { }
|
||||
public static class Profiles {
|
||||
|
||||
public static final String ADMIN = "x-smallrye-profile-admin";
|
||||
|
||||
private Profiles() { }
|
||||
}
|
||||
|
||||
public static class Admin {
|
||||
|
||||
private Admin() { }
|
||||
|
||||
public static class Tags {
|
||||
public static final String ATTACK_DETECTION = "Attack Detection";
|
||||
public static final String AUTHENTICATION_MANAGEMENT = "Authentication Management";
|
||||
public static final String CLIENTS = "Clients";
|
||||
public static final String CLIENTS_V2 = "Clients (v2)";
|
||||
public static final String CLIENT_ATTRIBUTE_CERTIFICATE = "Client Attribute Certificate";
|
||||
public static final String CLIENT_INITIAL_ACCESS = "Client Initial Access";
|
||||
public static final String CLIENT_REGISTRATION_POLICY = "Client Registration Policy";
|
||||
public static final String CLIENT_ROLE_MAPPINGS = "Client Role Mappings";
|
||||
public static final String CLIENT_SCOPES = "Client Scopes";
|
||||
public static final String COMPONENT = "Component";
|
||||
public static final String GROUPS = "Groups";
|
||||
public static final String IDENTITY_PROVIDERS = "Identity Providers";
|
||||
public static final String KEY = "Key";
|
||||
public static final String PROTOCOL_MAPPERS = "Protocol Mappers";
|
||||
public static final String REALMS_ADMIN = "Realms Admin";
|
||||
public static final String ROLES = "Roles";
|
||||
public static final String ROLES_BY_ID = "Roles (by ID)";
|
||||
public static final String ROLE_MAPPER = "Role Mapper";
|
||||
public static final String ROOT = "Root";
|
||||
public static final String SCOPE_MAPPINGS = "Scope Mappings";
|
||||
public static final String USERS = "Users";
|
||||
public static final String ORGANIZATIONS = "Organizations";
|
||||
public static final String WORKFLOWS = "Workflows";
|
||||
private Tags() { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@
|
||||
</dependencySourceIncludes>
|
||||
<dependencySourceExcludes>
|
||||
<dependencySourceExclude>org.keycloak:keycloak-operator</dependencySourceExclude>
|
||||
<dependencySourceExclude>org.keycloak:keycloak-admin-v2-rest</dependencySourceExclude>
|
||||
<dependencySourceExclude>org.keycloak:keycloak-admin-v2-api</dependencySourceExclude>
|
||||
</dependencySourceExcludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
<artifactId>keycloak-admin-v2-api</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
|
||||
@@ -54,8 +54,7 @@
|
||||
<!-- required during compilation by the exec-maven-plugin as we need the OpenAPI document stored in the resources -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<artifactId>keycloak-admin-v2-services</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
<!-- Enforce build order: openapi.yaml must be generated before JS build -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
<artifactId>keycloak-admin-v2-services</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
||||
@@ -123,10 +123,6 @@
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
|
||||
@@ -1121,7 +1121,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
<artifactId>keycloak-admin-v2-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -424,7 +424,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
<artifactId>keycloak-admin-v2-services</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
|
||||
+1
-6
@@ -19,8 +19,6 @@ package org.keycloak.quarkus.runtime.configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
|
||||
import picocli.CommandLine;
|
||||
|
||||
/**
|
||||
@@ -38,9 +36,6 @@ public class KcUnmatchedArgumentException extends CommandLine.UnmatchedArgumentE
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions() {
|
||||
// filter out disabled mappers
|
||||
return super.getSuggestions().stream()
|
||||
.filter(f -> PropertyMappers.getKcKeyFromCliKey(f).filter(PropertyMappers::isDisabledMapper).isEmpty())
|
||||
.toList();
|
||||
return super.getSuggestions();
|
||||
}
|
||||
}
|
||||
|
||||
+18
-41
@@ -10,7 +10,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-admin-v2-api</artifactId>
|
||||
<name>Keycloak Admin API v2 Interfaces</name>
|
||||
<name>Keycloak Admin API v2 APIs</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
@@ -22,52 +22,29 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi-private</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<artifactId>keycloak-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.enterprise</groupId>
|
||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.microprofile.openapi</groupId>
|
||||
<artifactId>microprofile-openapi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgument>
|
||||
-AgeneratedTranslationFilesPath=${project.build.directory}/generated-translation-files
|
||||
</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.services;
|
||||
package org.keycloak.admin.api;
|
||||
|
||||
public class PatchTypeNames {
|
||||
public static final String JSON_MERGE = "application/merge-patch+json";
|
||||
+1
-1
@@ -12,8 +12,8 @@ import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
import org.keycloak.services.PatchTypeNames;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
||||
+1
-1
@@ -12,8 +12,8 @@ import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
import org.keycloak.common.constants.KeycloakOpenAPI;
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
import org.keycloak.services.resources.KeycloakOpenAPI;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
||||
+4
-3
@@ -6,7 +6,6 @@ import java.util.Set;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
import org.keycloak.representations.admin.v2.validation.ClientUuidProvider;
|
||||
import org.keycloak.representations.admin.v2.validation.PatchClient;
|
||||
import org.keycloak.representations.admin.v2.validation.ProtocolUnmodified;
|
||||
import org.keycloak.representations.admin.v2.validation.PutClient;
|
||||
@@ -30,7 +29,7 @@ import org.hibernate.validator.constraints.URL;
|
||||
@JsonSubTypes.Type(value = OIDCClientRepresentation.class, name = OIDCClientRepresentation.PROTOCOL),
|
||||
@JsonSubTypes.Type(value = SAMLClientRepresentation.class, name = SAMLClientRepresentation.PROTOCOL)
|
||||
})
|
||||
@UuidUnmodified(uuidProvider = ClientUuidProvider.class, groups = {PutClient.class, PatchClient.class})
|
||||
@UuidUnmodified(groups = {PutClient.class, PatchClient.class})
|
||||
@ProtocolUnmodified(groups = {PutClient.class, PatchClient.class})
|
||||
@ValidRedirectUris
|
||||
public abstract class BaseClientRepresentation extends BaseRepresentation implements RepresentationWithUuid {
|
||||
@@ -141,7 +140,9 @@ public abstract class BaseClientRepresentation extends BaseRepresentation implem
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof BaseClientRepresentation that)) return false;
|
||||
if (!(o instanceof BaseClientRepresentation that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(uuid, that.uuid) && Objects.equals(clientId, that.clientId) && Objects.equals(displayName, that.displayName) && Objects.equals(description, that.description) && Objects.equals(enabled, that.enabled) && Objects.equals(appUrl, that.appUrl) && Objects.equals(redirectUris, that.redirectUris) && Objects.equals(roles, that.roles);
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -15,11 +15,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
* Validation constraint that requires the {@link OIDCClientRepresentation.Auth#getSecret()} is not blank
|
||||
* when {@link OIDCClientRepresentation.Auth#getMethod()} is the (JWT) client secret.
|
||||
*
|
||||
* @see ClientSecretNotBlankValidator#isClientSecret(String)
|
||||
*/
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
@Constraint(validatedBy = ClientSecretNotBlankValidator.class)
|
||||
@Constraint(validatedBy = {})
|
||||
public @interface ClientSecretNotBlank {
|
||||
|
||||
String message() default "Client secret must not be blank";
|
||||
|
||||
+1
-1
@@ -11,8 +11,8 @@ import jakarta.validation.Payload;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = {ProtocolUnmodifiedValidator.class})
|
||||
@Documented
|
||||
@Constraint(validatedBy = {})
|
||||
public @interface ProtocolUnmodified {
|
||||
String message() default "protocol cannot be changed for an existing client";
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
+1
-2
@@ -16,11 +16,10 @@ import jakarta.validation.Payload;
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = {UuidUnmodifiedValidator.class})
|
||||
@Documented
|
||||
@Constraint(validatedBy = {})
|
||||
public @interface UuidUnmodified {
|
||||
String message() default "UUID is server-managed and must not be user-specified";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
Class<? extends UuidProvider> uuidProvider();
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import jakarta.validation.Payload;
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = {ValidRedirectUrisValidator.class})
|
||||
@Constraint(validatedBy = {})
|
||||
@Documented
|
||||
public @interface ValidRedirectUris {
|
||||
String message() default "Invalid redirect URI";
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>rest</module>
|
||||
<module>api</module>
|
||||
<module>services</module>
|
||||
<module>tests</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -9,8 +9,8 @@
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-admin-v2-rest</artifactId>
|
||||
<name>Keycloak Admin API v2 REST Layer</name>
|
||||
<artifactId>keycloak-admin-v2-services</artifactId>
|
||||
<name>Keycloak Admin API v2 Services</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
@@ -24,25 +24,42 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-v2-api</artifactId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi</artifactId>
|
||||
<scope>provided</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server-spi-private</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.enterprise</groupId>
|
||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<scope>provided</scope>
|
||||
<artifactId>keycloak-admin-v2-api</artifactId>
|
||||
</dependency>
|
||||
<!-- used by OAS Filter during OpenAPI spec generation -->
|
||||
<dependency>
|
||||
@@ -55,6 +72,15 @@
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgument>
|
||||
-AgeneratedTranslationFilesPath=${project.build.directory}/generated-translation-files
|
||||
</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.smallrye</groupId>
|
||||
<artifactId>smallrye-open-api-maven-plugin</artifactId>
|
||||
-59
@@ -16,7 +16,6 @@ import org.keycloak.OAuth2Constants;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.eclipse.microprofile.openapi.OASFactory;
|
||||
import org.eclipse.microprofile.openapi.OASFilter;
|
||||
import org.eclipse.microprofile.openapi.models.OpenAPI;
|
||||
@@ -28,14 +27,10 @@ import org.eclipse.microprofile.openapi.models.security.SecurityScheme;
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.AnnotationValue;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.FieldInfo;
|
||||
import org.jboss.jandex.IndexView;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
import org.jboss.jandex.Type;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.keycloak.services.PatchTypeNames.JSON_MERGE;
|
||||
import static org.keycloak.utils.StringUtil.isNullOrEmpty;
|
||||
|
||||
public class OASModelFilter implements OASFilter {
|
||||
@@ -44,7 +39,6 @@ public class OASModelFilter implements OASFilter {
|
||||
private final Map<String, ClassInfo> simpleNameToClassInfoMap = new HashMap<>();
|
||||
|
||||
public static final String REF_PREFIX = "#/components/schemas/";
|
||||
private static final DotName JSON_NODE = DotName.createSimple(JsonNode.class);
|
||||
|
||||
public OASModelFilter(IndexView indexView) {
|
||||
log.debug("Index size: " + indexView.getKnownClasses().size());
|
||||
@@ -70,8 +64,6 @@ public class OASModelFilter implements OASFilter {
|
||||
|
||||
removeSchemaAndRefs(openAPI, "BaseRepresentation");
|
||||
|
||||
fixJsonMergePatchRequestObject(openAPI);
|
||||
|
||||
Map<String, Set<Schema>> discriminatorPropertiesToBeAdded = new HashMap<>();
|
||||
|
||||
// Follows https://swagger.io/docs/specification/v3_0/data-models/inheritance-and-polymorphism/
|
||||
@@ -129,57 +121,6 @@ public class OASModelFilter implements OASFilter {
|
||||
setter.accept(filtered.isEmpty() ? null : filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently, if endpoint consumes 'application/merge-patch+json' and the request object is 'JsonNode',
|
||||
* SmallRye OpenAPI generates array type schema for the endpoint.
|
||||
* See <a href="https://github.com/smallrye/smallrye-open-api/issues/2494">issue 2494</a> for more context.
|
||||
* What we need is either no schema, or an object with additional properties, so that the generated client
|
||||
* doesn't have empty body. This method removes schema.
|
||||
*/
|
||||
private void fixJsonMergePatchRequestObject(OpenAPI openAPI) {
|
||||
if (openAPI.getPaths() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
openAPI.getPaths().getPathItems().forEach((path, pathItem) -> {
|
||||
if (pathItem.getPATCH() != null && pathItem.getPATCH().getRequestBody() != null) {
|
||||
var patchOp = pathItem.getPATCH();
|
||||
var requestBody = patchOp.getRequestBody();
|
||||
|
||||
if (requestBody.getContent() != null && requestBody.getContent().getMediaType(JSON_MERGE) != null
|
||||
&& hasJsonNodeParameter(patchOp.getOperationId())) {
|
||||
var mediaTypeObject = requestBody.getContent().getMediaType(JSON_MERGE);
|
||||
mediaTypeObject.setSchema(null);
|
||||
log.debugf("Removed request body schema from PATCH path '%s' operation '%s' using content type '%s'", path, patchOp.getOperationId(), JSON_MERGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects REST interface method which name matches the operation name.
|
||||
*/
|
||||
private boolean hasJsonNodeParameter(String operationId) {
|
||||
if (operationId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ClassInfo classInfo : simpleNameToClassInfoMap.values()) {
|
||||
for (MethodInfo method : classInfo.methods()) {
|
||||
if (method.name().equals(operationId)) {
|
||||
for (Type paramType : method.parameterTypes()) {
|
||||
if (JSON_NODE.equals(paramType.name())) {
|
||||
log.debugf("Method '%s#%s' has parameter with type '%s'", classInfo.name(), method.name());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds discriminator and oneOf references to parent schemas that have Jackson @JsonTypeInfo
|
||||
* and @JsonSubTypes annotations. This enables OpenAPI generators to create proper class
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.representations.admin.v2.validation;
|
||||
package org.keycloak.representations.admin.v2.validators;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
@@ -6,6 +6,7 @@ import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.client.JWTClientSecretAuthenticator;
|
||||
import org.keycloak.representations.admin.v2.OIDCClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.validation.ClientSecretNotBlank;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
/**
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.representations.admin.v2.validation;
|
||||
package org.keycloak.representations.admin.v2.validators;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.representations.admin.v2.validation;
|
||||
package org.keycloak.representations.admin.v2.validators;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -7,6 +7,7 @@ import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.validation.ProtocolUnmodified;
|
||||
import org.keycloak.validation.jakarta.ValidationContext;
|
||||
|
||||
public class ProtocolUnmodifiedValidator implements ConstraintValidator<ProtocolUnmodified, BaseClientRepresentation> {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.representations.admin.v2.validation;
|
||||
package org.keycloak.representations.admin.v2.validators;
|
||||
|
||||
import org.keycloak.representations.admin.v2.RepresentationWithUuid;
|
||||
import org.keycloak.validation.jakarta.ValidationContext;
|
||||
+14
-13
@@ -1,9 +1,11 @@
|
||||
package org.keycloak.representations.admin.v2.validation;
|
||||
package org.keycloak.representations.admin.v2.validators;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.RepresentationWithUuid;
|
||||
import org.keycloak.representations.admin.v2.validation.UuidUnmodified;
|
||||
import org.keycloak.validation.jakarta.ValidationContext;
|
||||
|
||||
/**
|
||||
@@ -19,19 +21,16 @@ import org.keycloak.validation.jakarta.ValidationContext;
|
||||
*/
|
||||
public class UuidUnmodifiedValidator implements ConstraintValidator<UuidUnmodified, RepresentationWithUuid> {
|
||||
|
||||
private UuidProvider uuidProvider;
|
||||
|
||||
@Override
|
||||
public void initialize(UuidUnmodified constraintAnnotation) {
|
||||
try {
|
||||
uuidProvider = constraintAnnotation.uuidProvider().getDeclaredConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to instantiate UUID provider: " + constraintAnnotation.uuidProvider().getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(RepresentationWithUuid representation, ConstraintValidatorContext context) {
|
||||
Class<?> type = representation.getClass();
|
||||
UuidProvider uuidProvider = null;
|
||||
if (BaseClientRepresentation.class.isAssignableFrom(type)) {
|
||||
uuidProvider = new ClientUuidProvider();
|
||||
} else {
|
||||
throw new AssertionError("No UuidProvider defined for " + type);
|
||||
}
|
||||
|
||||
String providedUuid = representation.getUuid();
|
||||
if (providedUuid == null || providedUuid.isEmpty()) { // no UUID provided, so nothing to validate
|
||||
return true;
|
||||
@@ -41,7 +40,9 @@ public class UuidUnmodifiedValidator implements ConstraintValidator<UuidUnmodifi
|
||||
String persistedUuid = uuidProvider.getPersistedUuid(validationContext, representation);
|
||||
|
||||
if (persistedUuid != null) { // resource exists
|
||||
if (persistedUuid.equals(providedUuid)) return true;
|
||||
if (persistedUuid.equals(providedUuid)) {
|
||||
return true;
|
||||
}
|
||||
} else if (!uuidProvider.uuidExists(validationContext, providedUuid)) { // additional check for PUT create to check the resource was just not renamed
|
||||
return true;
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.representations.admin.v2.validation;
|
||||
package org.keycloak.representations.admin.v2.validators;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -7,6 +7,7 @@ import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.validation.ValidRedirectUris;
|
||||
|
||||
/**
|
||||
* Validates redirect URIs according to Keycloak's redirect URI rules.
|
||||
+4
-6
@@ -1,14 +1,13 @@
|
||||
package org.keycloak.admin.api;
|
||||
package org.keycloak.rest.admin.api;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
|
||||
import org.keycloak.admin.api.AdminApi;
|
||||
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 org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.rest.admin.api.client.DefaultClientsApi;
|
||||
import org.keycloak.services.resources.admin.AdminRoot;
|
||||
import org.keycloak.services.resources.admin.RealmAdminResource;
|
||||
import org.keycloak.services.resources.admin.RealmsAdminResource;
|
||||
@@ -32,9 +31,8 @@ public class DefaultAdminApi implements AdminApi {
|
||||
this.realmAdminResource = new RealmsAdminResource(session, authInfo, new TokenManager()).getRealmAdmin(realmName);
|
||||
}
|
||||
|
||||
@Path("clients/{version:v\\d+}")
|
||||
@Override
|
||||
public ClientsApi clients(@PathParam("version") String version) {
|
||||
public ClientsApi clients(String version) {
|
||||
return switch (version) {
|
||||
case "v2" -> new DefaultClientsApi(session, realm, permissions, realmAdminResource);
|
||||
default -> throw new NotFoundException();
|
||||
+3
-1
@@ -1,10 +1,12 @@
|
||||
package org.keycloak.admin.api;
|
||||
package org.keycloak.rest.admin.api;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import org.keycloak.admin.api.AdminApi;
|
||||
import org.keycloak.admin.api.AdminRootV2;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.services.resources.admin.AdminCorsPreflightService;
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.admin.api.client;
|
||||
package org.keycloak.rest.admin.api.client;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -12,6 +12,7 @@ import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
import org.keycloak.admin.api.client.ClientApi;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.admin.api.client;
|
||||
package org.keycloak.rest.admin.api.client;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -10,6 +10,8 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
import org.keycloak.admin.api.client.ClientApi;
|
||||
import org.keycloak.admin.api.client.ClientsApi;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
+2
@@ -4,6 +4,8 @@ import java.util.Optional;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
|
||||
public enum PatchType {
|
||||
JSON_MERGE(PatchTypeNames.JSON_MERGE);
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import static org.keycloak.representations.admin.v2.validation.ClientSecretNotBlankValidator.isClientSecret;
|
||||
import static org.keycloak.representations.admin.v2.validators.ClientSecretNotBlankValidator.isClientSecret;
|
||||
|
||||
/**
|
||||
* Legacy implementation of ClientService for Admin API v2 that uses Admin API v1 under hood.
|
||||
+1
-1
@@ -41,7 +41,7 @@ import org.keycloak.validation.jakarta.HibernateValidatorProvider;
|
||||
import org.keycloak.validation.jakarta.JakartaValidatorProvider;
|
||||
import org.keycloak.validation.jakarta.ValidationContext;
|
||||
|
||||
import static org.keycloak.representations.admin.v2.validation.ClientSecretNotBlankValidator.isClientSecret;
|
||||
import static org.keycloak.representations.admin.v2.validators.ClientSecretNotBlankValidator.isClientSecret;
|
||||
import static org.keycloak.utils.StringUtil.isBlank;
|
||||
|
||||
/**
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
org.keycloak.representations.admin.v2.validators.ClientSecretNotBlankValidator
|
||||
org.keycloak.representations.admin.v2.validators.ProtocolUnmodifiedValidator
|
||||
org.keycloak.representations.admin.v2.validators.UuidUnmodifiedValidator
|
||||
org.keycloak.representations.admin.v2.validators.ValidRedirectUrisValidator
|
||||
+1
-1
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
@@ -29,7 +30,6 @@ import org.keycloak.representations.admin.v2.OIDCClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.SAMLClientRepresentation;
|
||||
import org.keycloak.representations.idm.AdminEventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.services.PatchTypeNames;
|
||||
import org.keycloak.testframework.annotations.InjectHttpClient;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
||||
+1
-1
@@ -10,6 +10,7 @@ import java.util.Set;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.authorization.fgap.AdminPermissionsSchema;
|
||||
import org.keycloak.common.Profile;
|
||||
@@ -21,7 +22,6 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.services.PatchTypeNames;
|
||||
import org.keycloak.services.client.ClientServiceHelper;
|
||||
import org.keycloak.testframework.admin.AdminClientFactory;
|
||||
import org.keycloak.testframework.annotations.InjectAdminClientFactory;
|
||||
|
||||
+1
-1
@@ -27,6 +27,7 @@ import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.wrapper.Clients;
|
||||
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
||||
@@ -36,7 +37,6 @@ import org.keycloak.common.Profile;
|
||||
import org.keycloak.representations.admin.v2.BaseClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.OIDCClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.SAMLClientRepresentation;
|
||||
import org.keycloak.services.PatchTypeNames;
|
||||
import org.keycloak.services.error.ViolationExceptionResponse;
|
||||
import org.keycloak.testframework.annotations.InjectAdminClient;
|
||||
import org.keycloak.testframework.annotations.InjectClient;
|
||||
|
||||
+1
-1
@@ -26,6 +26,7 @@ import java.util.function.Consumer;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||
@@ -40,7 +41,6 @@ import org.keycloak.representations.idm.ClientPolicyExecutorRepresentation;
|
||||
import org.keycloak.representations.idm.ClientPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfileRepresentation;
|
||||
import org.keycloak.representations.idm.ClientProfilesRepresentation;
|
||||
import org.keycloak.services.PatchTypeNames;
|
||||
import org.keycloak.services.client.ClientServiceHelper;
|
||||
import org.keycloak.services.clientpolicy.ClientPolicyEvent;
|
||||
import org.keycloak.services.clientpolicy.condition.AnyClientConditionFactory;
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package org.keycloak.tests.admin.client.v2.validation;
|
||||
|
||||
import org.keycloak.admin.api.PatchTypeNames;
|
||||
import org.keycloak.representations.admin.v2.OIDCClientRepresentation;
|
||||
import org.keycloak.representations.admin.v2.SAMLClientRepresentation;
|
||||
import org.keycloak.services.PatchTypeNames;
|
||||
import org.keycloak.services.error.ViolationExceptionResponse;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package org.keycloak.tests.admin.client.v2.validation;
|
||||
|
||||
import org.keycloak.representations.admin.v2.validation.ValidRedirectUrisValidator;
|
||||
import org.keycloak.representations.admin.v2.validators.ValidRedirectUrisValidator;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
|
||||
@@ -17,49 +17,8 @@
|
||||
|
||||
package org.keycloak.services.resources;
|
||||
|
||||
/**
|
||||
* Class of constants relating to the OpenAPI annotations in Keycloak and the Keycloak Admin REST API
|
||||
*/
|
||||
public class KeycloakOpenAPI {
|
||||
public class KeycloakOpenAPI extends org.keycloak.common.constants.KeycloakOpenAPI {
|
||||
|
||||
private KeycloakOpenAPI() { }
|
||||
public static class Profiles {
|
||||
|
||||
public static final String ADMIN = "x-smallrye-profile-admin";
|
||||
|
||||
private Profiles() { }
|
||||
}
|
||||
|
||||
public static class Admin {
|
||||
|
||||
private Admin() { }
|
||||
|
||||
public static class Tags {
|
||||
public static final String ATTACK_DETECTION = "Attack Detection";
|
||||
public static final String AUTHENTICATION_MANAGEMENT = "Authentication Management";
|
||||
public static final String CLIENTS = "Clients";
|
||||
public static final String CLIENTS_V2 = "Clients (v2)";
|
||||
public static final String CLIENT_ATTRIBUTE_CERTIFICATE = "Client Attribute Certificate";
|
||||
public static final String CLIENT_INITIAL_ACCESS = "Client Initial Access";
|
||||
public static final String CLIENT_REGISTRATION_POLICY = "Client Registration Policy";
|
||||
public static final String CLIENT_ROLE_MAPPINGS = "Client Role Mappings";
|
||||
public static final String CLIENT_SCOPES = "Client Scopes";
|
||||
public static final String COMPONENT = "Component";
|
||||
public static final String GROUPS = "Groups";
|
||||
public static final String IDENTITY_PROVIDERS = "Identity Providers";
|
||||
public static final String KEY = "Key";
|
||||
public static final String PROTOCOL_MAPPERS = "Protocol Mappers";
|
||||
public static final String REALMS_ADMIN = "Realms Admin";
|
||||
public static final String ROLES = "Roles";
|
||||
public static final String ROLES_BY_ID = "Roles (by ID)";
|
||||
public static final String ROLE_MAPPER = "Role Mapper";
|
||||
public static final String ROOT = "Root";
|
||||
public static final String SCOPE_MAPPINGS = "Scope Mappings";
|
||||
public static final String USERS = "Users";
|
||||
public static final String ORGANIZATIONS = "Organizations";
|
||||
public static final String WORKFLOWS = "Workflows";
|
||||
private Tags() { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user