/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using Amazon.Runtime.CredentialManagement.Internal;
using Amazon.Runtime.Internal.Util;
using Amazon.Runtime;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Diagnostics.CodeAnalysis;
namespace Amazon.Runtime.CredentialManagement
{
///
/// Provides access to read and write to the shared credentials INI file.
/// The file is read, parsed, and validated at construction time.
/// Changes can be made using the RegisterProfile() and
/// UnregisterProfile() methods.
///
/// This class is not threadsafe.
///
public class SharedCredentialsFile : ICredentialProfileStore
{
public const string DefaultProfileName = "default";
public const string SharedCredentialsFileEnvVar = "AWS_SHARED_CREDENTIALS_FILE";
public const string SharedConfigFileEnvVar = "AWS_CONFIG_FILE";
private const string ToolkitArtifactGuidField = "toolkit_artifact_guid";
private const string RegionField = "region";
private const string EndpointDiscoveryEnabledField = "endpoint_discovery_enabled";
private const string ConfigFileName = "config";
private const string DefaultDirectoryName = ".aws";
private const string DefaultFileName = "credentials";
private const string DefaultConfigurationModeField = "defaults_mode";
private const string CredentialProcess = "credential_process";
private const string StsRegionalEndpointsField = "sts_regional_endpoints";
private const string S3UseArnRegionField = "s3_use_arn_region";
private const string S3RegionalEndpointField = "s3_us_east_1_regional_endpoint";
private const string S3DisableMultiRegionAccessPointsField = "s3_disable_multiregion_access_points";
private const string RetryModeField = "retry_mode";
private const string MaxAttemptsField = "max_attempts";
private const string SsoAccountId = "sso_account_id";
private const string SsoRegion = "sso_region";
private const string SsoRoleName = "sso_role_name";
private const string SsoStartUrl = "sso_start_url";
private const string SsoSession = "sso_session";
private const string EC2MetadataServiceEndpointField = "ec2_metadata_service_endpoint";
private const string EC2MetadataServiceEndpointModeField = "ec2_metadata_service_endpoint_mode";
private const string UseDualstackEndpointField = "use_dualstack_endpoint";
private const string UseFIPSEndpointField = "use_fips_endpoint";
private const string EndpointUrlField = "endpoint_url";
private const string ServicesField = "services";
private const string IgnoreConfiguredEndpointUrlsField = "ignore_configured_endpoint_urls";
private readonly Logger _logger = Logger.GetLogger(typeof(SharedCredentialsFile));
private static readonly HashSet ReservedPropertyNames = new HashSet(StringComparer.OrdinalIgnoreCase)
{
ToolkitArtifactGuidField,
RegionField,
EndpointDiscoveryEnabledField,
CredentialProcess,
StsRegionalEndpointsField,
S3UseArnRegionField,
S3RegionalEndpointField,
S3DisableMultiRegionAccessPointsField,
RetryModeField,
MaxAttemptsField,
SsoAccountId,
SsoRegion,
SsoRoleName,
SsoStartUrl,
SsoSession,
EC2MetadataServiceEndpointField,
EC2MetadataServiceEndpointModeField,
UseDualstackEndpointField,
UseFIPSEndpointField,
DefaultConfigurationModeField,
EndpointUrlField,
ServicesField,
IgnoreConfiguredEndpointUrlsField
};
///
/// To maintain compatibility with the CLI,
/// SharedCredentialsFile doesn't support the SAML profileTypes.
///
private static readonly HashSet ProfileTypeWhitelist =
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,
#if !BCL35
CredentialProfileType.SSO,
#endif
};
private static readonly CredentialProfilePropertyMapping PropertyMapping =
new CredentialProfilePropertyMapping(
new Dictionary()
{
{ "AccessKey", "aws_access_key_id" },
{ "CredentialSource", "credential_source" },
{ "EndpointName", null },
{ "ExternalID", "external_id" },
{ "MfaSerial", "mfa_serial" },
{ "RoleArn", "role_arn" },
{ "RoleSessionName", "role_session_name" },
{ "SecretKey", "aws_secret_access_key" },
{ "SourceProfile", "source_profile" },
{ "Token", "aws_session_token" },
{ "UserIdentity", null },
{ "CredentialProcess" , "credential_process" },
{ "WebIdentityTokenFile", "web_identity_token_file" },
{ "Services", "services" },
{ "EndpointUrl", "endpoint_url" },
#if !BCL35
{ nameof(CredentialProfileOptions.SsoAccountId), SsoAccountId },
{ nameof(CredentialProfileOptions.SsoRegion), SsoRegion },
{ nameof(CredentialProfileOptions.SsoRoleName), SsoRoleName },
{ nameof(CredentialProfileOptions.SsoSession), SsoSession },
{ nameof(CredentialProfileOptions.SsoStartUrl), SsoStartUrl },
#endif
}
);
///
/// The default directory for the credentials file. By default it searches in ~/.aws. This behavior can be overridden.
///
public static readonly string DefaultDirectory;
///
/// The default file path for the credentials file. By default it searches for ~/.aws/credentials. This behavior can be overriden.
///
public static string DefaultFilePath { get; private set; }
///
/// The default directory for the config file. By default it searches in ~/.aws This behavior can be overriden.
///
public static readonly string DefaultConfigDirectory;
///
/// The default file path for the config file. By default it searches in ~/.aws/config
///
public static string DefaultConfigFilePath { get; private set; }
static SharedCredentialsFile()
{
var awsCredentialsEnvironmentPath = Environment.GetEnvironmentVariable(SharedCredentialsFileEnvVar);
var awsConfigEnvironmentPath = Environment.GetEnvironmentVariable(SharedConfigFileEnvVar);
if (!string.IsNullOrEmpty(awsConfigEnvironmentPath))
{
if (File.Exists(awsConfigEnvironmentPath))
{
DefaultConfigDirectory = Directory.GetParent(awsConfigEnvironmentPath).FullName;
DefaultConfigFilePath = awsConfigEnvironmentPath;
}
}
if (!string.IsNullOrEmpty(awsCredentialsEnvironmentPath))
{
if (File.Exists(awsCredentialsEnvironmentPath))
{
DefaultDirectory = Directory.GetParent(awsCredentialsEnvironmentPath).FullName;
DefaultFilePath = awsCredentialsEnvironmentPath;
}
}
if (DefaultFilePath == null || DefaultConfigFilePath == null)
{
var baseDirectory = Environment.GetEnvironmentVariable("HOME");
if (string.IsNullOrEmpty(baseDirectory))
baseDirectory = Environment.GetEnvironmentVariable("USERPROFILE");
if (string.IsNullOrEmpty(baseDirectory))
#if NETSTANDARD
baseDirectory = Directory.GetCurrentDirectory();
#else
baseDirectory = Environment.CurrentDirectory;
#endif
if (DefaultFilePath == null)
{
DefaultDirectory = Path.Combine(baseDirectory, DefaultDirectoryName);
DefaultFilePath = Path.Combine(DefaultDirectory, DefaultFileName);
}
if (DefaultConfigFilePath == null)
{
DefaultConfigDirectory = Path.Combine(baseDirectory, DefaultDirectoryName);
DefaultConfigFilePath = Path.Combine(DefaultConfigDirectory, ConfigFileName);
}
}
}
private ProfileIniFile _credentialsFile;
private ProfileIniFile _configFile;
///
/// The path to the credentials file
///
public string FilePath { get; private set; }
///
/// The path to the config file
///
public string ConfigFilePath { get; private set; }
///
/// Construct a new SharedCredentialsFile in the default location.
///
public SharedCredentialsFile()
{
SetUpFilePath(null);
Refresh();
}
///
/// Construct a new SharedCredentialsFile.
///
/// The path of the shared credentials file.
public SharedCredentialsFile(string filePath)
{
SetUpFilePath(filePath);
Refresh();
}
///
/// SetUpFilePath sets FilePath and ConfigFilePath using the DefaultFilePath and DefaultConfigFilePath set in
/// the static constructor. If AWSConfigs.AWSProfilesLocation is provided, FilePath supercedes DefaultFilePath
///
///
private void SetUpFilePath(string filePath)
{
if (string.IsNullOrEmpty(filePath))
{
if (string.IsNullOrEmpty(AWSConfigs.AWSProfilesLocation))
{
FilePath = DefaultFilePath;
ConfigFilePath = DefaultConfigFilePath;
}
else
{
FilePath = AWSConfigs.AWSProfilesLocation;
ConfigFilePath = DefaultConfigFilePath;
}
}
else
{
FilePath = filePath;
ConfigFilePath = DefaultConfigFilePath;
}
}
public List ListProfileNames()
{
Refresh();
return ListProfiles().Select(p => p.Name).ToList();
}
public List ListProfiles()
{
Refresh();
var profiles = new List();
foreach (var profileName in ListAllProfileNames())
{
CredentialProfile profile = null;
if (TryGetProfile(profileName, doRefresh: false, isSsoSession: false,isServicesSection: false, out profile) && profile.CanCreateAWSCredentials)
{
profiles.Add(profile);
}
}
return profiles;
}
public bool TryGetProfile(string profileName, out CredentialProfile profile)
{
return TryGetProfile(profileName, doRefresh: true, isSsoSession: false, isServicesSection: false, out profile);
}
///
/// Add the profile given. If the profile already exists, update it.
///
/// The profile to be written.
public void RegisterProfile(CredentialProfile profile)
{
Refresh();
if (profile.CanCreateAWSCredentials || profile.Options.IsEmpty)
{
if (!IsSupportedProfileType(profile.ProfileType))
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
"Unable to update profile {0}. The CredentialProfile object provided represents a " +
"{1} profile but {2} does not support the {1} profile type.",
profile.Name, profile.ProfileType, GetType().Name));
}
RegisterProfileInternal(profile);
}
else
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture,
"Unable to update profile {0}. The CredentialProfile provided is not a valid profile.", profile.Name));
}
}
///
/// Update the profile on disk regardless of the profile type.
///
///
[SuppressMessage("Microsoft.Globalization", "CA1308", Justification = "Value is not surfaced to user. Booleans have been lowercased by SDK precedent.")]
private void RegisterProfileInternal(CredentialProfile profile)
{
var reservedProperties = new Dictionary();
if (profile.UniqueKey != null)
reservedProperties[ToolkitArtifactGuidField] = profile.UniqueKey.Value.ToString("D");
if (profile.Region != null)
reservedProperties[RegionField] = profile.Region.SystemName;
if (profile.EndpointDiscoveryEnabled != null)
reservedProperties[EndpointDiscoveryEnabledField] = profile.EndpointDiscoveryEnabled.Value.ToString().ToLowerInvariant();
if (profile.StsRegionalEndpoints != null)
reservedProperties[StsRegionalEndpointsField] = profile.StsRegionalEndpoints.ToString().ToLowerInvariant();
if (profile.S3UseArnRegion != null)
reservedProperties[S3UseArnRegionField] = profile.S3UseArnRegion.Value.ToString().ToLowerInvariant();
if (profile.S3RegionalEndpoint != null)
reservedProperties[S3RegionalEndpointField] = profile.S3RegionalEndpoint.ToString().ToLowerInvariant();
if (profile.S3DisableMultiRegionAccessPoints != null)
reservedProperties[S3DisableMultiRegionAccessPointsField] = profile.S3DisableMultiRegionAccessPoints.ToString().ToLowerInvariant();
if (profile.RetryMode != null)
reservedProperties[RetryModeField] = profile.RetryMode.ToString().ToLowerInvariant();
if (profile.MaxAttempts != null)
reservedProperties[MaxAttemptsField] = profile.MaxAttempts.ToString().ToLowerInvariant();
if (profile.EC2MetadataServiceEndpoint != null)
reservedProperties[EC2MetadataServiceEndpointField] = profile.EC2MetadataServiceEndpoint.ToString().ToLowerInvariant();
if (profile.EC2MetadataServiceEndpointMode != null)
reservedProperties[EC2MetadataServiceEndpointModeField] = profile.EC2MetadataServiceEndpointMode.ToString().ToLowerInvariant();
if (profile.UseDualstackEndpoint != null)
reservedProperties[UseDualstackEndpointField] = profile.UseDualstackEndpoint.ToString().ToLowerInvariant();
if (profile.UseFIPSEndpoint != null)
reservedProperties[UseFIPSEndpointField] = profile.UseFIPSEndpoint.ToString().ToLowerInvariant();
if(profile.IgnoreConfiguredEndpointUrls != null)
reservedProperties[IgnoreConfiguredEndpointUrlsField] = profile.IgnoreConfiguredEndpointUrls.ToString().ToLowerInvariant();
if(profile.EndpointUrl != null)
reservedProperties[EndpointUrlField] = profile.EndpointUrl.ToString().ToLowerInvariant();
var profileDictionary = PropertyMapping.CombineProfileParts(
profile.Options, ReservedPropertyNames, reservedProperties, profile.Properties);
// The config file might contain parts of the profile
// These parts are updated at the config file and removed from profileDictionary to avoid duplication
UpdateConfigSectionsFromProfile(profile, profileDictionary);
_credentialsFile.EditSection(profile.Name, new SortedDictionary(profileDictionary));
_credentialsFile.Persist();
profile.CredentialProfileStore = this;
}
private void UpdateConfigSectionsFromProfile(CredentialProfile profile, Dictionary profileDictionary)
{
if (_configFile == null || !_configFile.TryGetSection(profile.Name, out var configProperties))
return;
var configPropertiesNames = configProperties.Keys.ToArray();
foreach (var propertyName in configPropertiesNames)
{
if (profileDictionary.ContainsKey(propertyName))
{
configProperties[propertyName] = profileDictionary[propertyName];
profileDictionary.Remove(propertyName); // Remove the property from profileDictionary as we updated it in the config
}
else
{
configProperties[propertyName] = null;
}
}
_configFile.EditSection(profile.Name, new SortedDictionary(configProperties));
_configFile.Persist();
if (configProperties.TryGetValue(SsoSession, out var session)
&& _configFile.TryGetSection(session, true, out var ssoSessionProperties))
{
// Skip SsoSession properties as it might be used by other profiles
var ssoSessionPropertiesNames = ssoSessionProperties.Keys.ToArray();
foreach (var propertyName in ssoSessionPropertiesNames)
{
profileDictionary.Remove(propertyName);
}
}
}
///
/// Deletes the section with the given ProfileName from the SharedCredentialsFile, if one exists.
///
/// The ProfileName of the section to delete.
public void UnregisterProfile(string profileName)
{
Refresh();
_credentialsFile.DeleteSection(profileName);
_credentialsFile.Persist();
}
///
/// Rename the profile with oldProfileName to newProfileName.
///
/// The profile to rename.
/// The new name for the profile.
public void RenameProfile(string oldProfileName, string newProfileName)
{
RenameProfile(oldProfileName, newProfileName, false);
}
///
/// Rename the profile with oldProfileName to newProfileName.
///
/// The profile to rename.
/// The new name for the profile.
/// If true and the destination profile exists it will be overwritten.
public void RenameProfile(string oldProfileName, string newProfileName, bool force)
{
Refresh();
_credentialsFile.RenameSection(oldProfileName, newProfileName, force);
_credentialsFile.Persist();
}
///
/// Make a copy of the profile with fromProfileName called toProfileName.
///
/// The name of the profile to copy from.
/// The name of the new profile.
public void CopyProfile(string fromProfileName, string toProfileName)
{
CopyProfile(fromProfileName, toProfileName, false);
}
///
/// Make a copy of the profile with fromProfileName called toProfileName.
///
/// The name of the profile to copy from.
/// The name of the new profile.
/// If true and the destination profile exists it will be overwritten.
public void CopyProfile(string fromProfileName, string toProfileName, bool force)
{
Refresh();
// Do the copy but make sure to replace the toolkitArtifactGuid with a new one, if it's there.
_credentialsFile.CopySection(fromProfileName, toProfileName,
new Dictionary { { ToolkitArtifactGuidField, Guid.NewGuid().ToString() } }, force);
_credentialsFile.Persist();
}
private void Refresh()
{
_credentialsFile = new ProfileIniFile(FilePath, false);
//Re-check if they set an explicit config file path, use that if it's set
var awsConfigEnvironmentPath = Environment.GetEnvironmentVariable(SharedConfigFileEnvVar);
if (!string.IsNullOrEmpty(awsConfigEnvironmentPath))
{
_configFile = new ProfileIniFile(ConfigFilePath, true);
}
// If a config file exists in the same location as the credentials file and no env vars are set
// load it for use as a read-only source of profile properties.
else
{
var configPath = Path.Combine(Path.GetDirectoryName(FilePath), ConfigFileName);
if (File.Exists(configPath))
{
_configFile = new ProfileIniFile(configPath, true);
}
}
}
private HashSet ListAllProfileNames()
{
var profileNames = _credentialsFile.ListSectionNames();
if (_configFile != null)
{
profileNames.UnionWith(_configFile.ListSectionNames());
}
return profileNames;
}
private bool TryGetProfile(string profileName, bool doRefresh, bool isSsoSession, bool isServicesSection, out CredentialProfile profile)
{
if (doRefresh)
{
Refresh();
}
Dictionary> nestedProperties = null;
Dictionary profileDictionary = null;
if (TryGetSection(profileName, isSsoSession, isServicesSection, out profileDictionary, out nestedProperties))
{
CredentialProfileOptions profileOptions;
Dictionary reservedProperties;
Dictionary userProperties;
PropertyMapping.ExtractProfileParts(
profileDictionary,
ReservedPropertyNames,
out profileOptions,
out reservedProperties,
out userProperties);
string toolkitArtifactGuidStr;
Guid? toolkitArtifactGuid = null;
if (reservedProperties.TryGetValue(ToolkitArtifactGuidField, out toolkitArtifactGuidStr))
{
if (!GuidUtils.TryParseNullableGuid(toolkitArtifactGuidStr, out toolkitArtifactGuid))
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. GUID expected.", toolkitArtifactGuidStr, ToolkitArtifactGuidField, profileName);
profile = null;
return false;
}
}
string ignoreConfiguredEndpointUrlsString;
bool? ignoreConfiguredEndpointUrls = false;
if(reservedProperties.TryGetValue(IgnoreConfiguredEndpointUrlsField, out ignoreConfiguredEndpointUrlsString))
{
bool ignoreConfiguredEndpointUrlsOut;
if(!bool.TryParse(ignoreConfiguredEndpointUrlsString, out ignoreConfiguredEndpointUrlsOut))
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A boolean true/false is expected", ignoreConfiguredEndpointUrlsString, IgnoreConfiguredEndpointUrlsField, profileName);
profile = null;
return false;
}
else
{
ignoreConfiguredEndpointUrls = ignoreConfiguredEndpointUrlsOut;
}
}
string endpointUrlString = null;
if (ignoreConfiguredEndpointUrls == false)
{
string services;
if (profileDictionary.TryGetValue(ServicesField, out services))
{
_configFile.TryGetSection(services, isSsoSession: false, isServicesSection: true, out userProperties, out nestedProperties);
}
else
{
string endpointUrlTemp;
if (profileDictionary.TryGetValue(EndpointUrlField, out endpointUrlTemp))
endpointUrlString = endpointUrlTemp;
}
}
string regionString;
RegionEndpoint region = null;
if (reservedProperties.TryGetValue(RegionField, out regionString))
{
region = RegionEndpoint.GetBySystemName(regionString);
}
string endpointDiscoveryEnabledString;
bool? endpointDiscoveryEnabled = null;
if (reservedProperties.TryGetValue(EndpointDiscoveryEnabledField, out endpointDiscoveryEnabledString))
{
bool endpointDiscoveryEnabledOut;
if (!bool.TryParse(endpointDiscoveryEnabledString, out endpointDiscoveryEnabledOut))
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A boolean true/false is expected.", endpointDiscoveryEnabledString, EndpointDiscoveryEnabledField, profileName);
profile = null;
return false;
}
endpointDiscoveryEnabled = endpointDiscoveryEnabledOut;
}
StsRegionalEndpointsValue? stsRegionalEndpoints = null;
if (reservedProperties.TryGetValue(StsRegionalEndpointsField, out var stsRegionalEndpointsString))
{
#if BCL35
try
{
stsRegionalEndpoints = (StsRegionalEndpointsValue) Enum.Parse(typeof(StsRegionalEndpointsValue), stsRegionalEndpointsString, true);
}
catch (Exception)
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string regional/legacy is expected.", stsRegionalEndpointsString, StsRegionalEndpointsField, profileName);
profile = null;
return false;
}
#else
if (!Enum.TryParse(stsRegionalEndpointsString, true, out var stsRegionalEndpointsTemp))
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string regional/legacy is expected.", stsRegionalEndpointsString, StsRegionalEndpointsField, profileName);
profile = null;
return false;
}
stsRegionalEndpoints = stsRegionalEndpointsTemp;
#endif
}
string s3UseArnRegionString;
bool? s3UseArnRegion = null;
if (reservedProperties.TryGetValue(S3UseArnRegionField, out s3UseArnRegionString))
{
bool s3UseArnRegionOut;
if (!bool.TryParse(s3UseArnRegionString, out s3UseArnRegionOut))
{
profile = null;
return false;
}
s3UseArnRegion = s3UseArnRegionOut;
}
S3UsEast1RegionalEndpointValue? s3RegionalEndpoint = null;
if (reservedProperties.TryGetValue(S3RegionalEndpointField, out var s3RegionalEndpointString))
{
#if BCL35
try
{
s3RegionalEndpoint = (S3UsEast1RegionalEndpointValue) Enum.Parse(typeof(S3UsEast1RegionalEndpointValue), s3RegionalEndpointString, true);
}
catch (Exception)
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string regional/legacy is expected.", s3RegionalEndpointString, S3RegionalEndpointField, profileName);
profile = null;
return false;
}
#else
if (!Enum.TryParse(s3RegionalEndpointString, true, out var s3RegionalEndpointTemp))
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string regional/legacy is expected.", s3RegionalEndpointString, S3RegionalEndpointField, profileName);
profile = null;
return false;
}
s3RegionalEndpoint = s3RegionalEndpointTemp;
#endif
}
string s3DisableMultiRegionAccessPointsString;
bool? s3DisableMultiRegionAccessPoints = null;
if (reservedProperties.TryGetValue(S3DisableMultiRegionAccessPointsField, out s3DisableMultiRegionAccessPointsString))
{
bool s3DisableMultiRegionAccessPointsOut;
if (!bool.TryParse(s3DisableMultiRegionAccessPointsString, out s3DisableMultiRegionAccessPointsOut))
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A boolean true/false is expected.", s3DisableMultiRegionAccessPointsString, S3DisableMultiRegionAccessPointsField, profileName);
profile = null;
return false;
}
s3DisableMultiRegionAccessPoints = s3DisableMultiRegionAccessPointsOut;
}
RequestRetryMode? requestRetryMode = null;
if (reservedProperties.TryGetValue(RetryModeField, out var retryModeString))
{
#if BCL35
try
{
requestRetryMode = (RequestRetryMode) Enum.Parse(typeof(RequestRetryMode), retryModeString, true);
}
catch (Exception)
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string legacy/standard/adaptive is expected.", retryModeString, RetryModeField, profileName);
profile = null;
return false;
}
#else
if (!Enum.TryParse(retryModeString, true, out var retryModeTemp))
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string legacy/standard/adaptive is expected.", retryModeString, RetryModeField, profileName);
profile = null;
return false;
}
requestRetryMode = retryModeTemp;
#endif
}
int? maxAttempts = null;
if (reservedProperties.TryGetValue(MaxAttemptsField, out var maxAttemptsString))
{
if (!int.TryParse(maxAttemptsString, out var maxAttemptsTemp) || maxAttemptsTemp <= 0)
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A positive integer is expected.", maxAttemptsString, MaxAttemptsField, profileName);
profile = null;
return false;
}
maxAttempts = maxAttemptsTemp;
}
string defaultConfigurationModeName;
reservedProperties.TryGetValue(DefaultConfigurationModeField, out defaultConfigurationModeName);
string ec2MetadataServiceEndpoint;
if (reservedProperties.TryGetValue(EC2MetadataServiceEndpointField, out ec2MetadataServiceEndpoint))
{
if (!Uri.IsWellFormedUriString(ec2MetadataServiceEndpoint, UriKind.Absolute))
{
throw new AmazonClientException($"Invalid value {ec2MetadataServiceEndpoint} for {EC2MetadataServiceEndpointField} in profile {profileName}. A well-formed Uri is expected.");
}
}
EC2MetadataServiceEndpointMode? ec2MetadataServiceEndpointMode = null;
if (reservedProperties.TryGetValue(EC2MetadataServiceEndpointModeField, out var ec2MetadataServiceEndpointModeString))
{
#if BCL35
try
{
ec2MetadataServiceEndpointMode = (EC2MetadataServiceEndpointMode)Enum.Parse(typeof(EC2MetadataServiceEndpointMode), ec2MetadataServiceEndpointModeString, true);
}
catch (Exception)
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string IPv4 or IPV6 is expected.", ec2MetadataServiceEndpointModeString, EC2MetadataServiceEndpointModeField, profileName);
profile = null;
return false;
}
#else
if (!Enum.TryParse(ec2MetadataServiceEndpointModeString, true, out var ec2MetadataServiceEndpointModeTemp))
{
_logger.InfoFormat("Invalid value {0} for {1} in profile {2}. A string IPv4 or IPV6 is expected.", ec2MetadataServiceEndpointModeString, EC2MetadataServiceEndpointModeField, profileName);
profile = null;
return false;
}
ec2MetadataServiceEndpointMode = ec2MetadataServiceEndpointModeTemp;
#endif
}
#if !BCL35
if (profileDictionary.TryGetValue(SsoSession, out var session))
{
profileOptions.SsoSession = session;
if (TryGetProfile(session, doRefresh: false, isSsoSession: true, isServicesSection:false, out var sessionProfile))
{
profileOptions.SsoRegion = sessionProfile.Options.SsoRegion;
profileOptions.SsoStartUrl = sessionProfile.Options.SsoStartUrl;
}
else
{
_logger.InfoFormat($"Failed to find {SsoSession} [{session}]");
throw new AmazonClientException($"Invalid Configuration. Failed to find {SsoSession} [{session}]");
}
}
#endif
string useDualstackEndpointString;
bool? useDualstackEndpoint = null;
if (reservedProperties.TryGetValue(UseDualstackEndpointField, out useDualstackEndpointString))
{
bool useDualstackEndpointOut;
if (!bool.TryParse(useDualstackEndpointString, out useDualstackEndpointOut))
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A boolean true/false is expected.", useDualstackEndpointString, UseDualstackEndpointField, profileName);
profile = null;
return false;
}
useDualstackEndpoint = useDualstackEndpointOut;
}
string useFIPSEndpointString;
bool? useFIPSEndpoint = null;
if (reservedProperties.TryGetValue(UseFIPSEndpointField, out useFIPSEndpointString))
{
bool useFIPSEndpointOut;
if (!bool.TryParse(useFIPSEndpointString, out useFIPSEndpointOut))
{
Logger.GetLogger(GetType()).InfoFormat("Invalid value {0} for {1} in profile {2}. A boolean true/false is expected.", useFIPSEndpointString, UseFIPSEndpointField, profileName);
profile = null;
return false;
}
useFIPSEndpoint = useFIPSEndpointOut;
}
profile = new CredentialProfile(profileName, profileOptions)
{
UniqueKey = toolkitArtifactGuid,
Properties = userProperties,
Region = region,
CredentialProfileStore = this,
DefaultConfigurationModeName = defaultConfigurationModeName,
EndpointDiscoveryEnabled = endpointDiscoveryEnabled,
StsRegionalEndpoints = stsRegionalEndpoints,
S3UseArnRegion = s3UseArnRegion,
S3RegionalEndpoint = s3RegionalEndpoint,
S3DisableMultiRegionAccessPoints = s3DisableMultiRegionAccessPoints,
RetryMode = requestRetryMode,
MaxAttempts = maxAttempts,
EC2MetadataServiceEndpoint = ec2MetadataServiceEndpoint,
EC2MetadataServiceEndpointMode = ec2MetadataServiceEndpointMode,
UseDualstackEndpoint = useDualstackEndpoint,
UseFIPSEndpoint = useFIPSEndpoint,
NestedProperties = nestedProperties,
IgnoreConfiguredEndpointUrls = ignoreConfiguredEndpointUrls,
EndpointUrl = endpointUrlString
};
if (!IsSupportedProfileType(profile.ProfileType))
{
_logger.InfoFormat("The profile type {0} is not supported by SharedCredentialsFile.", profile.ProfileType);
profile = null;
return false;
}
return true;
}
profile = null;
return false;
}
///
/// Try to get a profile that may be partially in the credentials file and partially in the config file.
/// If there are identically named properties in both files, the properties in the credentials file take precedence.
///
private bool TryGetSection(string sectionName, bool isSsoSession, bool isServicesSection, out Dictionary iniProperties, out Dictionary> nestedProperties)
{
Dictionary credentialsProperties = null;
Dictionary configProperties = null;
nestedProperties = null;
var hasCredentialsProperties = _credentialsFile.TryGetSection(sectionName, isSsoSession, isServicesSection, out credentialsProperties, out nestedProperties);
var hasConfigProperties = false;
if (_configFile != null)
{
_configFile.ProfileMarkerRequired = sectionName != DefaultProfileName;
hasConfigProperties = _configFile.TryGetSection(sectionName, isSsoSession, isServicesSection, out configProperties, out nestedProperties);
}
if (hasConfigProperties)
{
iniProperties = configProperties;
if (hasCredentialsProperties)
{
// Add all the properties from the credentials file.
// If a property exits in both, the one from the credentials
// file takes precedence and overwrites the one from
// the config file.
foreach (var pair in credentialsProperties)
{
iniProperties[pair.Key] = pair.Value;
}
}
return true;
}
iniProperties = credentialsProperties;
return hasCredentialsProperties;
}
private static bool IsSupportedProfileType(CredentialProfileType? profileType)
{
return !profileType.HasValue || ProfileTypeWhitelist.Contains(profileType.Value);
}
}
}