Skip to content

Commit

Permalink
refactor credentials providers
Browse files Browse the repository at this point in the history
  • Loading branch information
yndu13 committed Dec 3, 2024
1 parent f8e6e72 commit 4e7e95f
Show file tree
Hide file tree
Showing 33 changed files with 2,078 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
public class AuthConstant {
public static final String SYSTEM_ACCESSKEYID = "alibabacloud.accessKeyId";
public static final String SYSTEM_ACCESSKEYSECRET = "alibabacloud.accessKeyIdSecret";
public static final String SYSTEM_ACCESSKEY_SECRET = "alibabacloud.accessKeySecret";
public static final String SYSTEM_SESSION_TOKEN = "alibabacloud.sessionToken";

public static final String DEFAULT_CREDENTIALS_FILE_PATH = System.getProperty("user.home") +
"/.alibabacloud/credentials.ini";
Expand All @@ -11,6 +13,7 @@ public class AuthConstant {
public static final String INI_TYPE = "type";
public static final String INI_TYPE_RAM = "ecs_ram_role";
public static final String INI_TYPE_ARN = "ram_role_arn";
public static final String INI_TYPE_OIDC = "oidc_role_arn";
public static final String INI_TYPE_KEY_PAIR = "rsa_key_pair";
public static final String INI_PUBLIC_KEY_ID = "public_key_id";
public static final String INI_PRIVATE_KEY_FILE = "private_key_file";
Expand All @@ -19,6 +22,8 @@ public class AuthConstant {
public static final String INI_ROLE_SESSION_NAME = "role_session_name";
public static final String INI_ROLE_ARN = "role_arn";
public static final String INI_POLICY = "policy";
public static final String INI_OIDC_PROVIDER_ARN = "oidc_provider_arn";
public static final String INI_OIDC_TOKEN_FILE_PATH = "oidc_token_file_path";
public static final long TSC_VALID_TIME_SECONDS = 3600L;
public static final String DEFAULT_REGION = "region_id";
public static final String INI_ENABLE = "enable";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
package com.aliyuncs.auth;

import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.utils.AuthUtils;
import com.aliyuncs.utils.StringUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CLIProfileCredentialsProvider implements AlibabaCloudCredentialsProvider {
private final String CLI_CREDENTIALS_CONFIG_PATH = System.getProperty("user.home") +
"/.aliyun/config.json";
private volatile AlibabaCloudCredentialsProvider credentialsProvider;
private volatile String currentProfileName;
private final Object credentialsProviderLock = new Object();

private CLIProfileCredentialsProvider(Builder builder) {
this.currentProfileName = builder.profileName == null ? System.getenv("ALIBABA_CLOUD_PROFILE") : builder.profileName;
}

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

@Override
public AlibabaCloudCredentials getCredentials() throws ClientException {
if (AuthUtils.isDisableCLIProfile()) {
throw new ClientException("CLI credentials file is disabled.");
}
Config config = null;
try {
config = parseProfile(CLI_CREDENTIALS_CONFIG_PATH);
} catch (IOException e) {
throw new ClientException("Unable to get profile from CLI credentials file: " + e);
}
if (null == config) {
throw new ClientException("Unable to get profile from empty CLI credentials file.");
}
String refreshedProfileName = System.getenv("ALIBABA_CLOUD_PROFILE");
if (shouldReloadCredentialsProvider(refreshedProfileName)) {
synchronized (credentialsProviderLock) {
if (shouldReloadCredentialsProvider(refreshedProfileName)) {
if (!StringUtils.isEmpty(refreshedProfileName)) {
this.currentProfileName = refreshedProfileName;
}
this.credentialsProvider = reloadCredentialsProvider(config, this.currentProfileName);
}
}
}
return this.credentialsProvider.getCredentials();
}

AlibabaCloudCredentialsProvider reloadCredentialsProvider(Config config, String profileName) throws ClientException {
String currentProfileName = !StringUtils.isEmpty(profileName) ? profileName : config.getCurrent();
List<Profile> profiles = config.getProfiles();
if (profiles != null && !profiles.isEmpty()) {
for (Profile profile : profiles) {
if (!StringUtils.isEmpty(profile.getName()) && profile.getName().equals(currentProfileName)) {
String mode = profile.getMode();

if ("AK".equals(mode)) {
return new StaticCredentialsProvider(
new BasicCredentials(profile.getAccessKeyId(), profile.getAccessKeySecret()));
} else if ("RamRoleArn".equals(mode)) {
AlibabaCloudCredentialsProvider innerProvider = new StaticCredentialsProvider(
new BasicCredentials(profile.getAccessKeyId(), profile.getAccessKeySecret()));
return STSAssumeRoleSessionCredentialsProvider.builder()
.credentialsProvider(innerProvider)
.durationSeconds(profile.getDurationSeconds())
.roleArn(profile.getRoleArn())
.roleSessionName(profile.getRoleSessionName())
.stsRegionId(profile.getStsRegionId())
.enableVpc(profile.getEnableVpc())
.policy(profile.getPolicy())
.externalId(profile.getExternalId())
.build();
} else if ("EcsRamRole".equals(mode)) {
return InstanceProfileCredentialsProvider.builder()
.roleName(profile.getRamRoleName())
.build();
} else if ("OIDC".equals(mode)) {
return OIDCCredentialsProvider.builder()
.durationSeconds(profile.getDurationSeconds())
.roleArn(profile.getRoleArn())
.roleSessionName(profile.getRoleSessionName())
.oidcProviderArn(profile.getOidcProviderArn())
.oidcTokenFilePath(profile.getOidcTokenFile())
.stsRegionId(profile.getStsRegionId())
.enableVpc(profile.getEnableVpc())
.policy(profile.getPolicy())
.build();
} else if ("ChainableRamRoleArn".equals(mode)) {
AlibabaCloudCredentialsProvider previousProvider = reloadCredentialsProvider(config, profile.getSourceProfile());
return STSAssumeRoleSessionCredentialsProvider.builder()
.credentialsProvider(previousProvider)
.durationSeconds(profile.getDurationSeconds())
.roleArn(profile.getRoleArn())
.roleSessionName(profile.getRoleSessionName())
.stsRegionId(profile.getStsRegionId())
.enableVpc(profile.getEnableVpc())
.policy(profile.getPolicy())
.externalId(profile.getExternalId())
.build();
} else {
throw new ClientException(String.format("Unsupported profile mode '%s' form CLI credentials file.", mode));
}
}
}
}
throw new ClientException(String.format("Unable to get profile with '%s' form CLI credentials file.", currentProfileName));
}

Config parseProfile(String configFilePath) throws ClientException, IOException {
File configFile = new File(configFilePath);
if (!configFile.exists() || !configFile.isFile() || !configFile.canRead()) {
throw new ClientException(String.format("Unable to open credentials file: %s.", configFile.getAbsolutePath()));
}
Gson gson = new Gson();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(configFile));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
String jsonContent = sb.toString();
return gson.fromJson(jsonContent, Config.class);
} catch (Exception e) {
throw new ClientException(String.format("Failed to parse credential form CLI credentials file: %s.", configFile.getAbsolutePath()));
} finally {
if (br != null) {
br.close();
}
}
}

boolean shouldReloadCredentialsProvider(String profileName) {
return this.credentialsProvider == null || (!StringUtils.isEmpty(this.currentProfileName) && !StringUtils.isEmpty(profileName) && !this.currentProfileName.equals(profileName));
}

String getProfileName() {
return this.currentProfileName;
}

static final class Builder {
private String profileName;

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

CLIProfileCredentialsProvider build() {
return new CLIProfileCredentialsProvider(this);
}
}

static class Config {
@SerializedName("current")
private String current;
@SerializedName("profiles")
private List<Profile> profiles;

public String getCurrent() {
return current;
}

public List<Profile> getProfiles() {
return profiles;
}
}

static class Profile {
@SerializedName("name")
private String name;
@SerializedName("mode")
private String mode;
@SerializedName("access_key_id")
private String accessKeyId;
@SerializedName("access_key_secret")
private String accessKeySecret;
@SerializedName("ram_role_arn")
private String roleArn;
@SerializedName("ram_session_name")
private String roleSessionName;
@SerializedName("expired_seconds")
private Integer durationSeconds;
@SerializedName("sts_region")
private String stsRegionId;
@SerializedName("enable_vpc")
private Boolean enableVpc;
@SerializedName("ram_role_name")
private String ramRoleName;
@SerializedName("oidc_token_file")
private String oidcTokenFile;
@SerializedName("oidc_provider_arn")
private String oidcProviderArn;
@SerializedName("source_profile")
private String sourceProfile;
@SerializedName("policy")
private String policy;
@SerializedName("external_id")
private String externalId;

public String getName() {
return name;
}

public String getMode() {
return mode;
}

public String getAccessKeyId() {
return accessKeyId;
}

public String getAccessKeySecret() {
return accessKeySecret;
}

public String getRoleArn() {
return roleArn;
}

public String getRoleSessionName() {
return roleSessionName;
}

public Integer getDurationSeconds() {
return durationSeconds;
}

public String getStsRegionId() {
return stsRegionId;
}

public Boolean getEnableVpc() {
return enableVpc;
}

public String getRamRoleName() {
return ramRoleName;
}

public String getOidcTokenFile() {
return oidcTokenFile;
}

public String getOidcProviderArn() {
return oidcProviderArn;
}

public String getSourceProfile() {
return sourceProfile;
}

public String getPolicy() {
return policy;
}

public String getExternalId() {
return externalId;
}
}
}
Loading

0 comments on commit 4e7e95f

Please sign in to comment.