From d8e368083db15804cf4c11358c38374b79283e33 Mon Sep 17 00:00:00 2001 From: zpp <865287328@qq.com> Date: Wed, 4 Sep 2024 16:28:44 +0800 Subject: [PATCH] feat: support OIDC credentials provider into default credentials provider chain. --- .../Provider/DefaultCredentialProviderTest.cs | 49 +++++++++++++++---- .../Provider/DefaultCredentialProvider.cs | 16 ++++++ .../Auth/Provider/OIDCCredentialsProvider.cs | 9 +++- .../Properties/AssemblyInfo.cs | 2 + aliyun-net-sdk-core/Utils/EnvironmentUtil.cs | 18 +++++++ 5 files changed, 83 insertions(+), 11 deletions(-) diff --git a/aliyun-net-sdk-core.Tests/Units/Auth/Provider/DefaultCredentialProviderTest.cs b/aliyun-net-sdk-core.Tests/Units/Auth/Provider/DefaultCredentialProviderTest.cs index fd5fb6c74b..55c3162a6d 100644 --- a/aliyun-net-sdk-core.Tests/Units/Auth/Provider/DefaultCredentialProviderTest.cs +++ b/aliyun-net-sdk-core.Tests/Units/Auth/Provider/DefaultCredentialProviderTest.cs @@ -64,7 +64,7 @@ public void GetCredentialFileAlibabaCloudCredentialWithAKType() var defaultCredentialProvider = new DefaultCredentialProvider(profile, null); TestHelper.CreateIniFileWithAkType(); - var credential = (BasicCredentials) defaultCredentialProvider.GetAlibabaCloudClientCredential(); + var credential = (BasicCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); TestHelper.DeleteIniFile(); @@ -81,6 +81,10 @@ Use credential chains [Fact] public void GetCredentialFileAlibabaCloudCredentialWithAKTypeButAKIsEmpty() { + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN", null); + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", null); + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_OIDC_TOKEN_FILE", null); + var profile = DefaultProfile.GetProfile(); profile.DefaultClientName = "default"; var defaultCredentialProvider = new DefaultCredentialProvider(profile, null); @@ -88,7 +92,7 @@ public void GetCredentialFileAlibabaCloudCredentialWithAKTypeButAKIsEmpty() var exception = Assert.Throws(() => { - var credential = (BasicCredentials) defaultCredentialProvider.GetAlibabaCloudClientCredential(); + var credential = (BasicCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); }); TestHelper.DeleteIniFile(); @@ -136,7 +140,7 @@ public void GetCredentialFileAlibabaCloudCredentialWithEcsRamRole() mockDefaultCredentialProvider.Setup(x => x.GetHomePath()).Returns(mockHomePath); var defaultCredentialProvider = mockDefaultCredentialProvider.Object; - var credential = (InstanceProfileCredentials) defaultCredentialProvider.GetAlibabaCloudClientCredential(); + var credential = (InstanceProfileCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); TestHelper.DeleteIniFile(); Assert.NotNull(credential); @@ -157,7 +161,7 @@ public void GetCredentialFileAlibabaCloudCredentialWithFileAndAkExist() var defaultCredentialProvider = new DefaultCredentialProvider(profile, null); - var credential = (BasicCredentials) defaultCredentialProvider.GetCredentialFileAlibabaCloudCredential(); + var credential = (BasicCredentials)defaultCredentialProvider.GetCredentialFileAlibabaCloudCredential(); TestHelper.DeleteIniFile(); Assert.NotNull(credential); @@ -225,7 +229,7 @@ public void GetCredentialFileAlibabaCloudCredentialWithRamRole() var defaultCredentialProvider = mockDefaultCredentialProvider.Object; - var credential = (InstanceProfileCredentials) defaultCredentialProvider.GetAlibabaCloudClientCredential(); + var credential = (InstanceProfileCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); TestHelper.DeleteIniFile(); Assert.NotNull(credential); @@ -253,7 +257,7 @@ public void GetCredentialFileAlibabaCloudCredentialWithRsaKey() var defaultCredentialProvider = mockDefaultCredentialProvider.Object; - var credential = (BasicSessionCredentials) defaultCredentialProvider.GetAlibabaCloudClientCredential(); + var credential = (BasicSessionCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); TestHelper.DeleteIniFile(); Assert.NotNull(credential); @@ -272,7 +276,7 @@ public void GetEnvironmentAlibabaCloudCredentialUseChain() TestHelper.InitializeEnvironmentValue(); var defaultCredentialProvider = new DefaultCredentialProvider(profile, null); - var credential = (BasicCredentials) defaultCredentialProvider.GetAlibabaCloudClientCredential(); + var credential = (BasicCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); Assert.NotNull(credential); Assert.Equal("ACCESS_KEY_ID", credential.GetAccessKeyId()); @@ -293,7 +297,7 @@ public void GetEnvironmentAlibabaCloudCredentialWithEnvAKTest() TestHelper.InitializeEnvironmentValue(); var defaultCredentialProvider = new DefaultCredentialProvider(profile, null); - var credential = (BasicCredentials) defaultCredentialProvider.GetEnvironmentAlibabaCloudCredential(); + var credential = (BasicCredentials)defaultCredentialProvider.GetEnvironmentAlibabaCloudCredential(); Assert.NotNull(credential); Assert.Equal("ACCESS_KEY_ID", credential.GetAccessKeyId()); @@ -309,7 +313,7 @@ public void GetEnvironmentAlibabaCloudCredentialWithEnvAKTest() public void GetEnvironmentClientCredentialWithoutAKTest() { var defaultCredentialProvider = new DefaultCredentialProvider(); - var credential = (BasicCredentials) defaultCredentialProvider.GetEnvironmentAlibabaCloudCredential(); + var credential = (BasicCredentials)defaultCredentialProvider.GetEnvironmentAlibabaCloudCredential(); Assert.Null(credential); } @@ -502,5 +506,32 @@ public void GetRsaKeyPairAlibabaCloudCredentialWithException() Assert.Equal("Missing required variable option for 'default Client'", exception.Message); } + + [Fact] + public void GetOIDCAlibabaCloudCredential() + { + var profile = DefaultProfile.GetProfile(); + var defaultCredentialProvider = new DefaultCredentialProvider(profile, null); + Assert.Null(defaultCredentialProvider.GetOIDCAlibabaCloudCredential()); + + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN", "role_arn"); + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", "oidc_provider_arn"); + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_OIDC_TOKEN_FILE", "oidc_token_file"); + + var mockDefaultCredentialProvider = new Mock(profile, null); + var basicSessionCredential = new BasicSessionCredentials("fakeak", "fakeaks", "fakesessiontoken", 4000); + mockDefaultCredentialProvider.Setup(p => p.GetOIDCAlibabaCloudCredential()).Returns(basicSessionCredential); + defaultCredentialProvider = mockDefaultCredentialProvider.Object; + var credential = (BasicSessionCredentials)defaultCredentialProvider.GetAlibabaCloudClientCredential(); + Assert.NotNull(credential); + Assert.Equal("fakeak", credential.GetAccessKeyId()); + Assert.Equal("fakeaks", credential.GetAccessKeySecret()); + Assert.Equal("fakesessiontoken", credential.GetSessionToken()); + Assert.False(credential.WillSoonExpire()); + + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_ROLE_ARN", null); + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", null); + Environment.SetEnvironmentVariable("ALIBABA_CLOUD_OIDC_TOKEN_FILE", null); + } } } diff --git a/aliyun-net-sdk-core/Auth/Provider/DefaultCredentialProvider.cs b/aliyun-net-sdk-core/Auth/Provider/DefaultCredentialProvider.cs index 235c4a849a..ee9c9a6083 100644 --- a/aliyun-net-sdk-core/Auth/Provider/DefaultCredentialProvider.cs +++ b/aliyun-net-sdk-core/Auth/Provider/DefaultCredentialProvider.cs @@ -17,6 +17,7 @@ * under the License. */ +using System; using System.IO; using Aliyun.Acs.Core.Exceptions; @@ -39,6 +40,8 @@ public class DefaultCredentialProvider private string regionId; private string roleArn; private string roleName; + private string oidcProviderArn; + private string oidcTokenFile; public DefaultCredentialProvider() { @@ -55,6 +58,9 @@ AlibabaCloudCredentialsProvider alibabaCloudCredentialProvider credentialFileLocation = EnvironmentUtil.GetEnvironmentCredentialFile(); roleName = EnvironmentUtil.GetEnvironmentRoleName(); defaultProfile = profile; + roleArn = EnvironmentUtil.GetEnvironmentRoleArn(); + oidcProviderArn = EnvironmentUtil.GetEnvironmentOIDCProviderArn(); + oidcTokenFile = EnvironmentUtil.GetEnvironmentOIDCTokenFile(); this.alibabaCloudCredentialProvider = alibabaCloudCredentialProvider; } @@ -75,6 +81,7 @@ AlibabaCloudCredentialsProvider alibabaCloudCredentialsProvider public AlibabaCloudCredentials GetAlibabaCloudClientCredential() { var credential = GetEnvironmentAlibabaCloudCredential() ?? + GetOIDCAlibabaCloudCredential() ?? GetCredentialFileAlibabaCloudCredential() ?? GetInstanceRamRoleAlibabaCloudCredential(); @@ -86,6 +93,15 @@ public AlibabaCloudCredentials GetAlibabaCloudClientCredential() return credential; } + internal virtual AlibabaCloudCredentials GetOIDCAlibabaCloudCredential() + { + if (string.IsNullOrEmpty(oidcProviderArn) || string.IsNullOrEmpty(roleArn) || string.IsNullOrEmpty(oidcTokenFile)) + { + return null; + } + return new OIDCCredentialsProvider(roleArn, oidcProviderArn, oidcTokenFile, null, null).GetCredentials(); + } + public AlibabaCloudCredentials GetEnvironmentAlibabaCloudCredential() { if (null == accessKeyId || null == accessKeySecret) diff --git a/aliyun-net-sdk-core/Auth/Provider/OIDCCredentialsProvider.cs b/aliyun-net-sdk-core/Auth/Provider/OIDCCredentialsProvider.cs index ec2d1196ee..cb820ea318 100644 --- a/aliyun-net-sdk-core/Auth/Provider/OIDCCredentialsProvider.cs +++ b/aliyun-net-sdk-core/Auth/Provider/OIDCCredentialsProvider.cs @@ -42,7 +42,7 @@ public OIDCCredentialsProvider(string roleArn, string oidcProviderArn, string oi if (string.IsNullOrEmpty(RoleSessionName)) { - RoleSessionName = "DEFAULT_ROLE_SESSION_NAME_FOR_C#_SDK_V1"; + RoleSessionName = GetNewRoleSessionName(); } if (string.IsNullOrEmpty(regionId)) @@ -57,6 +57,11 @@ public OIDCCredentialsProvider(string roleArn, string oidcProviderArn, string oi durationSeconds = 3600; } + public static string GetNewRoleSessionName() + { + return "aliyun-net-sdk-" + DateTime.UtcNow.currentTimeMillis(); + } + public string InvokeAssumeRoleWithOIDC() { var queries = new Dictionary @@ -138,7 +143,7 @@ internal static BasicSessionCredentials ParseCredentials(string body, long durat else if (map.ContainsKey("Credentials")) { var credentialsJson = JsonConvert.SerializeObject(DictionaryUtil.Get(map, "Credentials")); - var credentials = JsonConvert.DeserializeObject> (credentialsJson); + var credentials = JsonConvert.DeserializeObject>(credentialsJson); var accessKeyId = DictionaryUtil.Get(credentials, "AccessKeyId"); var accessKeySecret = DictionaryUtil.Get(credentials, "AccessKeySecret"); var securityToken = DictionaryUtil.Get(credentials, "SecurityToken"); diff --git a/aliyun-net-sdk-core/Properties/AssemblyInfo.cs b/aliyun-net-sdk-core/Properties/AssemblyInfo.cs index e938305365..9d9a78dbdb 100644 --- a/aliyun-net-sdk-core/Properties/AssemblyInfo.cs +++ b/aliyun-net-sdk-core/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -30,3 +31,4 @@ // [assembly: AssemblyVersion("1.5.11.0")] [assembly: AssemblyFileVersion("1.5.11.0")] +[assembly: InternalsVisibleTo("Aliyun.Net.Credentials.UnitTests")] diff --git a/aliyun-net-sdk-core/Utils/EnvironmentUtil.cs b/aliyun-net-sdk-core/Utils/EnvironmentUtil.cs index 286919323a..5f99232947 100644 --- a/aliyun-net-sdk-core/Utils/EnvironmentUtil.cs +++ b/aliyun-net-sdk-core/Utils/EnvironmentUtil.cs @@ -28,6 +28,9 @@ public class EnvironmentUtil private static readonly string ENV_REGION_ID = "ALIBABA_CLOUD_REGION_ID"; private static readonly string ENV_CREDENTIAL_FILE = "ALIBABA_CLOUD_CREDENTIALS_FILE"; private static readonly string ENV_ROLE_NAME = "ALIBABA_CLOUD_ECS_METADATA"; + private static readonly string ENV_ROLE_ARN = "ALIBABA_CLOUD_ROLE_ARN"; + private static readonly string ENV_OIDC_PROVIDER_ARN = "ALIBABA_CLOUD_OIDC_PROVIDER_ARN"; + private static readonly string ENV_OIDC_TOKEN_FILE = "ALIBABA_CLOUD_OIDC_TOKEN_FILE"; public static string GetHomePath() { @@ -68,6 +71,21 @@ public static string GetEnvironmentRoleName() return Environment.GetEnvironmentVariable(ENV_ROLE_NAME) ?? null; } + public static string GetEnvironmentRoleArn() + { + return Environment.GetEnvironmentVariable(ENV_ROLE_ARN) ?? null; + } + + public static string GetEnvironmentOIDCProviderArn() + { + return Environment.GetEnvironmentVariable(ENV_OIDC_PROVIDER_ARN) ?? null; + } + + public static string GetEnvironmentOIDCTokenFile() + { + return Environment.GetEnvironmentVariable(ENV_OIDC_TOKEN_FILE) ?? null; + } + public static string GetComposedPath(string homePath, string slash) { return homePath + slash + ".alibabacloud" + slash + "credentials.ini";