All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.edc.iam.oauth2.client.Oauth2ClientImpl Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
/*
 *  Copyright (c) 2022 Amadeus
 *
 *  This program and the accompanying materials are made available under the
 *  terms of the Apache License, Version 2.0 which is available at
 *  https://www.apache.org/licenses/LICENSE-2.0
 *
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Contributors:
 *       Amadeus - initial API and implementation
 *
 */

package org.eclipse.edc.iam.oauth2.client;

import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.Response;
import org.eclipse.edc.http.spi.EdcHttpClient;
import org.eclipse.edc.iam.oauth2.spi.client.Oauth2Client;
import org.eclipse.edc.iam.oauth2.spi.client.Oauth2CredentialsRequest;
import org.eclipse.edc.spi.iam.TokenRepresentation;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.spi.types.TypeManager;
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;

public class Oauth2ClientImpl implements Oauth2Client {

    private static final String ACCEPT = "Accept";
    private static final String CONTENT_TYPE = "Content-Type";
    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;

    public Oauth2ClientImpl(EdcHttpClient httpClient, TypeManager typeManager) {
        this.httpClient = httpClient;
        this.typeManager = typeManager;
    }

    private static Request toRequest(Oauth2CredentialsRequest request) {
        return new Request.Builder()
                .url(request.getUrl())
                .addHeader(ACCEPT, APPLICATION_JSON)
                .addHeader(CONTENT_TYPE, FORM_URLENCODED)
                .post(createRequestBody(request))
                .build();
    }

    private static FormBody createRequestBody(Oauth2CredentialsRequest request) {
        var builder = new FormBody.Builder();
        request.getParams().entrySet().stream()
                .filter(entry -> entry.getValue() != null)
                .forEach(entry -> builder.add(entry.getKey(), entry.getValue()));
        return builder.build();
    }

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

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

    private TokenRepresentation mapResponse(Map 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 getStringBody(Response response) {
        try (var body = response.body()) {
            if (body != null) {
                return Result.success(body.string());
            } else {
                return Result.failure("Body is null");
            }
        } catch (IOException e) {
            return Result.failure("Cannot read response body as String: " + e.getMessage());
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy