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

com.aliyun.auth.credentials.provider.EcsRamRoleCredentialProvider Maven / Gradle / Ivy

The newest version!
package com.aliyun.auth.credentials.provider;

import com.aliyun.auth.credentials.Credential;
import com.aliyun.auth.credentials.ICredential;
import com.aliyun.auth.credentials.exception.*;
import com.aliyun.auth.credentials.http.*;
import com.aliyun.auth.credentials.utils.*;
import com.aliyun.core.utils.StringUtils;
import com.google.gson.Gson;

import java.time.Instant;
import java.util.Map;

public final class EcsRamRoleCredentialProvider extends HttpCredentialProvider {

    private static final String URL_IN_ECS_METADATA = "/latest/meta-data/ram/security-credentials/";
    private static final String URL_IN_METADATA_TOKEN = "/latest/api/token";
    private static final String ECS_METADAT_FETCH_ERROR_MSG = "Failed to get RAM session credentials from ECS metadata service.";
    private final String roleName;
    private final String metadataServiceHost;
    private final Boolean disableIMDSv1;

    private final int connectionTimeout;
    private final int readTimeout;

    private final CompatibleUrlConnClient client;

    private EcsRamRoleCredentialProvider(BuilderImpl builder) {
        super(builder);
        if (AuthUtils.isDisableECSMetaData()) {
            throw new CredentialException("IMDS credentials is disabled.");
        }
        this.roleName = builder.roleName == null ? AuthUtils.getEnvironmentECSMetaData() : builder.roleName;
        this.disableIMDSv1 = builder.disableIMDSv1 == null ? AuthUtils.getDisableECSIMDSv1() : builder.disableIMDSv1;
        this.metadataServiceHost = builder.metadataServiceHost == null ? "100.100.100.200" : builder.metadataServiceHost;

        this.connectionTimeout = builder.connectionTimeout == null ? 1000 : builder.connectionTimeout;
        this.readTimeout = builder.readTimeout == null ? 1000 : builder.readTimeout;

        this.client = new CompatibleUrlConnClient();
        this.buildRefreshCache();
    }

    public static EcsRamRoleCredentialProvider create(String roleName) {
        return builder().roleName(roleName).build();
    }

    public static Builder builder() {
        return new BuilderImpl();
    }

    private String getMetadata(String url) {
        HttpRequest request = new HttpRequest(url);
        request.setSysMethod(MethodType.GET);
        request.setSysConnectTimeout(connectionTimeout);
        request.setSysReadTimeout(readTimeout);
        HttpResponse response;
        String metadataToken = this.getMetadataToken();
        if (metadataToken != null) {
            request.putHeaderParameter("X-aliyun-ecs-metadata-token", metadataToken);
        }

        try {
            response = client.syncInvoke(request);
        } catch (Exception e) {
            throw new CredentialException("Failed to connect ECS Metadata Service: " + e);
        }

        if (response.getResponseCode() == 404) {
            throw new CredentialException("The role name was not found in the instance.");
        }

        if (response.getResponseCode() != 200) {
            throw new CredentialException(ECS_METADAT_FETCH_ERROR_MSG + " HttpCode=" + response.getResponseCode());
        }

        return response.getHttpContentString();
    }

    private String getMetadataToken() {
        try {
            HttpRequest request = new HttpRequest("http://" + metadataServiceHost + URL_IN_METADATA_TOKEN);
            request.setSysMethod(MethodType.PUT);
            request.setSysConnectTimeout(connectionTimeout);
            request.setSysReadTimeout(readTimeout);
            request.putHeaderParameter("X-aliyun-ecs-metadata-token-ttl-seconds", "21600");
            HttpResponse response;
            try {
                response = client.syncInvoke(request);
            } catch (Exception e) {
                throw new CredentialException("Failed to connect ECS Metadata Service: " + e);
            }
            if (response.getResponseCode() != 200) {
                throw new CredentialException("Failed to get token from ECS Metadata Service. HttpCode=" + response.getResponseCode() + ", ResponseMessage=" + response.getHttpContentString());
            }
            return new String(response.getHttpContent());
        } catch (Exception ex) {
            return throwErrorOrReturn(ex);
        }
    }

    private String throwErrorOrReturn(Exception e) {
        if (this.disableIMDSv1) {
            throw new CredentialException("Failed to get token from ECS Metadata Service, and fallback to IMDS v1 is disabled via the disableIMDSv1 configuration is turned on. Original error: " + e.getMessage());
        }
        return null;
    }

    @Override
    public RefreshResult refreshCredentials() {
        String roleName = this.roleName;
        if (StringUtils.isEmpty(this.roleName)) {
            roleName = getMetadata("http://" + metadataServiceHost + URL_IN_ECS_METADATA);
        }

        String jsonContent = getMetadata("http://" + metadataServiceHost + URL_IN_ECS_METADATA + roleName);
        Map result = new Gson().fromJson(jsonContent, Map.class);

        if (!"Success".equals(result.get("Code"))) {
            throw new CredentialException(ECS_METADAT_FETCH_ERROR_MSG);
        }

        if (!result.containsKey("AccessKeyId") || !result.containsKey("AccessKeySecret") || !result.containsKey("SecurityToken")) {
            throw new CredentialException(String.format("Error retrieving credentials from IMDS result: %s.", jsonContent));
        }

        Instant expiration = ParameterHelper.getUTCDate(result.get("Expiration")).toInstant();
        ICredential credential = Credential.builder()
                .accessKeyId(result.get("AccessKeyId"))
                .accessKeySecret(result.get("AccessKeySecret"))
                .securityToken(result.get("SecurityToken"))
                .build();
        return RefreshResult.builder(credential)
                .staleTime(getStaleTime(expiration))
                .prefetchTime(getPrefetchTime(expiration))
                .build();
    }

    @Override
    public void close() {
        super.close();
        this.client.close();
    }

    public interface Builder extends HttpCredentialProvider.Builder {
        Builder roleName(String roleSessionName);

        Builder metadataServiceHost(String metadataServiceHost);

        Builder disableIMDSv1(Boolean disableIMDSv1);

        Builder connectionTimeout(Integer connectionTimeout);

        Builder readTimeout(Integer readTimeout);

        @Override
        EcsRamRoleCredentialProvider build();
    }

    private static final class BuilderImpl
            extends HttpCredentialProvider.BuilderImpl
            implements Builder {

        private String roleName;
        private String metadataServiceHost;
        private Boolean disableIMDSv1;
        private Integer connectionTimeout;
        private Integer readTimeout;

        public Builder roleName(String roleName) {
            this.roleName = roleName;
            return this;
        }

        public Builder metadataServiceHost(String metadataServiceHost) {
            this.metadataServiceHost = metadataServiceHost;
            return this;
        }

        public Builder disableIMDSv1(Boolean disableIMDSv1) {
            this.disableIMDSv1 = disableIMDSv1;
            return this;
        }

        public Builder connectionTimeout(Integer connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
            return this;
        }

        public Builder readTimeout(Integer readTimeout) {
            this.readTimeout = readTimeout;
            return this;
        }

        @Override
        public EcsRamRoleCredentialProvider build() {
            return new EcsRamRoleCredentialProvider(this);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy