From e51ca79954096c0897a730ff48367051f6fa8387 Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Fri, 14 May 2021 22:04:28 -0400 Subject: [PATCH] Document Jwt Client Authentication support Closes gh-9578 --- .../security/config/spring-security-5.5.rnc | 4 +- .../security/config/spring-security-5.5.xsd | 5 +- .../_includes/servlet/appendix/namespace.adoc | 2 +- .../servlet/oauth2/oauth2-client.adoc | 123 +++++++++++++++++- 4 files changed, 129 insertions(+), 5 deletions(-) diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-5.5.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-5.5.rnc index 281f3278af..a227e804d9 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-5.5.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-5.5.rnc @@ -526,8 +526,8 @@ client-registration.attlist &= ## The client secret. attribute client-secret {xsd:token}? client-registration.attlist &= - ## The method used to authenticate the client with the provider. The supported values are client_secret_basic, client_secret_post and none (public clients). - attribute client-authentication-method {"client_secret_basic" | "basic" | "client_secret_post" | "post" | "none"}? + ## The method used to authenticate the client with the provider. The supported values are client_secret_basic, client_secret_post, private_key_jwt, client_secret_jwt and none (public clients). + attribute client-authentication-method {"client_secret_basic" | "basic" | "client_secret_post" | "post" | "private_key_jwt" | "client_secret_jwt" | "none"}? client-registration.attlist &= ## The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The supported values are authorization_code, client_credentials, password, implicit, as well as, extension grant type urn:ietf:params:oauth:grant-type:jwt-bearer. attribute authorization-grant-type {"authorization_code" | "client_credentials" | "password" | "implicit" | "urn:ietf:params:oauth:grant-type:jwt-bearer"}? diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-5.5.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-5.5.xsd index c638082e11..8078b0af40 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-5.5.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-5.5.xsd @@ -1657,7 +1657,8 @@ The method used to authenticate the client with the provider. The supported values are - client_secret_basic, client_secret_post and none (public clients). + client_secret_basic, client_secret_post, private_key_jwt, client_secret_jwt and none + (public clients). @@ -1666,6 +1667,8 @@ + + diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc index c9e840663a..f65ec3349d 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc @@ -1061,7 +1061,7 @@ The client secret. [[nsa-client-registration-client-authentication-method]] * **client-authentication-method** The method used to authenticate the Client with the Provider. -The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. +The supported values are *client_secret_basic*, *client_secret_post*, *private_key_jwt*, *client_secret_jwt* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. [[nsa-client-registration-authorization-grant-type]] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc index c6243960fe..93615be30b 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-client.adoc @@ -12,6 +12,9 @@ At a high-level, the core features available are: * https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] * https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[JWT Bearer] +.Client Authentication support +* https://datatracker.ietf.org/doc/html/rfc7523#section-2.2[JWT Bearer] + .HTTP Client support * <> (for requesting protected resources) @@ -155,6 +158,8 @@ The following sections will go into more detail on the core components used by O ** <> ** <> ** <> +* <> +** <> * <> ** <> * <> @@ -207,7 +212,7 @@ public final class ClientRegistration { <2> `clientId`: The client identifier. <3> `clientSecret`: The client secret. <4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider. -The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. +The supported values are *client_secret_basic*, *client_secret_post*, *private_key_jwt*, *client_secret_jwt* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)]. <5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types. The supported values are `authorization_code`, `client_credentials`, `password`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`. <6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent @@ -1851,6 +1856,122 @@ class OAuth2ResourceServerController { ==== +[[oauth2Client-client-auth-support]] +=== Client Authentication Support + + +[[oauth2Client-jwt-bearer-auth]] +==== JWT Bearer + +[NOTE] +Please refer to JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants for further details on https://datatracker.ietf.org/doc/html/rfc7523#section-2.2[JWT Bearer] Client Authentication. + +The default implementation for JWT Bearer Client Authentication is `NimbusJwtClientAuthenticationParametersConverter`, +which is a `Converter` that customizes the Token Request parameters by adding +a signed JSON Web Token (JWS) in the `client_assertion` parameter. + +The `java.security.PrivateKey` or `javax.crypto.SecretKey` used for signing the JWS +is supplied by the `com.nimbusds.jose.jwk.JWK` resolver associated with `NimbusJwtClientAuthenticationParametersConverter`. + + +===== Authenticate using `private_key_jwt` + +Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: + +[source,yaml] +---- +spring: + security: + oauth2: + client: + registration: + okta: + client-id: okta-client-id + client-authentication-method: private_key_jwt + authorization-grant-type: authorization_code + ... +---- + +The following example shows how to configure `DefaultAuthorizationCodeTokenResponseClient`: + +==== +.Java +[source,java,role="primary"] +---- +Function jwkResolver = (clientRegistration) -> { + if (clientRegistration.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.PRIVATE_KEY_JWT)) { + // Assuming RSA key type + RSAPublicKey publicKey = ... + RSAPrivateKey privateKey = ... + return new RSAKey.Builder(publicKey) + .privateKey(privateKey) + .keyID(UUID.randomUUID().toString()) + .build(); + } + return null; +}; + +OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter = + new OAuth2AuthorizationCodeGrantRequestEntityConverter(); +requestEntityConverter.addParametersConverter( + new NimbusJwtClientAuthenticationParametersConverter<>(jwkResolver)); + +DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = + new DefaultAuthorizationCodeTokenResponseClient(); +tokenResponseClient.setRequestEntityConverter(requestEntityConverter); +---- +==== + + +===== Authenticate using `client_secret_jwt` + +Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration: + +[source,yaml] +---- +spring: + security: + oauth2: + client: + registration: + okta: + client-id: okta-client-id + client-secret: okta-client-secret + client-authentication-method: client_secret_jwt + authorization-grant-type: client_credentials + ... +---- + +The following example shows how to configure `DefaultClientCredentialsTokenResponseClient`: + +==== +.Java +[source,java,role="primary"] +---- +Function jwkResolver = (clientRegistration) -> { + if (clientRegistration.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) { + SecretKeySpec secretKey = new SecretKeySpec( + clientRegistration.getClientSecret().getBytes(StandardCharsets.UTF_8), + "HmacSHA256"); + return new OctetSequenceKey.Builder(secretKey) + .keyID(UUID.randomUUID().toString()) + .build(); + } + return null; +}; + +OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter = + new OAuth2ClientCredentialsGrantRequestEntityConverter(); +requestEntityConverter.addParametersConverter( + new NimbusJwtClientAuthenticationParametersConverter<>(jwkResolver)); + +DefaultClientCredentialsTokenResponseClient tokenResponseClient = + new DefaultClientCredentialsTokenResponseClient(); +tokenResponseClient.setRequestEntityConverter(requestEntityConverter); +---- +==== + + [[oauth2Client-additional-features]] === Additional Features