Skip to content

Commit

Permalink
feat: map expires_in in TokenRepresentation (#4131)
Browse files Browse the repository at this point in the history
* feat: map expires_in in TokenRepresentation

* chore: deps file

* chore: fix checkstyle
  • Loading branch information
wolf4ood authored Apr 22, 2024
1 parent 41a22c1 commit 5bae31c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static org.eclipse.edc.http.spi.FallbackFactories.retryWhenStatusIsNot;

Expand All @@ -38,6 +40,7 @@ public class Oauth2ClientImpl implements Oauth2Client {
private static final String FORM_URLENCODED = "application/x-www-form-urlencoded";
private static final String APPLICATION_JSON = "application/json";
private static final String RESPONSE_ACCESS_TOKEN_CLAIM = "access_token";
private static final String RESPONSE_EXPIRES_IN_CLAIM = "expires_in";

private final EdcHttpClient httpClient;
private final TypeManager typeManager;
Expand All @@ -47,18 +50,6 @@ public Oauth2ClientImpl(EdcHttpClient httpClient, TypeManager typeManager) {
this.typeManager = typeManager;
}

@Override
public Result<TokenRepresentation> requestToken(Oauth2CredentialsRequest request) {
return httpClient.execute(toRequest(request), List.of(retryWhenStatusIsNot(200)), this::handleResponse);
}

private Result<TokenRepresentation> handleResponse(Response response) {
return getStringBody(response)
.map(it -> typeManager.readValue(it, Map.class))
.map(it -> it.get(RESPONSE_ACCESS_TOKEN_CLAIM).toString())
.map(it -> TokenRepresentation.Builder.newInstance().token(it).build());
}

private static Request toRequest(Oauth2CredentialsRequest request) {
return new Request.Builder()
.url(request.getUrl())
Expand All @@ -76,6 +67,39 @@ private static FormBody createRequestBody(Oauth2CredentialsRequest request) {
return builder.build();
}

@Override
public Result<TokenRepresentation> requestToken(Oauth2CredentialsRequest request) {
return httpClient.execute(toRequest(request), List.of(retryWhenStatusIsNot(200)), this::handleResponse);
}

private Result<TokenRepresentation> handleResponse(Response response) {
return getStringBody(response)
.map(it -> typeManager.readValue(it, Map.class))
.map(this::mapResponse);
}

private TokenRepresentation mapResponse(Map<String, Object> response) {
var builder = TokenRepresentation.Builder.newInstance();
builder.token(response.get(RESPONSE_ACCESS_TOKEN_CLAIM).toString());

Optional.ofNullable(response.get(RESPONSE_EXPIRES_IN_CLAIM))
.flatMap(expiresIn -> {
if (expiresIn instanceof Number n) {
return Optional.of(n.longValue());
}
return Optional.empty();
})
.ifPresent(builder::expiresIn);

var additional = new HashMap<>(response);
additional.remove(RESPONSE_EXPIRES_IN_CLAIM);
additional.remove(RESPONSE_ACCESS_TOKEN_CLAIM);

builder.additional(additional);

return builder.build();
}

@NotNull
private Result<String> getStringBody(Response response) {
try (var body = response.body()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,71 @@ void verifyRequestTokenSuccess() {
assertThat(result.getContent().getToken()).isEqualTo("token");
}

@Test
void verifyRequestTokenSuccess_withExpiresIn() {
var request = createRequest();

var formParameters = new Parameters(
request.getParams().entrySet().stream()
.map(entry -> Parameter.param(entry.getKey(), entry.getValue()))
.collect(Collectors.toList())
);

var expectedRequest = HttpRequest.request().withBody(new ParameterBody(formParameters));
var responseBody = typeManager.writeValueAsString(Map.of("access_token", "token", "expires_in", 1800));
server.when(expectedRequest).respond(HttpResponse.response().withBody(responseBody, APPLICATION_JSON));

var result = client.requestToken(request);

assertThat(result.succeeded()).isTrue();
assertThat(result.getContent().getToken()).isEqualTo("token");
assertThat(result.getContent().getExpiresIn()).isEqualTo(1800);
assertThat(result.getContent().getAdditional()).doesNotContainKeys("token", "expires_in");
}

@Test
void verifyRequestTokenSuccess_withExpiresIn_whenNotNumber() {
var request = createRequest();

var formParameters = new Parameters(
request.getParams().entrySet().stream()
.map(entry -> Parameter.param(entry.getKey(), entry.getValue()))
.collect(Collectors.toList())
);

var expectedRequest = HttpRequest.request().withBody(new ParameterBody(formParameters));
var responseBody = typeManager.writeValueAsString(Map.of("access_token", "token", "expires_in", "wrong"));
server.when(expectedRequest).respond(HttpResponse.response().withBody(responseBody, APPLICATION_JSON));

var result = client.requestToken(request);

assertThat(result.succeeded()).isTrue();
assertThat(result.getContent().getToken()).isEqualTo("token");
assertThat(result.getContent().getExpiresIn()).isNull();
}

@Test
void verifyRequestTokenSuccess_withAdditionalProperties() {
var request = createRequest();

var formParameters = new Parameters(
request.getParams().entrySet().stream()
.map(entry -> Parameter.param(entry.getKey(), entry.getValue()))
.collect(Collectors.toList())
);

var expectedRequest = HttpRequest.request().withBody(new ParameterBody(formParameters));
var responseBody = typeManager.writeValueAsString(Map.of("access_token", "token", "expires_in", 1800, "scope", "test"));
server.when(expectedRequest).respond(HttpResponse.response().withBody(responseBody, APPLICATION_JSON));

var result = client.requestToken(request);

assertThat(result.succeeded()).isTrue();
assertThat(result.getContent().getToken()).isEqualTo("token");
assertThat(result.getContent().getExpiresIn()).isEqualTo(1800);
assertThat(result.getContent().getAdditional()).containsEntry("scope", "test");
}

@Test
void verifyFailureIfServerCallFails() {
var request = createRequest();
Expand Down

0 comments on commit 5bae31c

Please sign in to comment.