| 1 | /* | 
| 2 |   * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. | 
| 3 |   * | 
| 4 |   * Licensed under the Apache License, Version 2.0 (the "License"). | 
| 5 |   * You may not use this file except in compliance with the License. | 
| 6 |   * A copy of the License is located at | 
| 7 |   * | 
| 8 |   *  http://aws.amazon.com/apache2.0 | 
| 9 |   * | 
| 10 |   * or in the "license" file accompanying this file. This file is distributed | 
| 11 |   * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either | 
| 12 |   * express or implied. See the License for the specific language governing | 
| 13 |   * permissions and limitations under the License. | 
| 14 |   */ | 
| 15 |  | 
| 16 |  | 
| 17 | #include <aws/core/auth/AWSCredentialsProvider.h> | 
| 18 |  | 
| 19 | #include <aws/core/config/AWSProfileConfigLoader.h> | 
| 20 | #include <aws/core/platform/Environment.h> | 
| 21 | #include <aws/core/platform/FileSystem.h> | 
| 22 | #include <aws/core/platform/OSVersionInfo.h> | 
| 23 | #include <aws/core/utils/logging/LogMacros.h> | 
| 24 | #include <aws/core/utils/StringUtils.h> | 
| 25 | #include <aws/core/utils/json/JsonSerializer.h> | 
| 26 | #include <aws/core/utils/FileSystemUtils.h> | 
| 27 | #include <aws/core/client/AWSError.h> | 
| 28 | #include <aws/core/utils/StringUtils.h> | 
| 29 | #include <aws/core/utils/xml/XmlSerializer.h> | 
| 30 | #include <cstdlib> | 
| 31 | #include <fstream> | 
| 32 | #include <string.h> | 
| 33 | #include <climits> | 
| 34 |  | 
| 35 |  | 
| 36 | using namespace Aws::Utils; | 
| 37 | using namespace Aws::Utils::Logging; | 
| 38 | using namespace Aws::Auth; | 
| 39 | using namespace Aws::Internal; | 
| 40 | using namespace Aws::FileSystem; | 
| 41 | using namespace Aws::Utils::Xml; | 
| 42 | using namespace Aws::Client; | 
| 43 | using Aws::Utils::Threading::ReaderLockGuard; | 
| 44 | using Aws::Utils::Threading::WriterLockGuard; | 
| 45 |  | 
| 46 | static const char ACCESS_KEY_ENV_VAR[] = "AWS_ACCESS_KEY_ID" ; | 
| 47 | static const char SECRET_KEY_ENV_VAR[] = "AWS_SECRET_ACCESS_KEY" ; | 
| 48 | static const char SESSION_TOKEN_ENV_VAR[] = "AWS_SESSION_TOKEN" ; | 
| 49 | static const char DEFAULT_PROFILE[] = "default" ; | 
| 50 | static const char AWS_PROFILE_ENV_VAR[] = "AWS_PROFILE" ; | 
| 51 | static const char AWS_PROFILE_DEFAULT_ENV_VAR[] = "AWS_DEFAULT_PROFILE" ; | 
| 52 |  | 
| 53 | static const char AWS_CREDENTIALS_FILE[] = "AWS_SHARED_CREDENTIALS_FILE" ; | 
| 54 | extern const char AWS_CONFIG_FILE[] = "AWS_CONFIG_FILE" ; | 
| 55 |  | 
| 56 | extern const char PROFILE_DIRECTORY[] = ".aws" ; | 
| 57 | static const char DEFAULT_CREDENTIALS_FILE[] = "credentials" ; | 
| 58 | extern const char DEFAULT_CONFIG_FILE[] = "config" ; | 
| 59 |  | 
| 60 |  | 
| 61 | static const int EXPIRATION_GRACE_PERIOD = 5 * 1000; | 
| 62 |  | 
| 63 | void AWSCredentialsProvider::Reload() | 
| 64 | { | 
| 65 |     m_lastLoadedMs = DateTime::Now().Millis(); | 
| 66 | } | 
| 67 |  | 
| 68 | bool AWSCredentialsProvider::IsTimeToRefresh(long reloadFrequency) | 
| 69 | { | 
| 70 |     if (DateTime::Now().Millis() - m_lastLoadedMs > reloadFrequency) | 
| 71 |     { | 
| 72 |         return true; | 
| 73 |     } | 
| 74 |     return false; | 
| 75 | } | 
| 76 |  | 
| 77 |  | 
| 78 | static const char* ENVIRONMENT_LOG_TAG = "EnvironmentAWSCredentialsProvider" ; | 
| 79 |  | 
| 80 |  | 
| 81 | AWSCredentials EnvironmentAWSCredentialsProvider::GetAWSCredentials() | 
| 82 | { | 
| 83 |     auto accessKey = Aws::Environment::GetEnv(ACCESS_KEY_ENV_VAR); | 
| 84 |     AWSCredentials credentials; | 
| 85 |  | 
| 86 |     if (!accessKey.empty()) | 
| 87 |     { | 
| 88 |         credentials.SetAWSAccessKeyId(accessKey); | 
| 89 |  | 
| 90 |         AWS_LOGSTREAM_DEBUG(ENVIRONMENT_LOG_TAG, "Found credential in environment with access key id "  << accessKey); | 
| 91 |         auto secretKey = Aws::Environment::GetEnv(SECRET_KEY_ENV_VAR); | 
| 92 |  | 
| 93 |         if (!secretKey.empty()) | 
| 94 |         { | 
| 95 |             credentials.SetAWSSecretKey(secretKey); | 
| 96 |             AWS_LOGSTREAM_INFO(ENVIRONMENT_LOG_TAG, "Found secret key" ); | 
| 97 |         } | 
| 98 |  | 
| 99 |         auto sessionToken = Aws::Environment::GetEnv(SESSION_TOKEN_ENV_VAR); | 
| 100 |  | 
| 101 |         if(!sessionToken.empty()) | 
| 102 |         { | 
| 103 |             credentials.SetSessionToken(sessionToken); | 
| 104 |             AWS_LOGSTREAM_INFO(ENVIRONMENT_LOG_TAG, "Found sessionToken" ); | 
| 105 |         } | 
| 106 |     } | 
| 107 |  | 
| 108 |     return credentials; | 
| 109 | } | 
| 110 |  | 
| 111 | Aws::String Aws::Auth::GetConfigProfileFilename() | 
| 112 | { | 
| 113 |     auto configFileNameFromVar = Aws::Environment::GetEnv(AWS_CONFIG_FILE); | 
| 114 |     if (!configFileNameFromVar.empty()) | 
| 115 |     { | 
| 116 |         return configFileNameFromVar; | 
| 117 |     } | 
| 118 |     else | 
| 119 |     { | 
| 120 |         return Aws::FileSystem::GetHomeDirectory() + PROFILE_DIRECTORY + PATH_DELIM + DEFAULT_CONFIG_FILE; | 
| 121 |     } | 
| 122 | } | 
| 123 |  | 
| 124 | Aws::String Aws::Auth::GetConfigProfileName() | 
| 125 | { | 
| 126 |     auto profileFromVar = Aws::Environment::GetEnv(AWS_PROFILE_DEFAULT_ENV_VAR); | 
| 127 |     if (profileFromVar.empty()) | 
| 128 |     { | 
| 129 |         profileFromVar = Aws::Environment::GetEnv(AWS_PROFILE_ENV_VAR); | 
| 130 |     } | 
| 131 |  | 
| 132 |     if (profileFromVar.empty()) | 
| 133 |     { | 
| 134 |         return Aws::String(DEFAULT_PROFILE); | 
| 135 |     } | 
| 136 |     else | 
| 137 |     { | 
| 138 |         return profileFromVar; | 
| 139 |     } | 
| 140 | } | 
| 141 |  | 
| 142 | static const char* PROFILE_LOG_TAG = "ProfileConfigFileAWSCredentialsProvider" ; | 
| 143 |  | 
| 144 | Aws::String ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename() | 
| 145 | { | 
| 146 |     auto credentialsFileNameFromVar = Aws::Environment::GetEnv(AWS_CREDENTIALS_FILE); | 
| 147 |  | 
| 148 |     if (credentialsFileNameFromVar.empty()) | 
| 149 |     { | 
| 150 |         return Aws::FileSystem::GetHomeDirectory() + PROFILE_DIRECTORY + PATH_DELIM + DEFAULT_CREDENTIALS_FILE; | 
| 151 |     } | 
| 152 |     else | 
| 153 |     { | 
| 154 |         return credentialsFileNameFromVar; | 
| 155 |     } | 
| 156 | } | 
| 157 |  | 
| 158 | Aws::String ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory() | 
| 159 | { | 
| 160 |     Aws::String credentialsFileName = GetCredentialsProfileFilename(); | 
| 161 |     auto lastSeparator = credentialsFileName.find_last_of(PATH_DELIM); | 
| 162 |     if (lastSeparator != std::string::npos) | 
| 163 |     { | 
| 164 |         return credentialsFileName.substr(0, lastSeparator); | 
| 165 |     } | 
| 166 |     else | 
| 167 |     { | 
| 168 |         return {}; | 
| 169 |     } | 
| 170 | } | 
| 171 |  | 
| 172 | ProfileConfigFileAWSCredentialsProvider::ProfileConfigFileAWSCredentialsProvider(long refreshRateMs) : | 
| 173 |     m_profileToUse(Aws::Auth::GetConfigProfileName()), | 
| 174 |     m_credentialsFileLoader(GetCredentialsProfileFilename()), | 
| 175 |     m_loadFrequencyMs(refreshRateMs) | 
| 176 | { | 
| 177 |     AWS_LOGSTREAM_INFO(PROFILE_LOG_TAG, "Setting provider to read credentials from "  <<  GetCredentialsProfileFilename() << " for credentials file"  | 
| 178 |                                       << " and "  <<  GetConfigProfileFilename() << " for the config file "  | 
| 179 |                                       << ", for use with profile "  << m_profileToUse); | 
| 180 | } | 
| 181 |  | 
| 182 | ProfileConfigFileAWSCredentialsProvider::ProfileConfigFileAWSCredentialsProvider(const char* profile, long refreshRateMs) : | 
| 183 |     m_profileToUse(profile), | 
| 184 |     m_credentialsFileLoader(GetCredentialsProfileFilename()), | 
| 185 |     m_loadFrequencyMs(refreshRateMs) | 
| 186 | { | 
| 187 |     AWS_LOGSTREAM_INFO(PROFILE_LOG_TAG, "Setting provider to read credentials from "  <<  GetCredentialsProfileFilename() << " for credentials file"  | 
| 188 |                                       << " and "  <<  GetConfigProfileFilename() << " for the config file "  | 
| 189 |                                       << ", for use with profile "  << m_profileToUse); | 
| 190 | } | 
| 191 |  | 
| 192 | AWSCredentials ProfileConfigFileAWSCredentialsProvider::GetAWSCredentials() | 
| 193 | { | 
| 194 |     RefreshIfExpired(); | 
| 195 |     ReaderLockGuard guard(m_reloadLock); | 
| 196 |     auto credsFileProfileIter = m_credentialsFileLoader.GetProfiles().find(m_profileToUse); | 
| 197 |  | 
| 198 |     if(credsFileProfileIter != m_credentialsFileLoader.GetProfiles().end()) | 
| 199 |     { | 
| 200 |         return credsFileProfileIter->second.GetCredentials(); | 
| 201 |     } | 
| 202 |  | 
| 203 |     return AWSCredentials(); | 
| 204 | } | 
| 205 |  | 
| 206 |  | 
| 207 | void ProfileConfigFileAWSCredentialsProvider::Reload() | 
| 208 | { | 
| 209 |     m_credentialsFileLoader.Load(); | 
| 210 |     AWSCredentialsProvider::Reload(); | 
| 211 | } | 
| 212 |  | 
| 213 | void ProfileConfigFileAWSCredentialsProvider::RefreshIfExpired() | 
| 214 | { | 
| 215 |     ReaderLockGuard guard(m_reloadLock); | 
| 216 |     if (!IsTimeToRefresh(m_loadFrequencyMs)) | 
| 217 |     { | 
| 218 |        return; | 
| 219 |     } | 
| 220 |  | 
| 221 |     guard.UpgradeToWriterLock(); | 
| 222 |     if (!IsTimeToRefresh(m_loadFrequencyMs)) // double-checked lock to avoid refreshing twice | 
| 223 |     { | 
| 224 |         return; | 
| 225 |     } | 
| 226 |  | 
| 227 |     Reload(); | 
| 228 | } | 
| 229 |  | 
| 230 | static const char* INSTANCE_LOG_TAG = "InstanceProfileCredentialsProvider" ; | 
| 231 |  | 
| 232 | InstanceProfileCredentialsProvider::InstanceProfileCredentialsProvider(long refreshRateMs) : | 
| 233 |     m_ec2MetadataConfigLoader(Aws::MakeShared<Aws::Config::EC2InstanceProfileConfigLoader>(INSTANCE_LOG_TAG)), | 
| 234 |     m_loadFrequencyMs(refreshRateMs) | 
| 235 | { | 
| 236 |     AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Creating Instance with default EC2MetadataClient and refresh rate "  << refreshRateMs); | 
| 237 | } | 
| 238 |  | 
| 239 |  | 
| 240 | InstanceProfileCredentialsProvider::InstanceProfileCredentialsProvider(const std::shared_ptr<Aws::Config::EC2InstanceProfileConfigLoader>& loader, long refreshRateMs) : | 
| 241 |     m_ec2MetadataConfigLoader(loader), | 
| 242 |     m_loadFrequencyMs(refreshRateMs) | 
| 243 | { | 
| 244 |     AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Creating Instance with injected EC2MetadataClient and refresh rate "  << refreshRateMs); | 
| 245 | } | 
| 246 |  | 
| 247 |  | 
| 248 | AWSCredentials InstanceProfileCredentialsProvider::GetAWSCredentials() | 
| 249 | { | 
| 250 |     RefreshIfExpired(); | 
| 251 |     ReaderLockGuard guard(m_reloadLock); | 
| 252 |     auto profileIter = m_ec2MetadataConfigLoader->GetProfiles().find(Aws::Config::INSTANCE_PROFILE_KEY); | 
| 253 |  | 
| 254 |     if(profileIter != m_ec2MetadataConfigLoader->GetProfiles().end()) | 
| 255 |     { | 
| 256 |         return profileIter->second.GetCredentials(); | 
| 257 |     } | 
| 258 |  | 
| 259 |     return AWSCredentials(); | 
| 260 | } | 
| 261 |  | 
| 262 | void InstanceProfileCredentialsProvider::Reload() | 
| 263 | { | 
| 264 |     AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Credentials have expired attempting to repull from EC2 Metadata Service." ); | 
| 265 |     m_ec2MetadataConfigLoader->Load(); | 
| 266 |     AWSCredentialsProvider::Reload(); | 
| 267 | } | 
| 268 |  | 
| 269 | void InstanceProfileCredentialsProvider::RefreshIfExpired() | 
| 270 | { | 
| 271 |     AWS_LOGSTREAM_DEBUG(INSTANCE_LOG_TAG, "Checking if latest credential pull has expired." ); | 
| 272 |     ReaderLockGuard guard(m_reloadLock); | 
| 273 |     if (!IsTimeToRefresh(m_loadFrequencyMs)) | 
| 274 |     { | 
| 275 |         return; | 
| 276 |     } | 
| 277 |  | 
| 278 |     guard.UpgradeToWriterLock(); | 
| 279 |     if (!IsTimeToRefresh(m_loadFrequencyMs)) // double-checked lock to avoid refreshing twice | 
| 280 |     { | 
| 281 |         return; | 
| 282 |     } | 
| 283 |     Reload(); | 
| 284 | } | 
| 285 |  | 
| 286 | static const char TASK_ROLE_LOG_TAG[] = "TaskRoleCredentialsProvider" ; | 
| 287 |  | 
| 288 | TaskRoleCredentialsProvider::TaskRoleCredentialsProvider(const char* URI, long refreshRateMs) : | 
| 289 |     m_ecsCredentialsClient(Aws::MakeShared<Aws::Internal::ECSCredentialsClient>(TASK_ROLE_LOG_TAG, URI)), | 
| 290 |     m_loadFrequencyMs(refreshRateMs) | 
| 291 | { | 
| 292 |     AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Creating TaskRole with default ECSCredentialsClient and refresh rate "  << refreshRateMs); | 
| 293 | } | 
| 294 |  | 
| 295 | TaskRoleCredentialsProvider::TaskRoleCredentialsProvider(const char* endpoint, const char* token, long refreshRateMs) : | 
| 296 |     m_ecsCredentialsClient(Aws::MakeShared<Aws::Internal::ECSCredentialsClient>(TASK_ROLE_LOG_TAG, "" /*resourcePath*/, endpoint, token)), | 
| 297 |     m_loadFrequencyMs(refreshRateMs) | 
| 298 | { | 
| 299 |     AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Creating TaskRole with default ECSCredentialsClient and refresh rate "  << refreshRateMs); | 
| 300 | } | 
| 301 |  | 
| 302 | TaskRoleCredentialsProvider::TaskRoleCredentialsProvider( | 
| 303 |         const std::shared_ptr<Aws::Internal::ECSCredentialsClient>& client, long refreshRateMs) : | 
| 304 |     m_ecsCredentialsClient(client), | 
| 305 |     m_loadFrequencyMs(refreshRateMs) | 
| 306 | { | 
| 307 |     AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Creating TaskRole with default ECSCredentialsClient and refresh rate "  << refreshRateMs); | 
| 308 | } | 
| 309 |  | 
| 310 | AWSCredentials TaskRoleCredentialsProvider::GetAWSCredentials() | 
| 311 | { | 
| 312 |     RefreshIfExpired(); | 
| 313 |     ReaderLockGuard guard(m_reloadLock); | 
| 314 |     return m_credentials; | 
| 315 | } | 
| 316 |  | 
| 317 | bool TaskRoleCredentialsProvider::ExpiresSoon() const | 
| 318 | { | 
| 319 |     return ((m_credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < EXPIRATION_GRACE_PERIOD); | 
| 320 | } | 
| 321 |  | 
| 322 | void TaskRoleCredentialsProvider::Reload() | 
| 323 | { | 
| 324 |     AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Credentials have expired or will expire, attempting to repull from ECS IAM Service." ); | 
| 325 |  | 
| 326 |     auto credentialsStr = m_ecsCredentialsClient->GetECSCredentials(); | 
| 327 |     if (credentialsStr.empty()) return; | 
| 328 |  | 
| 329 |     Json::JsonValue credentialsDoc(credentialsStr); | 
| 330 |     if (!credentialsDoc.WasParseSuccessful()) | 
| 331 |     { | 
| 332 |         AWS_LOGSTREAM_ERROR(TASK_ROLE_LOG_TAG, "Failed to parse output from ECSCredentialService." ); | 
| 333 |         return; | 
| 334 |     } | 
| 335 |  | 
| 336 |     Aws::String accessKey, secretKey, token; | 
| 337 |     Utils::Json::JsonView credentialsView(credentialsDoc); | 
| 338 |     accessKey = credentialsView.GetString("AccessKeyId" ); | 
| 339 |     secretKey = credentialsView.GetString("SecretAccessKey" ); | 
| 340 |     token = credentialsView.GetString("Token" ); | 
| 341 |     AWS_LOGSTREAM_DEBUG(TASK_ROLE_LOG_TAG, "Successfully pulled credentials from metadata service with access key "  << accessKey); | 
| 342 |  | 
| 343 |     m_credentials.SetAWSAccessKeyId(accessKey); | 
| 344 |     m_credentials.SetAWSSecretKey(secretKey); | 
| 345 |     m_credentials.SetSessionToken(token); | 
| 346 |     m_credentials.SetExpiration(Aws::Utils::DateTime(credentialsView.GetString("Expiration" ), DateFormat::ISO_8601)); | 
| 347 |     AWSCredentialsProvider::Reload(); | 
| 348 | } | 
| 349 |  | 
| 350 | void TaskRoleCredentialsProvider::RefreshIfExpired() | 
| 351 | { | 
| 352 |     AWS_LOGSTREAM_DEBUG(TASK_ROLE_LOG_TAG, "Checking if latest credential pull has expired." ); | 
| 353 |     ReaderLockGuard guard(m_reloadLock); | 
| 354 |     if (!m_credentials.IsEmpty() && !IsTimeToRefresh(m_loadFrequencyMs) && !ExpiresSoon()) | 
| 355 |     { | 
| 356 |         return; | 
| 357 |     } | 
| 358 |  | 
| 359 |     guard.UpgradeToWriterLock(); | 
| 360 |  | 
| 361 |     if (!m_credentials.IsEmpty() && !IsTimeToRefresh(m_loadFrequencyMs) && !ExpiresSoon()) | 
| 362 |     { | 
| 363 |         return; | 
| 364 |     } | 
| 365 |  | 
| 366 |     Reload(); | 
| 367 | } | 
| 368 |  | 
| 369 | static const char PROCESS_LOG_TAG[] = "ProcessCredentialsProvider" ; | 
| 370 | ProcessCredentialsProvider::ProcessCredentialsProvider() : | 
| 371 |     m_profileToUse(Aws::Auth::GetConfigProfileName()) | 
| 372 | { | 
| 373 |     AWS_LOGSTREAM_INFO(PROCESS_LOG_TAG, "Setting process credentials provider to read config from "  <<  m_profileToUse); | 
| 374 | } | 
| 375 |  | 
| 376 | ProcessCredentialsProvider::ProcessCredentialsProvider(const Aws::String& profile) : | 
| 377 |     m_profileToUse(profile) | 
| 378 | { | 
| 379 |     AWS_LOGSTREAM_INFO(PROCESS_LOG_TAG, "Setting process credentials provider to read config from "  <<  m_profileToUse); | 
| 380 | } | 
| 381 |  | 
| 382 | AWSCredentials ProcessCredentialsProvider::GetAWSCredentials() | 
| 383 | { | 
| 384 |     RefreshIfExpired(); | 
| 385 |     ReaderLockGuard guard(m_reloadLock); | 
| 386 |     return m_credentials; | 
| 387 | } | 
| 388 |  | 
| 389 |  | 
| 390 | void ProcessCredentialsProvider::Reload() | 
| 391 | { | 
| 392 |     auto profile = Aws::Config::GetCachedConfigProfile(m_profileToUse); | 
| 393 |     const Aws::String &command = profile.GetCredentialProcess(); | 
| 394 |     if (command.empty()) | 
| 395 |     { | 
| 396 |         AWS_LOGSTREAM_ERROR(PROCESS_LOG_TAG, "Failed to find credential process's profile: "  << m_profileToUse); | 
| 397 |         return; | 
| 398 |     } | 
| 399 |     m_credentials = GetCredentialsFromProcess(command); | 
| 400 | } | 
| 401 |  | 
| 402 | void ProcessCredentialsProvider::RefreshIfExpired() | 
| 403 | { | 
| 404 |     ReaderLockGuard guard(m_reloadLock); | 
| 405 |     if (!m_credentials.IsExpiredOrEmpty()) | 
| 406 |     { | 
| 407 |        return; | 
| 408 |     } | 
| 409 |  | 
| 410 |     guard.UpgradeToWriterLock(); | 
| 411 |     if (!m_credentials.IsExpiredOrEmpty()) // double-checked lock to avoid refreshing twice | 
| 412 |     { | 
| 413 |         return; | 
| 414 |     } | 
| 415 |  | 
| 416 |     Reload(); | 
| 417 | } | 
| 418 |  | 
| 419 | AWSCredentials Aws::Auth::GetCredentialsFromProcess(const Aws::String& process) | 
| 420 | { | 
| 421 |     Aws::String command = process; | 
| 422 |     command.append(" 2>&1" ); // redirect stderr to stdout | 
| 423 |     Aws::String result = Aws::Utils::StringUtils::Trim(Aws::OSVersionInfo::GetSysCommandOutput(command.c_str()).c_str()); | 
| 424 |     Json::JsonValue credentialsDoc(result); | 
| 425 |     if (!credentialsDoc.WasParseSuccessful()) | 
| 426 |     { | 
| 427 |         AWS_LOGSTREAM_ERROR(PROFILE_LOG_TAG, "Failed to load credential from running: "  << command << " Error: "  << result); | 
| 428 |         return {}; | 
| 429 |     } | 
| 430 |  | 
| 431 |     Aws::Utils::Json::JsonView credentialsView(credentialsDoc); | 
| 432 |     if (!credentialsView.KeyExists("Version" ) || credentialsView.GetInteger("Version" ) != 1) | 
| 433 |     { | 
| 434 |         AWS_LOGSTREAM_ERROR(PROFILE_LOG_TAG, "Encountered an unsupported process credentials payload version:"  << credentialsView.GetInteger("Version" )); | 
| 435 |         return {}; | 
| 436 |     } | 
| 437 |  | 
| 438 |     AWSCredentials credentials; | 
| 439 |     Aws::String accessKey, secretKey, token, expire; | 
| 440 |     if (credentialsView.KeyExists("AccessKeyId" )) | 
| 441 |     { | 
| 442 |         credentials.SetAWSAccessKeyId(credentialsView.GetString("AccessKeyId" )); | 
| 443 |     } | 
| 444 |  | 
| 445 |     if (credentialsView.KeyExists("SecretAccessKey" )) | 
| 446 |     { | 
| 447 |         credentials.SetAWSSecretKey(credentialsView.GetString("SecretAccessKey" )); | 
| 448 |     } | 
| 449 |  | 
| 450 |     if (credentialsView.KeyExists("SessionToken" )) | 
| 451 |     { | 
| 452 |         credentials.SetSessionToken(credentialsView.GetString("SessionToken" )); | 
| 453 |     } | 
| 454 |  | 
| 455 |     if (credentialsView.KeyExists("Expiration" )) | 
| 456 |     { | 
| 457 |         const auto expiration = Aws::Utils::DateTime(credentialsView.GetString("Expiration" ), DateFormat::ISO_8601); | 
| 458 |         if (expiration.WasParseSuccessful()) | 
| 459 |         { | 
| 460 |             credentials.SetExpiration(expiration); | 
| 461 |         } | 
| 462 |         else | 
| 463 |         { | 
| 464 |             AWS_LOGSTREAM_ERROR(PROFILE_LOG_TAG, "Failed to parse credential's expiration value as an ISO 8601 Date. Credentials will be marked expired." ); | 
| 465 |             credentials.SetExpiration(Aws::Utils::DateTime::Now()); | 
| 466 |         } | 
| 467 |     } | 
| 468 |     else | 
| 469 |     { | 
| 470 |         credentials.SetExpiration(std::chrono::time_point<std::chrono::system_clock>::max()); | 
| 471 |     } | 
| 472 |  | 
| 473 |     AWS_LOGSTREAM_DEBUG(PROFILE_LOG_TAG, "Successfully pulled credentials from process credential with AccessKey: "  << accessKey << ", Expiration:"  << credentialsView.GetString("Expiration" )); | 
| 474 |     return credentials; | 
| 475 | } | 
| 476 |  | 
| 477 |  |