From 4c1bf3995b4475308e312195dce946779c1a4432 Mon Sep 17 00:00:00 2001 From: strehle Date: Mon, 18 Sep 2023 16:01:38 +0200 Subject: [PATCH] doc: Add documentation --- .../source/index.html.md.erb | 23 ++++++++++++ .../mock/clients/ClientAdminEndpointDocs.java | 35 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/uaa/slateCustomizations/source/index.html.md.erb b/uaa/slateCustomizations/source/index.html.md.erb index 26a06bc4f23..3476e859b30 100644 --- a/uaa/slateCustomizations/source/index.html.md.erb +++ b/uaa/slateCustomizations/source/index.html.md.erb @@ -2472,6 +2472,29 @@ _Request Fields_ <%= render('ClientAdminEndpointDocs/changeClientSecret/request-fields.md') %> +## Change Client JWT +This configuration can be done if client authentication is performed with method private_key_jwt +instead of secret based client authentication. See details for client authentiction with [OAuth2](https://oauth.net/2/client-authentication/) and/or +[OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication). + +The client can send a client_assertion for authentication. The signature of the assertion is validated either with the jwks_uri or the internal jwks public keys. + +<%= render('ClientAdminEndpointDocs/changeClientJwt/curl-request.md') %> +<%= render('ClientAdminEndpointDocs/changeClientJwt/http-request.md') %> +<%= render('ClientAdminEndpointDocs/changeClientJwt/http-response.md') %> + +_Path Parameters_ + +<%= render('ClientAdminEndpointDocs/changeClientJwt/path-parameters.md') %> + +_Request Headers_ + +<%= render('ClientAdminEndpointDocs/changeClientJwt/request-headers.md') %> + +_Request Fields_ + +<%= render('ClientAdminEndpointDocs/changeClientJwt/request-fields.md') %> + ## List <%= render('ClientAdminEndpointDocs/listClients/curl-request.md') %> diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointDocs.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointDocs.java index 7a0e31be0e5..8377c9f82eb 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointDocs.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointDocs.java @@ -77,6 +77,13 @@ class ClientAdminEndpointDocs extends AdminClientCreator { fieldWithPath("changeMode").optional(UPDATE).type(STRING).description("If change mode is set to `"+ADD+"`, the new `secret` will be added to the existing one and if the change mode is set to `"+DELETE+"`, the old secret will be deleted to support secret rotation. Currently only two client secrets are supported at any given time.") }; + private static final FieldDescriptor[] clientJwtChangeFields = new FieldDescriptor[]{ + fieldWithPath("client_id").required().description(clientIdDescription), + fieldWithPath("kid").optional(UPDATE).type(STRING).description("If change mode is set to `"+DELETE+"`, the `id of the key` that will be deleted. The kid parameter is only possible if jwks configuration is used."), + fieldWithPath("jwks").constrained("Optional if jwks_uri is used. Required otherwise.").type(STRING).description("A valid JSON string according JSON Web Key Set standard, see [RFC 7517](https://www.rfc-editor.org/rfc/rfc7517), e.g. content of /token_keys endpoint from UAA"), + fieldWithPath("jwks_uri").constrained("Optional if jwks is used. Required otherwise.").type(STRING).description("A valid URI to token keys endpoint. Must be compliant to jwks_uri from [OpenID Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html).") + }; + @BeforeEach void setup() throws Exception { clientAdminToken = testClient.getClientCredentialsOAuthAccessToken( @@ -255,6 +262,34 @@ void changeClientSecret() throws Exception { ); } + @Test + void changeClientJwt() throws Exception { + ClientDetails createdClientDetails = JsonUtils.readValue(createClientHelper().andReturn().getResponse().getContentAsString(), BaseClientDetails.class); + + ResultActions resultActions = mockMvc.perform(put("/oauth/clients/{client_id}/clientjwt", createdClientDetails.getClientId()) + .header("Authorization", "Bearer " + clientAdminToken) + .contentType(APPLICATION_JSON) + .accept(APPLICATION_JSON) + .content(writeValueAsString(map( + entry("client_id", createdClientDetails.getClientId()), + entry("jwks_uri", "http://localhost:8080/uaa/token_keys") + )))) + .andExpect(status().isOk()); + + resultActions.andDo(document("{ClassName}/{methodName}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("client_id").required().description(clientIdDescription) + ), + requestHeaders( + authorizationHeader, + IDENTITY_ZONE_ID_HEADER, + IDENTITY_ZONE_SUBDOMAIN_HEADER + ), + requestFields(clientJwtChangeFields) + ) + ); + } + @Test void deleteClient() throws Exception { ClientDetails createdClientDetails = JsonUtils.readValue(createClientHelper().andReturn().getResponse().getContentAsString(), BaseClientDetails.class);