// 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);
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        /// <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);
        }
Exemple #4
0
        /// <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);
            }
        }