aliyun-net-credentials/Provider/RamRoleArnCredentialProvider.cs (364 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Aliyun.Credentials.Exceptions;
using Aliyun.Credentials.Http;
using Aliyun.Credentials.Models;
using Aliyun.Credentials.Utils;
using Newtonsoft.Json;
namespace Aliyun.Credentials.Provider
{
/// <summary>
/// <para>By specifying <see href="https://ram.console.aliyun.com/#/role/list">RAM Role</see>, the credential will be able to automatically request maintenance of STS Token.</para>
/// <para>If you want to limit the permissions of STS Token, you can assign value for Policy.</para>
/// </summary>
public class RamRoleArnCredentialProvider : SessionCredentialsProvider
{
/// <summary>
/// Default duration for started sessions. Unit of Second
/// </summary>
public int durationSeconds = 3600;
/// <summary>
/// The arn of the role to be assumed.
/// </summary>
private string roleArn;
/// <summary>
/// An identifier for the assumed role session.
/// </summary>
private string roleSessionName = "credentials-csharp-" + (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
private string regionId = "cn-hangzhou";
private string policy;
/// <summary>
/// Unit of millisecond
/// </summary>
private int connectTimeout = 5000;
private int readTimeout = 10000;
/// <summary>
/// Endpoint of RAM OpenAPI
/// </summary>
private string STSEndpoint = "sts.aliyuncs.com";
private string externalId;
public IAlibabaCloudCredentialsProvider CredentialsProvider { get; set; }
[Obsolete("Use builder instead.")]
public RamRoleArnCredentialProvider(Config config)
{
if (!string.IsNullOrEmpty(config.SecurityToken))
{
CredentialsProvider = new StaticSTSCredentialsProvider(config);
}
else
{
CredentialsProvider = new StaticAKCredentialsProvider(config);
}
roleArn = config.RoleArn ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN");
connectTimeout = config.ConnectTimeout > 0 ? config.ConnectTimeout : connectTimeout;
readTimeout = config.Timeout > 0 ? config.Timeout : readTimeout;
durationSeconds = config.RoleSessionExpiration > 0 ? config.RoleSessionExpiration : durationSeconds;
policy = config.Policy;
roleSessionName = config.RoleSessionName ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_SESSION_NAME") ?? roleSessionName;
STSEndpoint = config.STSEndpoint ?? STSEndpoint;
externalId = config.ExternalId;
}
[Obsolete("Use builder instead.")]
public RamRoleArnCredentialProvider(string accessKeyId, string accessKeySecret, string roleArn)
{
CredentialsProvider = new StaticAKCredentialsProvider(accessKeyId, accessKeySecret);
this.roleArn = roleArn ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN");
}
[Obsolete("Use builder instead.")]
public RamRoleArnCredentialProvider(IAlibabaCloudCredentialsProvider provider, string roleArn)
{
CredentialsProvider = ParameterHelper.ValidateNotNull(provider, "Provider", "Must specify a previous credentials provider to asssume role.");
this.roleArn = roleArn ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN");
}
[Obsolete("Use builder instead.")]
public RamRoleArnCredentialProvider(IAlibabaCloudCredentialsProvider provider, string roleArn, int durationSeconds,
string roleSessionName) : this(provider, roleArn)
{
this.roleSessionName = roleSessionName ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_SESSION_NAME") ?? this.roleSessionName;
this.durationSeconds = durationSeconds;
}
[Obsolete("Use builder instead.")]
public RamRoleArnCredentialProvider(string accessKeyId, string accessKeySecret, string roleSessionName,
string roleArn, string regionId, string policy) : this(accessKeyId, accessKeySecret, roleArn)
{
this.roleSessionName = roleSessionName ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_SESSION_NAME") ?? this.roleSessionName;
this.regionId = regionId;
this.policy = policy;
}
[Obsolete("Use builder instead.")]
public RamRoleArnCredentialProvider(IAlibabaCloudCredentialsProvider provider, string roleSessionName,
string roleArn, string regionId, string policy) : this(provider, roleArn)
{
this.roleSessionName = roleSessionName ?? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_SESSION_NAME") ?? this.roleSessionName;
this.regionId = regionId;
this.policy = policy;
}
private RamRoleArnCredentialProvider(Builder builder): base(builder)
{
this.durationSeconds = (builder.durationSeconds == null || builder.durationSeconds == 0) ? 3600 : builder.durationSeconds.Value;
if (this.durationSeconds < 900)
{
throw new CredentialException("Session duration should be in the range of 900s - max session duration");
}
this.roleSessionName = string.IsNullOrEmpty(builder.roleSessionName)
? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_SESSION_NAME")
?? "credentials-csharp-" + (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
: builder.roleSessionName;
this.regionId = string.IsNullOrEmpty(builder.regionId) ? "cn-hangzhou" : builder.regionId;
this.roleArn = string.IsNullOrEmpty(builder.roleArn) ? Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN") : builder.roleArn;
this.policy = builder.policy;
this.connectTimeout = (builder.connectTimeout == null || builder.connectTimeout <= 0) ? 5000 : builder.connectTimeout.Value;
this.readTimeout = (builder.readTimeout == null || builder.readTimeout <= 0) ? 10000 : builder.readTimeout.Value;
this.externalId = builder.externalId;
this.STSEndpoint = builder.stsEndpoint;
if (string.IsNullOrEmpty(builder.stsEndpoint))
{
this.STSEndpoint = string.Format("sts{0}.aliyuncs.com", AuthUtils.GetStsRegionWithVpc(builder.stsRegionId, builder.enableVpc));
}
if (builder.credentialsProvider != null)
{
this.CredentialsProvider = builder.credentialsProvider;
}
else if (builder.securityToken == null)
{
this.CredentialsProvider = new StaticAKCredentialsProvider.Builder()
.AccessKeyId(builder.accessKeyId)
.AccessKeySecret(builder.accessKeySecret)
.Build();
}
else
{
this.CredentialsProvider = new StaticSTSCredentialsProvider.Builder()
.AccessKeyId(builder.accessKeyId)
.AccessKeySecret(builder.accessKeySecret)
.SecurityToken(builder.securityToken)
.Build();
}
}
public class Builder : SessionCredentialsProvider.Builder
{
internal int? durationSeconds;
internal string roleSessionName;
internal string regionId;
internal string roleArn;
internal string policy;
internal int? connectTimeout;
internal int? readTimeout;
internal string stsEndpoint;
internal IAlibabaCloudCredentialsProvider credentialsProvider;
internal string externalId;
internal string stsRegionId;
internal bool? enableVpc;
internal string accessKeyId;
internal string accessKeySecret;
internal string securityToken;
public Builder DurationSeconds(int? durationSeconds)
{
this.durationSeconds = durationSeconds;
return this;
}
public Builder RoleSessionName(string roleSessionName)
{
this.roleSessionName = roleSessionName;
return this;
}
public Builder RegionId(string regionId)
{
this.regionId = regionId;
return this;
}
public Builder RoleArn(string roleArn)
{
this.roleArn = roleArn;
return this;
}
public Builder Policy(string policy)
{
this.policy = policy;
return this;
}
public Builder ConnectTimeout(int? connectTimeout)
{
this.connectTimeout = connectTimeout;
return this;
}
public Builder ReadTimeout(int? readTimeout)
{
this.readTimeout = readTimeout;
return this;
}
public Builder STSEndpoint(string stsEndpoint)
{
this.stsEndpoint = stsEndpoint;
return this;
}
public Builder CredentialsProvider(IAlibabaCloudCredentialsProvider credentialsProvider)
{
this.credentialsProvider = credentialsProvider;
return this;
}
public Builder ExternalId(string externalId)
{
this.externalId = externalId;
return this;
}
public Builder StsRegionId(string stsRegionId)
{
this.stsRegionId = stsRegionId;
return this;
}
public Builder EnableVpc(bool? enableVpc)
{
this.enableVpc = enableVpc;
return this;
}
public Builder AccessKeyId(string accessKeyId)
{
this.accessKeyId = accessKeyId;
return this;
}
public Builder AccessKeySecret(string accessKeySecret)
{
this.accessKeySecret = accessKeySecret;
return this;
}
public Builder SecurityToken(string securityToken)
{
this.securityToken = securityToken;
return this;
}
public RamRoleArnCredentialProvider Build()
{
return new RamRoleArnCredentialProvider(this);
}
}
public override RefreshResult<CredentialModel> RefreshCredentials()
{
CompatibleUrlConnClient client = new CompatibleUrlConnClient();
return CreateCredential(client);
}
public override async Task<RefreshResult<CredentialModel>> RefreshCredentialsAsync()
{
CompatibleUrlConnClient client = new CompatibleUrlConnClient();
return await CreateCredentialAsync(client);
}
private RefreshResult<CredentialModel> CreateCredential(IConnClient client)
{
return GetNewSessionCredentials(client);
}
private async Task<RefreshResult<CredentialModel>> CreateCredentialAsync(IConnClient client)
{
return await GetNewSessionCredentialsAsync(client);
}
private RefreshResult<CredentialModel> GetNewSessionCredentials(IConnClient client)
{
HttpRequest httpRequest = new HttpRequest();
httpRequest.SetCommonUrlParameters();
httpRequest.AddUrlParameter("Action", "AssumeRole");
httpRequest.AddUrlParameter("Format", "JSON");
httpRequest.AddUrlParameter("Version", "2015-04-01");
httpRequest.AddUrlParameter("DurationSeconds", durationSeconds.ToString());
httpRequest.AddUrlParameter("RoleArn", this.roleArn);
CredentialModel previousCredentials = CredentialsProvider.GetCredentials();
ParameterHelper.ValidateNotNull(previousCredentials, "OriginalCredentials", "Unable to load original credentials from the providers in RAM role arn.");
httpRequest.AddUrlParameter("AccessKeyId", previousCredentials.AccessKeyId);
httpRequest.AddUrlParameter("SecurityToken", previousCredentials.SecurityToken);
httpRequest.AddUrlParameter("RoleSessionName", this.roleSessionName);
if (policy != null)
{
httpRequest.AddUrlParameter("Policy", this.policy);
}
if (externalId != null)
{
httpRequest.AddUrlParameter("ExternalId", this.externalId);
}
httpRequest.Method = MethodType.GET;
httpRequest.ConnectTimeout = connectTimeout;
httpRequest.ReadTimeout = readTimeout;
string strToSign = ParameterHelper.ComposeStringToSign(MethodType.GET, httpRequest.UrlParameters);
string signature = ParameterHelper.SignString(strToSign, previousCredentials.AccessKeySecret + "&");
httpRequest.AddUrlParameter("Signature", signature);
httpRequest.Url = ParameterHelper.ComposeUrl(STSEndpoint, httpRequest.UrlParameters,
"https");
HttpResponse httpResponse = client.DoAction(httpRequest);
Dictionary<string, object> map =
JsonConvert.DeserializeObject<Dictionary<string, object>>(httpResponse.GetHttpContentString());
if (map.ContainsKey("Credentials"))
{
string credentialsJson = JsonConvert.SerializeObject(DictionaryUtil.Get(map, "Credentials"));
Dictionary<string, string> credentials =
JsonConvert.DeserializeObject<Dictionary<string, string>>(credentialsJson);
string expirationStr =
DictionaryUtil.Get(credentials, "Expiration").Replace('T', ' ').Replace('Z', ' ');
var dt = Convert.ToDateTime(expirationStr);
long expiration = dt.GetTimeMillis();
CredentialModel credentialModel = new CredentialModel
{
AccessKeyId = DictionaryUtil.Get(credentials, "AccessKeyId"),
AccessKeySecret = DictionaryUtil.Get(credentials, "AccessKeySecret"),
SecurityToken = DictionaryUtil.Get(credentials, "SecurityToken"),
Expiration = expiration,
Type = AuthConstant.RamRoleArn,
ProviderName = string.Format("{0}/{1}", this.GetProviderName(),
string.IsNullOrEmpty(previousCredentials.ProviderName)
? CredentialsProvider.GetProviderName()
: previousCredentials.ProviderName)
};
return new RefreshResult<CredentialModel>(credentialModel, GetStaleTime(expiration));
}
throw new CredentialException(JsonConvert.SerializeObject(map));
}
private async Task<RefreshResult<CredentialModel>> GetNewSessionCredentialsAsync(IConnClient client)
{
HttpRequest httpRequest = new HttpRequest();
httpRequest.SetCommonUrlParameters();
httpRequest.AddUrlParameter("Action", "AssumeRole");
httpRequest.AddUrlParameter("Format", "JSON");
httpRequest.AddUrlParameter("Version", "2015-04-01");
httpRequest.AddUrlParameter("DurationSeconds", durationSeconds.ToString());
httpRequest.AddUrlParameter("RoleArn", this.roleArn);
CredentialModel previousCredentials = await CredentialsProvider.GetCredentialsAsync();
ParameterHelper.ValidateNotNull(previousCredentials, "OriginalCredentials", "Unable to load original credentials from the providers in RAM role arn.");
httpRequest.AddUrlParameter("AccessKeyId", previousCredentials.AccessKeyId);
httpRequest.AddUrlParameter("SecurityToken", previousCredentials.SecurityToken);
httpRequest.AddUrlParameter("RoleSessionName", this.roleSessionName);
if (policy != null)
{
httpRequest.AddUrlParameter("Policy", this.policy);
}
if (externalId != null)
{
httpRequest.AddUrlParameter("ExternalId", this.externalId);
}
httpRequest.Method = MethodType.GET;
httpRequest.ConnectTimeout = connectTimeout;
httpRequest.ReadTimeout = readTimeout;
string strToSign = ParameterHelper.ComposeStringToSign(MethodType.GET, httpRequest.UrlParameters);
string signature = ParameterHelper.SignString(strToSign, previousCredentials.AccessKeySecret + "&");
httpRequest.AddUrlParameter("Signature", signature);
httpRequest.Url = ParameterHelper.ComposeUrl(STSEndpoint, httpRequest.UrlParameters,
"https");
HttpResponse httpResponse = await client.DoActionAsync(httpRequest);
Dictionary<string, object> map =
JsonConvert.DeserializeObject<Dictionary<string, object>>(httpResponse.GetHttpContentString());
if (map.ContainsKey("Credentials"))
{
string credentialsJson = JsonConvert.SerializeObject(DictionaryUtil.Get(map, "Credentials"));
Dictionary<string, string> credentials =
JsonConvert.DeserializeObject<Dictionary<string, string>>(credentialsJson);
string expirationStr =
DictionaryUtil.Get(credentials, "Expiration").Replace('T', ' ').Replace('Z', ' ');
var dt = Convert.ToDateTime(expirationStr);
long expiration = dt.GetTimeMillis();
CredentialModel credentialModel = new CredentialModel
{
AccessKeyId = DictionaryUtil.Get(credentials, "AccessKeyId"),
AccessKeySecret = DictionaryUtil.Get(credentials, "AccessKeySecret"),
SecurityToken = DictionaryUtil.Get(credentials, "SecurityToken"),
Expiration = expiration,
Type = AuthConstant.RamRoleArn,
ProviderName = string.Format("{0}/{1}", this.GetProviderName(),
string.IsNullOrEmpty(previousCredentials.ProviderName)
? CredentialsProvider.GetProviderName()
: previousCredentials.ProviderName)
};
return new RefreshResult<CredentialModel>(credentialModel, GetStaleTime(expiration));
}
throw new CredentialException(JsonConvert.SerializeObject(map));
}
public override string GetProviderName()
{
return "ram_role_arn";
}
public string GetSTSEndpoint()
{
return this.STSEndpoint;
}
public string GetExternalId()
{
return this.externalId;
}
}
}