From 59c06403bcd57534e0ec7a345b47b8887f54d993 Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Wed, 9 Jul 2025 13:51:12 +0200
Subject: [PATCH 1/7] New resource for v3/users
---
.../CleanupCloudFoundryAfterClass.java | 27 +++++++++++++++++++
.../org/cloudfoundry/CloudFoundryCleaner.java | 25 ++++++++++++++++-
.../IntegrationTestConfiguration.java | 4 +--
.../client/v2/ApplicationsTest.java | 2 ++
.../client/v2/ServiceBrokersTest.java | 2 ++
.../org/cloudfoundry/client/v3/AdminTest.java | 1 -
.../client/v3/ApplicationsTest.java | 2 ++
.../client/v3/DeploymentsTest.java | 2 ++
.../cloudfoundry/client/v3/ProcessesTest.java | 2 ++
.../client/v3/ServiceBrokersTest.java | 2 ++
.../org/cloudfoundry/client/v3/TasksTest.java | 2 ++
.../operations/ApplicationsTest.java | 6 ++++-
.../cloudfoundry/operations/RoutesTest.java | 2 ++
.../operations/ServiceAdminTest.java | 7 +++--
.../cloudfoundry/operations/ServicesTest.java | 2 ++
15 files changed, 80 insertions(+), 8 deletions(-)
create mode 100644 integration-test/src/test/java/org/cloudfoundry/CleanupCloudFoundryAfterClass.java
diff --git a/integration-test/src/test/java/org/cloudfoundry/CleanupCloudFoundryAfterClass.java b/integration-test/src/test/java/org/cloudfoundry/CleanupCloudFoundryAfterClass.java
new file mode 100644
index 0000000000..88d8fd6303
--- /dev/null
+++ b/integration-test/src/test/java/org/cloudfoundry/CleanupCloudFoundryAfterClass.java
@@ -0,0 +1,27 @@
+package org.cloudfoundry;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+/**
+ * Meta-annotation to show that a test class will add too much to the CF instance, and that a full universe
+ * cleanup should occur. This is important because otherwise the integration tests create too many apps and
+ * blow up the memory quota. We do not want to recreate the full environment for EVERY test class because
+ * the process takes 30~60s, so in total it could add more than an hour to the integration tests.
+ *
+ * Technically, this is achieved by recreating a Spring ApplicationContext with {@link DirtiesContext}. The
+ * {@link CloudFoundryCleaner} bean will be destroyed, which triggers {@link CloudFoundryCleaner#clean()}.
+ * After that, every {@link Bean} in {@link IntegrationTestConfiguration} is recreated, including users,
+ * clients, organizations, etc: everything required to run a test.
+ *
+ * We use a meta-annotation instead of a raw {@link DirtiesContext} to make it clear what it does, rather
+ * than having to understand complicated lifecycle issues.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@DirtiesContext
+public @interface CleanupCloudFoundryAfterClass {}
diff --git a/integration-test/src/test/java/org/cloudfoundry/CloudFoundryCleaner.java b/integration-test/src/test/java/org/cloudfoundry/CloudFoundryCleaner.java
index c4fb056ad2..d515a86b09 100644
--- a/integration-test/src/test/java/org/cloudfoundry/CloudFoundryCleaner.java
+++ b/integration-test/src/test/java/org/cloudfoundry/CloudFoundryCleaner.java
@@ -116,12 +116,16 @@
import org.cloudfoundry.util.ResourceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuples;
import reactor.util.retry.Retry;
-final class CloudFoundryCleaner {
+final class CloudFoundryCleaner implements InitializingBean, DisposableBean {
+
+ private static boolean cleanSlateEnvironment = false;
private static final Logger LOGGER = LoggerFactory.getLogger("cloudfoundry-client.test");
@@ -162,6 +166,25 @@ final class CloudFoundryCleaner {
this.uaaClient = uaaClient;
}
+ /**
+ * Once at the beginning of the whole test suite, clean up the environment. It should only ever happen
+ * once, hence the static init variable.
+ */
+ @Override
+ public void afterPropertiesSet() {
+ if (!cleanSlateEnvironment) {
+ LOGGER.info(
+ "Performing clean slate cleanup. Should happen once per integration test run.");
+ this.clean();
+ cleanSlateEnvironment = true;
+ }
+ }
+
+ @Override
+ public void destroy() {
+ this.clean();
+ }
+
void clean() {
Flux.empty()
.thenMany(
diff --git a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java
index c3954a978a..c0b3f44b30 100644
--- a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java
+++ b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java
@@ -37,7 +37,6 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
-import java.util.Random;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.info.GetInfoRequest;
import org.cloudfoundry.client.v2.organizationquotadefinitions.CreateOrganizationQuotaDefinitionRequest;
@@ -243,14 +242,13 @@ String clientSecret(NameFactory nameFactory) {
return nameFactory.getClientSecret();
}
- @Bean(initMethod = "clean", destroyMethod = "clean")
+ @Bean
CloudFoundryCleaner cloudFoundryCleaner(
@Qualifier("admin") CloudFoundryClient cloudFoundryClient,
NameFactory nameFactory,
@Qualifier("admin") NetworkingClient networkingClient,
Version serverVersion,
@Qualifier("admin") UaaClient uaaClient) {
-
return new CloudFoundryCleaner(
cloudFoundryClient, nameFactory, networkingClient, serverVersion, uaaClient);
}
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v2/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v2/ApplicationsTest.java
index 6cfbab97d8..9774568bd0 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v2/ApplicationsTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v2/ApplicationsTest.java
@@ -36,6 +36,7 @@
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.client.CloudFoundryClient;
@@ -96,6 +97,7 @@
import reactor.test.StepVerifier;
import reactor.util.function.Tuple2;
+@CleanupCloudFoundryAfterClass
public final class ApplicationsTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v2/ServiceBrokersTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v2/ServiceBrokersTest.java
index 75486720fc..214577e4a9 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v2/ServiceBrokersTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v2/ServiceBrokersTest.java
@@ -25,6 +25,7 @@
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
import org.cloudfoundry.ApplicationUtils;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.ServiceBrokerUtils;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.servicebrokers.CreateServiceBrokerRequest;
@@ -43,6 +44,7 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
+@CleanupCloudFoundryAfterClass
public final class ServiceBrokersTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/AdminTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/AdminTest.java
index dd14124d1b..d185f15dea 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/AdminTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/AdminTest.java
@@ -26,7 +26,6 @@
import org.cloudfoundry.util.JobUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/ApplicationsTest.java
index 3354b24ed7..ef3ea073c8 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/ApplicationsTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/ApplicationsTest.java
@@ -28,6 +28,7 @@
import java.util.Collections;
import java.util.Map;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.client.CloudFoundryClient;
@@ -106,6 +107,7 @@
import reactor.test.StepVerifier;
import reactor.util.function.Tuples;
+@CleanupCloudFoundryAfterClass
public final class ApplicationsTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/DeploymentsTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/DeploymentsTest.java
index 61ec02076f..d823ad7b1c 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/DeploymentsTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/DeploymentsTest.java
@@ -22,6 +22,7 @@
import java.nio.file.Path;
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.client.CloudFoundryClient;
@@ -51,6 +52,7 @@
import reactor.test.StepVerifier;
@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_2_4)
+@CleanupCloudFoundryAfterClass
public final class DeploymentsTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/ProcessesTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/ProcessesTest.java
index b509114793..e4a4184e85 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/ProcessesTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/ProcessesTest.java
@@ -22,6 +22,7 @@
import java.nio.file.Path;
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.client.CloudFoundryClient;
@@ -42,6 +43,7 @@
import reactor.test.StepVerifier;
@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_2_0)
+@CleanupCloudFoundryAfterClass
public final class ProcessesTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceBrokersTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceBrokersTest.java
index f7c063c445..656a0b0efe 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceBrokersTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceBrokersTest.java
@@ -25,6 +25,7 @@
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
import org.cloudfoundry.ApplicationUtils;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.ServiceBrokerUtils;
@@ -49,6 +50,7 @@
import reactor.test.StepVerifier;
@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_2_10)
+@CleanupCloudFoundryAfterClass
public final class ServiceBrokersTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/TasksTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/TasksTest.java
index a4c962d0f1..0e3fdada8c 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/TasksTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/TasksTest.java
@@ -22,6 +22,7 @@
import java.io.IOException;
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.client.CloudFoundryClient;
@@ -50,6 +51,7 @@
import reactor.test.StepVerifier;
@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_1_12)
+@CleanupCloudFoundryAfterClass
public final class TasksTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java
index 5eb9f34a57..2ffd49b285 100644
--- a/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/operations/ApplicationsTest.java
@@ -26,6 +26,7 @@
import java.util.List;
import java.util.Map;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.CloudFoundryVersion;
import org.cloudfoundry.IfCloudFoundryVersion;
import org.cloudfoundry.logcache.v1.Envelope;
@@ -93,6 +94,7 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
+@CleanupCloudFoundryAfterClass
public final class ApplicationsTest extends AbstractIntegrationTest {
private static final String DEFAULT_ROUTER_GROUP = "default-tcp";
@@ -109,7 +111,9 @@ public final class ApplicationsTest extends AbstractIntegrationTest {
// To create a service in #pushBindService, the Service Broker must be installed first.
// We ensure it is by loading the serviceBrokerId @Lazy bean.
- @Qualifier("serviceBrokerId") @Autowired private Mono serviceBrokerId;
+ @Qualifier("serviceBrokerId")
+ @Autowired
+ private Mono serviceBrokerId;
@Test
public void copySource() throws IOException {
diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/RoutesTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/RoutesTest.java
index 5b86191b22..19db1a53b1 100644
--- a/integration-test/src/test/java/org/cloudfoundry/operations/RoutesTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/operations/RoutesTest.java
@@ -27,6 +27,7 @@
import java.util.Optional;
import java.util.function.Predicate;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.operations.applications.ApplicationHealthCheck;
import org.cloudfoundry.operations.applications.PushApplicationRequest;
import org.cloudfoundry.operations.domains.CreateDomainRequest;
@@ -49,6 +50,7 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
+@CleanupCloudFoundryAfterClass
public final class RoutesTest extends AbstractIntegrationTest {
private static final String DEFAULT_ROUTER_GROUP = "default-tcp";
diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ServiceAdminTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ServiceAdminTest.java
index 0d20e86188..7a8f1ec378 100644
--- a/integration-test/src/test/java/org/cloudfoundry/operations/ServiceAdminTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/operations/ServiceAdminTest.java
@@ -21,6 +21,7 @@
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.ServiceBrokerUtils;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.spaces.CreateSpaceRequest;
@@ -34,11 +35,11 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
-
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
+@CleanupCloudFoundryAfterClass
public final class ServiceAdminTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
@@ -57,7 +58,9 @@ public final class ServiceAdminTest extends AbstractIntegrationTest {
// To create a service in #pushBindService, the Service Broker must be installed first.
// We ensure it is by loading the serviceBrokerId @Lazy bean.
- @Qualifier("serviceBrokerId") @Autowired private Mono serviceBrokerId;
+ @Qualifier("serviceBrokerId")
+ @Autowired
+ private Mono serviceBrokerId;
@Test
public void disableServiceAccess() {
diff --git a/integration-test/src/test/java/org/cloudfoundry/operations/ServicesTest.java b/integration-test/src/test/java/org/cloudfoundry/operations/ServicesTest.java
index 1d3355a4ba..520027128b 100644
--- a/integration-test/src/test/java/org/cloudfoundry/operations/ServicesTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/operations/ServicesTest.java
@@ -23,6 +23,7 @@
import java.nio.file.Path;
import java.time.Duration;
import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CleanupCloudFoundryAfterClass;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.servicebindings.ListServiceBindingsRequest;
import org.cloudfoundry.client.v2.servicebindings.ServiceBindingResource;
@@ -64,6 +65,7 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
+@CleanupCloudFoundryAfterClass
public final class ServicesTest extends AbstractIntegrationTest {
@Autowired private CloudFoundryClient cloudFoundryClient;
From 327e239adc390e0019ca30738756b437142072a8 Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Wed, 16 Jul 2025 21:36:32 +0200
Subject: [PATCH 2/7] Adding user resource for v3
---
.../client/v3/users/ReactorUsersV3.java | 83 +++++++
.../client/v3/users/ReactorUsersTest.java | 215 ++++++++++++++++++
.../client/v3/users/GET_{id}_response.json | 17 ++
.../client/v3/users/PATCH_{id}_request.json | 10 +
.../client/v3/users/PATCH_{id}_response.json | 21 ++
.../client/v3/users/POST_request.json | 3 +
.../client/v3/users/POST_response.json | 17 ++
.../client/CloudFoundryClient.java | 6 +
.../cloudfoundry/client/v3/users/User.java | 53 +++++
.../cloudfoundry/client/v3/users/UsersV3.java | 58 +++++
.../client/v3/users/_CreateUserRequest.java | 58 +++++
.../client/v3/users/_CreateUserResponse.java | 27 +++
.../client/v3/users/_DeleteUserRequest.java | 33 +++
.../client/v3/users/_GetUserRequest.java | 33 +++
.../client/v3/users/_GetUserResponse.java | 28 +++
.../client/v3/users/_UpdateUserRequest.java | 45 ++++
.../client/v3/users/_UpdateUserResponse.java | 27 +++
.../client/v3/users/_UserResource.java | 27 +++
.../v3/users/CreateUserRequestTest.java | 25 ++
.../v3/users/DeleteUserRequestTest.java | 35 +++
.../client/v3/users/GetUserRequestTest.java | 38 ++++
.../org/cloudfoundry/client/v3/UsersTest.java | 142 ++++++++++++
22 files changed, 1001 insertions(+)
create mode 100644 cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersV3.java
create mode 100644 cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersTest.java
create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/GET_{id}_response.json
create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_request.json
create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_response.json
create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_request.json
create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_response.json
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/UsersV3.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserRequest.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserResponse.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_DeleteUserRequest.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserRequest.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserResponse.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserRequest.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserResponse.java
create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UserResource.java
create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/CreateUserRequestTest.java
create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/DeleteUserRequestTest.java
create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/GetUserRequestTest.java
create mode 100644 integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersV3.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersV3.java
new file mode 100644
index 0000000000..2d42f0fff4
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersV3.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.cloudfoundry.reactor.client.v3.users;
+
+import org.cloudfoundry.client.v3.users.*;
+import org.cloudfoundry.reactor.ConnectionContext;
+import org.cloudfoundry.reactor.TokenProvider;
+import org.cloudfoundry.reactor.client.v3.AbstractClientV3Operations;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+
+/**
+ * The Reactor-based implementation of {@link UsersV3}
+ */
+public class ReactorUsersV3 extends AbstractClientV3Operations implements UsersV3 {
+
+ /**
+ * Creates an instance
+ *
+ * @param connectionContext the {@link ConnectionContext} to use when communicating with the server
+ * @param root the root URI of the server. Typically, something like {@code https://api.cloudfoundry.your.company.com}.
+ * @param tokenProvider the {@link TokenProvider} to use when communicating with the server
+ * @param requestTags map with custom http headers which will be added to web request
+ */
+ public ReactorUsersV3(
+ ConnectionContext connectionContext,
+ Mono root,
+ TokenProvider tokenProvider,
+ Map requestTags) {
+ super(connectionContext, root, tokenProvider, requestTags);
+ }
+
+ @Override
+ public Mono create(CreateUserRequest request) {
+ return post(
+ request,
+ CreateUserResponse.class,
+ builder -> builder.pathSegment("users"))
+ .checkpoint();
+ }
+
+ @Override
+ public Mono get(GetUserRequest request) {
+ return get(
+ request,
+ GetUserResponse.class,
+ builder -> builder.pathSegment("users", request.getUserId()))
+ .checkpoint();
+ }
+
+ @Override
+ public Mono update(UpdateUserRequest request) {
+ return patch(
+ request,
+ UpdateUserResponse.class,
+ builder -> builder.pathSegment("users", request.getUserId()))
+ .checkpoint();
+ }
+
+ @Override
+ public Mono delete(DeleteUserRequest request) {
+ return delete(
+ request,
+ Void.class,
+ builder -> builder.pathSegment("users", request.getUserId()))
+ .checkpoint();
+ }
+}
\ No newline at end of file
diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersTest.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersTest.java
new file mode 100644
index 0000000000..91676e5c71
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/users/ReactorUsersTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.reactor.client.v3.users;
+
+import org.cloudfoundry.client.v3.Link;
+import org.cloudfoundry.client.v3.Metadata;
+import org.cloudfoundry.client.v3.users.*;
+import org.cloudfoundry.reactor.InteractionContext;
+import org.cloudfoundry.reactor.TestRequest;
+import org.cloudfoundry.reactor.TestResponse;
+import org.cloudfoundry.reactor.client.AbstractClientApiTest;
+import org.junit.jupiter.api.Test;
+import reactor.test.StepVerifier;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.Map;
+
+import static io.netty.handler.codec.http.HttpMethod.*;
+import static io.netty.handler.codec.http.HttpResponseStatus.*;
+
+final class ReactorUsersTest extends AbstractClientApiTest {
+ private final ReactorUsersV3 users =
+ new ReactorUsersV3(CONNECTION_CONTEXT, this.root, TOKEN_PROVIDER, Collections.emptyMap());
+
+ @Test
+ void create() {
+ mockRequest(
+ InteractionContext.builder()
+ .request(
+ TestRequest.builder()
+ .method(POST)
+ .path("/users")
+ .payload(
+ "fixtures/client/v3/users/POST_request.json")
+ .build())
+ .response(
+ TestResponse.builder()
+ .status(CREATED)
+ .payload(
+ "fixtures/client/v3/users/POST_response.json")
+ .build())
+ .build());
+
+ this.users
+ .create(CreateUserRequest.builder()
+ .userId("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build()
+ )
+ .as(StepVerifier::create)
+ .expectNext(
+ CreateUserResponse.builder()
+ .id("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .createdAt("2019-03-08T01:06:19Z")
+ .updatedAt("2019-03-08T01:06:19Z")
+ .username("some-name")
+ .presentationName("some-name")
+ .origin("uaa")
+ .metadata(
+ Metadata.builder()
+ .putAllAnnotations(Collections.emptyMap())
+ .putAllLabels(Collections.emptyMap())
+ .build())
+ .link(
+ "self",
+ Link.builder()
+ .href(
+ "https://api.example.org/v3/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build())
+ .build()
+ )
+ .expectComplete()
+ .verify(Duration.ofSeconds(5));
+ }
+
+ @Test
+ void get() {
+ mockRequest(
+ InteractionContext.builder()
+ .request(
+ TestRequest.builder()
+ .method(GET)
+ .path("/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build())
+ .response(
+ TestResponse.builder()
+ .status(OK)
+ .payload(
+ "fixtures/client/v3/users/GET_{id}_response.json")
+ .build())
+ .build());
+
+ this.users
+ .get(GetUserRequest.builder()
+ .userId("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build()
+ )
+ .as(StepVerifier::create)
+ .expectNext(
+ GetUserResponse.builder()
+ .id("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .createdAt("2019-03-08T01:06:19Z")
+ .updatedAt("2019-03-08T01:06:19Z")
+ .username("some-name")
+ .presentationName("some-name")
+ .origin("uaa")
+ .metadata(
+ Metadata.builder()
+ .putAllAnnotations(Collections.emptyMap())
+ .putAllLabels(Collections.emptyMap())
+ .build())
+ .link(
+ "self",
+ Link.builder()
+ .href(
+ "https://api.example.org/v3/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build())
+ .build()
+ )
+ .expectComplete()
+ .verify(Duration.ofSeconds(5));
+ }
+
+ @Test
+ void update() {
+ mockRequest(
+ InteractionContext.builder()
+ .request(
+ TestRequest.builder()
+ .method(PATCH)
+ .path("/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .payload(
+ "fixtures/client/v3/users/PATCH_{id}_request.json")
+ .build())
+ .response(
+ TestResponse.builder()
+ .status(CREATED)
+ .payload(
+ "fixtures/client/v3/users/PATCH_{id}_response.json")
+ .build())
+ .build());
+
+ this.users
+ .update(UpdateUserRequest.builder()
+ .userId("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .metadata(Metadata.builder()
+ .putAllAnnotations(Map.of("note", "detailed information"))
+ .putAllLabels(Map.of("environment", "production"))
+ .build())
+ .build()
+ )
+ .as(StepVerifier::create)
+ .expectNext(
+ UpdateUserResponse.builder()
+ .id("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .createdAt("2019-03-08T01:06:19Z")
+ .updatedAt("2019-03-08T01:06:19Z")
+ .username("some-name")
+ .presentationName("some-name")
+ .origin("uaa")
+ .metadata(Metadata.builder()
+ .putAllAnnotations(Map.of("note", "detailed information"))
+ .putAllLabels(Map.of("environment", "production"))
+ .build())
+ .link(
+ "self",
+ Link.builder()
+ .href(
+ "https://api.example.org/v3/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build())
+ .build()
+ )
+ .expectComplete()
+ .verify(Duration.ofSeconds(5));
+ }
+
+ @Test
+ void delete() {
+ mockRequest(
+ InteractionContext.builder()
+ .request(
+ TestRequest.builder()
+ .method(DELETE)
+ .path("/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build())
+ .response(
+ TestResponse.builder()
+ .status(ACCEPTED)
+ .build())
+ .build());
+
+ this.users
+ .delete(DeleteUserRequest.builder()
+ .userId("3a5d3d89-3f89-4f05-8188-8a2b298c79d5")
+ .build()
+ )
+ .as(StepVerifier::create)
+ .expectComplete()
+ .verify(Duration.ofSeconds(5));
+ }
+
+}
diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/GET_{id}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/GET_{id}_response.json
new file mode 100644
index 0000000000..b60ce5ab33
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/GET_{id}_response.json
@@ -0,0 +1,17 @@
+{
+ "guid": "3a5d3d89-3f89-4f05-8188-8a2b298c79d5",
+ "created_at": "2019-03-08T01:06:19Z",
+ "updated_at": "2019-03-08T01:06:19Z",
+ "username": "some-name",
+ "presentation_name": "some-name",
+ "origin": "uaa",
+ "metadata": {
+ "labels": {},
+ "annotations": {}
+ },
+ "links": {
+ "self": {
+ "href": "https://api.example.org/v3/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5"
+ }
+ }
+}
\ No newline at end of file
diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_request.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_request.json
new file mode 100644
index 0000000000..52c4a1b610
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_request.json
@@ -0,0 +1,10 @@
+{
+ "metadata": {
+ "labels": {
+ "environment": "production"
+ },
+ "annotations": {
+ "note": "detailed information"
+ }
+ }
+}
\ No newline at end of file
diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_response.json
new file mode 100644
index 0000000000..9275a05c46
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/PATCH_{id}_response.json
@@ -0,0 +1,21 @@
+{
+ "guid": "3a5d3d89-3f89-4f05-8188-8a2b298c79d5",
+ "created_at": "2019-03-08T01:06:19Z",
+ "updated_at": "2019-03-08T01:06:19Z",
+ "username": "some-name",
+ "presentation_name": "some-name",
+ "origin": "uaa",
+ "metadata": {
+ "labels": {
+ "environment": "production"
+ },
+ "annotations": {
+ "note": "detailed information"
+ }
+ },
+ "links": {
+ "self": {
+ "href": "https://api.example.org/v3/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5"
+ }
+ }
+}
diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_request.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_request.json
new file mode 100644
index 0000000000..e5463b4edb
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_request.json
@@ -0,0 +1,3 @@
+{
+ "guid": "3a5d3d89-3f89-4f05-8188-8a2b298c79d5"
+}
\ No newline at end of file
diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_response.json
new file mode 100644
index 0000000000..b60ce5ab33
--- /dev/null
+++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/users/POST_response.json
@@ -0,0 +1,17 @@
+{
+ "guid": "3a5d3d89-3f89-4f05-8188-8a2b298c79d5",
+ "created_at": "2019-03-08T01:06:19Z",
+ "updated_at": "2019-03-08T01:06:19Z",
+ "username": "some-name",
+ "presentation_name": "some-name",
+ "origin": "uaa",
+ "metadata": {
+ "labels": {},
+ "annotations": {}
+ },
+ "links": {
+ "self": {
+ "href": "https://api.example.org/v3/users/3a5d3d89-3f89-4f05-8188-8a2b298c79d5"
+ }
+ }
+}
\ No newline at end of file
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java
index d3c0ec8164..b3caad6f24 100644
--- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java
@@ -72,6 +72,7 @@
import org.cloudfoundry.client.v3.spaces.SpacesV3;
import org.cloudfoundry.client.v3.stacks.StacksV3;
import org.cloudfoundry.client.v3.tasks.Tasks;
+import org.cloudfoundry.client.v3.users.UsersV3;
/**
* Main entry point to the Cloud Foundry Client API
@@ -363,4 +364,9 @@ public interface CloudFoundryClient {
* Main entry point to the Cloud Foundry Users Client API
*/
Users users();
+
+ /**
+ * Main entry point to the Cloud Foundry Users Client API
+ */
+ UsersV3 usersV3();
}
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java
new file mode 100644
index 0000000000..7517e40cb8
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.cloudfoundry.Nullable;
+import org.cloudfoundry.client.v3.Metadata;
+import org.cloudfoundry.client.v3.Resource;
+
+/**
+ * Base class for responses that are users
+ */
+public abstract class User extends Resource {
+
+ /**
+ * The username
+ */
+ @JsonProperty("username")
+ public abstract String getUsername();
+
+ /**
+ * The presentation name
+ */
+ @JsonProperty("presentation_name")
+ public abstract String getPresentationName();
+
+ /**
+ * The origin
+ */
+ @JsonProperty("origin")
+ @Nullable
+ public abstract String getOrigin();
+
+ /**
+ * The metadata
+ */
+ @JsonProperty("metadata")
+ @Nullable
+ public abstract Metadata getMetadata();
+}
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/UsersV3.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/UsersV3.java
new file mode 100644
index 0000000000..574fd48cb3
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/UsersV3.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+
+import reactor.core.publisher.Mono;
+
+
+/**
+ * Main entry point to the Cloud Foundry Users V3 Client API
+ */
+public interface UsersV3 {
+
+ /**
+ * Makes the Create a User request
+ *
+ * @param request the Create User request
+ * @return the response from the Create User request
+ */
+ Mono create(CreateUserRequest request);
+
+ /**
+ * Makes the Get a User request
+ *
+ * @param request the Get User request
+ * @return the response from the Get User request
+ */
+ Mono get(GetUserRequest request);
+
+ /**
+ * Makes the Update a Stack request
+ *
+ * @param request the Update User request
+ * @return the response from the Update User request
+ */
+ Mono update(UpdateUserRequest request);
+
+ /**
+ * Makes the Delete a User request
+ *
+ * @param request the Delete User request
+ * @return void
+ */
+ Mono delete(DeleteUserRequest request);
+}
\ No newline at end of file
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserRequest.java
new file mode 100644
index 0000000000..aaa9a537a9
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserRequest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.cloudfoundry.Nullable;
+import org.cloudfoundry.client.v3.Metadata;
+import org.immutables.value.Value;
+
+/**
+ * The request payload for the Create User operation
+ */
+@JsonSerialize
+@Value.Immutable
+abstract class _CreateUserRequest {
+
+ /**
+ * The user id
+ */
+ @JsonProperty("guid")
+ @Nullable
+ abstract String getUserId();
+
+ /**
+ * The username
+ */
+ @JsonProperty("username")
+ @Nullable
+ abstract String getUsername();
+
+ /**
+ * The origin
+ */
+ @JsonProperty("origin")
+ @Nullable
+ abstract String getOrigin();
+
+ /**
+ * The metadata
+ */
+ @JsonProperty("metadata")
+ @Nullable
+ abstract Metadata getMetadata();
+}
\ No newline at end of file
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserResponse.java
new file mode 100644
index 0000000000..2109e2526e
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_CreateUserResponse.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.immutables.value.Value;
+
+/**
+ * The response payload for the Create Stack operation
+ */
+@JsonDeserialize
+@Value.Immutable
+abstract class _CreateUserResponse extends User {
+}
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_DeleteUserRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_DeleteUserRequest.java
new file mode 100644
index 0000000000..1ce5d06c78
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_DeleteUserRequest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.immutables.value.Value;
+
+/**
+ * The request payload for the Delete User operation
+ */
+@Value.Immutable
+abstract class _DeleteUserRequest {
+
+ /**
+ * The User id
+ */
+ @JsonIgnore
+ abstract String getUserId();
+
+}
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserRequest.java
new file mode 100644
index 0000000000..6354513615
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserRequest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.immutables.value.Value;
+
+/**
+ * The request payload for the Get User operation
+ */
+@Value.Immutable
+abstract class _GetUserRequest {
+
+ /**
+ * The user id
+ */
+ @JsonIgnore
+ abstract String getUserId();
+
+}
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserResponse.java
new file mode 100644
index 0000000000..3d7258aaee
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_GetUserResponse.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.immutables.value.Value;
+
+/**
+ * The response payload for the Get User operation
+ */
+@JsonDeserialize
+@Value.Immutable
+abstract class _GetUserResponse extends User {
+}
+
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserRequest.java
new file mode 100644
index 0000000000..2d959eb48d
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserRequest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.cloudfoundry.Nullable;
+import org.cloudfoundry.client.v3.Metadata;
+import org.immutables.value.Value;
+
+/**
+ * The request payload for the Update User operation
+ */
+@JsonSerialize
+@Value.Immutable
+abstract class _UpdateUserRequest {
+
+ /**
+ * The stack id
+ */
+ @JsonIgnore
+ abstract String getUserId();
+
+ /**
+ * The metadata
+ */
+ @JsonProperty("metadata")
+ @Nullable
+ abstract Metadata getMetadata();
+
+}
\ No newline at end of file
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserResponse.java
new file mode 100644
index 0000000000..11fee6b6d1
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UpdateUserResponse.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.immutables.value.Value;
+
+/**
+ * The response payload for the Update User operation
+ */
+@JsonDeserialize
+@Value.Immutable
+abstract class _UpdateUserResponse extends User {
+}
\ No newline at end of file
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UserResource.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UserResource.java
new file mode 100644
index 0000000000..1ab8203e60
--- /dev/null
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/_UserResource.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.immutables.value.Value;
+
+/**
+ * The Resource response payload for the List Organizations operation
+ */
+@JsonDeserialize
+@Value.Immutable
+abstract class _UserResource extends User {
+}
diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/CreateUserRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/CreateUserRequestTest.java
new file mode 100644
index 0000000000..b6c22e1650
--- /dev/null
+++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/CreateUserRequestTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import org.junit.jupiter.api.Test;
+
+class CreateUserRequestTest {
+ @Test
+ void valid() {
+ CreateUserRequest.builder().userId("test-user-id").build();
+ }
+}
diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/DeleteUserRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/DeleteUserRequestTest.java
new file mode 100644
index 0000000000..23ee0e0ea5
--- /dev/null
+++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/DeleteUserRequestTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class DeleteUserRequestTest {
+
+ @Test
+ void noUserId() {
+ assertThrows(
+ IllegalStateException.class,
+ () -> DeleteUserRequest.builder().build());
+ }
+
+ @Test
+ void valid() {
+ DeleteUserRequest.builder().userId("test-stack-id").build();
+ }
+}
diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/GetUserRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/GetUserRequestTest.java
new file mode 100644
index 0000000000..4b353ec495
--- /dev/null
+++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/users/GetUserRequestTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cloudfoundry.client.v3.users;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class GetUserRequestTest {
+
+ @Test
+ void noUserId() {
+ assertThrows(
+ IllegalStateException.class,
+ () -> GetUserRequest.builder().build());
+ }
+
+ @Test
+ void valid() {
+ GetUserRequest.builder()
+ .userId("test-user-id")
+ .build();
+ }
+}
+
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
new file mode 100644
index 0000000000..ddfc0b1592
--- /dev/null
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2013-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.cloudfoundry.client.v3;
+
+
+import org.cloudfoundry.AbstractIntegrationTest;
+import org.cloudfoundry.CloudFoundryVersion;
+import org.cloudfoundry.IfCloudFoundryVersion;
+import org.cloudfoundry.client.CloudFoundryClient;
+import org.cloudfoundry.client.v3.users.*;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import java.time.Duration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_4_v3)
+public final class UsersTest extends AbstractIntegrationTest {
+
+ @Autowired
+ private CloudFoundryClient cloudFoundryClient;
+
+ public UsersTest(CloudFoundryClient cloudFoundryClient) {
+ this.cloudFoundryClient = cloudFoundryClient;
+ }
+
+ private static Mono createUser(
+ CloudFoundryClient cloudFoundryClient, String userId) {
+ return cloudFoundryClient
+ .usersV3()
+ .create(CreateUserRequest.builder().userId(userId).build());
+ }
+
+ private static Mono getUser(
+ CloudFoundryClient cloudFoundryClient, String userId) {
+ return cloudFoundryClient
+ .usersV3()
+ .get(GetUserRequest.builder().userId(userId).build());
+ }
+
+ @Test
+ public void create() {
+ String userId = this.nameFactory.getUserId();
+
+ this.cloudFoundryClient
+ .usersV3()
+ .create(CreateUserRequest.builder()
+ .userId(userId)
+ .build()
+ )
+ .single()
+ .as(StepVerifier::create)
+ .expectNextCount(1)
+ .expectComplete()
+ .verify(Duration.ofMinutes(5));
+ }
+
+ @Test
+ public void get() {
+ String userId = this.nameFactory.getUserId();
+
+ createUser(this.cloudFoundryClient, userId)
+ .flatMap(createUserResponse ->
+ this.cloudFoundryClient.usersV3()
+ .get(GetUserRequest.builder()
+ .userId(userId)
+ .build()))
+ .map(GetUserResponse::getId)
+ .as(StepVerifier::create)
+ .expectNext(userId)
+ .expectComplete()
+ .verify(Duration.ofMinutes(5));
+ }
+
+ @Test
+ public void update() {
+ String userId = this.nameFactory.getUserId();
+
+ createUser(this.cloudFoundryClient, userId)
+ .flatMap(createUserResponse ->
+ this.cloudFoundryClient.usersV3()
+ .update(UpdateUserRequest.builder()
+ .userId(userId)
+ .metadata(Metadata.builder()
+ .annotation(
+ "annotationKey",
+ "annotationValue")
+ .label(
+ "labelKey",
+ "labelValue")
+ .build())
+ .build()))
+ .then(getUser(cloudFoundryClient, userId))
+ .as(StepVerifier::create)
+ .consumeNextWith(
+ GetUserResponse -> {
+ Metadata metadata = GetUserResponse.getMetadata();
+ assertThat(metadata.getAnnotations().get("annotationKey"))
+ .isEqualTo("annotationValue");
+ assertThat(metadata.getLabels().get("labelKey"))
+ .isEqualTo("labelValue");
+ })
+ .expectComplete()
+ .verify(Duration.ofMinutes(5));
+
+ }
+
+ @Test
+ public void delete() {
+ String userId = this.nameFactory.getUserId();
+
+ createUser(this.cloudFoundryClient, userId)
+ .flatMap(
+ createUserResponse ->
+ this.cloudFoundryClient
+ .usersV3()
+ .delete(
+ DeleteUserRequest.builder()
+ .userId(createUserResponse.getId())
+ .build()))
+ .as(StepVerifier::create)
+ .expectComplete()
+ .verify(Duration.ofMinutes(5));
+ }
+}
From ee52ccd0d033061ef3f5685b441ab53cd4f3cd4d Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Sat, 19 Jul 2025 10:15:04 +0200
Subject: [PATCH 3/7] Adding user resource for v3
---
.../reactor/client/_ReactorCloudFoundryClient.java | 8 ++++++++
.../main/java/org/cloudfoundry/client/v3/users/User.java | 2 ++
.../test/java/org/cloudfoundry/client/v3/UsersTest.java | 4 ----
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java
index 319a1bcfd6..d6ae05f47e 100644
--- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java
+++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java
@@ -73,6 +73,7 @@
import org.cloudfoundry.client.v3.spaces.SpacesV3;
import org.cloudfoundry.client.v3.stacks.StacksV3;
import org.cloudfoundry.client.v3.tasks.Tasks;
+import org.cloudfoundry.client.v3.users.UsersV3;
import org.cloudfoundry.reactor.ConnectionContext;
import org.cloudfoundry.reactor.TokenProvider;
import org.cloudfoundry.reactor.client.v2.applications.ReactorApplicationsV2;
@@ -131,6 +132,7 @@
import org.cloudfoundry.reactor.client.v3.spaces.ReactorSpacesV3;
import org.cloudfoundry.reactor.client.v3.stacks.ReactorStacksV3;
import org.cloudfoundry.reactor.client.v3.tasks.ReactorTasks;
+import org.cloudfoundry.reactor.client.v3.users.ReactorUsersV3;
import org.immutables.value.Value;
import reactor.core.publisher.Mono;
@@ -491,6 +493,12 @@ public Users users() {
return new ReactorUsers(getConnectionContext(), getRootV2(), getTokenProvider(), getRequestTags());
}
+ @Override
+ @Value.Derived
+ public UsersV3 usersV3() {
+ return new ReactorUsersV3(getConnectionContext(), getRootV3(), getTokenProvider(), getRequestTags());
+ }
+
/**
* The connection context
*/
diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java
index 7517e40cb8..9f60d78b49 100644
--- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java
+++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/users/User.java
@@ -29,12 +29,14 @@ public abstract class User extends Resource {
* The username
*/
@JsonProperty("username")
+ @Nullable
public abstract String getUsername();
/**
* The presentation name
*/
@JsonProperty("presentation_name")
+ @Nullable
public abstract String getPresentationName();
/**
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
index ddfc0b1592..1dbdfa336d 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
@@ -37,10 +37,6 @@ public final class UsersTest extends AbstractIntegrationTest {
@Autowired
private CloudFoundryClient cloudFoundryClient;
- public UsersTest(CloudFoundryClient cloudFoundryClient) {
- this.cloudFoundryClient = cloudFoundryClient;
- }
-
private static Mono createUser(
CloudFoundryClient cloudFoundryClient, String userId) {
return cloudFoundryClient
From 60e70c30caadcf460de4384ef07cd3059c271346 Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Sat, 19 Jul 2025 10:15:04 +0200
Subject: [PATCH 4/7] Adding user resource for v3
---
.../src/test/java/org/cloudfoundry/client/v3/UsersTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
index 1dbdfa336d..d7b15c6771 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
@@ -35,7 +35,7 @@
public final class UsersTest extends AbstractIntegrationTest {
@Autowired
- private CloudFoundryClient cloudFoundryClient;
+ private final CloudFoundryClient cloudFoundryClient;
private static Mono createUser(
CloudFoundryClient cloudFoundryClient, String userId) {
From a97f9a563384b6405ccf57b723f12af8613965bb Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Sun, 20 Jul 2025 19:39:50 +0200
Subject: [PATCH 5/7] Adding user resource for v3 Adding GrantType value for
jwt-bearer grant type
---
.../main/java/org/cloudfoundry/uaa/tokens/GrantType.java | 9 ++++++++-
.../test/java/org/cloudfoundry/client/v3/UsersTest.java | 2 +-
2 files changed, 9 insertions(+), 2 deletions(-)
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 6dd626c52d..fec9b5d99f 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
@@ -47,7 +47,12 @@ public enum GrantType {
/**
* The refresh token grant type
*/
- REFRESH_TOKEN("refresh_token");
+ REFRESH_TOKEN("refresh_token"),
+
+ /**
+ * The jwt-bearer token grant type
+ */
+ JWT_BEARER("urn:ietf:params:oauth:grant-type:jwt-bearer");
private final String value;
@@ -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));
}
diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
index d7b15c6771..1dbdfa336d 100644
--- a/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
+++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/UsersTest.java
@@ -35,7 +35,7 @@
public final class UsersTest extends AbstractIntegrationTest {
@Autowired
- private final CloudFoundryClient cloudFoundryClient;
+ private CloudFoundryClient cloudFoundryClient;
private static Mono createUser(
CloudFoundryClient cloudFoundryClient, String userId) {
From e520de8ea2c0d54365a279211e7d24f0c9d16ac0 Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Sun, 20 Jul 2025 19:59:07 +0200
Subject: [PATCH 6/7] Adding user resource for v3 Adding GrantType value for
jwt-bearer grant type Adding GrantType value for saml2-bearer grant type
---
.../main/java/org/cloudfoundry/uaa/tokens/GrantType.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
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 fec9b5d99f..ed8ef366cf 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
@@ -52,7 +52,12 @@ public enum GrantType {
/**
* The jwt-bearer token grant type
*/
- JWT_BEARER("urn:ietf:params:oauth:grant-type:jwt-bearer");
+ JWT_BEARER("urn:ietf:params:oauth:grant-type:jwt-bearer"),
+
+ /**
+ * The jwt-bearer token grant type
+ */
+ SAML2_BEARER("urn:ietf:params:oauth:grant-type:saml2-bearer");
private final String value;
@@ -75,6 +80,8 @@ public static GrantType from(String s) {
return REFRESH_TOKEN;
case "urn:ietf:params:oauth:grant-type:jwt-bearer":
return JWT_BEARER;
+ case "urn:ietf:params:oauth:grant-type:saml2-bearer":
+ return SAML2_BEARER;
default:
throw new IllegalArgumentException(String.format("Unknown grant type: %s", s));
}
From 10466b3a43279a94fca72641c792b9e41ee20bcc Mon Sep 17 00:00:00 2001
From: "joda (damzog)" <16135207+damzog@users.noreply.github.com>
Date: Sun, 20 Jul 2025 20:08:38 +0200
Subject: [PATCH 7/7] Adding user resource for v3 Adding GrantType value for
jwt-bearer grant type Adding GrantType value for saml2-bearer grant type
Adding GrantType value for user token grant type
---
.../java/org/cloudfoundry/uaa/tokens/GrantType.java | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
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 ed8ef366cf..1e9eb36cc4 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
@@ -55,9 +55,14 @@ public enum GrantType {
JWT_BEARER("urn:ietf:params:oauth:grant-type:jwt-bearer"),
/**
- * The jwt-bearer token grant type
+ * The saml2-bearer token grant type
+ */
+ SAML2_BEARER("urn:ietf:params:oauth:grant-type:saml2-bearer"),
+
+ /**
+ * The user token token grant type
*/
- SAML2_BEARER("urn:ietf:params:oauth:grant-type:saml2-bearer");
+ USER_TOKEN("user_token");
private final String value;
@@ -82,6 +87,8 @@ public static GrantType from(String s) {
return JWT_BEARER;
case "urn:ietf:params:oauth:grant-type:saml2-bearer":
return SAML2_BEARER;
+ case "user_token":
+ return USER_TOKEN;
default:
throw new IllegalArgumentException(String.format("Unknown grant type: %s", s));
}