1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-28 15:35:08 +03:00

Bug 1941: Support reading S3 credentials from AWS CLI configuration

https://winscp.net/tracker/1941

Source commit: 484df495dbbbf9937495ed8315d67f43260c2932
This commit is contained in:
Martin Prikryl
2021-01-19 11:49:14 +00:00
parent f50e0dc8d5
commit 1bcbb70a45
12 changed files with 333 additions and 61 deletions

View File

@@ -27,6 +27,13 @@
//---------------------------------------------------------------------------
#define FILE_OPERATION_LOOP_TERMINAL FTerminal
//---------------------------------------------------------------------------
#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_CONFIG_FILE L"AWS_CONFIG_FILE"
#define AWS_PROFILE L"AWS_PROFILE"
#define AWS_PROFILE_DEFAULT L"default"
//---------------------------------------------------------------------------
static std::unique_ptr<TCriticalSection> LibS3Section(TraceInitPtr(new TCriticalSection()));
//---------------------------------------------------------------------------
UTF8String LibS3Delimiter(L"/");
@@ -46,6 +53,84 @@ UnicodeString __fastcall S3LibDefaultRegion()
return StrFromS3(S3_DEFAULT_REGION);
}
//---------------------------------------------------------------------------
bool S3ConfigFileTried = false;
std::unique_ptr<TCustomIniFile> S3ConfigFile;
UnicodeString S3Profile;
//---------------------------------------------------------------------------
UnicodeString GetS3ConfigValue(const UnicodeString & Name, UnicodeString * Source)
{
UnicodeString Result;
UnicodeString ASource;
TGuard Guard(LibS3Section.get());
try
{
Result = GetEnvironmentVariable(Name);
if (!Result.IsEmpty())
{
ASource = FORMAT(L"%%%s%%", (Name));
}
else
{
if (!S3ConfigFileTried)
{
S3ConfigFileTried = true;
S3Profile = GetEnvironmentVariable(AWS_PROFILE);
if (S3Profile.IsEmpty())
{
S3Profile = AWS_PROFILE_DEFAULT;
}
UnicodeString ConfigFileName = GetEnvironmentVariable(AWS_CONFIG_FILE);
if (Result.IsEmpty())
{
UnicodeString ProfilePath = GetShellFolderPath(CSIDL_PROFILE);
UnicodeString DefaultConfigFileName = IncludeTrailingBackslash(ProfilePath) + L".aws\\credentials";
if (FileExists(DefaultConfigFileName))
{
ConfigFileName = DefaultConfigFileName;
}
}
S3ConfigFile.reset(new TMemIniFile(ConfigFileName));
}
if (S3ConfigFile.get() != NULL)
{
Result = S3ConfigFile->ReadString(S3Profile, Name, UnicodeString());
if (!Result.IsEmpty())
{
ASource = FORMAT(L"%s/%s", (ExtractFileName(S3ConfigFile->FileName), S3Profile));
}
}
}
}
catch (Exception & E)
{
throw ExtException(&E, MainInstructions(LoadStr(S3_CONFIG_ERROR)));
}
if (Source != NULL)
{
*Source = ASource;
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString S3EnvUserName(UnicodeString * Source)
{
return GetS3ConfigValue(AWS_ACCESS_KEY_ID, Source);
}
//---------------------------------------------------------------------------
UnicodeString S3EnvPassword(UnicodeString * Source)
{
return GetS3ConfigValue(AWS_SECRET_ACCESS_KEY, Source);
}
//---------------------------------------------------------------------------
UnicodeString S3EnvSessionToken(UnicodeString * Source)
{
return GetS3ConfigValue(AWS_SESSION_TOKEN, Source);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
const int TS3FileSystem::S3MinMultiPartChunkSize = 5 * 1024 * 1024;
const int TS3FileSystem::S3MaxMultiPartChunks = 10000;
@@ -105,7 +190,17 @@ void __fastcall TS3FileSystem::Open()
FAccessKeyId.SetLength(S3_MAX_ACCESS_KEY_ID_LENGTH);
}
UnicodeString SecretAccessKey = UTF8String(NormalizeString(Data->Password));
UnicodeString Password = Data->Password;
if (Password.IsEmpty() && Data->S3CredentialsEnv)
{
UnicodeString PasswordSource;
Password = S3EnvPassword(&PasswordSource);
if (!Password.IsEmpty())
{
FTerminal->LogEvent(FORMAT(L"Password (secret access key) read from %s", (PasswordSource)));
}
}
UnicodeString SecretAccessKey = UTF8String(NormalizeString(Password));
if (SecretAccessKey.IsEmpty() && !FTerminal->SessionData->FingerprintScan)
{
if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(S3_SECRET_ACCESS_KEY_TITLE), L"",
@@ -117,7 +212,17 @@ void __fastcall TS3FileSystem::Open()
}
FSecretAccessKey = UTF8String(SecretAccessKey);
FSecurityTokenBuf = UTF8String(Data->S3SessionToken);
UnicodeString SessionToken = Data->S3SessionToken;
if (SessionToken.IsEmpty() && Data->S3CredentialsEnv)
{
UnicodeString SessionTokenSource;
SessionToken = S3EnvSessionToken(&SessionTokenSource);
if (!SessionToken.IsEmpty())
{
FTerminal->LogEvent(FORMAT(L"Session token read from %s", (SessionTokenSource)));
}
}
FSecurityTokenBuf = UTF8String(SessionToken);
FSecurityToken = static_cast<const char *>(FSecurityTokenBuf.data());
FHostName = UTF8String(Data->HostNameExpanded);