1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00

AWS credential profiles in config file are also recognized + Bug fix: AWS credentials file path was resolved using AWS_CONFIG_FILE environment variable instead of correct AWS_SHARED_CREDENTIALS_FILE

Source commit: fd25d9213d71c28c9b3ea62e2ae995d5572959c1
This commit is contained in:
Martin Prikryl
2024-04-09 14:27:21 +00:00
parent bc8880137d
commit 481218e7d7

View File

@@ -34,9 +34,11 @@
#define AWS_ACCESS_KEY_ID L"AWS_ACCESS_KEY_ID"
#define AWS_SECRET_ACCESS_KEY L"AWS_SECRET_ACCESS_KEY"
#define AWS_SESSION_TOKEN L"AWS_SESSION_TOKEN"
#define AWS_SHARED_CREDENTIALS_FILE L"AWS_SHARED_CREDENTIALS_FILE"
#define AWS_CONFIG_FILE L"AWS_CONFIG_FILE"
#define AWS_PROFILE L"AWS_PROFILE"
#define AWS_PROFILE_DEFAULT L"default"
#define AWS_CONFIG_PROFILE_PREFIX L"profile "
//---------------------------------------------------------------------------
static std::unique_ptr<TCriticalSection> LibS3Section(TraceInitPtr(new TCriticalSection()));
//---------------------------------------------------------------------------
@@ -57,6 +59,38 @@ UnicodeString __fastcall S3LibDefaultRegion()
return StrFromS3(S3_DEFAULT_REGION);
}
//---------------------------------------------------------------------------
static void NeedS3Config(
UnicodeString & FileName, TDateTime & TimeStamp, std::unique_ptr<TCustomIniFile> & File,
const UnicodeString & DefaultName, const UnicodeString & EnvName)
{
if (FileName.IsEmpty())
{
FileName = GetEnvironmentVariable(EnvName);
if (FileName.IsEmpty())
{
UnicodeString ProfilePath = GetShellFolderPath(CSIDL_PROFILE);
UnicodeString DefaultFileName = IncludeTrailingBackslash(ProfilePath) + L".aws\\" + DefaultName;
if (FileExists(DefaultFileName))
{
FileName = DefaultFileName;
}
}
}
TDateTime CurrentTimestamp;
FileAge(FileName, CurrentTimestamp);
if (TimeStamp != CurrentTimestamp)
{
TimeStamp = CurrentTimestamp;
// TMemIniFile silently ignores empty paths or non-existing files
AppLogFmt(L"Reading AWS '%s' file", (FileName));
File.reset(new TMemIniFile(FileName));
}
}
//---------------------------------------------------------------------------
UnicodeString S3CredentialsFileName;
TDateTime S3CredentialsTimestamp;
std::unique_ptr<TCustomIniFile> S3CredentialsFile;
UnicodeString S3ConfigFileName;
TDateTime S3ConfigTimestamp;
std::unique_ptr<TCustomIniFile> S3ConfigFile;
@@ -79,29 +113,33 @@ static void NeedS3Config()
}
}
if (S3ConfigFileName.IsEmpty())
NeedS3Config(S3CredentialsFileName, S3CredentialsTimestamp, S3CredentialsFile, L"credentials", AWS_SHARED_CREDENTIALS_FILE);
NeedS3Config(S3ConfigFileName, S3ConfigTimestamp, S3ConfigFile, L"config", AWS_CONFIG_FILE);
}
//---------------------------------------------------------------------------
void GetS3Profiles(TStrings * Profiles, TCustomIniFile * File, const UnicodeString & Prefix = EmptyStr)
{
if (File != NULL)
{
S3ConfigFileName = GetEnvironmentVariable(AWS_CONFIG_FILE);
if (S3ConfigFileName.IsEmpty())
std::unique_ptr<TStrings> Sections(new TStringList());
File->ReadSections(Sections.get());
for (int Index = 0; Index < Sections->Count; Index++)
{
UnicodeString ProfilePath = GetShellFolderPath(CSIDL_PROFILE);
UnicodeString DefaultConfigFileName = IncludeTrailingBackslash(ProfilePath) + L".aws\\credentials";
if (FileExists(DefaultConfigFileName))
UnicodeString Section = Sections->Strings[Index];
if (Prefix.IsEmpty() || StartsText(Prefix, Section))
{
S3ConfigFileName = DefaultConfigFileName;
// This is not consistent with AWS CLI.
// AWS CLI fails if one of AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY is set and other is missing:
// "Partial credentials found in env, missing: AWS_SECRET_ACCESS_KEY"
if (!File->ReadString(Section, AWS_ACCESS_KEY_ID, EmptyStr).IsEmpty() ||
!File->ReadString(Section, AWS_SECRET_ACCESS_KEY, EmptyStr).IsEmpty() ||
!File->ReadString(Section, AWS_SESSION_TOKEN, EmptyStr).IsEmpty())
{
Profiles->Add(MidStr(Section, Prefix.Length() + 1));
}
}
}
}
TDateTime Timestamp;
FileAge(S3ConfigFileName, Timestamp);
if (S3ConfigTimestamp != Timestamp)
{
S3ConfigTimestamp = Timestamp;
// TMemIniFile silently ignores empty paths or non-existing files
AppLog(L"Reading AWS credentials file");
S3ConfigFile.reset(new TMemIniFile(S3ConfigFileName));
}
}
//---------------------------------------------------------------------------
TStrings * GetS3Profiles()
@@ -109,30 +147,9 @@ TStrings * GetS3Profiles()
NeedS3Config();
// S3 allegedly treats the section case-sensitively, but our GetS3ConfigValue (ReadString) does not,
// so consistently we return case-insensitive list.
std::unique_ptr<TStrings> Result(new TStringList());
if (S3ConfigFile.get() != NULL)
{
S3ConfigFile->ReadSections(Result.get());
int Index = 0;
while (Index < Result->Count)
{
UnicodeString Section = Result->Strings[Index];
// This is not consistent with AWS CLI.
// AWS CLI fails if one of AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY is set and other is missing:
// "Partial credentials found in env, missing: AWS_SECRET_ACCESS_KEY"
if (S3ConfigFile->ReadString(Section, AWS_ACCESS_KEY_ID, EmptyStr).IsEmpty() &&
S3ConfigFile->ReadString(Section, AWS_SECRET_ACCESS_KEY, EmptyStr).IsEmpty() &&
S3ConfigFile->ReadString(Section, AWS_SESSION_TOKEN, EmptyStr).IsEmpty())
{
Result->Delete(Index);
}
else
{
Index++;
}
}
}
std::unique_ptr<TStrings> Result(CreateSortedStringList());
GetS3Profiles(Result.get(), S3CredentialsFile.get());
GetS3Profiles(Result.get(), S3ConfigFile.get(), AWS_CONFIG_PROFILE_PREFIX);
return Result.release();
}
//---------------------------------------------------------------------------
@@ -145,6 +162,29 @@ UnicodeString ReadUrl(const UnicodeString & Url)
return Http->Response.Trim();
}
//---------------------------------------------------------------------------
static UnicodeString GetS3ConfigValue(
TCustomIniFile * File, const UnicodeString & Profile, const UnicodeString & Name, const UnicodeString & Prefix, UnicodeString & Source)
{
UnicodeString Result;
if (File != NULL)
{
UnicodeString ConfigSection = Profile;
if (!SameText(ConfigSection, AWS_PROFILE_DEFAULT))
{
ConfigSection = Prefix + ConfigSection;
}
// This is not consistent with AWS CLI.
// AWS CLI fails if one of aws_access_key_id or aws_secret_access_key is set and other is missing:
// "Partial credentials found in shared-credentials-file, missing: aws_secret_access_key"
Result = File->ReadString(ConfigSection, Name, EmptyStr);
if (!Result.IsEmpty())
{
Source = FORMAT(L"%s/%s", (ExtractFileName(File->FileName), Profile));
}
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString GetS3ConfigValue(
const UnicodeString & Profile, const UnicodeString & Name, const UnicodeString & CredentialsName, UnicodeString * Source)
{
@@ -166,17 +206,11 @@ UnicodeString GetS3ConfigValue(
{
NeedS3Config();
if (S3ConfigFile.get() != NULL)
UnicodeString AProfile = DefaultStr(Profile, S3Profile);
Result = GetS3ConfigValue(S3CredentialsFile.get(), AProfile, Name, EmptyStr, ASource);
if (Result.IsEmpty())
{
UnicodeString AProfile = DefaultStr(Profile, S3Profile);
// This is not consistent with AWS CLI.
// AWS CLI fails if one of aws_access_key_id or aws_secret_access_key is set and other is missing:
// "Partial credentials found in shared-credentials-file, missing: aws_secret_access_key"
Result = S3ConfigFile->ReadString(AProfile, Name, EmptyStr);
if (!Result.IsEmpty())
{
ASource = FORMAT(L"%s/%s", (ExtractFileName(S3ConfigFile->FileName), AProfile));
}
Result = GetS3ConfigValue(S3ConfigFile.get(), AProfile, Name, AWS_CONFIG_PROFILE_PREFIX, ASource);
}
}
}