diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/util/RequestLogger.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/util/RequestLogger.java
index d0f3cc5ae3..4c94223c57 100644
--- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/util/RequestLogger.java
+++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/util/RequestLogger.java
@@ -34,7 +34,7 @@ public class RequestLogger {
private long requestSentTime;
public void request(HttpClientRequest request) {
- request(String.format("%-6s {}", request.method()), request.uri());
+ request(String.format("%-6s {}", request.method()), request.resourceUrl());
}
public void response(HttpClientResponse response) {
diff --git a/integration-test/pom.xml b/integration-test/pom.xml
index ca0b9009f1..63cf18f873 100644
--- a/integration-test/pom.xml
+++ b/integration-test/pom.xml
@@ -70,6 +70,16 @@
${project.version}
test
+
+ io.github.resilience4j
+ resilience4j-ratelimiter
+ 1.7.0
+
+
+ io.github.resilience4j
+ resilience4j-reactor
+ 1.7.0
+
org.cloudfoundry
cloudfoundry-util
diff --git a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java
index c0b3f44b30..5d1062f9fd 100644
--- a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java
+++ b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java
@@ -192,18 +192,19 @@ NetworkingClient adminNetworkingClient(
@Bean
@Qualifier("admin")
- ReactorUaaClient adminUaaClient(
+ UaaClient adminUaaClient(
ConnectionContext connectionContext,
@Value("${test.admin.clientId}") String clientId,
@Value("${test.admin.clientSecret}") String clientSecret) {
- return ReactorUaaClient.builder()
- .connectionContext(connectionContext)
- .tokenProvider(
- ClientCredentialsGrantTokenProvider.builder()
- .clientId(clientId)
- .clientSecret(clientSecret)
- .build())
- .build();
+ return new ThrottlingUaaClient(
+ ReactorUaaClient.builder()
+ .connectionContext(connectionContext)
+ .tokenProvider(
+ ClientCredentialsGrantTokenProvider.builder()
+ .clientId(clientId)
+ .clientSecret(clientSecret)
+ .build())
+ .build());
}
@Bean(initMethod = "block")
@@ -643,11 +644,12 @@ PasswordGrantTokenProvider tokenProvider(
}
@Bean
- ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
- return ReactorUaaClient.builder()
- .connectionContext(connectionContext)
- .tokenProvider(tokenProvider)
- .build();
+ UaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
+ return new ThrottlingUaaClient(
+ ReactorUaaClient.builder()
+ .connectionContext(connectionContext)
+ .tokenProvider(tokenProvider)
+ .build());
}
@Bean(initMethod = "block")
diff --git a/integration-test/src/test/java/org/cloudfoundry/ThrottlingUaaClient.java b/integration-test/src/test/java/org/cloudfoundry/ThrottlingUaaClient.java
new file mode 100644
index 0000000000..0d8c6de7c9
--- /dev/null
+++ b/integration-test/src/test/java/org/cloudfoundry/ThrottlingUaaClient.java
@@ -0,0 +1,321 @@
+package org.cloudfoundry;
+
+import io.github.resilience4j.ratelimiter.RateLimiter;
+import io.github.resilience4j.ratelimiter.RateLimiterConfig;
+import io.github.resilience4j.reactor.ratelimiter.operator.RateLimiterOperator;
+import java.time.Duration;
+import org.cloudfoundry.uaa.UaaClient;
+import org.cloudfoundry.uaa.authorizations.Authorizations;
+import org.cloudfoundry.uaa.clients.Clients;
+import org.cloudfoundry.uaa.groups.AddMemberRequest;
+import org.cloudfoundry.uaa.groups.AddMemberResponse;
+import org.cloudfoundry.uaa.groups.CheckMembershipRequest;
+import org.cloudfoundry.uaa.groups.CheckMembershipResponse;
+import org.cloudfoundry.uaa.groups.CreateGroupRequest;
+import org.cloudfoundry.uaa.groups.CreateGroupResponse;
+import org.cloudfoundry.uaa.groups.DeleteGroupRequest;
+import org.cloudfoundry.uaa.groups.DeleteGroupResponse;
+import org.cloudfoundry.uaa.groups.GetGroupRequest;
+import org.cloudfoundry.uaa.groups.GetGroupResponse;
+import org.cloudfoundry.uaa.groups.Groups;
+import org.cloudfoundry.uaa.groups.ListExternalGroupMappingsRequest;
+import org.cloudfoundry.uaa.groups.ListExternalGroupMappingsResponse;
+import org.cloudfoundry.uaa.groups.ListGroupsRequest;
+import org.cloudfoundry.uaa.groups.ListGroupsResponse;
+import org.cloudfoundry.uaa.groups.ListMembersRequest;
+import org.cloudfoundry.uaa.groups.ListMembersResponse;
+import org.cloudfoundry.uaa.groups.MapExternalGroupRequest;
+import org.cloudfoundry.uaa.groups.MapExternalGroupResponse;
+import org.cloudfoundry.uaa.groups.RemoveMemberRequest;
+import org.cloudfoundry.uaa.groups.RemoveMemberResponse;
+import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupDisplayNameRequest;
+import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupDisplayNameResponse;
+import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupIdRequest;
+import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupIdResponse;
+import org.cloudfoundry.uaa.groups.UpdateGroupRequest;
+import org.cloudfoundry.uaa.groups.UpdateGroupResponse;
+import org.cloudfoundry.uaa.identityproviders.IdentityProviders;
+import org.cloudfoundry.uaa.identityzones.IdentityZones;
+import org.cloudfoundry.uaa.serverinformation.ServerInformation;
+import org.cloudfoundry.uaa.tokens.Tokens;
+import org.cloudfoundry.uaa.users.ChangeUserPasswordRequest;
+import org.cloudfoundry.uaa.users.ChangeUserPasswordResponse;
+import org.cloudfoundry.uaa.users.CreateUserRequest;
+import org.cloudfoundry.uaa.users.CreateUserResponse;
+import org.cloudfoundry.uaa.users.DeleteUserRequest;
+import org.cloudfoundry.uaa.users.DeleteUserResponse;
+import org.cloudfoundry.uaa.users.ExpirePasswordRequest;
+import org.cloudfoundry.uaa.users.ExpirePasswordResponse;
+import org.cloudfoundry.uaa.users.GetUserVerificationLinkRequest;
+import org.cloudfoundry.uaa.users.GetUserVerificationLinkResponse;
+import org.cloudfoundry.uaa.users.InviteUsersRequest;
+import org.cloudfoundry.uaa.users.InviteUsersResponse;
+import org.cloudfoundry.uaa.users.ListUsersRequest;
+import org.cloudfoundry.uaa.users.ListUsersResponse;
+import org.cloudfoundry.uaa.users.LookupUserIdsRequest;
+import org.cloudfoundry.uaa.users.LookupUserIdsResponse;
+import org.cloudfoundry.uaa.users.UpdateUserRequest;
+import org.cloudfoundry.uaa.users.UpdateUserResponse;
+import org.cloudfoundry.uaa.users.UserInfoRequest;
+import org.cloudfoundry.uaa.users.UserInfoResponse;
+import org.cloudfoundry.uaa.users.Users;
+import org.cloudfoundry.uaa.users.VerifyUserRequest;
+import org.cloudfoundry.uaa.users.VerifyUserResponse;
+import reactor.core.publisher.Mono;
+
+public class ThrottlingUaaClient implements UaaClient {
+
+ private final UaaClient delegate;
+
+ private final RateLimiter rateLimiter;
+ private final ThrottledUsers users;
+ private Groups groups;
+
+ public ThrottlingUaaClient(UaaClient delegate) {
+ this.delegate = delegate;
+ RateLimiterConfig config =
+ RateLimiterConfig.custom()
+ .limitForPeriod(5)
+ .limitRefreshPeriod(Duration.ofSeconds(1))
+ .build();
+ this.rateLimiter = RateLimiter.of("uaa", config);
+ this.users = new ThrottledUsers();
+ this.groups = new ThrottledGroups();
+ }
+
+ @Override
+ public Authorizations authorizations() {
+ return this.delegate.authorizations();
+ }
+
+ @Override
+ public Clients clients() {
+ return this.delegate.clients();
+ }
+
+ @Override
+ public Mono getUsername() {
+ return this.delegate.getUsername();
+ }
+
+ @Override
+ public IdentityProviders identityProviders() {
+ return this.delegate.identityProviders();
+ }
+
+ @Override
+ public IdentityZones identityZones() {
+ return this.delegate.identityZones();
+ }
+
+ @Override
+ public ServerInformation serverInformation() {
+ return this.delegate.serverInformation();
+ }
+
+ @Override
+ public Tokens tokens() {
+ return this.delegate.tokens();
+ }
+
+ @Override
+ public Users users() {
+ return users;
+ }
+
+ @Override
+ public Groups groups() {
+ return groups;
+ }
+
+ public class ThrottledUsers implements Users {
+
+ private final Users usersDelegate;
+
+ public ThrottledUsers() {
+ this.usersDelegate = delegate.users();
+ }
+
+ @Override
+ public Mono changePassword(ChangeUserPasswordRequest request) {
+ return this.usersDelegate
+ .changePassword(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono create(CreateUserRequest request) {
+ return this.usersDelegate
+ .create(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono delete(DeleteUserRequest request) {
+ return this.usersDelegate
+ .delete(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono expirePassword(ExpirePasswordRequest request) {
+ return this.usersDelegate
+ .expirePassword(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono getVerificationLink(
+ GetUserVerificationLinkRequest request) {
+ return this.usersDelegate
+ .getVerificationLink(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono invite(InviteUsersRequest request) {
+ return this.usersDelegate
+ .invite(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono list(ListUsersRequest request) {
+ return this.usersDelegate
+ .list(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono lookup(LookupUserIdsRequest request) {
+ return this.usersDelegate
+ .lookup(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono update(UpdateUserRequest request) {
+ return this.usersDelegate
+ .update(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono userInfo(UserInfoRequest request) {
+ return this.usersDelegate
+ .userInfo(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono verify(VerifyUserRequest request) {
+ return this.usersDelegate
+ .verify(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+ }
+
+ public class ThrottledGroups implements Groups {
+
+ public final Groups groupsDelegate;
+
+ public ThrottledGroups() {
+ this.groupsDelegate = delegate.groups();
+ }
+
+ @Override
+ public Mono addMember(AddMemberRequest request) {
+ return this.groupsDelegate
+ .addMember(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono checkMembership(CheckMembershipRequest request) {
+ return this.groupsDelegate
+ .checkMembership(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono create(CreateGroupRequest request) {
+ return this.groupsDelegate
+ .create(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono delete(DeleteGroupRequest request) {
+ return this.groupsDelegate
+ .delete(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono get(GetGroupRequest request) {
+ return this.groupsDelegate
+ .get(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono list(ListGroupsRequest request) {
+ return this.groupsDelegate
+ .list(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono listExternalGroupMappings(
+ ListExternalGroupMappingsRequest request) {
+ return this.groupsDelegate
+ .listExternalGroupMappings(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono listMembers(ListMembersRequest request) {
+ return this.groupsDelegate
+ .listMembers(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono mapExternalGroup(MapExternalGroupRequest request) {
+ return this.groupsDelegate
+ .mapExternalGroup(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono removeMember(RemoveMemberRequest request) {
+ return this.groupsDelegate
+ .removeMember(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono
+ unmapExternalGroupByGroupDisplayName(
+ UnmapExternalGroupByGroupDisplayNameRequest request) {
+ return this.groupsDelegate
+ .unmapExternalGroupByGroupDisplayName(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono unmapExternalGroupByGroupId(
+ UnmapExternalGroupByGroupIdRequest request) {
+ return this.groupsDelegate
+ .unmapExternalGroupByGroupId(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+
+ @Override
+ public Mono update(UpdateGroupRequest request) {
+ return this.groupsDelegate
+ .update(request)
+ .transformDeferred(RateLimiterOperator.of(rateLimiter));
+ }
+ }
+}
diff --git a/integration-test/src/test/resources/logback-test.xml b/integration-test/src/test/resources/logback-test.xml
index 4d9869fc6e..0872bbe5aa 100644
--- a/integration-test/src/test/resources/logback-test.xml
+++ b/integration-test/src/test/resources/logback-test.xml
@@ -26,7 +26,7 @@
-
+