diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/AddInvitedRegistrationCall.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/AddInvitedRegistrationCall.java index 0aefd7168c141f47a806b24aece170d997eaadee..d0a1ad4ce706082acb6fc4ead041c149421370b3 100644 --- a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/AddInvitedRegistrationCall.java +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/AddInvitedRegistrationCall.java @@ -22,7 +22,8 @@ public class AddInvitedRegistrationCall extends BaseGmsCall { String endpoint = "invited-registration"; - String bodyParams = "token_hash=" + tokenHash + // plus symbol in token hash is encoded to %2B, otherwise it will be interpreted as space + String bodyParams = "token_hash=" + tokenHash.replace("+", "%2B") + "&email=" + email + "&groups=" + String.join("\n", groupsPermissions.entrySet() .stream().map(e -> e.getKey() + " " + e.getValue()) diff --git a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java index 54ce5b82212e534fc7ff1a6ba5a2125dd2a4da86..b086de3f764f6649034f9779f2076622efe86429 100644 --- a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java +++ b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java @@ -7,14 +7,23 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.net.http.HttpClient; import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublisher; import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodySubscriber; +import java.net.http.HttpResponse.BodySubscribers; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Flow; +import java.util.concurrent.Flow.Subscriber; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.AdditionalMatchers; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; import static org.mockito.ArgumentMatchers.any; @@ -145,6 +154,72 @@ public class GmsClientTest { verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "permission/LBT.INAF?user_id=user"), any()); } + @Test + public void testInvitedRegistration() { + + CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(201)); + + when(httpClient.sendAsync(any(), any())).thenReturn(response); + Map<String, Permission> permissionsMap = new HashMap<>(); + permissionsMap.put("group1", Permission.MANAGE_MEMBERS); + permissionsMap.put("group2", Permission.MANAGE_MEMBERS); + client.addInvitedRegistration("bvjsgqu423", "email", permissionsMap); + // hash = AOyojiwaRR7BHPde6Tomg3+BMoQQggNM3wUHEarXuNQ= + + verify(httpClient, times(1)).sendAsync( + AdditionalMatchers.and( + endpointEq("POST", "invited-registration"), + ArgumentMatchers.argThat(req -> { + String reqbody = req.bodyPublisher().map(p -> { + var bodySubscriber = BodySubscribers.ofString(StandardCharsets.UTF_8); + var flowSubscriber = new StringSubscriber(bodySubscriber); + p.subscribe(flowSubscriber); + return bodySubscriber.getBody().toCompletableFuture().join(); + }).get(); + + // If the resulting hash contains a + symbol it has to be encoded to %2B, + // otherwise it will be interpreted as a space and wrong value will be + // stored into the database + String expectedBody = "token_hash=AOyojiwaRR7BHPde6Tomg3%2BBMoQQggNM3wUHEarXuNQ=" + + "&email=email&groups=group2 MANAGE_MEMBERS\n" + + "group1 MANAGE_MEMBERS"; + + return reqbody.equals(expectedBody); + })), any()); + } + + /** + * Credit: https://stackoverflow.com/a/55816685/771431 + */ + static final class StringSubscriber implements Flow.Subscriber<ByteBuffer> { + + final BodySubscriber<String> wrapped; + + StringSubscriber(BodySubscriber<String> wrapped) { + this.wrapped = wrapped; + } + + @Override + public void onSubscribe(Flow.Subscription subscription) { + wrapped.onSubscribe(subscription); + } + + @Override + public void onNext(ByteBuffer item) { + wrapped.onNext(List.of(item)); + } + + @Override + public void onError(Throwable throwable) { + wrapped.onError(throwable); + } + + @Override + public void onComplete() { + wrapped.onComplete(); + } + } + private HttpResponse getMockedResponse(int statusCode, String body) { HttpResponse response = getMockedResponse(statusCode); InputStream in = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));