001
002package io.vrap.rmf.base.client.oauth2;
003
004import static io.vrap.rmf.base.client.ApiHttpHeaders.headerEntry;
005
006import java.net.URI;
007import java.nio.charset.StandardCharsets;
008import java.util.Base64;
009import java.util.concurrent.CompletableFuture;
010import java.util.concurrent.CompletionException;
011
012import io.vrap.rmf.base.client.*;
013import io.vrap.rmf.base.client.utils.Utils;
014import io.vrap.rmf.base.client.utils.json.JsonUtils;
015
016public class RefreshFlowTokenSupplier extends BaseAuthTokenSupplier implements RefreshableTokenSupplier {
017    private final TokenStorage tokenStorage;
018
019    public RefreshFlowTokenSupplier(final String clientId, final String clientSecret, final String tokenEndpoint,
020            final TokenStorage tokenStorage, final VrapHttpClient vrapHttpClient) {
021        super(vrapHttpClient, constructApiHttpRequest(clientId, clientSecret, tokenEndpoint));
022        this.tokenStorage = tokenStorage;
023    }
024
025    @Override
026    public CompletableFuture<AuthenticationToken> refreshToken() {
027        final AuthenticationToken token = tokenStorage.getToken();
028        if (token.getRefreshToken() == null) {
029            throw new AuthException(400, "No refresh_token given", null);
030        }
031        final String body = String.format("grant_type=refresh_token&refresh_token=%s",
032            urlEncode(token.getRefreshToken()));
033        final ApiHttpRequest request = apiHttpRequest.withBody(body);
034        logger.debug(() -> request);
035        return vrapHttpClient.execute(request).whenComplete((response, throwable) -> {
036            logger.info(() -> String.format("%s %s %s", apiHttpRequest.getMethod().name(), apiHttpRequest.getUri(),
037                response.getStatusCode()));
038            if (throwable != null) {
039                logger.error(() -> response, throwable);
040            }
041            else {
042                logger.debug(() -> response);
043            }
044        }).thenApply(apiHttpResponse -> {
045            if (apiHttpResponse.getStatusCode() < 200 || apiHttpResponse.getStatusCode() > 299) {
046                throw new CompletionException(new Throwable(new String(apiHttpResponse.getBody())));
047            }
048            return apiHttpResponse;
049        })
050                .thenApply(Utils.wrapToCompletionException((ApiHttpResponse<byte[]> response) -> JsonUtils
051                        .fromJsonByteArray(response.getBody(), AuthenticationToken.class)));
052    }
053
054    @Override
055    public CompletableFuture<AuthenticationToken> getToken() {
056        return refreshToken();
057    }
058
059    private static ApiHttpRequest constructApiHttpRequest(final String clientId, final String clientSecret,
060            final String tokenEndpoint) {
061        String auth = Base64.getEncoder()
062                .encodeToString((clientId + ":" + clientSecret).getBytes(StandardCharsets.UTF_8));
063        final ApiHttpHeaders apiHttpHeaders = new ApiHttpHeaders(
064            headerEntry(ApiHttpHeaders.AUTHORIZATION, String.format("Basic %s", auth)),
065            headerEntry(ApiHttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded"));
066        return new ApiHttpRequest(ApiHttpMethod.POST, URI.create(tokenEndpoint), apiHttpHeaders, null);
067    }
068}