From ce028c91cf1d2728bbb8e922550a6fb69aa5b7e6 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Thu, 2 Jun 2022 15:57:51 +0200 Subject: [PATCH] POC of how we could develop version 2 of the admin REST API --- services/pom.xml | 20 ++ .../services/resources/admin/AdminRoot.java | 5 + .../admin/ClientExampleResource.java | 48 ++++ services/src/main/resources/clients.yaml | 271 ++++++++++++++++++ 4 files changed, 344 insertions(+) create mode 100644 services/src/main/java/org/keycloak/services/resources/admin/ClientExampleResource.java create mode 100644 services/src/main/resources/clients.yaml diff --git a/services/pom.xml b/services/pom.xml index bf4e4fbd4011..89cc73a15cde 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -188,6 +188,26 @@ + + org.openapitools + openapi-generator-maven-plugin + + + + generate + + + ${project.basedir}/src/main/resources/clients.yaml + jaxrs-spec + interfaceOnly=true,useSwaggerAnnotations=false + + src/gen/java/main + org.keycloak.services.resources.admin + + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java index dcb88bc0866f..262d0d85a7db 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java @@ -149,6 +149,11 @@ public AdminConsole getAdminConsole(final @PathParam("realm") String name) { return service; } + @Path("v2/clients") + public ClientExampleResource getNewClientResource() { + return new ClientExampleResource(); + } + protected AdminAuth authenticateRealmAdminRequest(HttpHeaders headers) { String tokenString = AppAuthManager.extractAuthorizationHeaderToken(headers); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientExampleResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientExampleResource.java new file mode 100644 index 000000000000..21a6176a2f7a --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientExampleResource.java @@ -0,0 +1,48 @@ +package org.keycloak.services.resources.admin; + +import java.util.ArrayList; +import java.util.List; + +import org.openapitools.model.Client; +import org.openapitools.model.PartialClient; + +/** + * The interface is generated and we "only" need to implement them. + * PartialClient is to have type save responses instead of passing in `briefRepresentation` and only partially filling the entity + */ +public class ClientExampleResource implements ClientsApi { + @Override + public void createClient(Client client) { + + } + + @Override + public void deleteClient(String clientId) { + + } + + @Override + public Client getClient(String clientId) { + return null; + } + + @Override + public List getClients() { + List partialClients = new ArrayList<>(2); + final PartialClient client = new PartialClient(); + client.id("71e7f5d7-a093-4ddc-8847-3f45be0a662b"); + client.setClientId("account"); + partialClients.add(client); + final PartialClient client2 = new PartialClient(); + client2.id("4389e5be-22b7-44d9-9c9c-ee4bc6da0159"); + client2.setClientId("security-admin-console"); + partialClients.add(client2); + + return partialClients; + } + + @Override + public void updateClient(String clientId, Client client) { + + } +} diff --git a/services/src/main/resources/clients.yaml b/services/src/main/resources/clients.yaml new file mode 100644 index 000000000000..6159f0054e32 --- /dev/null +++ b/services/src/main/resources/clients.yaml @@ -0,0 +1,271 @@ +openapi: 3.0.0 +info: + title: Admin Rest API v2 + version: '1.0' + description: 'Example of how we could create a contract fist based rest api' +servers: + - + url: '{scheme}://localhost:8180/{basePath}' + variables: + scheme: + enum: + - https + - http + default: http + basePath: + default: /admin/realms/ +paths: + /clients: + summary: Path used to manage the list of clients. + description: >- + The REST endpoint/path used to list and create zero or more `Client` entities. This path contains + a `GET` and `POST` operation to perform the list and create tasks, respectively. + get: + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PartialClient' + description: Successful response - returns an array of `PartialClient` entities. + operationId: getClients + summary: List All Clients + description: Gets a list of all `PartialClient` entities. + post: + requestBody: + description: A new `Client` to be created. + content: + application/json: + schema: + $ref: '#/components/schemas/Client' + required: true + responses: + '201': + description: Successful response. + operationId: createClient + summary: Create a Client + description: Creates a new instance of a `Client`. + '/clients/{clientId}': + summary: Path used to manage a single Client. + description: >- + The REST endpoint/path used to get, update, and delete single instances of an `Client`. This path + contains `GET`, `PUT`, and `DELETE` operations used to perform the get, update, and delete tasks, + respectively. + get: + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Client' + description: Successful response - returns a single `Client`. + operationId: getClient + summary: Get a Client + description: Gets the details of a single instance of a `Client`. + put: + requestBody: + description: Updated `Client` information. + content: + application/json: + schema: + $ref: '#/components/schemas/Client' + required: true + responses: + '202': + description: Successful response. + operationId: updateClient + summary: Update a Client + description: Updates an existing `Client`. + delete: + responses: + '204': + description: Successful response. + operationId: deleteClient + summary: Delete a Client + description: Deletes an existing `Client`. + parameters: + - + name: clientId + description: A unique identifier for a `Client`. + schema: + type: string + in: path + required: true +components: + schemas: + ErrorModel: + type: object + properties: + code: + type: string + Client: + title: Root Type for Client + description: '' + required: + - id + - clientId + - protocol + - access + type: object + properties: + id: + type: string + readOnly: true + clientId: + type: string + rootUrl: + type: string + adminUrl: + type: string + surrogateAuthRequired: + type: boolean + enabled: + type: boolean + alwaysDisplayInConsole: + type: boolean + clientAuthenticatorType: + type: string + redirectUris: + type: array + items: + type: string + webOrigins: + type: array + items: + type: string + notBefore: + format: int32 + type: integer + bearerOnly: + type: boolean + consentRequired: + type: boolean + standardFlowEnabled: + type: boolean + implicitFlowEnabled: + type: boolean + directAccessGrantsEnabled: + type: boolean + serviceAccountsEnabled: + type: boolean + publicClient: + type: boolean + frontchannelLogout: + type: boolean + protocol: + type: string + attributes: + type: object + properties: + backchannel.logout.session.required: + type: string + backchannel.logout.revoke.offline.tokens: + type: string + authenticationFlowBindingOverrides: + type: object + fullScopeAllowed: + type: boolean + nodeReRegistrationTimeout: + format: int32 + type: integer + defaultClientScopes: + type: array + items: + type: string + optionalClientScopes: + type: array + items: + type: string + access: + properties: + view: + type: boolean + configure: + type: boolean + manage: + type: boolean + example: + id: bfae6a3b-ff81-48ee-a545-99d300b0c09d + clientId: security-admin-console-v2 + rootUrl: 'http://localhost:8080/' + adminUrl: 'http://localhost:8080/' + surrogateAuthRequired: false + enabled: true + alwaysDisplayInConsole: false + clientAuthenticatorType: client-secret + redirectUris: + - 'http://localhost:8080/*' + webOrigins: + - 'http://localhost:8080' + notBefore: 0 + bearerOnly: false + consentRequired: false + standardFlowEnabled: true + implicitFlowEnabled: false + directAccessGrantsEnabled: true + serviceAccountsEnabled: false + publicClient: true + frontchannelLogout: false + protocol: openid-connect + attributes: + backchannel.logout.session.required: 'true' + backchannel.logout.revoke.offline.tokens: 'false' + authenticationFlowBindingOverrides: {} + fullScopeAllowed: true + nodeReRegistrationTimeout: -1 + defaultClientScopes: + - web-origins + - roles + - profile + - email + optionalClientScopes: + - address + - phone + - offline_access + - microprofile-jwt + access: + view: true + configure: true + manage: true + PartialClient: + description: '' + required: + - id + - clientId + type: object + properties: + id: + description: '' + type: string + readOnly: true + clientId: + description: '' + type: string + protocol: + description: '' + type: string + description: + description: '' + type: string + baseUrl: + description: '' + type: string + example: + id: ebf0406a-5c70-4a04-8a29-25267c9d50bc + clientId: admin-cli + protocol: openid-connect + description: '' + baseUrl: /realms/master/account/ + securitySchemes: + JWT: + type: apiKey + description: | + You can create a JSON Web Token (JWT) during auth. + Usage format: `Bearer ` + name: Authorization + in: header +tags: + - + name: master \ No newline at end of file