mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Add OpenAPI and OpenAPI-UI to management interface (#41853)
Signed-off-by: Robin Meese <39960884+robson90@users.noreply.github.com>
This commit is contained in:
parent
eca1333027
commit
4f4ed315d3
@ -0,0 +1,17 @@
|
||||
package org.keycloak.config;
|
||||
|
||||
public class OpenApiOptions {
|
||||
|
||||
public static final Option<Boolean> OPENAPI_ENABLED = new OptionBuilder<>("openapi-enabled", Boolean.class)
|
||||
.category(OptionCategory.OPENAPI)
|
||||
.description("If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is available at '/openapi'.")
|
||||
.buildTime(true)
|
||||
.defaultValue(Boolean.FALSE)
|
||||
.build();
|
||||
public static final Option<Boolean> OPENAPI_UI_ENABLED = new OptionBuilder<>("openapi-ui-enabled", Boolean.class)
|
||||
.category(OptionCategory.OPENAPI)
|
||||
.description("If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI UI is available at '/openapi/ui'.")
|
||||
.buildTime(true)
|
||||
.defaultValue(Boolean.FALSE)
|
||||
.build();
|
||||
}
|
||||
@ -23,6 +23,7 @@ public enum OptionCategory {
|
||||
SECURITY("Security", 120, ConfigSupportLevel.SUPPORTED),
|
||||
EXPORT("Export", 130, ConfigSupportLevel.SUPPORTED),
|
||||
IMPORT("Import", 140, ConfigSupportLevel.SUPPORTED),
|
||||
OPENAPI("OpenAPI configuration", 150, ConfigSupportLevel.PREVIEW),
|
||||
BOOTSTRAP_ADMIN("Bootstrap Admin", 998, ConfigSupportLevel.SUPPORTED),
|
||||
GENERAL("General", 999, ConfigSupportLevel.SUPPORTED);
|
||||
|
||||
|
||||
@ -240,6 +240,14 @@
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-smallrye-health-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-smallrye-openapi-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-swagger-ui-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-micrometer-deployment</artifactId>
|
||||
|
||||
@ -138,6 +138,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId>
|
||||
<version>${org.mapstruct.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Hibernate validator -->
|
||||
@ -151,7 +152,14 @@
|
||||
<groupId>io.smallrye.config</groupId>
|
||||
<artifactId>smallrye-config-source-keystore</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-smallrye-openapi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-swagger-ui</artifactId>
|
||||
</dependency>
|
||||
<!-- CLI -->
|
||||
<dependency>
|
||||
<groupId>info.picocli</groupId>
|
||||
@ -408,6 +416,7 @@
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
|
||||
@ -21,6 +21,7 @@ import org.keycloak.config.HttpOptions;
|
||||
import org.keycloak.config.ManagementOptions;
|
||||
import org.keycloak.config.ManagementOptions.Scheme;
|
||||
import org.keycloak.config.MetricsOptions;
|
||||
import org.keycloak.config.OpenApiOptions;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
|
||||
import static org.keycloak.config.ManagementOptions.LEGACY_OBSERVABILITY_INTERFACE;
|
||||
@ -126,9 +127,9 @@ public class ManagementPropertyMappers {
|
||||
if (isTrue(LEGACY_OBSERVABILITY_INTERFACE)) {
|
||||
return false;
|
||||
}
|
||||
var isManagementOccupied = isTrue(MetricsOptions.METRICS_ENABLED)
|
||||
|| (isTrue(HealthOptions.HEALTH_ENABLED) && isTrue(ManagementOptions.HTTP_MANAGEMENT_HEALTH_ENABLED));
|
||||
return isManagementOccupied;
|
||||
return (isTrue(HealthOptions.HEALTH_ENABLED) && isTrue(ManagementOptions.HTTP_MANAGEMENT_HEALTH_ENABLED))
|
||||
|| isTrue(MetricsOptions.METRICS_ENABLED)
|
||||
|| isTrue(OpenApiOptions.OPENAPI_ENABLED);
|
||||
}
|
||||
|
||||
private static String managementEnabledTransformer() {
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package org.keycloak.quarkus.runtime.configuration.mappers;
|
||||
|
||||
import org.keycloak.config.OpenApiOptions;
|
||||
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.isTrue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
|
||||
|
||||
public final class OpenApiPropertyMappers {
|
||||
|
||||
private OpenApiPropertyMappers() {
|
||||
}
|
||||
|
||||
public static PropertyMapper<?>[] getOpenApiPropertyMappers() {
|
||||
return new PropertyMapper[]{
|
||||
fromOption(OpenApiOptions.OPENAPI_ENABLED)
|
||||
.to("quarkus.smallrye-openapi.enable")
|
||||
.build(),
|
||||
fromOption(OpenApiOptions.OPENAPI_UI_ENABLED)
|
||||
.isEnabled(OpenApiPropertyMappers::isUiEnabled, "OpenAPI Endpoint is enabled")
|
||||
.to("quarkus.swagger-ui.enable")
|
||||
.build(),
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isUiEnabled() {
|
||||
return isTrue(OpenApiOptions.OPENAPI_ENABLED);
|
||||
}
|
||||
}
|
||||
@ -62,6 +62,7 @@ public final class PropertyMappers {
|
||||
MAPPERS.addAll(ConfigKeystorePropertyMappers.getConfigKeystorePropertyMappers());
|
||||
MAPPERS.addAll(ManagementPropertyMappers.getManagementPropertyMappers());
|
||||
MAPPERS.addAll(MetricsPropertyMappers.getMetricsPropertyMappers());
|
||||
MAPPERS.addAll(OpenApiPropertyMappers.getOpenApiPropertyMappers());
|
||||
MAPPERS.addAll(EventPropertyMappers.getMetricsPropertyMappers());
|
||||
MAPPERS.addAll(ProxyPropertyMappers.getProxyPropertyMappers());
|
||||
MAPPERS.addAll(VaultPropertyMappers.getVaultPropertyMappers());
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
package org.keycloak.quarkus.runtime.oas;
|
||||
|
||||
import io.quarkus.smallrye.openapi.OpenApiFilter;
|
||||
import org.eclipse.microprofile.openapi.OASFactory;
|
||||
import org.eclipse.microprofile.openapi.OASFilter;
|
||||
import org.eclipse.microprofile.openapi.models.OpenAPI;
|
||||
import org.eclipse.microprofile.openapi.models.Operation;
|
||||
import org.eclipse.microprofile.openapi.models.PathItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@OpenApiFilter(OpenApiFilter.RunStage.BUILD)
|
||||
public class OASModelFilter implements OASFilter {
|
||||
|
||||
@Override
|
||||
public void filterOpenAPI(OpenAPI openAPI) {
|
||||
// Filter Paths that have the '/admin/api/v2' prefix
|
||||
Map<String, PathItem> newPaths = openAPI.getPaths().getPathItems().entrySet().stream()
|
||||
.filter(entry -> entry.getKey().startsWith("/admin/api/v2"))
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
entry -> sortOperationsByMethod(entry.getValue())
|
||||
));
|
||||
|
||||
// Replace ALL Paths with filtered Paths
|
||||
var paths = OASFactory.createPaths();
|
||||
newPaths.forEach(paths::addPathItem);
|
||||
openAPI.setPaths(paths);
|
||||
|
||||
// Compute tags that are actually used by remaining operations
|
||||
Set<String> usedTags = newPaths.values().stream()
|
||||
.flatMap(pi -> operationsOf(pi).stream())
|
||||
.flatMap(op -> Optional.ofNullable(op.getTags()).orElseGet(List::of).stream())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// Drop top-level tags not used anywhere
|
||||
if (openAPI.getTags() != null) {
|
||||
var filteredTags = openAPI.getTags().stream()
|
||||
.filter(t -> t.getName() != null && usedTags.contains(t.getName()))
|
||||
.collect(Collectors.toList());
|
||||
openAPI.setTags(filteredTags.isEmpty() ? null : filteredTags);
|
||||
}
|
||||
}
|
||||
|
||||
private PathItem sortOperationsByMethod(PathItem pathItem) {
|
||||
PathItem sortedPathItem = OASFactory.createPathItem();
|
||||
|
||||
// Add operations order: GET -> POST -> PUT -> PATCH -> DELETE -> HEAD -> OPTIONS -> TRACE
|
||||
if (pathItem.getGET() != null) {
|
||||
sortedPathItem.setGET(pathItem.getGET());
|
||||
}
|
||||
if (pathItem.getPOST() != null) {
|
||||
sortedPathItem.setPOST(pathItem.getPOST());
|
||||
}
|
||||
if (pathItem.getPUT() != null) {
|
||||
sortedPathItem.setPUT(pathItem.getPUT());
|
||||
}
|
||||
if (pathItem.getPATCH() != null) {
|
||||
sortedPathItem.setPATCH(pathItem.getPATCH());
|
||||
}
|
||||
if (pathItem.getDELETE() != null) {
|
||||
sortedPathItem.setDELETE(pathItem.getDELETE());
|
||||
}
|
||||
if (pathItem.getHEAD() != null) {
|
||||
sortedPathItem.setHEAD(pathItem.getHEAD());
|
||||
}
|
||||
if (pathItem.getOPTIONS() != null) {
|
||||
sortedPathItem.setOPTIONS(pathItem.getOPTIONS());
|
||||
}
|
||||
if (pathItem.getTRACE() != null) {
|
||||
sortedPathItem.setTRACE(pathItem.getTRACE());
|
||||
}
|
||||
|
||||
sortedPathItem.setSummary(pathItem.getSummary());
|
||||
sortedPathItem.setDescription(pathItem.getDescription());
|
||||
sortedPathItem.setServers(pathItem.getServers());
|
||||
sortedPathItem.setParameters(pathItem.getParameters());
|
||||
|
||||
return sortedPathItem;
|
||||
}
|
||||
|
||||
private List<Operation> operationsOf(PathItem pi) {
|
||||
List<Operation> ops = new ArrayList<>(8);
|
||||
if (pi.getGET() != null) ops.add(pi.getGET());
|
||||
if (pi.getPOST() != null) ops.add(pi.getPOST());
|
||||
if (pi.getPUT() != null) ops.add(pi.getPUT());
|
||||
if (pi.getPATCH() != null) ops.add(pi.getPATCH());
|
||||
if (pi.getDELETE() != null) ops.add(pi.getDELETE());
|
||||
if (pi.getHEAD() != null) ops.add(pi.getHEAD());
|
||||
if (pi.getOPTIONS() != null) ops.add(pi.getOPTIONS());
|
||||
if (pi.getTRACE() != null) ops.add(pi.getTRACE());
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
@ -87,3 +87,16 @@ quarkus.http.limits.max-header-size=65535
|
||||
#logging defaults
|
||||
kc.log-console-output=default
|
||||
kc.log-file=${kc.home.dir:default}${file.separator}data${file.separator}log${file.separator}keycloak.log
|
||||
|
||||
#OpenAPI defaults
|
||||
quarkus.smallrye-openapi.path=/openapi
|
||||
quarkus.smallrye-openapi.store-schema-directory=${openapi.schema.target}
|
||||
quarkus.swagger-ui.path=${quarkus.smallrye-openapi.path}/ui
|
||||
quarkus.swagger-ui.always-include=true
|
||||
quarkus.swagger-ui.filter=true
|
||||
mp.openapi.filter=org.keycloak.quarkus.runtime.oas.OASModelFilter
|
||||
mp.openapi.extensions.smallrye.remove-unused-schemas.enable=true
|
||||
|
||||
# Disable Error messages from smallrye.openapi
|
||||
# related issue: https://github.com/keycloak/keycloak/issues/41871
|
||||
quarkus.log.category."io.smallrye.openapi.runtime.scanner.dataobject".level=off
|
||||
@ -40,6 +40,10 @@
|
||||
<artifactId>importmap</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-smallrye-openapi</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
@ -70,6 +74,7 @@
|
||||
<kc.home.dir>${kc.home.dir}</kc.home.dir>
|
||||
<kc.db>dev-file</kc.db>
|
||||
<java.util.concurrent.ForkJoinPool.common.threadFactory>io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory</java.util.concurrent.ForkJoinPool.common.threadFactory>
|
||||
<openapi.schema.target>${project.build.directory}</openapi.schema.target>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
||||
79
quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/OpenApiDistTest.java
vendored
Normal file
79
quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/OpenApiDistTest.java
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2021 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.it.cli.dist;
|
||||
|
||||
import io.quarkus.test.junit.main.Launch;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.it.junit5.extension.CLIResult;
|
||||
import org.keycloak.it.junit5.extension.DistributionTest;
|
||||
import org.keycloak.it.junit5.extension.DryRun;
|
||||
import org.keycloak.it.utils.KeycloakDistribution;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.restassured.RestAssured.when;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@DistributionTest(keepAlive = true,
|
||||
requestPort = 9000,
|
||||
containerExposedPorts = {8080, 9000})
|
||||
@Tag(DistributionTest.SLOW)
|
||||
public class OpenApiDistTest {
|
||||
|
||||
private static final String OPENAPI_ENDPOINT = "/openapi";
|
||||
private static final String OPENAPI_UI_ENDPOINT = "/openapi/ui";
|
||||
|
||||
@Test
|
||||
@Launch({"start-dev"})
|
||||
void testOpenApiEndpointNotEnabled(KeycloakDistribution distribution) {
|
||||
assertThrows(IOException.class, () -> when().get(OPENAPI_ENDPOINT), "Connection refused must be thrown");
|
||||
assertThrows(IOException.class, () -> when().get(OPENAPI_UI_ENDPOINT), "Connection refused must be thrown");
|
||||
|
||||
distribution.setRequestPort(8080);
|
||||
|
||||
when().get(OPENAPI_ENDPOINT).then()
|
||||
.statusCode(404);
|
||||
when().get(OPENAPI_UI_ENDPOINT).then()
|
||||
.statusCode(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({"start-dev", "--openapi-enabled=true"})
|
||||
void testOpenApiEndpointEnabled(KeycloakDistribution distribution) {
|
||||
when().get(OPENAPI_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({"start-dev", "--openapi-ui-enabled=true", "--openapi-enabled=true"})
|
||||
void testOpenApiUiEndpointEnabled(KeycloakDistribution distribution) {
|
||||
when().get(OPENAPI_UI_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200);
|
||||
}
|
||||
|
||||
@DryRun
|
||||
@Test
|
||||
@Launch({ "start", "--openapi-ui-enabled=true"})
|
||||
void testOpenApiUiFailsWhenOpenApiIsNotEnabled(CLIResult cliResult) {
|
||||
cliResult.assertError("Disabled option: '--openapi-ui-enabled'. Available only when OpenAPI Endpoint is enabled");
|
||||
}
|
||||
}
|
||||
@ -457,6 +457,16 @@ Export:
|
||||
'different_files'. Increasing this number leads to exponentially increasing
|
||||
export times. Default: 50.
|
||||
|
||||
OpenAPI configuration (Preview):
|
||||
|
||||
--openapi-enabled <true|false>
|
||||
Preview: If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is
|
||||
available at '/openapi'. Default: false.
|
||||
--openapi-ui-enabled <true|false>
|
||||
Preview: If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI
|
||||
UI is available at '/openapi/ui'. Default: false. Available only when
|
||||
OpenAPI Endpoint is enabled.
|
||||
|
||||
Bootstrap Admin:
|
||||
|
||||
--bootstrap-admin-client-id <client id>
|
||||
|
||||
@ -451,6 +451,16 @@ Import:
|
||||
Set if existing data should be overwritten. If set to false, data will be
|
||||
ignored. Default: true.
|
||||
|
||||
OpenAPI configuration (Preview):
|
||||
|
||||
--openapi-enabled <true|false>
|
||||
Preview: If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is
|
||||
available at '/openapi'. Default: false.
|
||||
--openapi-ui-enabled <true|false>
|
||||
Preview: If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI
|
||||
UI is available at '/openapi/ui'. Default: false. Available only when
|
||||
OpenAPI Endpoint is enabled.
|
||||
|
||||
Bootstrap Admin:
|
||||
|
||||
--bootstrap-admin-client-id <client id>
|
||||
|
||||
@ -689,6 +689,16 @@ Security:
|
||||
feature is enabled. Possible values are: non-strict, strict. Default:
|
||||
disabled.
|
||||
|
||||
OpenAPI configuration (Preview):
|
||||
|
||||
--openapi-enabled <true|false>
|
||||
Preview: If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is
|
||||
available at '/openapi'. Default: false.
|
||||
--openapi-ui-enabled <true|false>
|
||||
Preview: If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI
|
||||
UI is available at '/openapi/ui'. Default: false. Available only when
|
||||
OpenAPI Endpoint is enabled.
|
||||
|
||||
Bootstrap Admin:
|
||||
|
||||
--bootstrap-admin-client-id <client id>
|
||||
|
||||
@ -690,6 +690,16 @@ Security:
|
||||
feature is enabled. Possible values are: non-strict, strict. Default:
|
||||
disabled.
|
||||
|
||||
OpenAPI configuration (Preview):
|
||||
|
||||
--openapi-enabled <true|false>
|
||||
Preview: If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is
|
||||
available at '/openapi'. Default: false.
|
||||
--openapi-ui-enabled <true|false>
|
||||
Preview: If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI
|
||||
UI is available at '/openapi/ui'. Default: false. Available only when
|
||||
OpenAPI Endpoint is enabled.
|
||||
|
||||
Bootstrap Admin:
|
||||
|
||||
--bootstrap-admin-client-id <client id>
|
||||
|
||||
@ -689,6 +689,16 @@ Security:
|
||||
feature is enabled. Possible values are: non-strict, strict. Default:
|
||||
disabled.
|
||||
|
||||
OpenAPI configuration (Preview):
|
||||
|
||||
--openapi-enabled <true|false>
|
||||
Preview: If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is
|
||||
available at '/openapi'. Default: false.
|
||||
--openapi-ui-enabled <true|false>
|
||||
Preview: If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI
|
||||
UI is available at '/openapi/ui'. Default: false. Available only when
|
||||
OpenAPI Endpoint is enabled.
|
||||
|
||||
Bootstrap Admin:
|
||||
|
||||
--bootstrap-admin-client-id <client id>
|
||||
|
||||
@ -687,6 +687,16 @@ Security:
|
||||
feature is enabled. Possible values are: non-strict, strict. Default:
|
||||
disabled.
|
||||
|
||||
OpenAPI configuration (Preview):
|
||||
|
||||
--openapi-enabled <true|false>
|
||||
Preview: If the server should expose OpenAPI Endpoint. If enabled, OpenAPI is
|
||||
available at '/openapi'. Default: false.
|
||||
--openapi-ui-enabled <true|false>
|
||||
Preview: If the server should expose OpenApi-UI Endpoint. If enabled, OpenAPI
|
||||
UI is available at '/openapi/ui'. Default: false. Available only when
|
||||
OpenAPI Endpoint is enabled.
|
||||
|
||||
Bootstrap Admin:
|
||||
|
||||
--bootstrap-admin-client-id <client id>
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@ -5,6 +5,9 @@ import java.util.stream.Stream;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.groups.ConvertGroup;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
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;
|
||||
@ -17,17 +20,22 @@ import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.keycloak.representations.admin.v2.validation.CreateClient;
|
||||
import org.keycloak.services.resources.KeycloakOpenAPI;
|
||||
|
||||
@Tag(name = KeycloakOpenAPI.Admin.Tags.CLIENTS_V2)
|
||||
@Extension(name = KeycloakOpenAPI.Profiles.ADMIN, value = "")
|
||||
public interface ClientsApi extends Provider {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Get all clients", description = "Returns a list of all clients in the realm")
|
||||
Stream<ClientRepresentation> getClients();
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Create a new client", description = "Creates a new client in the realm")
|
||||
ClientRepresentation createClient(@Valid @ConvertGroup(to = CreateClient.class) ClientRepresentation client,
|
||||
@QueryParam("fieldValidation") FieldValidation fieldValidation);
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ public class KeycloakOpenAPI {
|
||||
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";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user