// Test credentials existence and expiration time // should update if: // credentials have not been loaded yet // it's past the expiration time. At this point currentState.Expiration may // have the PreemptExpiryTime baked into to the expiration from a call to // UpdateToGeneratedCredentials but it may not if this is new application // load. private static bool ShouldUpdateState(CredentialsRefreshState state, TimeSpan preemptExpiryTime) { // it's past the expiration time. At this point currentState.Expiration may // have the PreemptExpiryTime baked into to the expiration from a call to // UpdateToGeneratedCredentials but it may not if this is new application // load. var isExpired = state?.IsExpiredWithin(TimeSpan.Zero); if (isExpired == true) { #pragma warning disable CS0612 // Type or member is obsolete var logger = Logger.GetLogger(typeof(RefreshingAWSCredentials)); logger.InfoFormat("Determined refreshing credentials should update. Expiration time: {0}, Current time: {1}", state.Expiration.Add(preemptExpiryTime).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", CultureInfo.InvariantCulture), AWSSDKUtils.CorrectedUtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", CultureInfo.InvariantCulture)); #pragma warning restore CS0612 // Type or member is obsolete } return(isExpired ?? true); }
protected override CredentialsRefreshState GenerateNewCredentials() { CredentialsRefreshState newState = null; var token = EC2InstanceMetadata.FetchApiToken(); try { // Attempt to get early credentials. OK to fail at this point. newState = GetRefreshState(token); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); throw; } var logger = Logger.GetLogger(typeof(InstanceProfileAWSCredentials)); logger.InfoFormat("Error getting credentials from Instance Profile service: {0}", e); // if we already have cached credentials, we'll continue to use those credentials, // but try again to refresh them in 2 minutes. if (null != _currentRefreshState) { #pragma warning disable CS0612 // Type or member is obsolete var newExpiryTime = AWSSDKUtils.CorrectedUtcNow.ToLocalTime() + TimeSpan.FromMinutes(2); #pragma warning restore CS0612 // Type or member is obsolete _currentRefreshState = new CredentialsRefreshState(_currentRefreshState.Credentials.Copy(), newExpiryTime); return(_currentRefreshState); } } if (newState?.IsExpiredWithin(TimeSpan.Zero) == true) { // special case - credentials returned are expired _logger.InfoFormat(_receivedExpiredCredentialsFromIMDS); // use a custom refresh time #pragma warning disable CS0612 // Type or member is obsolete var newExpiryTime = AWSSDKUtils.CorrectedUtcNow.ToLocalTime() + TimeSpan.FromMinutes(new Random().Next(5, 16)); #pragma warning restore CS0612 // Type or member is obsolete _currentRefreshState = new CredentialsRefreshState(newState.Credentials.Copy(), newExpiryTime); return(_currentRefreshState); } // If successful, save new credentials if (newState != null) { _currentRefreshState = newState; } // If still not successful (no credentials available at start), attempt once more to // get credentials, but now without swallowing exception if (_currentRefreshState == null) { try { _currentRefreshState = GetRefreshState(token); } catch (Exception e) { HttpStatusCode?httpStatusCode = ExceptionUtils.DetermineHttpStatusCode(e); if (httpStatusCode == HttpStatusCode.Unauthorized) { EC2InstanceMetadata.ClearTokenFlag(); Logger.GetLogger(typeof(EC2InstanceMetadata)).Error(e, "EC2 Metadata service returned unauthorized for token based secure data flow."); } throw; } } // Return credentials that will expire in at most one hour CredentialsRefreshState state = GetEarlyRefreshState(_currentRefreshState); return(state); }
/// <summary> /// Refresh credentials after expiry. If the role profile is configured with user identity /// information and a callback has been registered to obtain the user credential, the callback /// will be invoked ahead of authentication. For role profiles configured with user identity /// but no callback registration, the SDK will fall back to attempting to use the default /// user identity of the current process. /// </summary> /// <returns></returns> protected override CredentialsRefreshState GenerateNewCredentials() { Validate(); // If the profile indicates the user has already authenticated and received // credentials which are still valid, adopt them instead of requiring a fresh // authentication. SAMLImmutableCredentials currentSession; if (TryGetRoleSession(out currentSession)) { // Since cached role session credentials can be obtained, stored credentials exist // and they were not expired. However, since the stored credentials are actual // expiration time and not preempt expiration time we must preempt the expiration // to check that they will not expire before this call completes. var cachedState = new CredentialsRefreshState(currentSession, currentSession.Expires); // Use the cached credentials as long as they are not within the preempt expiry window // or have since actually expired since the prior call to TryGetRoleSession. //Verify the actual expiration is not within the preempt expiration time. if (!cachedState.IsExpiredWithin(PreemptExpiryTime)) { // The credentials have plenty of time left before they expire so they can be used. After // return the expiration time will be preempted for future checks using ShouldUpdate. return(cachedState); } } CredentialsRefreshState newState = null; var attempts = 0; do { try { NetworkCredential userCredential = null; if (Options.UserIdentity != null) { if (Options.CredentialRequestCallback != null) { var callbackArgs = new CredentialRequestCallbackArgs { ProfileName = Options.ProfileName, UserIdentity = Options.UserIdentity, CustomState = Options.CustomCallbackState, PreviousAuthenticationFailed = attempts > 0 }; userCredential = Options.CredentialRequestCallback(callbackArgs); if (userCredential == null) // user declined to authenticate { throw new FederatedAuthenticationCancelledException( "User cancelled credential request."); } } else { var logger = Logger.GetLogger(typeof(FederatedAWSCredentials)); logger.InfoFormat( "FederatedAWSCredentials configured for a specific user but no credential request callback registered; falling back to default identity."); } } newState = Authenticate(userCredential); } catch (FederatedAuthenticationFailureException) { if (attempts < MaxAuthenticationRetries) { attempts++; } else { throw; } } } while (newState == null && attempts < MaxAuthenticationRetries); return(newState); }
/// <summary> /// Refresh credentials after expiry. If the role profile is configured with user identity /// information and a callback has been registered to obtain the user credential, the callback /// will be invoked ahead of authentication. For role profiles configured with user identity /// but no callback registration, the SDK will fall back to attempting to use the default /// user identity of the current process. /// </summary> /// <returns></returns> protected override CredentialsRefreshState GenerateNewCredentials() { Validate(); // lock across the entire process for generating credentials so multiple // threads don't attempt to invoke any registered callback at the same time // and if we do callback, we only do it once to get the user authentication // data lock (syncLock) { // If the profile indicates the user has already authenticated and received // credentials which are still valid, adopt them instead of requiring a fresh // authentication. SAMLImmutableCredentials currentSession; if (TryGetRoleSession(out currentSession)) { // Since cached role session credentials can be obtained, stored credentials exist // and they were not expired. However, since the stored credentials are actual // expiration time and not preempt expiration time we must preempt the expiration // to check that they will not expire before this call completes. var cachedState = new CredentialsRefreshState(currentSession, currentSession.Expires); // If currentState is null this is a new SDK startup. In this case we can possibly // use the cached credentials as long as they are not within the preempt expiry window // or have since actually expired since the prior call to TryGetRoleSession. if (currentState == null) { //Verify the actual expiration is not within the preempt expiration time. if (!cachedState.IsExpiredWithin(PreemptExpiryTime)) { // The credentials have plenty of time left before they expire so they can be used. After // return the expiration time will be preempted for future checks using ShouldUpdate. return(cachedState); } } else if (!ShouldUpdate) { // If currentState is not null we already have the credential state. This could // have come from a cached load or a new authentication. The preempted expiration // time would have already been built in to the ShouldUpdate check in this case. return(cachedState); } // If the currentState was null but the credentials are already in the preempt expiry window // or the currentState was not null and we are currently in the preempt expiry window // new credentials must be obtained before the window closes. No longer use the cached // credentials so fall through to obtain new ones. } CredentialsRefreshState newState = null; var attempts = 0; do { try { NetworkCredential userCredential = null; if (Options.UserIdentity != null) { if (Options.CredentialRequestCallback != null) { var callbackArgs = new CredentialRequestCallbackArgs { ProfileName = Options.ProfileName, UserIdentity = Options.UserIdentity, CustomState = Options.CustomCallbackState, PreviousAuthenticationFailed = attempts > 0 }; userCredential = Options.CredentialRequestCallback(callbackArgs); if (userCredential == null) // user declined to authenticate { throw new FederatedAuthenticationCancelledException("User cancelled credential request."); } } else { var logger = Logger.GetLogger(typeof(FederatedAWSCredentials)); logger.InfoFormat("FederatedAWSCredentials configured for a specific user but no credential request callback registered; falling back to default identity."); } } newState = Authenticate(userCredential); } catch (FederatedAuthenticationFailureException) { if (attempts < MaxAuthenticationRetries) { attempts++; } else { throw; } } } while (newState == null && attempts < MaxAuthenticationRetries); return(newState); } }