Skip to content

Commit

Permalink
feature: publish in well-known and document private_key_jwt parameter…
Browse files Browse the repository at this point in the history
…s in rest API (#2509)

* documentation: start to change and add parameters for private_key_jwt

* Use of client_secret is optional
* ..

* update

* update

* update

* correct spelling - thanks adrian

PKCE https://datatracker.ietf.org/doc/html/rfc7636

* again missed the versions
  • Loading branch information
strehle authored Oct 18, 2023
1 parent 973dfdc commit 41165e0
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class OpenIdConfiguration {
private String tokenUrl;

@JsonProperty("token_endpoint_auth_methods_supported")
private String[] tokenAMR = new String[]{"client_secret_basic", "client_secret_post"};
private String[] tokenAMR = new String[]{"client_secret_basic", "client_secret_post", "private_key_jwt"};

@JsonProperty("token_endpoint_auth_signing_alg_values_supported")
private String[] tokenEndpointAuthSigningValues = new String[]{"RS256", "HS256"};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void defaultClaims() {
assertEquals("issuer", defaultConfig.getIssuer());
assertEquals("/uaa/oauth/authorize", defaultConfig.getAuthUrl());
assertEquals("/uaa/oauth/token", defaultConfig.getTokenUrl());
assertArrayEquals(new String[]{"client_secret_basic", "client_secret_post"}, defaultConfig.getTokenAMR());
assertArrayEquals(new String[]{"client_secret_basic", "client_secret_post", "private_key_jwt"}, defaultConfig.getTokenAMR());
assertArrayEquals(new String[]{"RS256", "HS256"}, defaultConfig.getTokenEndpointAuthSigningValues());
assertEquals("/uaa/userinfo", defaultConfig.getUserInfoUrl());
assertEquals("/uaa/token_keys", defaultConfig.getJwksUri());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"token_endpoint": "<context path>/oauth/token",
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
"client_secret_post",
"private_key_jwt"
],
"token_endpoint_auth_signing_alg_values_supported": [
"RS256",
Expand Down
9 changes: 6 additions & 3 deletions uaa/slateCustomizations/source/index.html.md.erb
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,12 @@ _Response Headers_

# Token

The `/oauth/token` endpoint requires client authentication to be accessed. Client Authentication can be passed as
as part of the request authorization header, using basic authentication, or as part of the request parameters, using the `client_id` and `client_secret` parameter
names.
The `/oauth/token` endpoint requires client authentication to be accessed, except you allow the public usage. For more details about public usage see
allowpublic flag in client details configuration. For confidential client usages, the client authentication can be passed as part of the request
authorization header, using basic authentication, or as part of the request parameters, using the combination of `client_id` and `client_secret` or
`client_assertion_type` and `client_assertion` parameter names. The client authentication methods are explained in the
[OpenID Core specification](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication). UAA supports currently none, client_secret_basic,
client_secret_post and private_key_jwt.

## Authorization Code Grant

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ void document_jwt_bearer_grant() throws Exception {
Snippet requestParameters = requestParameters(
parameterWithName("assertion").type(STRING).required().description("JWT token identifying representing the user to be authenticated"),
parameterWithName("client_id").type(STRING).required().description("Required, client with "),
parameterWithName("client_secret").type(STRING).required().description("Required unless a basic authorization header is used"),
parameterWithName("client_secret").type(STRING).optional(null).description("The [secret passphrase configured](#change-secret) for the OAuth client. Optional if it is passed as part of the Basic Authorization header or if client_assertion is sent as part of private_key_jwt authentication."),
parameterWithName("client_assertion").type(STRING).optional(null).description("<small><mark>UAA 76.23.0</mark></small> Client authentication using method [private_key_jwt](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication). Optional as replacement of methods client_secret_basic or client_secret_post using secrets. The client needs to have a valid [JWT confiuration](#change-client-jwt) for trust to JWT in client_assertion."),
parameterWithName("client_assertion_type").type(STRING).optional(null).description("<small><mark>UAA 76.23.0</mark></small> [RFC 7523](https://tools.ietf.org/html/rfc7523) describes the type. Must be set to `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` if `client_assertion` parameter is present."),
parameterWithName("grant_type").type(STRING).required().description("Must be set to `"+ GRANT_TYPE_JWT_BEARER+"`"),
parameterWithName("scope").type(STRING).optional(null).description("Optional parameter to limit the number of scopes in the `scope` claim of the access token"),
parameterWithName("response_type").type(STRING).optional(null).description("May be set to `token` or `token id_token` or `id_token`"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@

package org.cloudfoundry.identity.uaa.mock.token;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.type.TypeReference;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.mock.util.JwtTokenUtils;
import org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils;
import org.cloudfoundry.identity.uaa.oauth.KeyInfoService;
import org.cloudfoundry.identity.uaa.oauth.token.CompositeToken;
import org.cloudfoundry.identity.uaa.oauth.token.TokenConstants;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
import org.cloudfoundry.identity.uaa.provider.JdbcIdentityProviderProvisioning;
Expand Down Expand Up @@ -238,6 +236,8 @@ ResultActions perform_grant_in_zone(IdentityZone theZone, String assertion) thro
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.param("client_id", client.getClientId())
.param("client_secret", client.getClientSecret())
.param("client_assertion", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjU4ZDU1YzUwMGNjNmI1ODM3OTYxN2UwNmU3ZGVjNmNhIn0.eyJzdWIiOiJsb2dpbiIsImlzcyI6ImxvZ2luIiwianRpIjoiNThkNTVjNTAwY2M2YjU4Mzc5NjE3ZTA2ZTdhZmZlZSIsImV4cCI6MTIzNDU2NzgsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91YWEvb2F1dGgvdG9rZW4ifQ.jwWw0OKZecd4ZjtwQ_ievqBVrh2SieqMF6vY74Oo5H6v-Ibcmumq96NLNtoUEwaAEQQOHb8MWcC8Gwi9dVQdCrtpomC86b_LKkihRBSKuqpw0udL9RMH5kgtC04ctsN0yZNifUWMP85VHn97Ual5eZ2miaBFob3H5jUe98CcBj1TSRehr64qBFYuwt9vD19q6U-ONhRt0RXBPB7ayHAOMYtb1LFIzGAiKvqWEy9f-TBPXSsETjKkAtSuM-WVWi4EhACMtSvI6iJN15f7qlverRSkGIdh1j2vPXpKKBJoRhoLw6YqbgcUC9vAr17wfa_POxaRHvh9JPty0ZXLA4XPtA")
.param("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
.param(GRANT_TYPE, GRANT_TYPE_JWT_BEARER)
.param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.TokenFormat.OPAQUE.getStringValue())
.param("response_type", "token id_token")
Expand All @@ -260,6 +260,8 @@ private String performJWTBearerGrantForJWT(IdentityZone theZone, String assertio
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.param("client_id", client.getClientId())
.param("client_secret", client.getClientSecret())
.param("client_assertion", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjU4ZDU1YzUwMGNjNmI1ODM3OTYxN2UwNmU3ZGVjNmNhIn0.eyJzdWIiOiJsb2dpbiIsImlzcyI6ImxvZ2luIiwianRpIjoiNThkNTVjNTAwY2M2YjU4Mzc5NjE3ZTA2ZTdhZmZlZSIsImV4cCI6MTIzNDU2NzgsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91YWEvb2F1dGgvdG9rZW4ifQ.jwWw0OKZecd4ZjtwQ_ievqBVrh2SieqMF6vY74Oo5H6v-Ibcmumq96NLNtoUEwaAEQQOHb8MWcC8Gwi9dVQdCrtpomC86b_LKkihRBSKuqpw0udL9RMH5kgtC04ctsN0yZNifUWMP85VHn97Ual5eZ2miaBFob3H5jUe98CcBj1TSRehr64qBFYuwt9vD19q6U-ONhRt0RXBPB7ayHAOMYtb1LFIzGAiKvqWEy9f-TBPXSsETjKkAtSuM-WVWi4EhACMtSvI6iJN15f7qlverRSkGIdh1j2vPXpKKBJoRhoLw6YqbgcUC9vAr17wfa_POxaRHvh9JPty0ZXLA4XPtA")
.param("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
.param(GRANT_TYPE, GRANT_TYPE_JWT_BEARER)
.param(TokenConstants.REQUEST_TOKEN_FORMAT, TokenConstants.TokenFormat.JWT.getStringValue())
.param("response_type", "token id_token")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void testWellKnownEndpoint() throws Exception {
assertEquals("http://" + host + ":8080/uaa/oauth/token", openIdConfiguration.getIssuer());
assertEquals("http://" + host + "/oauth/authorize", openIdConfiguration.getAuthUrl());
assertEquals("http://" + host + "/oauth/token", openIdConfiguration.getTokenUrl());
assertArrayEquals(new String[]{"client_secret_basic", "client_secret_post"}, openIdConfiguration.getTokenAMR());
assertArrayEquals(new String[]{"client_secret_basic", "client_secret_post", "private_key_jwt"}, openIdConfiguration.getTokenAMR());
assertArrayEquals(new String[]{"RS256", "HS256"}, openIdConfiguration.getTokenEndpointAuthSigningValues());
assertEquals("http://" + host + "/userinfo", openIdConfiguration.getUserInfoUrl());
assertArrayEquals(new String[]{"openid", "profile", "email", "phone", ROLES, USER_ATTRIBUTES}, openIdConfiguration.getScopes());
Expand Down

0 comments on commit 41165e0

Please sign in to comment.