diff --git a/generator/.DevConfigs/8a48524d-da8b-4c04-b57e-ad196a51debb.json b/generator/.DevConfigs/8a48524d-da8b-4c04-b57e-ad196a51debb.json new file mode 100644 index 000000000000..f84c715b6532 --- /dev/null +++ b/generator/.DevConfigs/8a48524d-da8b-4c04-b57e-ad196a51debb.json @@ -0,0 +1,9 @@ +{ + "core": { + "changeLogMessages": [ + "Support Account ID based endpoints. Account-based endpoints help ensure high performance and scalability by using your AWS account ID to route requests for services that support this feature. For more information visit [account id based endpoints on our docs](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html)." + ], + "type": "patch", + "updateMinimum": true + } + } \ No newline at end of file diff --git a/sdk/src/Core/Amazon.Runtime/CredentialManagement/AWSCredentialsFactory.cs b/sdk/src/Core/Amazon.Runtime/CredentialManagement/AWSCredentialsFactory.cs index f6817ed03f93..8c8a7c7e56eb 100644 --- a/sdk/src/Core/Amazon.Runtime/CredentialManagement/AWSCredentialsFactory.cs +++ b/sdk/src/Core/Amazon.Runtime/CredentialManagement/AWSCredentialsFactory.cs @@ -202,44 +202,17 @@ private static AWSCredentials GetAWSCredentialsInternal( switch (profileType) { case CredentialProfileType.Basic: - case CredentialProfileType.BasicWithServices: - case CredentialProfileType.BasicWithGlobalEndpoint: - case CredentialProfileType.BasicWithServicesAndGlobalEndpoint: - return new BasicAWSCredentials(options.AccessKey, options.SecretKey); + return new BasicAWSCredentials(options.AccessKey, options.SecretKey, options.AwsAccountId); case CredentialProfileType.Session: - case CredentialProfileType.SessionWithServices: - case CredentialProfileType.SessionWithGlobalEndpoint: - case CredentialProfileType.SessionWithServicesAndGlobalEndpoint: - return new SessionAWSCredentials(options.AccessKey, options.SecretKey, options.Token); + return new SessionAWSCredentials(options.AccessKey, options.SecretKey, options.Token, options.AwsAccountId); case CredentialProfileType.AssumeRole: - case CredentialProfileType.AssumeRoleWithServices: - case CredentialProfileType.AssumeRoleWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleExternal: - case CredentialProfileType.AssumeRoleExternalWithServices: - case CredentialProfileType.AssumeRoleExternalWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleExternalWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleMFA: - case CredentialProfileType.AssumeRoleMFAWithServices: - case CredentialProfileType.AssumeRoleMFAWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleMFAWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleExternalMFA: - case CredentialProfileType.AssumeRoleExternalMFAWithServices: - case CredentialProfileType.AssumeRoleExternalMFAWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleExternalMFAWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleSessionName: - case CredentialProfileType.AssumeRoleSessionNameWithServices: - case CredentialProfileType.AssumeRoleSessionNameWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleSessionNameWithServicesAndGlobalEndpoint: - case CredentialProfileType.AssumeRoleMFASessionNameWithServices: - case CredentialProfileType.AssumeRoleMFASessionNameWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleMFASessionNameWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleExternalSessionName: case CredentialProfileType.AssumeRoleMFASessionName: case CredentialProfileType.AssumeRoleExternalMFASessionName: - case CredentialProfileType.AssumeRoleExternalMFASessionNameWithServices: - case CredentialProfileType.AssumeRoleExternalMFASessionNameWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleExternalMFASessionNameWithServicesAndGlobalEndpoint: if (profileName != null) { if (profileLoopAvoidance == null) @@ -278,13 +251,7 @@ private static AWSCredentials GetAWSCredentialsInternal( }; return new AssumeRoleAWSCredentials(sourceCredentials, options.RoleArn, roleSessionName, assumeRoleOptions); case CredentialProfileType.AssumeRoleCredentialSource: - case CredentialProfileType.AssumeRoleCredentialSourceWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleCredentialSourceWithServices: - case CredentialProfileType.AssumeRoleCredentialSourceWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleCredentialSourceSessionName: - case CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithServices: - case CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithServicesAndGlobalEndpoint: // get credentials specified by credentialSource try { @@ -304,13 +271,7 @@ private static AWSCredentials GetAWSCredentialsInternal( assumeRoleOptions = new AssumeRoleAWSCredentialsOptions(); return new AssumeRoleAWSCredentials(sourceCredentials, options.RoleArn, roleSessionName, assumeRoleOptions); case CredentialProfileType.AssumeRoleWithWebIdentity: - case CredentialProfileType.AssumeRoleWithWebIdentityWithServices: - case CredentialProfileType.AssumeRoleWithWebIdentityWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleWithWebIdentityWithServicesAndGlobalEndpoint: case CredentialProfileType.AssumeRoleWithWebIdentitySessionName: - case CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithServices: - case CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithGlobalEndpoint: - case CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithServicesAndGlobalEndpoint: return new AssumeRoleWithWebIdentityCredentials(options.WebIdentityTokenFile, options.RoleArn, options.RoleSessionName); case CredentialProfileType.SSO: @@ -329,13 +290,7 @@ private static AWSCredentials GetAWSCredentialsInternal( } case CredentialProfileType.SAMLRole: - case CredentialProfileType.SAMLRoleWithServices: - case CredentialProfileType.SAMLRoleWithGlobalEndpoint: - case CredentialProfileType.SAMLRoleWithServicesAndGlobalEndpoint: case CredentialProfileType.SAMLRoleUserIdentity: - case CredentialProfileType.SAMLRoleUserIdentityWithServices: - case CredentialProfileType.SAMLRoleUserIdentityWithGlobalEndpoint: - case CredentialProfileType.SAMLRoleUserIdentityWithServicesAndGlobalEndpoint: if (UserCrypto.IsUserCryptAvailable) { @@ -353,7 +308,7 @@ private static AWSCredentials GetAWSCredentialsInternal( return ThrowOrReturnNull("Federated credentials are not available on this platform.", null, throwIfInvalid); } case CredentialProfileType.CredentialProcess: - return new ProcessAWSCredentials(options.CredentialProcess); + return new ProcessAWSCredentials(options.CredentialProcess, options.AwsAccountId); default: var defaultMessage = profileName == null diff --git a/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfile.cs b/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfile.cs index 2128112bcd73..f0450d5d0a69 100644 --- a/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfile.cs +++ b/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfile.cs @@ -161,6 +161,21 @@ internal Dictionary> NestedProperties /// public string ClientAppId { get; set; } + /// + /// The name of the section which contains the custom endpoints for a service or services. + /// For example: + /// [profile foo] + /// services = bar + /// [services bar] + /// s3 = + /// endpoint_url = https://custom-endpoint-s3:80 + /// ec2 = + /// endpoint_url = https://custome-endpoint_ec2:80 + /// This will tell the SDK to look for custom endpoints in "bar" for the profile "foo. + /// A single Services section can contain configurations for multiple services. + /// + public string Services { get; set; } + /// /// Determines the behavior for calculating checksums for request payloads. diff --git a/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfileOptions.cs b/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfileOptions.cs index 35683e2fd3c8..f07ddb9291bb 100644 --- a/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfileOptions.cs +++ b/sdk/src/Core/Amazon.Runtime/CredentialManagement/CredentialProfileOptions.cs @@ -89,24 +89,6 @@ public class CredentialProfileOptions /// Absolute path to the file on disk containing an OIDC token. /// public string WebIdentityTokenFile { get; set; } - /// - /// The name of the section which contains the custom endpoints for a service or services. - /// For example: - /// [profile foo] - /// services = bar - /// [services bar] - /// s3 = - /// endpoint_url = https://custom-endpoint-s3:80 - /// ec2 = - /// endpoint_url = https://custome-endpoint_ec2:80 - /// This will tell the SDK to look for custom endpoints in "bar" for the profile "foo. - /// A single Services section can contain configurations for multiple services. - /// - public string Services { get; set; } - /// - /// The global endpoint to use for a profile. Service specific endpoints will always override this value. - /// - public string EndpointUrl { get; set; } /// /// The AWS account ID that temporary AWS credentials will be resolved for using AWS SSO. @@ -139,7 +121,12 @@ public class CredentialProfileOptions /// Provided by the SSO service via the web console. /// public string SsoStartUrl { get; set; } - + + /// + /// The account id to use for account id based endpoint routing + /// + public string AwsAccountId { get; set; } + /// /// Return true the properties are all null or empty, false otherwise. /// @@ -159,15 +146,14 @@ internal bool IsEmpty string.IsNullOrEmpty(SourceProfile) && string.IsNullOrEmpty(Token) && string.IsNullOrEmpty(CredentialProcess) && - string.IsNullOrEmpty(Services) && - string.IsNullOrEmpty(EndpointUrl) && string.IsNullOrEmpty(SsoAccountId) && string.IsNullOrEmpty(SsoRegion) && string.IsNullOrEmpty(SsoRegistrationScopes) && string.IsNullOrEmpty(SsoRoleName) && string.IsNullOrEmpty(SsoStartUrl) && string.IsNullOrEmpty(SsoSession) && - string.IsNullOrEmpty(WebIdentityTokenFile); + string.IsNullOrEmpty(WebIdentityTokenFile) && + string.IsNullOrEmpty(AwsAccountId); } } public override string ToString() @@ -181,8 +167,6 @@ public override string ToString() "RoleSessionName=" + RoleSessionName + ", " + "SecretKey=XXXXX, " + "SourceProfile=" + SourceProfile + ", " + - "EndpointUrl=" + EndpointUrl + ", " + - "Services=" + Services + ", " + "Token=" + Token + ", " + "UserIdentity=" + UserIdentity + ", " + "CredentialProcess=" + CredentialProcess + @@ -193,6 +177,7 @@ public override string ToString() ", " + "SsoRoleName=" + SsoRoleName + ", " + "SsoStartUrl=" + SsoStartUrl + ", " + "SsoSession=" + SsoSession + + ", " + "AwsAccountId=" + AwsAccountId + "]"; } @@ -206,13 +191,13 @@ public override bool Equals(object obj) return false; return AWSSDKUtils.AreEqual( - new object[] { AccessKey, EndpointName, ExternalID, MfaSerial, RoleArn, RoleSessionName, SecretKey, SourceProfile, Token, UserIdentity, CredentialProcess, WebIdentityTokenFile, SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession, Services, EndpointUrl }, - new object[] { po.AccessKey, po.EndpointName, po.ExternalID, po.MfaSerial, po.RoleArn, po.RoleSessionName, po.SecretKey, po.SourceProfile, po.Token, po.UserIdentity, po.CredentialProcess, po.WebIdentityTokenFile, po.SsoAccountId, po.SsoRegion, po.SsoRegistrationScopes, po.SsoRoleName, po.SsoStartUrl, po.SsoSession, po.Services, po.EndpointUrl }); + new object[] { AccessKey, EndpointName, ExternalID, MfaSerial, RoleArn, RoleSessionName, SecretKey, SourceProfile, Token, UserIdentity, CredentialProcess, WebIdentityTokenFile, SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession, AwsAccountId }, + new object[] { po.AccessKey, po.EndpointName, po.ExternalID, po.MfaSerial, po.RoleArn, po.RoleSessionName, po.SecretKey, po.SourceProfile, po.Token, po.UserIdentity, po.CredentialProcess, po.WebIdentityTokenFile, po.SsoAccountId, po.SsoRegion, po.SsoRegistrationScopes, po.SsoRoleName, po.SsoStartUrl, po.SsoSession, po.AwsAccountId }); } public override int GetHashCode() { - return Hashing.Hash(AccessKey, EndpointName, ExternalID, MfaSerial, RoleArn, RoleSessionName, SecretKey, SourceProfile, Token, UserIdentity, CredentialProcess, WebIdentityTokenFile, SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession, Services, EndpointUrl); + return Hashing.Hash(AccessKey, EndpointName, ExternalID, MfaSerial, RoleArn, RoleSessionName, SecretKey, SourceProfile, Token, UserIdentity, CredentialProcess, WebIdentityTokenFile, SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession, AwsAccountId); } } } diff --git a/sdk/src/Core/Amazon.Runtime/CredentialManagement/Internal/CredentialProfileTypeDetector.cs b/sdk/src/Core/Amazon.Runtime/CredentialManagement/Internal/CredentialProfileTypeDetector.cs index 8061afebbf4d..70563f01e048 100644 --- a/sdk/src/Core/Amazon.Runtime/CredentialManagement/Internal/CredentialProfileTypeDetector.cs +++ b/sdk/src/Core/Amazon.Runtime/CredentialManagement/Internal/CredentialProfileTypeDetector.cs @@ -41,56 +41,6 @@ public enum CredentialProfileType AssumeRoleExternalMFASessionName, AssumeRoleMFASessionName, SSO, - AssumeRoleWithServices, - AssumeRoleWithGlobalEndpoint, - AssumeRoleWithServicesAndGlobalEndpoint, - AssumeRoleCredentialSourceWithGlobalEndpoint, - AssumeRoleCredentialSourceWithServices, - AssumeRoleCredentialSourceWithServicesAndGlobalEndpoint, - AssumeRoleExternalWithServices, - AssumeRoleExternalWithGlobalEndpoint, - AssumeRoleExternalWithServicesAndGlobalEndpoint, - AssumeRoleExternalMFAWithServices, - AssumeRoleExternalMFAWithGlobalEndpoint, - AssumeRoleExternalMFAWithServicesAndGlobalEndpoint, - AssumeRoleMFAWithServices, - AssumeRoleMFAWithGlobalEndpoint, - AssumeRoleMFAWithServicesAndGlobalEndpoint, - BasicWithServices, - BasicWithGlobalEndpoint, - BasicWithServicesAndGlobalEndpoint, - AssumeRoleWithWebIdentityWithServices, - AssumeRoleWithWebIdentityWithGlobalEndpoint, - AssumeRoleWithWebIdentityWithServicesAndGlobalEndpoint, - AssumeRoleWithWebIdentitySessionNameWithServices, - AssumeRoleWithWebIdentitySessionNameWithGlobalEndpoint, - AssumeRoleWithWebIdentitySessionNameWithServicesAndGlobalEndpoint, - AssumeRoleSessionNameWithServices, - AssumeRoleSessionNameWithGlobalEndpoint, - AssumeRoleSessionNameWithServicesAndGlobalEndpoint, - AssumeRoleCredentialSourceSessionNameWithServices, - AssumeRoleCredentialSourceSessionNameWithGlobalEndpoint, - AssumeRoleCredentialSourceSessionNameWithServicesAndGlobalEndpoint, - AssumeRoleExternalSessionNameWithServices, - AssumeRoleExternalSessionNameWithGlobalEndpoint, - AssumeRoleExternalSessionNameWithServicesAndGlobalEndpoint, - AssumeRoleExternalMFASessionNameWithServices, - AssumeRoleExternalMFASessionNameWithGlobalEndpoint, - AssumeRoleExternalMFASessionNameWithServicesAndGlobalEndpoint, - AssumeRoleMFASessionNameWithServices, - AssumeRoleMFASessionNameWithGlobalEndpoint, - AssumeRoleMFASessionNameWithServicesAndGlobalEndpoint, - SAMLRoleWithServices, - SAMLRoleWithGlobalEndpoint, - SAMLRoleWithServicesAndGlobalEndpoint, - SAMLRoleUserIdentityWithServices, - SAMLRoleUserIdentityWithGlobalEndpoint, - SAMLRoleUserIdentityWithServicesAndGlobalEndpoint, - SessionWithServices, - SessionWithGlobalEndpoint, - SessionWithServicesAndGlobalEndpoint, - - } public enum CredentialSourceType @@ -107,7 +57,7 @@ public static class CredentialProfileTypeDetector private const string AssumeRoleCredentials = "Assume Role"; private const string AssumeRoleWithWebIdentityCredentials = "Assume Role with OIDC Web Identity"; private const string SAMLCredentials = "SAML"; - + private const string Services = "Services"; private const string AccessKey = "AccessKey"; private const string CredentialSource = "CredentialSource"; @@ -117,12 +67,13 @@ public static class CredentialProfileTypeDetector private const string RoleArn = "RoleArn"; private const string RoleSessionName = "RoleSessionName"; private const string SecretKey = "SecretKey"; - private const string SourceProfile = "SourceProfile"; + private const string SourceProfile = "SourceProfile"; private const string Token = "Token"; private const string WebIdentityTokenFile = "WebIdentityTokenFile"; private const string UserIdentity = "UserIdentity"; private const string CredentialProcess = "CredentialProcess"; private const string EndpointUrl = "EndpointUrl"; + private const string AwsAccountId = "AwsAccountId"; private const string SsoAccountId = nameof(CredentialProfileOptions.SsoAccountId); private const string SsoRegion = nameof(CredentialProfileOptions.SsoRegion); @@ -132,607 +83,119 @@ public static class CredentialProfileTypeDetector private const string SsoSession = nameof(CredentialProfileOptions.SsoSession); private static HashSet SsoProperties = new HashSet( - new string[] {SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession}, + new string[] { SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession }, StringComparer.OrdinalIgnoreCase); - - private static Dictionary> TypePropertyDictionary = - new Dictionary>() + private static Dictionary>> TypePropertyDictionary = + new Dictionary>>() { - { - CredentialProfileType.CredentialProcess, new HashSet() - { - CredentialProcess - } - }, - { - CredentialProfileType.AssumeRole, new HashSet() - { - RoleArn, - SourceProfile, - } - }, - { - CredentialProfileType.AssumeRoleWithServices, new HashSet() - { - RoleArn, - SourceProfile, - Services - } - }, - { - CredentialProfileType.AssumeRoleWithGlobalEndpoint, new HashSet() - { - RoleArn, - SourceProfile, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleWithServicesAndGlobalEndpoint, new HashSet() - { - RoleArn, - SourceProfile, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleCredentialSource, new HashSet() - { - RoleArn, - CredentialSource, - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceWithGlobalEndpoint, new HashSet() - { - RoleArn, - CredentialSource, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceWithServices, new HashSet() - { - RoleArn, - CredentialSource, - Services - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceWithServicesAndGlobalEndpoint, new HashSet() - { - RoleArn, - CredentialSource, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleExternal, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - } - }, - { - CredentialProfileType.AssumeRoleExternalWithServices, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - Services - } - }, - { - CredentialProfileType.AssumeRoleExternalWithGlobalEndpoint, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleExternalWithServicesAndGlobalEndpoint, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.AssumeRoleExternalMFA, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - } - }, - { - CredentialProfileType.AssumeRoleExternalMFAWithServices, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - Services - } - }, - { - CredentialProfileType.AssumeRoleExternalMFAWithGlobalEndpoint, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleExternalMFAWithServicesAndGlobalEndpoint, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentity, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentityWithServices, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - Services - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentityWithGlobalEndpoint, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentityWithServicesAndGlobalEndpoint, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentitySessionName, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - RoleSessionName - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithServices, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - RoleSessionName, - Services - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithGlobalEndpoint, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - RoleSessionName, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithServicesAndGlobalEndpoint, new HashSet() - { - RoleArn, - WebIdentityTokenFile, - RoleSessionName, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleMFA, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - } - }, - { - CredentialProfileType.AssumeRoleMFAWithServices, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - Services - } - }, - { - CredentialProfileType.AssumeRoleMFAWithGlobalEndpoint, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleMFAWithServicesAndGlobalEndpoint, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.Basic, new HashSet() - { - AccessKey, - SecretKey, - } - }, - { - CredentialProfileType.BasicWithServices, new HashSet() - { - AccessKey, - SecretKey, - Services - } - }, - { - CredentialProfileType.BasicWithGlobalEndpoint, new HashSet() - { - AccessKey, - SecretKey, - EndpointUrl - } - }, - { - CredentialProfileType.BasicWithServicesAndGlobalEndpoint, new HashSet() - { - AccessKey, - SecretKey, - EndpointUrl, - Services - } + { + CredentialProfileType.CredentialProcess, new List>() + { + new HashSet { CredentialProcess } , + new HashSet { CredentialProcess, AwsAccountId } + } }, - { - CredentialProfileType.SAMLRole, new HashSet() - { - EndpointName, - RoleArn, - } - }, - { - CredentialProfileType.SAMLRoleWithServices, new HashSet() - { - EndpointName, - RoleArn, - Services - } - }, - { - CredentialProfileType.SAMLRoleWithGlobalEndpoint, new HashSet() - { - EndpointName, - RoleArn, - EndpointUrl - } - }, - { - CredentialProfileType.SAMLRoleWithServicesAndGlobalEndpoint, new HashSet() - { - EndpointName, - RoleArn, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.SAMLRoleUserIdentity, new HashSet() - { - EndpointName, - RoleArn, - UserIdentity, - } - }, - { - CredentialProfileType.SAMLRoleUserIdentityWithServices, new HashSet() - { - EndpointName, - RoleArn, - UserIdentity, - Services - } - }, - { - CredentialProfileType.SAMLRoleUserIdentityWithGlobalEndpoint, new HashSet() - { - EndpointName, - RoleArn, - UserIdentity, - EndpointUrl - } - }, - { - CredentialProfileType.SAMLRoleUserIdentityWithServicesAndGlobalEndpoint, new HashSet() - - { - EndpointName, - RoleArn, - UserIdentity, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.Session, new HashSet() - { - AccessKey, - SecretKey, - Token, - } - }, - { - CredentialProfileType.SessionWithServices, new HashSet() - { - AccessKey, - SecretKey, - Token, - Services - } - }, - { - CredentialProfileType.SessionWithGlobalEndpoint, new HashSet() - { - AccessKey, - SecretKey, - Token, - EndpointUrl - - } - }, - { - CredentialProfileType.SessionWithServicesAndGlobalEndpoint, new HashSet() - { - AccessKey, - SecretKey, - Token, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.AssumeRoleSessionName, new HashSet() - { - RoleArn, - SourceProfile, - RoleSessionName - } - }, - { - CredentialProfileType.AssumeRoleSessionNameWithServices, new HashSet() - { - RoleArn, - SourceProfile, - RoleSessionName, - Services - } - }, - { - CredentialProfileType.AssumeRoleSessionNameWithGlobalEndpoint, new HashSet() - { - RoleArn, - SourceProfile, - RoleSessionName, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleSessionNameWithServicesAndGlobalEndpoint, new HashSet() - { - RoleArn, - SourceProfile, - RoleSessionName, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceSessionName, new HashSet() - { - RoleArn, - CredentialSource, - RoleSessionName - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithServices, new HashSet() - { - RoleArn, - CredentialSource, - RoleSessionName, - Services - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithGlobalEndpoint, new HashSet() - { - RoleArn, - CredentialSource, - RoleSessionName, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithServicesAndGlobalEndpoint, new HashSet() - { - RoleArn, - CredentialSource, - RoleSessionName, - EndpointUrl, - Services - } - }, - { - CredentialProfileType.AssumeRoleExternalSessionName, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - RoleSessionName - } - }, - { - CredentialProfileType.AssumeRoleExternalSessionNameWithServices, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - RoleSessionName, - Services - } - }, - { - CredentialProfileType.AssumeRoleExternalSessionNameWithGlobalEndpoint, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - RoleSessionName, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleExternalSessionNameWithServicesAndGlobalEndpoint, new HashSet() - { - ExternalID, - RoleArn, - SourceProfile, - RoleSessionName, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleExternalMFASessionName, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName - } - }, - { - CredentialProfileType.AssumeRoleExternalMFASessionNameWithServices, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName, - Services - } - }, - { - CredentialProfileType.AssumeRoleExternalMFASessionNameWithGlobalEndpoint, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleExternalMFASessionNameWithServicesAndGlobalEndpoint, new HashSet() - { - ExternalID, - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleMFASessionName, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName - } - }, - { - CredentialProfileType.AssumeRoleMFASessionNameWithServices, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName, - Services - } - }, - { - CredentialProfileType.AssumeRoleMFASessionNameWithGlobalEndpoint, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName, - EndpointUrl - } - }, - { - CredentialProfileType.AssumeRoleMFASessionNameWithServicesAndGlobalEndpoint, new HashSet() - { - MfaSerial, - RoleArn, - SourceProfile, - RoleSessionName, - Services, - EndpointUrl - } - }, - { - CredentialProfileType.SSO, new HashSet() - { - SsoAccountId, - SsoRegion, - SsoRegistrationScopes, - SsoRoleName, - SsoStartUrl, - SsoSession - } + { + CredentialProfileType.AssumeRole, new List>() + { + new HashSet { RoleArn, SourceProfile }, + new HashSet { RoleArn, SourceProfile, AwsAccountId }, + } + }, + { + CredentialProfileType.AssumeRoleCredentialSource, new List>() + { + new HashSet { RoleArn, CredentialSource }, + new HashSet { RoleArn, CredentialSource, AwsAccountId } + } + }, + { + CredentialProfileType.AssumeRoleExternal, new List>() + { + new HashSet { ExternalID, RoleArn, SourceProfile }, + new HashSet { ExternalID, RoleArn, SourceProfile, AwsAccountId }, + } + }, + { CredentialProfileType.AssumeRoleExternalMFA, new List>() { new HashSet { ExternalID, RoleArn, SourceProfile, MfaSerial } } }, + { + CredentialProfileType.AssumeRoleWithWebIdentity, new List>() + { + new HashSet { RoleArn, WebIdentityTokenFile }, + new HashSet { RoleArn, WebIdentityTokenFile, CredentialSource }, + new HashSet { RoleArn, WebIdentityTokenFile, CredentialSource, AwsAccountId }, + } + }, + { + CredentialProfileType.AssumeRoleWithWebIdentitySessionName, new List>() + { + new HashSet { RoleArn, WebIdentityTokenFile, RoleSessionName }, + new HashSet { RoleArn, WebIdentityTokenFile, RoleSessionName, AwsAccountId } , + } + }, + { + CredentialProfileType.AssumeRoleMFA, new List>() + { + new HashSet { MfaSerial, RoleArn, SourceProfile }, + new HashSet { MfaSerial, RoleArn, SourceProfile, AwsAccountId }, + } + }, + { CredentialProfileType.Basic, new List>() + { + new HashSet { AccessKey, SecretKey }, + new HashSet { AccessKey, SecretKey, AwsAccountId }, + } + }, + { + CredentialProfileType.SAMLRole, new List>() + { + new HashSet { EndpointName, RoleArn }, + new HashSet { EndpointName, RoleArn, AwsAccountId }, + } + }, + { CredentialProfileType.SAMLRoleUserIdentity, new List>() { new HashSet { EndpointName, RoleArn, UserIdentity } } }, + { + CredentialProfileType.Session, new List>() + { + new HashSet { AccessKey, SecretKey, Token }, + new HashSet { AccessKey, SecretKey, Token, AwsAccountId }, + } + }, + { + CredentialProfileType.AssumeRoleSessionName, new List>() + { + new HashSet { RoleArn, SourceProfile, RoleSessionName }, + new HashSet { RoleArn, SourceProfile, RoleSessionName, AwsAccountId }, + } + }, + { + CredentialProfileType.AssumeRoleCredentialSourceSessionName, new List>() + { + new HashSet { RoleArn, CredentialSource, RoleSessionName }, + new HashSet { RoleArn, CredentialSource, RoleSessionName, AwsAccountId}, + } + }, + { + CredentialProfileType.AssumeRoleExternalSessionName, new List>() + { + new HashSet { ExternalID, RoleArn, SourceProfile, RoleSessionName }, + new HashSet { ExternalID, RoleArn, SourceProfile, RoleSessionName, AwsAccountId }, + } + }, + { + CredentialProfileType.AssumeRoleExternalMFASessionName, new List>() + { + new HashSet { ExternalID, MfaSerial, RoleArn, SourceProfile, RoleSessionName }, + new HashSet { ExternalID, MfaSerial, RoleArn, SourceProfile, RoleSessionName, AwsAccountId }, + } + }, + { CredentialProfileType.SSO, new List>() { new HashSet { SsoAccountId, SsoRegion, SsoRegistrationScopes, SsoRoleName, SsoStartUrl, SsoSession } } }, + { + CredentialProfileType.AssumeRoleMFASessionName, new List>() + { + new HashSet { MfaSerial, RoleArn, SourceProfile, RoleSessionName }, + new HashSet { MfaSerial, RoleArn, SourceProfile, RoleSessionName, AwsAccountId }, + } }, }; @@ -740,7 +203,6 @@ public static class CredentialProfileTypeDetector new Dictionary() { { CredentialProfileType.AssumeRole, AssumeRoleCredentials }, - { CredentialProfileType.AssumeRoleWithServices, AssumeRoleCredentials }, { CredentialProfileType.AssumeRoleExternal, AssumeRoleCredentials }, { CredentialProfileType.AssumeRoleExternalMFA, AssumeRoleCredentials }, { CredentialProfileType.AssumeRoleMFA, AssumeRoleCredentials }, @@ -755,9 +217,6 @@ public static class CredentialProfileTypeDetector { CredentialProfileType.SAMLRoleUserIdentity, SAMLCredentials }, { CredentialProfileType.Session, SessionCredentials }, { CredentialProfileType.CredentialProcess, CredentialProcess }, - { CredentialProfileType.BasicWithServices, BasicCredentials }, - { CredentialProfileType.BasicWithGlobalEndpoint, BasicCredentials }, - {CredentialProfileType.BasicWithServicesAndGlobalEndpoint, BasicCredentials }, }; @@ -788,10 +247,12 @@ public static string GetUserFriendlyCredentialType(CredentialProfileType? profil // brute force algorithm - but it's a very small set foreach (var pair in TypePropertyDictionary) { - if (pair.Value.SetEquals(propertyNames)) + foreach (var item in pair.Value) { - // exact match - profileType = pair.Key; + if (item.SetEquals(propertyNames)) + { + profileType = pair.Key; + } } } @@ -800,7 +261,7 @@ public static string GetUserFriendlyCredentialType(CredentialProfileType? profil public static HashSet GetPropertiesForProfileType(CredentialProfileType profileType) { - return new HashSet(TypePropertyDictionary[profileType]); + return new HashSet(TypePropertyDictionary[profileType].FirstOrDefault()); } private static HashSet GetPropertyNames(CredentialProfileOptions profileOptions) diff --git a/sdk/src/Core/Amazon.Runtime/CredentialManagement/NetSDKCredentialsFile.cs b/sdk/src/Core/Amazon.Runtime/CredentialManagement/NetSDKCredentialsFile.cs index 179cd1c0e340..75cc94bb7f26 100644 --- a/sdk/src/Core/Amazon.Runtime/CredentialManagement/NetSDKCredentialsFile.cs +++ b/sdk/src/Core/Amazon.Runtime/CredentialManagement/NetSDKCredentialsFile.cs @@ -107,8 +107,7 @@ public class NetSDKCredentialsFile : ICredentialProfileStore { "SourceProfile", SettingsConstants.SourceProfileField }, { "Token", SettingsConstants.SessionTokenField }, { "UserIdentity", SettingsConstants.UserIdentityField }, - { "Services", SettingsConstants.Services }, - { "EndpointUrl", SettingsConstants.EndpointUrl }, + { "AwsAccountId", SettingsConstants.AwsAccountId }, // Not implemented for NetSDKCredentials. Applicable only // for SharedCredentials { "CredentialProcess" , SettingsConstants.CredentialProcess }, diff --git a/sdk/src/Core/Amazon.Runtime/CredentialManagement/SharedCredentialsFile.cs b/sdk/src/Core/Amazon.Runtime/CredentialManagement/SharedCredentialsFile.cs index 983ecd18905d..06cd7c0d770d 100644 --- a/sdk/src/Core/Amazon.Runtime/CredentialManagement/SharedCredentialsFile.cs +++ b/sdk/src/Core/Amazon.Runtime/CredentialManagement/SharedCredentialsFile.cs @@ -71,6 +71,7 @@ public class SharedCredentialsFile : ICredentialProfileStore private const string AccountIdEndpointModeField = "account_id_endpoint_mode"; private const string RequestChecksumCalculationField = "request_checksum_calculation"; private const string ResponseChecksumValidationField = "response_checksum_validation"; + private const string AwsAccountIdField = "aws_account_id"; private readonly Logger _logger = Logger.GetLogger(typeof(SharedCredentialsFile)); private static readonly HashSet ReservedPropertyNames = new HashSet(StringComparer.OrdinalIgnoreCase) @@ -105,6 +106,7 @@ public class SharedCredentialsFile : ICredentialProfileStore AccountIdEndpointModeField, RequestChecksumCalculationField, ResponseChecksumValidationField, + AwsAccountIdField, }; /// @@ -115,62 +117,20 @@ public class SharedCredentialsFile : ICredentialProfileStore new HashSet() { CredentialProfileType.AssumeRole, - CredentialProfileType.AssumeRoleWithServices, - CredentialProfileType.AssumeRoleWithGlobalEndpoint, - CredentialProfileType.AssumeRoleWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleCredentialSource, - CredentialProfileType.AssumeRoleCredentialSourceWithGlobalEndpoint, - CredentialProfileType.AssumeRoleCredentialSourceWithServices, - CredentialProfileType.AssumeRoleCredentialSourceWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleExternal, - CredentialProfileType.AssumeRoleExternalWithServices, - CredentialProfileType.AssumeRoleExternalWithGlobalEndpoint, - CredentialProfileType.AssumeRoleExternalWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleExternalMFA, - CredentialProfileType.AssumeRoleExternalMFAWithServices, - CredentialProfileType.AssumeRoleExternalMFAWithGlobalEndpoint, - CredentialProfileType.AssumeRoleExternalMFAWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleMFA, - CredentialProfileType.AssumeRoleMFAWithServices, - CredentialProfileType.AssumeRoleMFAWithGlobalEndpoint, - CredentialProfileType.AssumeRoleMFAWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleWithWebIdentity, - CredentialProfileType.AssumeRoleWithWebIdentityWithServices, - CredentialProfileType.AssumeRoleWithWebIdentityWithGlobalEndpoint, - CredentialProfileType.AssumeRoleWithWebIdentityWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleWithWebIdentitySessionName, - CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithServices, - CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithGlobalEndpoint, - CredentialProfileType.AssumeRoleWithWebIdentitySessionNameWithServicesAndGlobalEndpoint, CredentialProfileType.Basic, CredentialProfileType.Session, - CredentialProfileType.SessionWithServices, - CredentialProfileType.SessionWithGlobalEndpoint, - CredentialProfileType.SessionWithServicesAndGlobalEndpoint, CredentialProfileType.CredentialProcess, CredentialProfileType.AssumeRoleSessionName, - CredentialProfileType.AssumeRoleSessionNameWithServices, - CredentialProfileType.AssumeRoleSessionNameWithGlobalEndpoint, - CredentialProfileType.AssumeRoleSessionNameWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleCredentialSourceSessionName, - CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithServices, - CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithGlobalEndpoint, - CredentialProfileType.AssumeRoleCredentialSourceSessionNameWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleExternalSessionName, - CredentialProfileType.AssumeRoleExternalSessionNameWithServices, - CredentialProfileType.AssumeRoleExternalSessionNameWithGlobalEndpoint, - CredentialProfileType.AssumeRoleExternalSessionNameWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleExternalMFASessionName, - CredentialProfileType.AssumeRoleExternalMFASessionNameWithServices, - CredentialProfileType.AssumeRoleExternalMFASessionNameWithGlobalEndpoint, - CredentialProfileType.AssumeRoleExternalMFASessionNameWithServicesAndGlobalEndpoint, CredentialProfileType.AssumeRoleMFASessionName, - CredentialProfileType.AssumeRoleMFASessionNameWithServices, - CredentialProfileType.AssumeRoleMFASessionNameWithGlobalEndpoint, - CredentialProfileType.AssumeRoleMFASessionNameWithServicesAndGlobalEndpoint, - CredentialProfileType.BasicWithGlobalEndpoint, - CredentialProfileType.BasicWithServices, - CredentialProfileType.BasicWithServicesAndGlobalEndpoint, CredentialProfileType.SSO, }; @@ -191,8 +151,7 @@ public class SharedCredentialsFile : ICredentialProfileStore { "UserIdentity", null }, { "CredentialProcess" , "credential_process" }, { "WebIdentityTokenFile", "web_identity_token_file" }, - { "Services", "services" }, - { "EndpointUrl", "endpoint_url" }, + { "AwsAccountId", "aws_account_id" }, { nameof(CredentialProfileOptions.SsoAccountId), SsoAccountId }, { nameof(CredentialProfileOptions.SsoRegion), SsoRegion }, { nameof(CredentialProfileOptions.SsoRegistrationScopes), SsoRegistrationScopes }, @@ -439,9 +398,13 @@ private void RegisterProfileInternal(CredentialProfile profile) if (profile.ClientAppId != null) reservedProperties[ClientAppIdField] = profile.ClientAppId; + if (profile.AccountIdEndpointMode != null) reservedProperties[AccountIdEndpointModeField] = profile.AccountIdEndpointMode.ToString().ToLowerInvariant(); + if (profile.Services != null) + reservedProperties[ServicesField] = profile.Services.ToString().ToLowerInvariant(); + var profileDictionary = PropertyMapping.CombineProfileParts( profile.Options, ReservedPropertyNames, reservedProperties, profile.Properties); @@ -857,6 +820,10 @@ private bool TryGetProfile(string profileName, bool doRefresh, bool isSsoSession } } + string servicesSection = null; + reservedProperties.TryGetValue(ServicesField, out servicesSection); + + AccountIdEndpointMode? accountIdEndpointMode = null; if (reservedProperties.TryGetValue(AccountIdEndpointModeField, out var accountIdEndpointModeString)) { @@ -958,7 +925,8 @@ private bool TryGetProfile(string profileName, bool doRefresh, bool isSsoSession AccountIdEndpointMode = accountIdEndpointMode, RequestChecksumCalculation = requestChecksumCalculation, ResponseChecksumValidation = responseChecksumValidation, - }; + Services = servicesSection + }; if (!IsSupportedProfileType(profile.ProfileType)) { diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleAWSCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleAWSCredentials.cs index 903be96a6b74..007462915d87 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleAWSCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleAWSCredentials.cs @@ -86,7 +86,6 @@ public AssumeRoleAWSCredentials(AWSCredentials sourceCredentials, string roleArn RoleSessionName = roleSessionName; Options = options; - // Make sure to fetch new credentials well before the current credentials expire to avoid // any request being made with expired credentials. PreemptExpiryTime = TimeSpan.FromMinutes(15); diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleImmutableCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleImmutableCredentials.cs index a09abaec6ae2..c750a7b5154f 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleImmutableCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleImmutableCredentials.cs @@ -37,19 +37,35 @@ public class AssumeRoleImmutableCredentials : ImmutableCredentials /// The security token for the credentials. /// The expiration time for the credentials. public AssumeRoleImmutableCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token, DateTime expiration) - : base(awsAccessKeyId, awsSecretAccessKey, token) + : this (awsAccessKeyId, awsSecretAccessKey, token, expiration, null) + { + + + } + + /// + /// Constructs an instance with supplied keys, token, expiration, and account id. When the account id is set + /// and the service supports account id based endpoints, AWS will send the request using the account-based endpoint rather + /// than the regional endpount. Account-based endpoints take the form https://.ddb.region.amazonaws.com + /// the request to + /// + /// The AccessKey for the credentials + /// The SecretKey for the credentials. + /// The security token for the credentials. + /// The expiration time for the credentials. + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012. + public AssumeRoleImmutableCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token, DateTime expiration, string accountId) : base (awsAccessKeyId, awsSecretAccessKey, token, accountId) { if (string.IsNullOrEmpty(token)) throw new ArgumentNullException("token"); Expiration = expiration; } - /// /// Get a copy of this AssumeRoleImmutableCredentials object. /// /// A copy of this object. new public AssumeRoleImmutableCredentials Copy() { - return new AssumeRoleImmutableCredentials(AccessKey, SecretKey, Token, Expiration); + return new AssumeRoleImmutableCredentials(AccessKey, SecretKey, Token, Expiration, AccountId); } public override int GetHashCode() diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleWithWebIdentityCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleWithWebIdentityCredentials.cs index 6c6ed5a684c0..36fdb67675e9 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleWithWebIdentityCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/AssumeRoleWithWebIdentityCredentials.cs @@ -47,7 +47,6 @@ public partial class AssumeRoleWithWebIdentityCredentials : RefreshingAWSCredent public const string WebIdentityTokenFileEnvVariable = "AWS_WEB_IDENTITY_TOKEN_FILE"; public const string RoleArnEnvVariable = "AWS_ROLE_ARN"; public const string RoleSessionNameEnvVariable = "AWS_ROLE_SESSION_NAME"; - private const string RoleSessionNameRegexPattern = @"^[\w+=,.@-]{2,64}$"; #if NET8_0_OR_GREATER diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/BasicAWSCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/BasicAWSCredentials.cs index a31f923d9ad0..dea05f910eb3 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/BasicAWSCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/BasicAWSCredentials.cs @@ -36,13 +36,27 @@ public class BasicAWSCredentials : AWSCredentials /// /// Constructs a BasicAWSCredentials object for the specified accessKey and secretKey. /// - /// - /// - public BasicAWSCredentials(string accessKey, string secretKey) + /// The access key for the credentials. + /// The secret key for the credentials. + public BasicAWSCredentials(string accessKey, string secretKey) : this (accessKey, secretKey, null) + { + } + + /// + /// Constructs a BasicAWSCredentials object for the specified accessKey, secretKey, and accountId. + /// When the account id is set and the service supports account id based endpoints, AWS will send the request + /// using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://.ddb.region.amazonaws.com + /// the request to + /// + /// The access key for the credentials. + /// The secret key for the credentials. + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012 + public BasicAWSCredentials(string accessKey, string secretKey, string accountId) { if (!string.IsNullOrEmpty(accessKey)) { - _credentials = new ImmutableCredentials(accessKey, secretKey, null); + _credentials = new ImmutableCredentials(accessKey, secretKey, null, accountId); } } diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/EnvironmentVariablesAWSCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/EnvironmentVariablesAWSCredentials.cs index 1fa02c07b3d5..9cd528851983 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/EnvironmentVariablesAWSCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/EnvironmentVariablesAWSCredentials.cs @@ -36,6 +36,7 @@ public class EnvironmentVariablesAWSCredentials : AWSCredentials public const string ENVIRONMENT_VARIABLE_ACCESSKEY = "AWS_ACCESS_KEY_ID"; public const string ENVIRONMENT_VARIABLE_SECRETKEY = "AWS_SECRET_ACCESS_KEY"; public const string ENVIRONMENT_VARIABLE_SESSION_TOKEN = "AWS_SESSION_TOKEN"; + public const string ENVIRONMENT_VARIABLE_ACCOUNT_ID = "AWS_ACCOUNT_ID"; // this legacy key was used by previous versions of the AWS SDK for .NET and is // used if no value exists for the standard key for backwards compatibility. @@ -83,10 +84,10 @@ public ImmutableCredentials FetchCredentials() } string sessionToken = Environment.GetEnvironmentVariable(ENVIRONMENT_VARIABLE_SESSION_TOKEN); - + string accountId = Environment.GetEnvironmentVariable(ENVIRONMENT_VARIABLE_ACCOUNT_ID); logger.InfoFormat("Credentials found using environment variables."); - return new ImmutableCredentials(accessKeyId, secretKey, sessionToken); + return new ImmutableCredentials(accessKeyId, secretKey, sessionToken, accountId); } /// diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/GenericContainerCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/GenericContainerCredentials.cs index ab156ece85a1..32c8b25ccbb0 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/GenericContainerCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/GenericContainerCredentials.cs @@ -108,7 +108,7 @@ protected override CredentialsRefreshState GenerateNewCredentials() AWSSDKUtils.Sleep(retry.Next()); } - return new CredentialsRefreshState(new ImmutableCredentials(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.Token), credentials.Expiration); + return new CredentialsRefreshState(new ImmutableCredentials(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.Token, credentials.AccountId), credentials.Expiration); } protected override async Task GenerateNewCredentialsAsync() @@ -148,7 +148,7 @@ protected override async Task GenerateNewCredentialsAsy await Task.Delay(retry.Next()).ConfigureAwait(false); } - return new CredentialsRefreshState(new ImmutableCredentials(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.Token), credentials.Expiration); + return new CredentialsRefreshState(new ImmutableCredentials(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.Token, credentials.AccountId), credentials.Expiration); } /// diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/ImmutableCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/ImmutableCredentials.cs index 349c8a151aae..4bb0e2f0bbd5 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/ImmutableCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/ImmutableCredentials.cs @@ -49,6 +49,10 @@ public class ImmutableCredentials /// /// Gets the AccountId property for the current credentials. + /// The account id is your 12 digit account number with no hypens. For example: 123456789012. + /// When the account id is set and the service supports account id based endpoints, AWS will send the request + /// using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://accountid.ddb.region.amazonaws.com /// public string AccountId { get; private set; } #endregion @@ -76,11 +80,15 @@ public ImmutableCredentials(string awsAccessKeyId, string awsSecretAccessKey, st /// /// Constructs an ImmutableCredentials object with supplied accessKey, secretKey, and aws account id. + /// When the account id is set and the service supports account id based endpoints, AWS will send the request + /// using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://.ddb.region.amazonaws.com /// - /// - /// + /// The access key for the credentials. + /// The secret access key for the credentials. /// Optional. Can be set to null or empty for non-session credentials. - /// Optional. If is set to preferred or required, the account id will be used in endpoint resolution. + /// Optional. If is set to preferred or required, the account id will be used in endpoint resolution. + /// The account id is your 12 digit account number with no hyphens. For example: 123456789012. public ImmutableCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token, string accountId) : this(awsAccessKeyId, awsSecretAccessKey, token) { AccountId = accountId; @@ -104,6 +112,7 @@ public virtual ImmutableCredentials Copy() AccessKey = this.AccessKey, SecretKey = this.SecretKey, Token = this.Token, + AccountId = this.AccountId }; return credentials; } diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/ProcessAWSCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/ProcessAWSCredentials.cs index ae9acfbc56d0..f157909b4b95 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/ProcessAWSCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/ProcessAWSCredentials.cs @@ -43,6 +43,7 @@ public class ProcessAWSCredentials : RefreshingAWSCredentials { #region Private members private const string _versionString = "Version"; + private string _accountId; private Logger _logger = Logger.GetLogger(typeof(ProcessAWSCredentials)); private readonly ProcessStartInfo _processStartInfo; private static JsonDocumentOptions _options = new JsonDocumentOptions @@ -52,15 +53,31 @@ public class ProcessAWSCredentials : RefreshingAWSCredentials #endregion #region Public constructors - + /// + /// Constructs an instance of credentials that can be retrieved by running an external process. + /// + /// Contains the executable information to be used by the process credential retriever. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public ProcessAWSCredentials(string processCredentialInfo) + public ProcessAWSCredentials(string processCredentialInfo) : this(processCredentialInfo, null) + { + + } + + /// + /// Constructs an instance of credentials that can be retrieved by running an external process. + /// + /// Contains the executable information to be used by the process credential retriever + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012 + /// If account id is fetched from the executable then that will be used instead of the one set in the constructor. + /// + public ProcessAWSCredentials(string processCredentialInfo, string accountId) { processCredentialInfo = processCredentialInfo.Trim(); - + //Default to cmd on Windows since that is the only thing BCL runs on. var fileName = "cmd.exe"; var arguments = $@"/c {processCredentialInfo}"; + _accountId = accountId; #if NETSTANDARD //If it is netstandard and not running on Windows use sh. if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -182,10 +199,10 @@ private CredentialsRefreshState SetCredentialsRefreshState(ProcessExecutionResul { throw new ProcessAWSCredentialException("The response back from the process credential provider returned back a malformed JSON document.", e); } - + string accountId = processCredentialDataV1.AccountId == null ? _accountId : processCredentialDataV1.AccountId; return new CredentialsRefreshState( new ImmutableCredentials(processCredentialDataV1.AccessKeyId, - processCredentialDataV1.SecretAccessKey, processCredentialDataV1.SessionToken), processCredentialDataV1.Expiration); + processCredentialDataV1.SecretAccessKey, processCredentialDataV1.SessionToken, accountId), processCredentialDataV1.Expiration); default: throw new ProcessAWSCredentialException(string.Format(CultureInfo.CurrentCulture, "Unsupported credential version: {0}" + version)); } diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/ProcessCredentialVersion1.cs b/sdk/src/Core/Amazon.Runtime/Credentials/ProcessCredentialVersion1.cs index 8661e655b0bb..48156c492ec7 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/ProcessCredentialVersion1.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/ProcessCredentialVersion1.cs @@ -55,5 +55,10 @@ public class ProcessCredentialVersion1 /// ISO8601 formatted timestamp till when the credential is valid. /// public DateTime Expiration { get; set; } = DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc); + + /// + /// The AccountId used for AccountId based endpoints. + /// + public string AccountId { get; set; } } } \ No newline at end of file diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/SAMLImmutableCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/SAMLImmutableCredentials.cs index 04f33c75eec3..7c157235f812 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/SAMLImmutableCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/SAMLImmutableCredentials.cs @@ -58,7 +58,47 @@ public SAMLImmutableCredentials(string awsAccessKeyId, string token, DateTime expires, string subject) - : base(awsAccessKeyId, awsSecretAccessKey, token) + : this(awsAccessKeyId, awsSecretAccessKey, token, expires, subject, null) + { + } + + /// + /// Constructs an instance with supplied keys SAML assertion data, and an account id. + /// When the account id is set and the service supports account id based endpoints, AWS will send the request + /// using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://.ddb.region.amazonaws.com + /// + /// + /// + /// + /// + /// + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012. + public SAMLImmutableCredentials(string awsAccessKeyId, + string awsSecretAccessKey, + string token, + DateTime expires, + string subject, + string accountId) + : base(awsAccessKeyId, awsSecretAccessKey, token, accountId) + { + Expires = expires; + Subject = subject; + } + /// + /// Constructs an instance with supplied keys and SAML assertion data and an account id. + /// When the account id is set and the service supports account id based endpoints, AWS will send the request + /// using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://.ddb.region.amazonaws.com + /// + /// + /// + /// + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012. + public SAMLImmutableCredentials(ImmutableCredentials credentials, + DateTime expires, + string subject, + string accountId) : base(credentials.AccessKey, credentials.SecretKey, credentials.Token, accountId) { Expires = expires; Subject = subject; @@ -73,10 +113,8 @@ public SAMLImmutableCredentials(string awsAccessKeyId, public SAMLImmutableCredentials(ImmutableCredentials credentials, DateTime expires, string subject) - : base(credentials.AccessKey, credentials.SecretKey, credentials.Token) + : this(credentials, expires, subject, null) { - Expires = expires; - Subject = subject; } #endregion @@ -110,7 +148,7 @@ public override bool Equals(object obj) /// public override ImmutableCredentials Copy() { - return new SAMLImmutableCredentials(AccessKey, SecretKey, Token, Expires, Subject); + return new SAMLImmutableCredentials(AccessKey, SecretKey, Token, Expires, Subject, AccountId); } #endregion diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/SessionAWSCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/SessionAWSCredentials.cs index e43e8046beb1..786824ef2ab4 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/SessionAWSCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/SessionAWSCredentials.cs @@ -31,13 +31,27 @@ public class SessionAWSCredentials : AWSCredentials /// /// /// - public SessionAWSCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token) + public SessionAWSCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token) : this(awsAccessKeyId, awsSecretAccessKey, token, null) + { + } + + /// + /// Constructs a SessionAWSCredentials object for the specified accessKey, secretKey, and account id. + /// When the account id is set and the service supports account id based endpoints, AWS will send the request + /// using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://.ddb.region.amazonaws.com + /// + /// + /// + /// + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012. + /// + public SessionAWSCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token, string accountId) { if (string.IsNullOrEmpty(awsAccessKeyId)) throw new ArgumentNullException("awsAccessKeyId"); if (string.IsNullOrEmpty(awsSecretAccessKey)) throw new ArgumentNullException("awsSecretAccessKey"); if (string.IsNullOrEmpty(token)) throw new ArgumentNullException("token"); - - _lastCredentials = new ImmutableCredentials(awsAccessKeyId, awsSecretAccessKey, token); + _lastCredentials = new ImmutableCredentials(awsAccessKeyId, awsSecretAccessKey, token, accountId); } #endregion diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/_bcl+netstandard/SSOImmutableCredentials.cs b/sdk/src/Core/Amazon.Runtime/Credentials/_bcl+netstandard/SSOImmutableCredentials.cs index 53953d9b45bb..4ba36e30fa73 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/_bcl+netstandard/SSOImmutableCredentials.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/_bcl+netstandard/SSOImmutableCredentials.cs @@ -39,8 +39,23 @@ public class SSOImmutableCredentials : ImmutableCredentials /// The expiration time for the credentials. public SSOImmutableCredentials( string awsAccessKeyId, string awsSecretAccessKey, - string token, DateTime expiration) - : base(awsAccessKeyId, awsSecretAccessKey, token) + string token, DateTime expiration) : this(awsAccessKeyId, awsSecretAccessKey, token, expiration, null) + { + } + + /// + /// Constructs an instance with supplied keys, token, expiration, and account id. + /// When the account id is set and the service supports account id based endpoints, + /// AWS will send the request using the account-based endpoint rather than the regional endpount. + /// Account-based endpoints take the form https://.ddb.region.amazonaws.com + /// + /// + /// + /// + /// + /// The account id for the credentials. The account id is your 12 digit account number with no hyphens. For example: 123456789012. + /// + public SSOImmutableCredentials(string awsAccessKeyId, string awsSecretAccessKey, string token, DateTime expiration, string accountId) : base(awsAccessKeyId, awsSecretAccessKey, token, accountId) { if (string.IsNullOrEmpty(token)) throw new ArgumentNullException(nameof(token)); Expiration = expiration; @@ -52,12 +67,12 @@ public SSOImmutableCredentials( /// A copy of this object. public new SSOImmutableCredentials Copy() { - return new SSOImmutableCredentials(AccessKey, SecretKey, Token, Expiration); + return new SSOImmutableCredentials(AccessKey, SecretKey, Token, Expiration, AccountId); } public override int GetHashCode() { - return Hashing.Hash(AccessKey, SecretKey, Token, Expiration); + return Hashing.Hash(AccessKey, SecretKey, Token, Expiration, AccountId); } public override bool Equals(object obj) @@ -70,8 +85,8 @@ public override bool Equals(object obj) return false; return AWSSDKUtils.AreEqual( - new object[] { AccessKey, SecretKey, Token, Expiration }, - new object[] { ssoImmutableCredentials.AccessKey, ssoImmutableCredentials.SecretKey, ssoImmutableCredentials.Token, Expiration }); + new object[] { AccessKey, SecretKey, Token, Expiration, AccountId }, + new object[] { ssoImmutableCredentials.AccessKey, ssoImmutableCredentials.SecretKey, ssoImmutableCredentials.Token, Expiration, AccountId }); } } } diff --git a/sdk/src/Core/Amazon.Runtime/Internal/Settings/SettingsConstants.cs b/sdk/src/Core/Amazon.Runtime/Internal/Settings/SettingsConstants.cs index f8477d796942..744c3795a6ac 100644 --- a/sdk/src/Core/Amazon.Runtime/Internal/Settings/SettingsConstants.cs +++ b/sdk/src/Core/Amazon.Runtime/Internal/Settings/SettingsConstants.cs @@ -56,6 +56,7 @@ public static class SettingsConstants public const string WebIdentityTokenFile = "WebIdentityTokenFile"; public const string Services = "services"; public const string EndpointUrl = "endpoint_url"; + public const string AwsAccountId = "aws_account_id"; // present in endpoint definitions in SAMLEndpoints.json file public const string EndpointField = "Endpoint"; diff --git a/sdk/src/Services/SSO/Custom/Internal/_bcl+netstandard/CoreAmazonSSO.cs b/sdk/src/Services/SSO/Custom/Internal/_bcl+netstandard/CoreAmazonSSO.cs index 7b9e911fd1f1..1bd036927464 100644 --- a/sdk/src/Services/SSO/Custom/Internal/_bcl+netstandard/CoreAmazonSSO.cs +++ b/sdk/src/Services/SSO/Custom/Internal/_bcl+netstandard/CoreAmazonSSO.cs @@ -60,7 +60,8 @@ public static ImmutableCredentials CredentialsFromSsoAccessToken(IAmazonSSO clie response.RoleCredentials.AccessKeyId, response.RoleCredentials.SecretAccessKey, response.RoleCredentials.SessionToken, - credentialsExpiration); + credentialsExpiration, + accountId); } /// @@ -105,7 +106,8 @@ public static async Task CredentialsFromSsoAccessTokenAsyn response.RoleCredentials.AccessKeyId, response.RoleCredentials.SecretAccessKey, response.RoleCredentials.SessionToken, - credentialsExpiration); + credentialsExpiration, + accountId); } /// diff --git a/sdk/src/Services/SecurityToken/Custom/AmazonSecurityTokenServiceClient.Extension.cs b/sdk/src/Services/SecurityToken/Custom/AmazonSecurityTokenServiceClient.Extension.cs index c4ba189bb268..37a5f64e55c5 100644 --- a/sdk/src/Services/SecurityToken/Custom/AmazonSecurityTokenServiceClient.Extension.cs +++ b/sdk/src/Services/SecurityToken/Custom/AmazonSecurityTokenServiceClient.Extension.cs @@ -23,6 +23,8 @@ using Amazon.SecurityToken.Model; using Amazon.SecurityToken.SAML; using Amazon.Util.Internal; +using Amazon.Util; +using Amazon.Runtime.Internal.Endpoints.StandardLibrary; using System.Threading.Tasks; namespace Amazon.SecurityToken @@ -148,7 +150,7 @@ AssumeRoleImmutableCredentials ICoreAmazonSTS.CredentialsFromAssumeRoleWithWebId { var response = AssumeRoleWithWebIdentity(request); return new AssumeRoleImmutableCredentials(response.Credentials.AccessKeyId, response.Credentials.SecretAccessKey, - response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault()); + response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault(), response.AssumedRoleUser != null ? Arn.Parse(response.AssumedRoleUser.Arn).AccountId : null); } catch (Exception e) { @@ -175,7 +177,7 @@ async Task ICoreAmazonSTS.CredentialsFromAssumeR { var response = await AssumeRoleWithWebIdentityAsync(request).ConfigureAwait(false); return new AssumeRoleImmutableCredentials(response.Credentials.AccessKeyId, response.Credentials.SecretAccessKey, - response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault()); + response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault(), response.AssumedRoleUser != null ? Arn.Parse(response.AssumedRoleUser.Arn).AccountId : null); } catch (Exception e) { @@ -202,7 +204,7 @@ AssumeRoleImmutableCredentials ICoreAmazonSTS.CredentialsFromAssumeRoleAuthentic var response = AssumeRole(request); return new AssumeRoleImmutableCredentials(response.Credentials.AccessKeyId, response.Credentials.SecretAccessKey, - response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault()); + response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault(), response.AssumedRoleUser != null ? Arn.Parse(response.AssumedRoleUser.Arn).AccountId : null); } catch (Exception e) { diff --git a/sdk/src/Services/SecurityToken/Custom/SAML/SAMLAssertion.cs b/sdk/src/Services/SecurityToken/Custom/SAML/SAMLAssertion.cs index 42d7be4deda1..50ab2fde120d 100644 --- a/sdk/src/Services/SecurityToken/Custom/SAML/SAMLAssertion.cs +++ b/sdk/src/Services/SecurityToken/Custom/SAML/SAMLAssertion.cs @@ -116,10 +116,10 @@ public SAMLImmutableCredentials GetRoleCredentials( #else var response = stsClient.AssumeRoleWithSAML(assumeSamlRequest); #endif - return new SAMLImmutableCredentials(response.Credentials.GetCredentials(), response.Credentials.Expiration.GetValueOrDefault().ToUniversalTime(), - response.Subject); + response.Subject, + response.AssumedRoleUser != null ? Arn.Parse(response.AssumedRoleUser.Arn).AccountId : null); } /// diff --git a/sdk/test/Services/SecurityToken/UnitTests/Custom/StaticCheckTests.cs b/sdk/test/Services/SecurityToken/UnitTests/Custom/StaticCheckTests.cs index 1b576b6ae127..dcddc01e7fb1 100644 --- a/sdk/test/Services/SecurityToken/UnitTests/Custom/StaticCheckTests.cs +++ b/sdk/test/Services/SecurityToken/UnitTests/Custom/StaticCheckTests.cs @@ -43,7 +43,7 @@ public void LookForAssumeRoleRequestChanges() [TestCategory("SecurityToken")] public void LookForProfileTypeChanges() { - var expectedHash = "E15E66896846B0235881B8623AF005AA80B9DEDF4303348FC494290E0D6E2732"; + var expectedHash = "1C76F6CC5D3B18FD76D4A811E5EB2FD96E97F4D4F202F38B5FBE5FAC56BE09FB"; AssertExtensions.AssertEnumUnchanged( typeof(CredentialProfileType), expectedHash, @@ -63,16 +63,19 @@ public void EnsureCredentialProfileDetectorSetup() // avoid making TypePropertyDictionary public just for unit testing var field = typeof(CredentialProfileTypeDetector).GetFields(BindingFlags.Static | BindingFlags.NonPublic). Where((fi) => fi.Name == "TypePropertyDictionary").First(); - var typePropertyDictionary = (Dictionary>)field.GetValue(null); + var typePropertyDictionary = (Dictionary>>)field.GetValue(null); foreach (var pair in typePropertyDictionary) { referencedProfileTypes.Add(pair.Key); - foreach (var propertyName in pair.Value) + foreach (var propertyType in pair.Value) { - if (!referencedProfileOptionsProperties.Contains(propertyName)) + foreach (var propertyName in propertyType) { - referencedProfileOptionsProperties.Add(propertyName); + if (!referencedProfileOptionsProperties.Contains(propertyName)) + { + referencedProfileOptionsProperties.Add(propertyName); + } } } } diff --git a/sdk/test/UnitTests/AWSSDK.UnitTests.Custom.NetFramework.csproj b/sdk/test/UnitTests/AWSSDK.UnitTests.Custom.NetFramework.csproj index 733ae3aee9d1..0a6ebc81b69a 100644 --- a/sdk/test/UnitTests/AWSSDK.UnitTests.Custom.NetFramework.csproj +++ b/sdk/test/UnitTests/AWSSDK.UnitTests.Custom.NetFramework.csproj @@ -104,4 +104,10 @@ This project file should not be used as part of a release pipeline. + + + + Always + + \ No newline at end of file diff --git a/sdk/test/UnitTests/Custom/Runtime/Credentials/AccountIdEndpointTests/AccountIdBasedEndpointsTest.cs b/sdk/test/UnitTests/Custom/Runtime/Credentials/AccountIdEndpointTests/AccountIdBasedEndpointsTest.cs new file mode 100644 index 000000000000..339835c8a99c --- /dev/null +++ b/sdk/test/UnitTests/Custom/Runtime/Credentials/AccountIdEndpointTests/AccountIdBasedEndpointsTest.cs @@ -0,0 +1,1165 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq; +using Amazon.Runtime; +using Amazon.Runtime.SharedInterfaces; +using Amazon.SecurityToken; +using Amazon.SecurityToken.Model; +using Amazon.SSO.Internal; +using System.Net; +using Amazon; +using Amazon.SecurityToken.SAML; +using System.Net.Mail; +using Amazon.Runtime.Credentials; +using System.Security.Principal; +using Amazon.SSO; +using Amazon.SSO.Model; +using Amazon.Runtime.CredentialManagement; +using Amazon.CloudWatch; +using System.Runtime.CompilerServices; +using Amazon.Runtime.Internal; +using Amazon.Util.Internal; +using System.IO; +using Amazon.EC2.Model.Internal.MarshallTransformations; +using System.Text.RegularExpressions; +using System.Runtime.InteropServices; +namespace AWSSDK.UnitTests +{ + /// + /// Test cases can be found in accountid-source-testcases.json file in the same folder + /// + [TestClass] + public class AccountIdBasedEndpointsTest + { + + private static readonly string ProjectPath = + Regex.Match(Directory.GetCurrentDirectory(), @"^.*?(?=\\bin\\)").Captures[0].Value; + + public static readonly string Executable = Path.Combine(ProjectPath, @"Custom\Util\get_credentials.sh"); + private static bool _isWindows = false; + + static AccountIdBasedEndpointsTest() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Executable = Path.Combine(ProjectPath, @"Custom\Util\get_credentials.bat"); + _isWindows = true; + } + } + + [TestCleanup] + public void Cleanup() + { + if (File.Exists(Executable)) + File.Delete(Executable); + + } + + //STS:1 + [TestMethod] + public void StsAssumeRoleAccountId() + { + var request = new AssumeRoleRequest + { + RoleArn = "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name", + RoleSessionName = "testSession" + }; + var expectedResponse = new AssumeRoleResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz", + Expiration = DateTime.UtcNow.AddHours(1) + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name", + AssumedRoleId = "roleId" + } + }; + var mockStsClient = new Mock(); + mockStsClient.Setup(x => x.AssumeRole(It.IsAny())).Returns(expectedResponse); + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + //doesn't matter what we pass in here since the assumerole call is mocked + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleAuthentication("arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name", "testSession", new AssumeRoleAWSCredentialsOptions()); + + Assert.AreEqual("123456789001", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + + //STS:2 + [TestMethod] + public void StsAssumeRoleWithSamlAccountId() + { + var expectedResponse = new AssumeRoleWithSAMLResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz" + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name", + AssumedRoleId = "roleId" + } + }; + var mockStsClient = new Mock(); + mockStsClient.Setup(x => x.AssumeRoleWithSAML(It.IsAny())).Returns(expectedResponse); + + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromSAMLAuthentication("foo", "bar", "fizz", TimeSpan.FromHours(1), null); + Assert.AreEqual("123456789001", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + + //STS:3 + /// + /// When calling Sts::AssumeRoleWithWebIdentity successfully, find account ID in response + /// + [TestMethod] + public void StsAssumeRoleWithWebIdentityAccountId() + { + var expectedResponse = new AssumeRoleWithWebIdentityResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz" + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name", + AssumedRoleId = "roleId" + } + }; + var mockStsClient = new Mock(); + mockStsClient.Setup(x => x.AssumeRoleWithWebIdentity(It.IsAny())).Returns(expectedResponse); + + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleWithWebIdentityAuthentication("token", "any-arn", "test-arn", null); + Assert.AreEqual("123456789001", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + //STS:4 (SKIP) none of our credential providers call GetFederationToken and there is no point in asserting a mocked response returns what is expected + + /// + /// When environment is configured with web identity, find account ID in response + /// In the sdk flow, AssumeRoleWithWebIdentityCredentials.FromEnvironmentVariable() will be called, which sets the access key, secret access key and web identity + /// token file path and role arn. The response from AssumeRoleWithWebIdentity is what is used to populate account id and not what is set in the env variable. + /// + // STS:5" + [TestMethod] + public void EnvironmentVariableConfiguredWithWebIdentitySetsAccountId() + { + var beforeAwsWebIdentityTokenFileEnvVar = Environment.GetEnvironmentVariable(AssumeRoleWithWebIdentityCredentials.WebIdentityTokenFileEnvVariable); + var beforeAwsRoleArn = Environment.GetEnvironmentVariable(AssumeRoleWithWebIdentityCredentials.RoleArnEnvVariable); + var beforeAwsAccountId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID); + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + try + { + Environment.SetEnvironmentVariable(AssumeRoleWithWebIdentityCredentials.WebIdentityTokenFileEnvVariable, "some_path"); + Environment.SetEnvironmentVariable(AssumeRoleWithWebIdentityCredentials.RoleArnEnvVariable, "arn:aws:iam::123456789001:role"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, "123456789002"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + + var mockStsClient = new Mock(); + var expectedResponse = new AssumeRoleWithWebIdentityResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz" + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:iam::123456789001:role", + AssumedRoleId = "roleId" + } + }; + mockStsClient.Setup(x => x.AssumeRoleWithWebIdentity(It.IsAny())).Returns(expectedResponse); + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleWithWebIdentityAuthentication("token", "any-arn", "test-arn", null); + + Assert.AreEqual("123456789001", actualCreds.AccountId); + } + finally + { + Environment.SetEnvironmentVariable(AssumeRoleWithWebIdentityCredentials.WebIdentityTokenFileEnvVariable, beforeAwsWebIdentityTokenFileEnvVar); + Environment.SetEnvironmentVariable(AssumeRoleWithWebIdentityCredentials.RoleArnEnvVariable, beforeAwsRoleArn); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, beforeAwsAccountId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, beforeAwsAccessKeyId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeAwsSecretAccessKey); + } + } + /// + /// When calling Sso::GetCredentials successfully, find account ID in request + /// SSO:1 + /// + [TestMethod] + public void SsoSuccessfulGetCredentialsFindsAccountIdInRequest() + { + var mockSsoClient = new Mock(); + var getRoleCredentialsRequest = new GetRoleCredentialsRequest + { + AccountId = "123456789001", + RoleName = "anything", + AccessToken = "anything" + }; + var expectedResponse = new GetRoleCredentialsResponse + { + RoleCredentials = new RoleCredentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz" + } + }; + mockSsoClient.Setup(client => client.GetRoleCredentials(It.IsAny())).Returns(expectedResponse); + + var credentials = CoreAmazonSSO.CredentialsFromSsoAccessToken( + mockSsoClient.Object, + getRoleCredentialsRequest.AccountId, + getRoleCredentialsRequest.RoleName, + getRoleCredentialsRequest.AccessToken, + null); + + Assert.AreEqual("123456789001", credentials.AccountId); + Assert.AreEqual("foo", credentials.AccessKey); + Assert.AreEqual("bar", credentials.SecretKey); + Assert.AreEqual("baz", credentials.Token); + } + /// + /// SSO:2 + /// When calling Sso::GetCredentials unsuccessfully, does not find account ID + /// + [TestMethod] + public void SsoUnsuccessfulCallDoesNotFindAccountIdInRequest() + { + var mockSsoClient = new Mock(); + var getRoleCredentialsRequest = new GetRoleCredentialsRequest + { + AccountId = "123456789001", + RoleName = "anything", + AccessToken = "anything" + }; + var expectedResponse = new ResourceNotFoundException("The request resource doesn't exist"); + mockSsoClient.Setup(client => client.GetRoleCredentials(It.IsAny())).Throws(expectedResponse); + ImmutableCredentials credentials = null; + try + { + credentials = CoreAmazonSSO.CredentialsFromSsoAccessToken( + mockSsoClient.Object, + getRoleCredentialsRequest.AccountId, + getRoleCredentialsRequest.RoleName, + getRoleCredentialsRequest.AccessToken, + null); + } + + catch (ResourceNotFoundException e) + { + Assert.IsNull(credentials); + Assert.IsNotNull(e); + } + } + + /// + /// When profile is configured with role, accountid and call is successful, find account ID in call response + /// + private static string cfg1 = new StringBuilder().AppendLine("[profile assume-role]") + .AppendLine("role_arn = arn:aws:iam::123456789002:role/MyRole") + .AppendLine("source_profile = assume-creds") + .AppendLine("[profile assume-creds]") + .AppendLine("aws_access_key_id = abc123") + .AppendLine("aws_secret_access_key = def456") + .AppendLine("aws_account_id = 123456789001") + .ToString(); + [TestMethod] + public void AssumeRoleProfileReturnsCorrectAccountId() + { + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg1)) + { + sharedCredentialsFile.CredentialsFile.TryGetProfile("assume-role", out CredentialProfile profile); + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("assume-role", out AWSCredentials creds); + Assert.IsInstanceOfType(creds, typeof(AssumeRoleAWSCredentials)); + //AssumeRoleAWSCredentials.GetCredentials() will call CredentialsFromAssumeRoleAuthentication + var mockStsClient = new Mock(); + var expectedResponse = new AssumeRoleResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz", + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:iam::123456789002:role/MyRole", + AssumedRoleId = "roleId" + } + }; + mockStsClient.Setup(x => x.AssumeRole(It.IsAny())).Returns(expectedResponse); + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleAuthentication("anything", "anything", null); + Assert.AreEqual("123456789002", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + } + private static string cfg2 = new StringBuilder() + .AppendLine("[profile final-role]") + .AppendLine("role_arn = arn:aws:iam::123456789003:role/MyRole") + .AppendLine("source_profile = chained-role") + .AppendLine("[profile chained-role]") + .AppendLine("role_arn = arn:aws:iam::123456789002:role/MyRole") + .AppendLine("source_profile = assume-creds") + .AppendLine("[profile assume-creds]") + .AppendLine("aws_access_key_id = abc123") + .AppendLine("aws_secret_access_key = def456") + .AppendLine("aws_account_id = 123456789001") + .ToString(); + /// + /// When profile is configured with chained roles, accountid and calls are successful, find account ID in call response + /// + [TestMethod] + public void AssumeRoleChainedProfilesReturnCorrectAccountId() + { + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg2)) + { + sharedCredentialsFile.CredentialsFile.TryGetProfile("final-role", out CredentialProfile profile); + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("final-role", out AWSCredentials creds); + Assert.IsNotNull(creds); + Assert.IsInstanceOfType(creds, typeof(AssumeRoleAWSCredentials)); + var mockStsClient = new Mock(); + var expectedResponse = new AssumeRoleResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz", + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:iam::123456789003:role/MyRole", + AssumedRoleId = "roleId" + } + }; + mockStsClient.Setup(x => x.AssumeRole(It.IsAny())).Returns(expectedResponse); + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleAuthentication("anything", "anything", null); + Assert.AreEqual("123456789003", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + } + private static string cfg3 = new StringBuilder() + .AppendLine("[profile test-role]") + .AppendLine("role_arn = arn:aws:iam::123456789003:role/MyRole") + .AppendLine("credential_source = Environment") + .AppendLine("aws_account_id = 123456789001") + .ToString(); + //CFG:3 + /// + /// When profile is configured with role, accountid and env var credentials_source, find account ID in call response + /// + [TestMethod] + public void AccountIdInResponseTakesPrecedenceOverEnvVariables() + { + var beforeAwsAccountId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID); + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + try + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, "123456789002"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg3)) + { + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("test-role", out AWSCredentials creds); + Assert.IsNotNull(creds); + Assert.IsInstanceOfType(creds, typeof(AssumeRoleAWSCredentials)); + + var mockStsClient = new Mock(); + var expectedResponse = new AssumeRoleResponse + { + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz", + }, + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:iam::123456789003:role/MyRole", + AssumedRoleId = "roleId" + } + }; + + mockStsClient.Setup(x => x.AssumeRole(It.IsAny())).Returns(expectedResponse); + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleAuthentication("anything", "anything", null); + Assert.AreEqual("123456789003", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + } + finally + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, beforeAwsAccountId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, beforeAwsAccessKeyId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeAwsSecretAccessKey); + } + } + private static string cfg4 = new StringBuilder() + .AppendLine("[profile test-role]") + .AppendLine("role_arn = arn:aws:iam::123456789003:role/MyRole") + .AppendLine("web_identity_token_file = C:\\temp\\") + .AppendLine("credential_source = Environment") + .AppendLine("aws_account_id = 123456789001") + .ToString(); + + // CFG:4 + /// + /// When profile is configured with web identity, find account ID in response + /// + [TestMethod] + public void FindAccountIdInResponseWhenProfileIsConfiguredWithWebIdentity() + { + var beforeAwsAccountId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID); + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg4)) + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, "123456789002"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("test-role", out AWSCredentials creds); + Assert.IsNotNull(creds); + Assert.IsInstanceOfType(creds, typeof(AssumeRoleWithWebIdentityCredentials)); + + var expectedResponse = new AssumeRoleWithWebIdentityResponse + { + AssumedRoleUser = new AssumedRoleUser + { + Arn = "arn:aws:iam::123456789003:role" + }, + Credentials = new Credentials + { + AccessKeyId = "foo", + SecretAccessKey = "bar", + SessionToken = "baz" + } + }; + + var mockStsClient = new Mock(); + mockStsClient.Setup(client => client.AssumeRoleWithWebIdentity(It.IsAny())).Returns(expectedResponse); + var testableAmazonStsClient = new TestableAmazonSTSClient(mockStsClient.Object); + var actualCreds = testableAmazonStsClient.CredentialsFromAssumeRoleWithWebIdentityAuthentication("any", "any", "any", null); + Assert.AreEqual("123456789003", actualCreds.AccountId); + } + } + + private static string cfg5 = new StringBuilder() + .AppendLine("[default]") + .AppendLine("aws_access_key_id = foo") + .AppendLine("aws_secret_access_key = bar") + .AppendLine("aws_account_id = 123456789001") + .ToString(); + /// + /// When profile is configured with static credentials and accountid, find account id in profile + /// + [TestMethod] + public void AccountIdConfiguredInProfileWorks() + { + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg5)) + { + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("default", out AWSCredentials creds); + Assert.IsNotNull(creds); + var immutableCreds = creds.GetCredentials(); + Assert.AreEqual("123456789001", immutableCreds.AccountId); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + + } + } + + private static string cfg6 = new StringBuilder() + .AppendLine("[default]") + .AppendLine("aws_access_key_id = foo") + .AppendLine("aws_secret_access_key = bar") + .ToString(); + /// + /// When profile is configured with static credentials but no accountid, does not find accountid + /// + [TestMethod] + public void AccountIdNotFoundInProfileIfUnavailable() + { + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg6)) + { + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("default", out AWSCredentials creds); + Assert.IsNotNull(creds); + var actualCreds = creds.GetCredentials(); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.IsNull(actualCreds.AccountId); + } + } + + private static string cfg7 = new StringBuilder() + .AppendLine("[default]") + .AppendLine("aws_access_key_id = foo") + .AppendLine("aws_secret_access_key = bar") + .AppendLine("aws_session_token = baz") + .AppendLine("aws_account_id = 123456789001") + .ToString(); + /// + /// When profile is configured with static credentials, session token and accountid, find account id in profile + /// + [TestMethod] + public void AccountIdFoundInSessionProfile() + { + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg7)) + { + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("default", out AWSCredentials creds); + Assert.IsNotNull(creds); + var actualCreds = creds.GetCredentials(); + + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + Assert.AreEqual("123456789001", actualCreds.AccountId); + } + } + + private static string cfg8 = new StringBuilder() + .AppendLine("[default]") + .AppendLine("aws_access_key_id = foo") + .AppendLine("aws_secret_access_key = bar") + .AppendLine("aws_session_token = baz") + .ToString(); + /// + /// When profile is configured with static credentials, session token but no accountid, does not find accountid + /// + [TestMethod] + public void AccountIdNotFoundInSessionProfileIfUnavailable() + { + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg8)) + { + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("default", out AWSCredentials creds); + Assert.IsNotNull(creds); + var actualCreds = creds.GetCredentials(); + + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + Assert.IsNull(actualCreds.AccountId); + } + } + /// + /// STA:2 + /// When static credentials and accountid are configured, finds accountid + /// + [TestMethod] + public void StaticCredsWithAcctIdWorks() + { + var creds = new ImmutableCredentials("foo", "bar", null, "123456789001"); + Assert.AreEqual("123456789001", creds.AccountId); + Assert.AreEqual("foo", creds.AccessKey); + Assert.AreEqual("bar", creds.SecretKey); + } + + /// + /// STA:3 + /// When static credentials but no accountid are configured, does not find accountid + /// + [TestMethod] + public void StaticCredsWithNoAcctIdWorks() + { + var creds = new ImmutableCredentials("foo", "bar", null); + Assert.AreEqual("foo", creds.AccessKey); + Assert.AreEqual("bar", creds.SecretKey); + Assert.IsNull(creds.AccountId); + } + + /// + /// STA:4 + /// When session credentials and accountid are configured, finds accountid + /// + [TestMethod] + public void SessionCredsWithAcctIdWorks() + { + var temp = new SessionAWSCredentials("foo", "bar", "baz", "123456789001"); + var creds = temp.GetCredentials(); + Assert.AreEqual("123456789001", creds.AccountId); + Assert.AreEqual("foo", creds.AccessKey); + Assert.AreEqual("bar", creds.SecretKey); + Assert.AreEqual("baz", creds.Token); + } + + /// + /// ENV:1 + /// When environment variables contain static credentials and accountid, find account id in env vars + /// + [TestMethod] + public void EnvVarsContainingAcctIdWorks() + { + var beforeAwsAccountId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID); + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + try + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, "123456789001"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + DefaultAWSCredentialsIdentityResolver resolver = new DefaultAWSCredentialsIdentityResolver(); + AWSCredentials creds = resolver.ResolveIdentity(); + var actualCreds = creds.GetCredentials(); + Assert.AreEqual("123456789001", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + } + finally + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, beforeAwsAccountId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, beforeAwsAccessKeyId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeAwsSecretAccessKey); + } + } + + /// + /// ENV:2 + /// When environment variables contain static credentials but no accountid, does not find accountid + /// + [TestMethod] + public void EnvVarsContainingNoAcctIdWorks() + { + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + try + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + DefaultAWSCredentialsIdentityResolver resolver = new DefaultAWSCredentialsIdentityResolver(); + AWSCredentials creds = resolver.ResolveIdentity(); + var actualCreds = creds.GetCredentials(); + Assert.IsNull(actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + } + finally + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, beforeAwsAccessKeyId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeAwsSecretAccessKey); + } + } + + /// + /// ENV:3 + /// When environment variables contain static credentials, session token and accountid, find account id in env vars + /// + [TestMethod] + public void EnvVarsContainingAcctIdAndTokenWorks() + { + var beforeAwsAccountId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID); + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + var beforeSessionToken = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SESSION_TOKEN); + try + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, "123456789001"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SESSION_TOKEN, "baz"); + DefaultAWSCredentialsIdentityResolver resolver = new DefaultAWSCredentialsIdentityResolver(); + AWSCredentials creds = resolver.ResolveIdentity(); + var actualCreds = creds.GetCredentials(); + Assert.AreEqual("123456789001", actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + finally + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCOUNT_ID, beforeAwsAccountId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, beforeAwsAccessKeyId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeAwsSecretAccessKey); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeSessionToken); + } + } + + /// + /// ENV:4 + /// When environment variables contain static credentials, session token but no accountid, does not find accountid + /// + [TestMethod] + public void EnvVarsContainingTokenAndNoAcctIdWorks() + { + var beforeAwsAccessKeyId = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY); + var beforeAwsSecretAccessKey = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY); + var beforeSessionToken = Environment.GetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SESSION_TOKEN); + try + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, "foo"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, "bar"); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SESSION_TOKEN, "baz"); + DefaultAWSCredentialsIdentityResolver resolver = new DefaultAWSCredentialsIdentityResolver(); + AWSCredentials creds = resolver.ResolveIdentity(); + var actualCreds = creds.GetCredentials(); + Assert.IsNull(actualCreds.AccountId); + Assert.AreEqual("foo", actualCreds.AccessKey); + Assert.AreEqual("bar", actualCreds.SecretKey); + Assert.AreEqual("baz", actualCreds.Token); + } + finally + { + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_ACCESSKEY, beforeAwsAccessKeyId); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeAwsSecretAccessKey); + Environment.SetEnvironmentVariable(EnvironmentVariablesAWSCredentials.ENVIRONMENT_VARIABLE_SECRETKEY, beforeSessionToken); + } + } + + private static string process1 = new StringBuilder() + .AppendLine("{\"Version\": 1,") + .AppendLine("\"AccessKeyId\":\"foo\",") + .AppendLine("\"SecretAccessKey\":\"bar\",") + .AppendLine("\"SessionToken\":\"baz\",") + .AppendLine("\"AccountId\":\"123456789001\",") + .AppendLine("}") + .ToString(); + + /// + /// PRO:1 + /// When you use process credentials provider and process returns session credentials and accountid, find accountid in response + /// + [TestMethod] + public void ProcessCredentialsProviderWithAccountIdWorks() + { + ProcessCredentialVersion1 processCreds = JsonSerializerHelper.Deserialize(process1, ProcessCredentialVersion1JsonSerializerContexts.Default); + ImmutableCredentials immutableCreds = new ImmutableCredentials(processCreds.AccessKeyId, processCreds.SecretAccessKey, processCreds.SessionToken, processCreds.AccountId); + Assert.AreEqual("123456789001", immutableCreds.AccountId); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("baz", immutableCreds.Token); + } + private static string process2 = new StringBuilder() + .AppendLine("{\"Version\": 1,") + .AppendLine("\"AccessKeyId\":\"foo\",") + .AppendLine("\"SecretAccessKey\":\"bar\",") + .AppendLine("\"SessionToken\":\"baz\",") + .AppendLine("}") + .ToString(); + + /// + /// PRO:2 + /// When you use process credentials provider and process returns session credentials but not accountid, does not find accountid + /// + [TestMethod] + public void ProcessCredsWithNoAcctIdWorks() + { + ProcessCredentialVersion1 processCreds = JsonSerializerHelper.Deserialize(process2, ProcessCredentialVersion1JsonSerializerContexts.Default); + ImmutableCredentials immutableCreds = new ImmutableCredentials(processCreds.AccessKeyId, processCreds.SecretAccessKey, processCreds.SessionToken, processCreds.AccountId); + Assert.IsNull(immutableCreds.AccountId); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("baz", immutableCreds.Token); + } + + /// + /// CFG:10 + /// When profile is configured with process source and process returns session credentials and accountid, find accountid in response + /// + [TestMethod] + public void ProcessCredsFromCredentialProcess() + { + //CFG10 + var cfg10 = new StringBuilder() + .AppendLine("[profile process-role]") + .AppendFormat("credential_process = {0}\n", Executable) + .ToString(); + + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg10)) + { + var processScript = new ProcessScript + { + Version = "1", + AccessKey = "foo", + SecretKey = "bar", + Token = "baz", + AccountId = "123456789002" + }; + + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("process-role", out AWSCredentials creds); + Assert.IsInstanceOfType(creds, typeof(ProcessAWSCredentials)); + if (_isWindows) + WriteWindowsProcessCredentialScript(processScript); + else + WriteLinuxProcessCredentialScript(processScript); + + ImmutableCredentials immutableCreds = creds.GetCredentials(); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("baz", immutableCreds.Token); + Assert.AreEqual("123456789002", immutableCreds.AccountId); + } + } + + /// + /// CFG:11 + /// When profile is configured with process source, accountid and process returns session credentials and accountid, find accountid in response + /// + [TestMethod] + public void ProcessCredsFromCredentialProcessWithAccountId() + { + var cfg11 = new StringBuilder() + .AppendLine("[profile process-role]") + .AppendFormat("credential_process = {0}\n", Executable) + .AppendLine("aws_account_id = 123456789001") + .ToString(); + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg11)) + { + + var processScript = new ProcessScript + { + Version = "1", + AccessKey = "foo", + SecretKey = "bar", + Token = "baz", + AccountId = "123456789002" + }; + + if (_isWindows) + WriteWindowsProcessCredentialScript(processScript); + else + WriteLinuxProcessCredentialScript(processScript); + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("process-role", out AWSCredentials creds); + Assert.IsInstanceOfType(creds, typeof(ProcessAWSCredentials)); + + var immutableCreds = creds.GetCredentials(); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("baz", immutableCreds.Token); + Assert.AreEqual("123456789002", immutableCreds.AccountId); + } + } + + /// + /// When profile is configured with process source, accountid and process returns session credentials but no accountid, find accountid in profile + /// CFG:12 + /// + [TestMethod] + public void ProcessCredsNoAcctIdWorks() + { + // Since executable can change from a shell script to a batch file cfg cannot be a static string + var cfg12 = new StringBuilder() + .AppendLine("[profile process-role]") + .AppendFormat("credential_process = {0}\n", Executable) + .AppendLine("aws_account_id = 123456789001") + .ToString(); + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg12)) + { + var processScript = new ProcessScript + { + AccessKey = "foo", + SecretKey = "bar", + Token = "baz", + Version = "1" + }; + if (_isWindows) + WriteWindowsProcessCredentialScript(processScript); + else + WriteLinuxProcessCredentialScript(processScript); + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("process-role", out AWSCredentials creds); + Assert.IsInstanceOfType(creds, typeof(ProcessAWSCredentials)); + var immutableCreds = creds.GetCredentials(); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("baz", immutableCreds.Token); + Assert.AreEqual("123456789001", immutableCreds.AccountId); + } + } + + /// + /// When profile is configured with process source and process returns session credentials but no accountid, does not find accountid + /// CFG:13 + /// + [TestMethod] + public void ProcessWithTokenAndNoAcctIdWorks() + { + var cfg13 = new StringBuilder() + .AppendLine("[profile process-role]") + .AppendFormat("credential_process = {0}\n", Executable) + .ToString(); + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg13)) + { + var processScript = new ProcessScript + { + Version = "1", + AccessKey = "foo", + SecretKey = "bar", + Token = "baz" + }; + if (_isWindows) + WriteWindowsProcessCredentialScript(processScript); + else + WriteLinuxProcessCredentialScript(processScript); + + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("process-role", out AWSCredentials creds); + Assert.IsInstanceOfType(creds, typeof(ProcessAWSCredentials)); + + var immutableCreds = creds.GetCredentials(); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("baz", immutableCreds.Token); + Assert.IsNull(immutableCreds.AccountId); + } + } + + /// + /// When profile is configured with process source and process returns static credentials and accountid, find accountid in response + /// CFG:14 + /// + [TestMethod] + public void ProcessWithAcctIdWorks() + { + var cfg14 = new StringBuilder() + .AppendLine("[profile process-role]") + .AppendFormat("credential_process = {0}\n", Executable) + .ToString(); + + using (var sharedCredentialsFile = new SharedCredentialsFileTestFixture(credentialsFileContents: null, configFileContents: cfg14)) + { + var processScript = new ProcessScript + { + Version = "1", + AccessKey = "foo", + SecretKey = "bar", + AccountId = "123456789001" + }; + if (_isWindows) + WriteWindowsProcessCredentialScript(processScript); + else + WriteLinuxProcessCredentialScript(processScript); + + var chain = new CredentialProfileStoreChain(sharedCredentialsFile.ConfigFilePath); + chain.TryGetAWSCredentials("process-role", out AWSCredentials creds); + Assert.IsInstanceOfType(creds, typeof(ProcessAWSCredentials)); + var immutableCreds = creds.GetCredentials(); + Assert.AreEqual("foo", immutableCreds.AccessKey); + Assert.AreEqual("bar", immutableCreds.SecretKey); + Assert.AreEqual("", immutableCreds.Token); + Assert.AreEqual("123456789001", immutableCreds.AccountId); + } + } + + + private static void WriteLinuxProcessCredentialScript(ProcessScript processScript) + { + string expirationDate = DateTime.UtcNow.AddDays(5).ToString("yyyy-MM-ddTHH:mm:ssZ"); + using (var streamWriter = File.CreateText(Executable)) + { + streamWriter.WriteLine("#!/usr/bin/env bash"); + streamWriter.WriteLine("echo \'{\';"); + streamWriter.WriteLine("echo \'\"Version\":{0},\';", processScript.Version); + streamWriter.WriteLine("echo \'\"AccessKeyId\":\"{0}\"\',;", processScript.AccessKey); + streamWriter.WriteLine("echo \'\"SecretAccessKey\": \"{0}\"\',;", processScript.SecretKey); + if (!string.IsNullOrEmpty(processScript.Token)) + { + streamWriter.WriteLine("echo \'\"SessionToken\": \"{0}\"\',;",processScript.Token); + streamWriter.WriteLine("echo \'\"Expiration\": \"{0}\"\',;", expirationDate); + } + if (!string.IsNullOrEmpty(processScript.AccountId)) + { + streamWriter.WriteLine("echo \'\"AccountId\": \"{0}\"\',;", processScript.AccountId); + } + streamWriter.WriteLine("echo \'}\';"); + } + } + + private static void WriteWindowsProcessCredentialScript(ProcessScript processScript) + { + string expirationDate = DateTime.UtcNow.AddDays(5).ToString("yyyy-MM-ddTHH:mm:ssZ"); + using (var streamWriter = File.CreateText(Executable)) + { + streamWriter.WriteLine("@echo off"); + streamWriter.WriteLine("echo {"); + streamWriter.WriteLine("echo \"Version\":{0},", processScript.Version); + streamWriter.WriteLine("echo \"AccessKeyId\":\"{0}\",", processScript.AccessKey); + streamWriter.WriteLine("echo \"SecretAccessKey\": \"{0}\",", processScript.SecretKey); + if (!string.IsNullOrEmpty(processScript.Token)) + { + streamWriter.WriteLine("echo \"SessionToken\": \"{0}\",", processScript.Token); + streamWriter.WriteLine("echo \"Expiration\": \"{0}\",", expirationDate); + } + if (!string.IsNullOrEmpty(processScript.AccountId)) + { + streamWriter.WriteLine("echo \"AccountId\": \"{0}\"", processScript.AccountId); + } + streamWriter.WriteLine("echo }"); + } + } + private class ProcessScript + { + public string Version { get; set; } + public string AccessKey { get; set; } + public string SecretKey { get; set; } + public string Token { get; set; } + public string AccountId { get; set; } + } + } + + // It felt more correct to mock the API Call given the test case definitions, rather than mock these methods + // to return the correct immutable credentials so I went with this path + // instead of creating a testable credential inheriting from the base class. The test cases explicitly call out + // API call. It isn't an exact 1:1 mapping of the logic, but it does the important part of making the API call. + + // A testable implementation of ICoreAmazonSTS which can accept an injected mocked client + public class TestableAmazonSTSClient : ICoreAmazonSTS + { + private readonly IAmazonSecurityTokenService _stsClient; + + public TestableAmazonSTSClient(IAmazonSecurityTokenService stsClient) + { + _stsClient = stsClient; + } + + public AssumeRoleImmutableCredentials CredentialsFromAssumeRoleAuthentication(string roleArn, string roleSessionName, AssumeRoleAWSCredentialsOptions options) + { + try + { + var request = new AssumeRoleRequest + { + RoleArn = roleArn, + RoleSessionName = roleSessionName + }; + if (options != null) + { + request.ExternalId = options.ExternalId; + request.SerialNumber = options.MfaSerialNumber; + request.TokenCode = options.MfaTokenCode; + request.Policy = options.Policy; + request.SourceIdentity = options.SourceIdentity; + + if (options.DurationSeconds.HasValue) + { + request.DurationSeconds = options.DurationSeconds.Value; + } + + if (options.Tags != null && options.Tags.Count > 0) + { + request.Tags = options.Tags.Select(kv => new Tag() { Key = kv.Key, Value = kv.Value }).ToList(); + } + + if (options.TransitiveTagKeys != null && options.TransitiveTagKeys.Count > 0) + { + request.TransitiveTagKeys = options.TransitiveTagKeys; + } + } + var response = _stsClient.AssumeRole(request); + + return new AssumeRoleImmutableCredentials( + response.Credentials.AccessKeyId, + response.Credentials.SecretAccessKey, + response.Credentials.SessionToken, + response.Credentials.Expiration.GetValueOrDefault(), + Arn.Parse(response.AssumedRoleUser.Arn).AccountId + ); + } + + catch (Exception e) + { + var msg = "Error calling AssumeRole for role " + roleArn; + var exception = new AmazonClientException(msg, e); + throw exception; + } + } + public Task CredentialsFromAssumeRoleAuthenticationAsync(string roleArn, string roleSessionName, AssumeRoleAWSCredentialsOptions options) + { + throw new NotImplementedException(); + } + + public AssumeRoleImmutableCredentials CredentialsFromAssumeRoleWithWebIdentityAuthentication(string webIdentityToken, string roleArn, string roleSessionName, AssumeRoleWithWebIdentityCredentialsOptions options) + { + var request = new AssumeRoleWithWebIdentityRequest + { + WebIdentityToken = webIdentityToken, + RoleArn = roleArn, + RoleSessionName = roleSessionName + }; + var response = _stsClient.AssumeRoleWithWebIdentity(request); + return new AssumeRoleImmutableCredentials(response.Credentials.AccessKeyId, response.Credentials.SecretAccessKey, + response.Credentials.SessionToken, response.Credentials.Expiration.GetValueOrDefault(), Arn.Parse(response.AssumedRoleUser.Arn).AccountId); + } + + public Task CredentialsFromAssumeRoleWithWebIdentityAuthenticationAsync(string webIdentityToken, string roleArn, string roleSessionName, AssumeRoleWithWebIdentityCredentialsOptions options) + { + throw new NotImplementedException(); + } + + //What we really want to test is if the account id is properly populated after an AssumeRoleWithSAML call and not all the SAML assertion logic, so skip that. + public SAMLImmutableCredentials CredentialsFromSAMLAuthentication(string endpoint, string authenticationType, string roleArn, TimeSpan credentialDuration, ICredentials userCredential) + { + var assumeSamlRequest = new AssumeRoleWithSAMLRequest + { + SAMLAssertion = "AssertionDocument", + RoleArn = roleArn, + PrincipalArn = "prinicpalArn", + DurationSeconds = 0 + }; + + var response = _stsClient.AssumeRoleWithSAML(assumeSamlRequest); + + return new SAMLImmutableCredentials(response.Credentials.GetCredentials(), + response.Credentials.Expiration.GetValueOrDefault().ToUniversalTime(), + response.Subject, + Arn.Parse(response.AssumedRoleUser.Arn).AccountId); + } + + public Task CredentialsFromSAMLAuthenticationAsync(string endpoint, + string authenticationType, + string roleARN, + TimeSpan credentialDuration, + ICredentials userCredential) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + } +} diff --git a/sdk/test/UnitTests/Custom/Runtime/Credentials/AccountIdEndpointTests/accountid-source-testcases.json b/sdk/test/UnitTests/Custom/Runtime/Credentials/AccountIdEndpointTests/accountid-source-testcases.json new file mode 100644 index 000000000000..42c7674301af --- /dev/null +++ b/sdk/test/UnitTests/Custom/Runtime/Credentials/AccountIdEndpointTests/accountid-source-testcases.json @@ -0,0 +1,576 @@ +[ + { + "documentation": "When calling Sts::AssumeRole successfully, find account ID in response", + "identitySource": "StsCredentialsProvider", + "id": "STS:1", + "input": { + "apiCall": [ + { + "name" : "assumeRole", + "response" : { + "assumedRoleUser": { + "assumedRoleId": "roleId", + "arn": "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When calling Sts::AssumeRoleWithSaml successfully, find account ID in response", + "identitySource": "StsCredentialsProvider", + "id": "STS:2", + "input": { + "apiCall": [ + { + "name" : "assumeRoleWithSaml", + "response" : { + "assumedRoleUser": { + "assumedRoleId": "roleId", + "arn": "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When calling Sts::AssumeRoleWithWebIdentity successfully, find account ID in response", + "identitySource": "StsCredentialsProvider", + "id": "STS:3", + "input": { + "apiCall": [ + { + "name" : "assumeRoleWithWebIdentity", + "response" : { + "assumedRoleUser": { + "assumedRoleId": "roleId", + "arn": "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When calling Sts::GetFederationToken successfully, find account ID in response", + "identitySource": "StsCredentialsProvider", + "id": "STS:4", + "input": { + "apiCall": [ + { + "name" : "getFederationToken", + "response" : { + "federatedUser": { + "federatedUserId": "roleId", + "arn": "arn:aws:sts::123456789001:assumed-role/assume-role-integration-test-role/Name" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When environment is configured with web identity, find account ID in response", + "identitySource": "StsCredentialsProvider", + "id": "STS:5", + "input": { + "environment": { + "AWS_WEB_IDENTITY_TOKEN_FILE": "some_path", + "AWS_ROLE_ARN" : "arn:aws:iam::123456789001:role", + "AWS_ACCOUNT_ID": "123456789002", + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar" + } + }, + "expected": { + "accountId": "123456789001" + } + }, + { + "documentation": "When calling Sso::GetCredentials successfully, find account ID in request", + "identitySource": "SsoCredentialsProvider", + "id": "SSO:1", + "input": { + "apiCall": [ + { + "name": "getCredentials", + "request": { + "accountId": "123456789001" + }, + "response": { + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When calling Sso::GetCredentials unsuccessfully, does not find account ID", + "identitySource": "SsoCredentialsProvider", + "id": "SSO:2", + "input": { + "apiCall": [ + { + "name": "getCredentials", + "request": { + "accountId": "123456789001" + }, + "error": {} + } + ] + }, + "expected": {} + }, + { + "documentation": "When profile is configured with role, accountid and call is successful, find account ID in call response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:1", + "input": { + "configFile": "[profile assume-role]\nrole_arn = arn:aws:iam::123456789002:role/MyRole\nsource_profile = assume-creds\n\n[profile assume-creds]\naws_access_key_id = abc123\naws_secret_access_key = def456\naws_account_id = 123456789001", + "apiCall": [ + { + "name" : "assumeRole", + "response" : { + "assumedRoleUser": { + "assumedRoleId": "roleId", + "arn": "arn:aws:iam::123456789002:role/MyRole" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789002", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with chained roles, accountid and calls are successful, find account ID in call response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:2", + "input": { + "configFile": "[profile final-role]\nrole_arn = arn:aws:iam::123456789003:role/MyRole\nsource_profile = chained-role\n\n[profile chained-role]\nrole_arn = arn:aws:iam::123456789002:role/MyRole\nsource_profile = assume-creds\n\n[profile assume-creds]\naws_access_key_id = abc123\naws_secret_access_key = def456\naws_account_id = 123456789001", + "apiCall": [ + { + "name" : "assumeRole", + "response" : { + "assumedRoleUser": { + "assumedRoleId": "roleId", + "arn": "arn:aws:iam::123456789003:role/MyRole" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789003", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with role, accountid and env var credentials_source, find account ID in call response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:3", + "input": { + "configFile": "[profile test-role]\nrole_arn = arn:aws:iam::123456789003:role/MyRole\ncredential_source = Environment\naws_account_id = 123456789001\n", + "environment": { + "AWS_ACCOUNT_ID": "123456789002", + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar" + }, + "apiCall": [ + { + "name" : "assumeRole", + "response" : { + "assumedRoleUser": { + "assumedRoleId": "roleId", + "arn": "arn:aws:iam::123456789003:role/MyRole" + }, + "credentials": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + } + } + ] + }, + "expected": { + "accountId": "123456789003", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with web identity, find account ID in response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:4", + "input": { + "configFile": "[profile test-role]\nrole_arn = arn:aws:iam::123456789003:role/MyRole\nweb_identity_token_file = some_path\ncredential_source = Environment\naws_account_id = 123456789001\n", + "environment": { + "AWS_ACCOUNT_ID": "123456789002", + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar" + } + }, + "expected": { + "accountId": "123456789003" + } + }, + { + "documentation": "When profile is configured with static credentials and accountid, find account id in profile", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:5", + "input": { + "configFile": "[default]\naws_access_key_id = foo\naws_secret_access_key = bar\naws_account_id = 123456789001" + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + { + "documentation": "When profile is configured with static credentials but no accountid, does not find accountid", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:6", + "input": { + "configFile": "[default]\naws_access_key_id = foo\naws_secret_access_key = bar\n" + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + { + "documentation": "When profile is configured with static credentials, session token and accountid, find account id in profile", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:7", + "input": { + "configFile": "[default]\naws_access_key_id = foo\naws_secret_access_key = bar\naws_session_token = baz\naws_account_id = 123456789001" + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with static credentials, session token but no accountid, does not find accountid", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:8", + "input": { + "configFile": "[default]\naws_access_key_id = foo\naws_secret_access_key = bar\naws_session_token = baz\n" + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with static credentials, session token but no accountid, does not find accountid", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:9", + "input": { + "configFile": "[default]\naws_access_key_id = foo\naws_secret_access_key = bar\naws_session_token = baz\n" + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When static credentials and accountid are configured, finds accountid", + "identitySource": "StaticCredentialsProvider", + "id": "STA:2", + "input": { + "static": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + { + "documentation": "When static credentials but no accountid are configured, does not find accountid", + "identitySource": "StaticCredentialsProvider", + "id": "STA:3", + "input": { + "static": { + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + { + "documentation": "When session credentials and accountid are configured, finds accountid", + "identitySource": "StaticCredentialsProvider", + "id": "STA:4", + "input": { + "static": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When environment variables contain static credentials and accountid, find account id in env vars", + "identitySource": "EnvironmentVariableCredentialsProvider", + "id": "ENV:1", + "input": { + "environment": { + "AWS_ACCOUNT_ID": "123456789001", + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar" + } + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + { + "documentation": "When environment variables contain static credentials but no accountid, does not find accountid", + "identitySource": "EnvironmentVariableCredentialsProvider", + "id": "ENV:2", + "input": { + "environment": { + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar" + } + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + }, + { + "documentation": "When environment variables contain static credentials, session token and accountid, find account id in env vars", + "identitySource": "EnvironmentVariableCredentialsProvider", + "id": "ENV:3", + "input": { + "environment": { + "AWS_ACCOUNT_ID": "123456789001", + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar", + "AWS_SESSION_TOKEN": "baz" + } + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When environment variables contain static credentials, session token but no accountid, does not find accountid", + "identitySource": "EnvironmentVariableCredentialsProvider", + "id": "ENV:4", + "input": { + "environment": { + "AWS_ACCESS_KEY_ID": "foo", + "AWS_SECRET_ACCESS_KEY": "bar", + "AWS_SESSION_TOKEN": "baz" + } + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When you use process credentials provider and process returns session credentials and accountid, find accountid in response", + "identitySource": "ProcessCredentialsProvider", + "id": "PRO:1", + "input": { + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"SessionToken\": \"baz\"\n\"AccountId\": \"123456789001\"}" + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When you use process credentials provider and process returns session credentials but not accountid, does not find accountid", + "identitySource": "ProcessCredentialsProvider", + "id": "PRO:2", + "input": { + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"SessionToken\": \"baz\"}" + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with process source and process returns session credentials and accountid, find accountid in response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:10", + "input": { + "configFile": "[profile process-role]\ncredential_process = get_credentials.sh\n", + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"SessionToken\": \"baz\"\n\"AccountId\": \"123456789002\"}" + }, + "expected": { + "accountId": "123456789002", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with process source, accountid and process returns session credentials and accountid, find accountid in response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:11", + "input": { + "configFile": "[profile process-role]\ncredential_process = get_credentials.sh\naws_account_id = 123456789001\n", + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"SessionToken\": \"baz\"\n\"AccountId\": \"123456789002\"}" + }, + "expected": { + "accountId": "123456789002", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with process source, accountid and process returns session credentials but no accountid, find accountid in profile", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:12", + "input": { + "configFile": "[profile process-role]\ncredential_process = get_credentials.sh\naws_account_id = 123456789001\n", + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"SessionToken\": \"baz\"}" + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with process source and process returns session credentials but no accountid, does not find accountid", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:13", + "input": { + "configFile": "[profile process-role]\ncredential_process = get_credentials.sh\n", + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"SessionToken\": \"baz\"}" + }, + "expected": { + "accessKeyId": "foo", + "secretAccessKey": "bar", + "sessionToken": "baz" + } + }, + { + "documentation": "When profile is configured with process source and process returns static credentials and accountid, find accountid in response", + "identitySource": "ProfileCredentialsProvider", + "id": "CFG:14", + "input": { + "configFile": "[profile process-role]\ncredential_process = get_credentials.sh\n", + "process": "{\"Version\": 1,\n\"AccessKeyId\": \"foo\",\n\"SecretAccessKey\": \"bar\",\n\"AccountId\": \"123456789001\"}" + }, + "expected": { + "accountId": "123456789001", + "accessKeyId": "foo", + "secretAccessKey": "bar" + } + } +] \ No newline at end of file diff --git a/sdk/test/UnitTests/Custom/Runtime/Credentials/SharedCredentialsFileTest.cs b/sdk/test/UnitTests/Custom/Runtime/Credentials/SharedCredentialsFileTest.cs index c4aedb91ed16..bc45aea0e7f5 100644 --- a/sdk/test/UnitTests/Custom/Runtime/Credentials/SharedCredentialsFileTest.cs +++ b/sdk/test/UnitTests/Custom/Runtime/Credentials/SharedCredentialsFileTest.cs @@ -214,7 +214,6 @@ private static class SampleValues { AccessKey = "basic_aws_access_key_id", SecretKey = "basic_aws_secret_access_key", - Services = "foo" }; private static readonly string BasicProfileTextCredentialsPrecedence = new StringBuilder() @@ -541,7 +540,7 @@ public void ServicesConfigurationCanContainMultipleProperties() { "name", "value" }, { "name2", "value2" } }; - tester.ReadAndAssertProfile("bar", BasicProfileOptionsWithServices, expectedProperties); + tester.ReadAndAssertProfile("bar", BasicProfileOptions, expectedProperties); } }