From 4537c109761b11d26bdd57257936556a245adb22 Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Tue, 17 Feb 2026 17:20:47 +0100 Subject: [PATCH 1/5] Support JWT GrantType --- .../reactor/uaa/clients/ReactorClientsTest.java | 2 ++ .../resources/fixtures/uaa/clients/GET_{id}_response.json | 3 ++- .../main/java/org/cloudfoundry/uaa/tokens/GrantType.java | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/clients/ReactorClientsTest.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/clients/ReactorClientsTest.java index c36ac4f4434..a9d730008a5 100644 --- a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/clients/ReactorClientsTest.java +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/clients/ReactorClientsTest.java @@ -24,6 +24,7 @@ import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static org.cloudfoundry.uaa.tokens.GrantType.AUTHORIZATION_CODE; import static org.cloudfoundry.uaa.tokens.GrantType.CLIENT_CREDENTIALS; +import static org.cloudfoundry.uaa.tokens.GrantType.JWT_BEARER; import static org.cloudfoundry.uaa.tokens.GrantType.REFRESH_TOKEN; import java.time.Duration; @@ -620,6 +621,7 @@ void get() { .allowedProviders("uaa", "ldap", "my-saml-provider") .authorities("clients.read", "clients.write") .authorizedGrantType(CLIENT_CREDENTIALS) + .authorizedGrantType(JWT_BEARER) .autoApprove("true") .clientId("4Z3t1r") .lastModified(1468364445592L) diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/clients/GET_{id}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/clients/GET_{id}_response.json index d8b2187e478..2a05df3d702 100644 --- a/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/clients/GET_{id}_response.json +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/clients/GET_{id}_response.json @@ -8,7 +8,8 @@ "none" ], "authorized_grant_types": [ - "client_credentials" + "client_credentials", + "urn:ietf:params:oauth:grant-type:jwt-bearer" ], "redirect_uri": [ "http*://ant.path.wildcard/**/passback/*", diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/tokens/GrantType.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/tokens/GrantType.java index 6dd626c52d7..0d84a4b2380 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/tokens/GrantType.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/tokens/GrantType.java @@ -39,6 +39,11 @@ public enum GrantType { */ IMPLICIT("implicit"), + /** + * The JWT bearer grant type + */ + JWT_BEARER("urn:ietf:params:oauth:grant-type:jwt-bearer"), + /** * The password grant type */ @@ -68,6 +73,8 @@ public static GrantType from(String s) { return PASSWORD; case "refresh_token": return REFRESH_TOKEN; + case "urn:ietf:params:oauth:grant-type:jwt-bearer": + return JWT_BEARER; default: throw new IllegalArgumentException(String.format("Unknown grant type: %s", s)); } From 5a993ec91a6a1f10997b2f76518a2f9871a9e950 Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Tue, 17 Feb 2026 17:21:21 +0100 Subject: [PATCH 2/5] Support default identity provider property --- .../uaa/identityzones/ReactorIdentityZonesTest.java | 2 ++ .../fixtures/uaa/identity-zones/GET_response.json | 1 + .../uaa/identityzones/_IdentityZoneConfiguration.java | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/identityzones/ReactorIdentityZonesTest.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/identityzones/ReactorIdentityZonesTest.java index 62674816d25..f0a5a60d1ff 100644 --- a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/identityzones/ReactorIdentityZonesTest.java +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/identityzones/ReactorIdentityZonesTest.java @@ -832,6 +832,8 @@ void list() { + " /passcode)") .build()) .ldapDiscoveryEnabled(false) + .defaultIdentityProvider( + "test-identity-provider") .accountChooserEnabled(false) .build()) .name("The Twiglet Zone") diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/identity-zones/GET_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/identity-zones/GET_response.json index a5980a1815b..817cb189274 100644 --- a/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/identity-zones/GET_response.json +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/identity-zones/GET_response.json @@ -97,6 +97,7 @@ "text": "One Time Code (Get on at /passcode)" } ], + "defaultIdentityProvider": "test-identity-provider", "idpDiscoveryEnabled": false, "accountChooserEnabled": false }, diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/identityzones/_IdentityZoneConfiguration.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/identityzones/_IdentityZoneConfiguration.java index 0c98a54a24c..a3cc9886423 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/identityzones/_IdentityZoneConfiguration.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/identityzones/_IdentityZoneConfiguration.java @@ -65,6 +65,13 @@ abstract class _IdentityZoneConfiguration { @Nullable abstract CorsPolicy getCorsPolicy(); + /** + * The default identity provider for this zone + */ + @JsonProperty("defaultIdentityProvider") + @Nullable + abstract String getDefaultIdentityProvider(); + /** * The issuer of this zone */ From 71055c3ab453f62909c08da6161758b0726a2fb5 Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Mon, 23 Feb 2026 16:19:06 +0100 Subject: [PATCH 3/5] Accept "access_denied: Access Denied" from UAA Some UAA seem to send a slightly different reply. This accepts and tests for both. --- .../src/test/java/org/cloudfoundry/uaa/TokensTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/uaa/TokensTest.java b/integration-test/src/test/java/org/cloudfoundry/uaa/TokensTest.java index 40b02850f02..39d956f801b 100644 --- a/integration-test/src/test/java/org/cloudfoundry/uaa/TokensTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/uaa/TokensTest.java @@ -84,7 +84,7 @@ public void checkTokenNotAuthorized() { t -> assertThat(t) .isInstanceOf(UaaException.class) - .hasMessage("access_denied: Access is denied")) + .hasMessageContainingAll("access_denied", "Access")) .verify(Duration.ofMinutes(5)); } From 1d3eae3b31436f78dc9835279bc0ee29e837977b Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Mon, 23 Feb 2026 16:27:49 +0100 Subject: [PATCH 4/5] Support defaultIdpName of newer UAA See https://github.com/cloudfoundry/uaa/blob/284dd502db2316bfbdb05c47d9a6d23e3c82ba6a/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java#L277 --- .../serverinformation/ReactorServerInformationTest.java | 1 + .../test/resources/fixtures/uaa/info/GET_response.json | 3 ++- .../uaa/serverinformation/_GetInfoResponse.java | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/serverinformation/ReactorServerInformationTest.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/serverinformation/ReactorServerInformationTest.java index a0e921ef75a..e49bb077a82 100644 --- a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/serverinformation/ReactorServerInformationTest.java +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/uaa/serverinformation/ReactorServerInformationTest.java @@ -151,6 +151,7 @@ void getInfo() { .showLoginLinks(true) .timestamp("2017-09-08T23:11:58+0000") .zoneName("uaa") + .defaultIdpName("test-idp-name") .build()) .expectComplete() .verify(Duration.ofSeconds(5)); diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/info/GET_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/info/GET_response.json index 6c6784819cf..2d681f7b5f3 100644 --- a/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/info/GET_response.json +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/uaa/info/GET_response.json @@ -30,5 +30,6 @@ "One Time Code ( Get one at http://localhost:8080/uaa/passcode )" ] }, - "timestamp": "2017-09-08T23:11:58+0000" + "timestamp": "2017-09-08T23:11:58+0000", + "defaultIdpName": "test-idp-name" } \ No newline at end of file diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/serverinformation/_GetInfoResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/serverinformation/_GetInfoResponse.java index 018661777ad..4b571ac7090 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/serverinformation/_GetInfoResponse.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/uaa/serverinformation/_GetInfoResponse.java @@ -93,4 +93,12 @@ abstract class _GetInfoResponse { @Nullable abstract String getZoneName(); + /** + * The default identity provider name + */ + @JsonProperty("defaultIdpName") + @Nullable + abstract String getDefaultIdpName(); + + } From d9afcd69168fcb879b275d2dbe87db82e094f152 Mon Sep 17 00:00:00 2001 From: Joris Baum Date: Mon, 23 Feb 2026 16:42:07 +0100 Subject: [PATCH 5/5] Support uaa setups without password reset endpoint Tests login endpoint instead, which should usually be present --- .../java/org/cloudfoundry/uaa/ServerInformationTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/uaa/ServerInformationTest.java b/integration-test/src/test/java/org/cloudfoundry/uaa/ServerInformationTest.java index f12fa616dc4..fb1298c9163 100644 --- a/integration-test/src/test/java/org/cloudfoundry/uaa/ServerInformationTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/uaa/ServerInformationTest.java @@ -95,13 +95,17 @@ public void getInfo() { this.uaaClient .serverInformation() .getInfo(GetInfoRequest.builder().build()) - .map(response -> response.getLinks().getPassword()) + .map(response -> response.getLinks().getLogin()) .as(StepVerifier::create) - .consumeNextWith(endsWithExpectation("password")) + .consumeNextWith(containsExpectation("login")) .expectComplete() .verify(Duration.ofMinutes(5)); } + private static Consumer containsExpectation(String substring) { + return actual -> assertThat(actual).contains(substring); + } + private static Consumer endsWithExpectation(String suffix) { return actual -> assertThat(actual).endsWith(suffix); }