2222
2323namespace nix {
2424
25- namespace {
26-
27- // Global credential provider cache using boost's concurrent map
28- // Key: profile name (empty string for default profile)
29- using CredentialProviderCache =
30- boost::concurrent_flat_map<std::string, std::shared_ptr<Aws::Crt::Auth::ICredentialsProvider>>;
31-
32- static CredentialProviderCache credentialProviderCache;
33-
34- /* *
35- * Clear all cached credential providers.
36- * Called automatically by CrtWrapper destructor during static destruction.
37- */
38- static void clearAwsCredentialsCache ()
25+ AwsAuthError::AwsAuthError (int errorCode)
26+ : Error(" AWS authentication error: '%s' (%d)" , aws_error_str(errorCode), errorCode)
27+ , errorCode(errorCode)
3928{
40- credentialProviderCache.clear ();
4129}
4230
43- static void initAwsCrt ()
44- {
45- struct CrtWrapper
46- {
47- Aws::Crt::ApiHandle apiHandle;
48-
49- CrtWrapper ()
50- {
51- apiHandle.InitializeLogging (Aws::Crt::LogLevel::Warn, static_cast <FILE *>(nullptr ));
52- }
53-
54- ~CrtWrapper ()
55- {
56- try {
57- // CRITICAL: Clear credential provider cache BEFORE AWS CRT shuts down
58- // This ensures all providers (which hold references to ClientBootstrap)
59- // are destroyed while AWS CRT is still valid
60- clearAwsCredentialsCache ();
61- // Now it's safe for ApiHandle destructor to run
62- } catch (...) {
63- ignoreExceptionInDestructor ();
64- }
65- }
66- };
67-
68- static CrtWrapper crt;
69- }
31+ namespace {
7032
7133static AwsCredentials getCredentialsFromProvider (std::shared_ptr<Aws::Crt::Auth::ICredentialsProvider> provider)
7234{
@@ -79,8 +41,7 @@ static AwsCredentials getCredentialsFromProvider(std::shared_ptr<Aws::Crt::Auth:
7941
8042 provider->GetCredentials ([prom](std::shared_ptr<Aws::Crt::Auth::Credentials> credentials, int errorCode) {
8143 if (errorCode != 0 || !credentials) {
82- prom->set_exception (
83- std::make_exception_ptr (AwsAuthError (" Failed to resolve AWS credentials: error code %d" , errorCode)));
44+ prom->set_exception (std::make_exception_ptr (AwsAuthError (errorCode)));
8445 } else {
8546 auto accessKeyId = Aws::Crt::ByteCursorToStringView (credentials->GetAccessKeyId ());
8647 auto secretAccessKey = Aws::Crt::ByteCursorToStringView (credentials->GetSecretAccessKey ());
@@ -113,7 +74,35 @@ static AwsCredentials getCredentialsFromProvider(std::shared_ptr<Aws::Crt::Auth:
11374
11475} // anonymous namespace
11576
116- AwsCredentials getAwsCredentials (const std::string & profile)
77+ class AwsCredentialProviderImpl : public AwsCredentialProvider
78+ {
79+ public:
80+ AwsCredentialProviderImpl ()
81+ {
82+ apiHandle.InitializeLogging (Aws::Crt::LogLevel::Warn, static_cast <FILE *>(nullptr ));
83+ }
84+
85+ AwsCredentials getCredentialsRaw (const std::string & profile);
86+
87+ AwsCredentials getCredentials (const ParsedS3URL & url) override
88+ {
89+ auto profile = url.profile .value_or (" " );
90+ try {
91+ return getCredentialsRaw (profile);
92+ } catch (AwsAuthError & e) {
93+ warn (" AWS authentication failed for S3 request %s: %s" , url.toHttpsUrl (), e.message ());
94+ credentialProviderCache.erase (profile);
95+ throw ;
96+ }
97+ }
98+
99+ private:
100+ Aws::Crt::ApiHandle apiHandle;
101+ boost::concurrent_flat_map<std::string, std::shared_ptr<Aws::Crt::Auth::ICredentialsProvider>>
102+ credentialProviderCache;
103+ };
104+
105+ AwsCredentials AwsCredentialProviderImpl::getCredentialsRaw (const std::string & profile)
117106{
118107 // Get or create credential provider with caching
119108 std::shared_ptr<Aws::Crt::Auth::ICredentialsProvider> provider;
@@ -132,8 +121,6 @@ AwsCredentials getAwsCredentials(const std::string & profile)
132121 profile.empty () ? " (default)" : profile.c_str ());
133122
134123 try {
135- initAwsCrt ();
136-
137124 if (profile.empty ()) {
138125 Aws::Crt::Auth::CredentialsProviderChainDefaultConfig config;
139126 config.Bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap ();
@@ -173,17 +160,15 @@ AwsCredentials getAwsCredentials(const std::string & profile)
173160 return getCredentialsFromProvider (provider);
174161}
175162
176- void invalidateAwsCredentials ( const std::string & profile )
163+ ref<AwsCredentialProvider> makeAwsCredentialsProvider ( )
177164{
178- credentialProviderCache. erase (profile );
165+ return make_ref<AwsCredentialProviderImpl>( );
179166}
180167
181- AwsCredentials preResolveAwsCredentials ( const ParsedS3URL & s3Url )
168+ ref<AwsCredentialProvider> getAwsCredentialsProvider ( )
182169{
183- std::string profile = s3Url.profile .value_or (" " );
184-
185- // Get credentials (automatically cached)
186- return getAwsCredentials (profile);
170+ static auto instance = makeAwsCredentialsProvider ();
171+ return instance;
187172}
188173
189174} // namespace nix
0 commit comments