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

com.obs.services.RefreshAkSkStsTokenProvider Maven / Gradle / Ivy

package com.obs.services;

import com.obs.log.ILogger;
import com.obs.log.LoggerBuilder;
import com.obs.services.internal.security.BasicSecurityKey;
import com.obs.services.model.ISecurityKey;
import okhttp3.*;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;


public class RefreshAkSkStsTokenProvider implements IObsCredentialsProvider {

    private static final ILogger log = LoggerBuilder.getLogger(RefreshAkSkStsTokenProvider.class);

    private ISecurityKey securityKey;
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private static final long REFRESH_INTERVAL_MINUTES = 10;
    private final OkHttpClient httpClient;
    private String iamDomain;
    private String iamUser;
    private String iamPassword;
    private String iamEndpoint;
    private boolean refreshTaskStarted = false;

    private final Map patternCache = new ConcurrentHashMap<>();

    public RefreshAkSkStsTokenProvider(String iamDomain, String iamUser, String iamPassword, String iamEndpoint, OkHttpClient httpClient) {
        this.iamDomain = iamDomain;
        this.iamUser = iamUser;
        this.iamPassword = iamPassword;
        this.iamEndpoint = iamEndpoint;
        this.httpClient = httpClient != null ? httpClient : new OkHttpClient();
    }

    public void startTokenRefreshTask() {
        if (!refreshTaskStarted) {
            scheduler.scheduleAtFixedRate(this::refreshSecurityKey, 0, REFRESH_INTERVAL_MINUTES, TimeUnit.MINUTES);
            refreshTaskStarted = true;
        }
    }

    @Override
    public void setSecurityKey(ISecurityKey securityKey) {
        this.securityKey = securityKey;
    }

    @Override
    public ISecurityKey getSecurityKey() {
        refreshSecurityKey();
        return this.securityKey;
    }

    private void refreshSecurityKey() {
        try {
            ISecurityKey newSecurityKey = fetchAkSkStsToken();
            setSecurityKey(newSecurityKey);
            log.debug("Security key refreshed successfully.");
        } catch (Exception e) {
            log.error("Failed to refresh security key: " + e.getMessage(), e);
        }
    }

    private ISecurityKey fetchAkSkStsToken() throws IOException {
        String subjectToken = getSubjectToken();
        if (subjectToken == null) {
            log.error("Failed to fetch subject token.");
            throw new IOException("Subject token is null.");
        }
        return getSecurityToken(subjectToken);
    }

    private String getSubjectToken() throws IOException {
        String jsonPayload = "{ " +
                    "\"auth\": { " +
                        "\"identity\": { " +
                            "\"methods\": [\"password\"], " +
                            "\"password\": { " +
                                "\"user\": { " +
                                    "\"domain\": { " +
                                         "\"name\": \"" + iamDomain + "\" " +
                                    "}, " +
                                    "\"name\": \"" + iamUser + "\", " +
                                    "\"password\": \"" + iamPassword + "\" " +
                                "} " +
                            "} " +
                        "}, " +
                        "\"scope\": { " +
                            "\"domain\": { " +
                                "\"name\": \"" + iamDomain + "\" " +
                            "} " +
                        "} " +
                    "} " +
                "}";

        RequestBody body = RequestBody.create(jsonPayload, MediaType.get("application/json; charset=utf-8"));
        Request request = new Request.Builder().url(iamEndpoint + "/v3/auth/tokens").post(body).build();

        Call call = httpClient.newCall(request);
        if (call == null) {
            throw new IllegalStateException("OkHttpClient failed to create a new Call. " +
                    "Ensure httpClient is properly initialized with " + iamEndpoint + "/v3/auth/tokens");
        }

        try (Response response = call.execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            return response.header("X-Subject-Token");
        }
    }

    private ISecurityKey getSecurityToken(String subjectToken) throws IOException {
        String jsonPayload = "{ " +
                    "\"auth\": { " +
                        "\"identity\": { " +
                            "\"methods\": [\"token\"], " +
                                "\"token\": { " +
                                    "\"id\": \"" + subjectToken + "\", " +
                                    "\"duration_seconds\": 900 " +
                                "} " +
                            "} " +
                        "} " +
                    "}";
        RequestBody body = RequestBody.create(jsonPayload, MediaType.get("application/json; charset=utf-8"));
        Request request = new Request.Builder().url(iamEndpoint + "/v3.0/OS-CREDENTIAL/securitytokens").post(body).build();

        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }

            ResponseBody responseBody = response.body();
            if (responseBody == null) {
                throw new IOException("Response body is null");
            }

            String responseBodyString = responseBody.string();

            String newAccessKey = extractJsonField(responseBodyString, "access");
            String newSecretKey = extractJsonField(responseBodyString, "secret");
            String newSecurityToken = extractJsonField(responseBodyString, "securitytoken");

            if (newAccessKey == null || newSecretKey == null || newSecurityToken == null) {
                throw new IllegalStateException("Failed to extract security keys.");
            }

            return new BasicSecurityKey(newAccessKey, newSecretKey, newSecurityToken);
        }
    }


    private String extractJsonField(String json, String field) {
        java.util.regex.Pattern pattern = patternCache.computeIfAbsent(field, key ->
                java.util.regex.Pattern.compile("\"" + field + "\":\"([^\"]+)\"")
        );

        java.util.regex.Matcher matcher = pattern.matcher(json);
        return matcher.find() ? matcher.group(1) : null;
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy