Ejemplo n.º 1
0
            public async Task <TokenSet> Handle(RefreshActionstepCredentialsCommand message, CancellationToken token)
            {
                if (message is null)
                {
                    throw new ArgumentNullException(nameof(message));
                }

                ValidationResult result = _validator.Validate(message);

                if (!result.IsValid)
                {
                    throw new ValidationException("Invalid input.", result.Errors);
                }

                var tokenToRefresh = await _tokenSetRepository.GetTokenSetById(message.ActionstepCredentialIdToRefresh.ToString(CultureInfo.InvariantCulture));

                if (tokenToRefresh == null)
                {
                    throw new InvalidOperationException($"No Actionstep credentials found with the id {message.ActionstepCredentialIdToRefresh}. No credentials to be refreshed.");
                }

                return(await _actionstepService.RefreshAccessTokenIfExpired(tokenToRefresh, forceRefresh : true));
            }
        public async Task Run(
#pragma warning disable CA1801 // Remove unused parameter: Required by framework
            [TimerTrigger("0 0 3 * * *")] TimerInfo myTimer,
#pragma warning restore CA1801 // Remove unused parameter
            ILogger logger)
        {
            if (logger is null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            var individualCredentialRefreshExceptions = new List <Exception>();

            const int minimumTokenValidityInDays        = 5;
            var       latestRefreshTokenExpiryToRefresh = _clock.GetCurrentInstant().Plus(Duration.FromDays(minimumTokenValidityInDays));

            logger.LogInformation(
                "Retrieving tokens expiring within the next {MinimumTokenValidityInDays} days. Checking for tokens that expire between now and before {LatestRefreshTokenExpiryToRefresh}.",
                minimumTokenValidityInDays, latestRefreshTokenExpiryToRefresh);

            var tokensNearingExpiry = await _tokenSetRepository.GetTokensByRefreshExpiry(latestRefreshTokenExpiryToRefresh);

            int refreshedCount  = 0;
            int skippedCount    = 0;
            int errorCount      = 0;
            int totalTokenCount = 0;

            foreach (var tokenSet in tokensNearingExpiry)
            {
                totalTokenCount++;

                try
                {
                    if (!tokenSet.RefreshTokenAppearsValid(_clock))
                    {
                        skippedCount++;
                        var revokedAt = tokenSet.RevokedAt.HasValue ? tokenSet.RevokedAt.Value.ToString() : "Not revoked";
                        logger.LogInformation(
                            "Skipping invalid TokenSet. TokenSet ID: '{TokenSetId}', User ID: '{UserId}', OrgKey: '{OrgKey}', Revoked at (UTC): '{RevokedAt}', Refresh token expires at (UTC): '{RefreshTokenExpiresAt}'",
                            tokenSet.Id, tokenSet.UserId, tokenSet.OrgKey, revokedAt, tokenSet.RefreshTokenExpiresAt.ToString());
                    }
                    else
                    {
                        await _actionstepService.RefreshAccessTokenIfExpired(tokenSet, forceRefresh : true);

                        refreshedCount++;

                        logger.LogInformation(
                            "Successfully refreshed TokenSet. TokenSet ID: '{TokenSetId}', User ID: '{UserId}', OrgKey: '{OrgKey}', Refresh token expires at (UTC): '{RefreshTokenExpiresAt}'",
                            tokenSet.Id, tokenSet.UserId, tokenSet.OrgKey, tokenSet.RefreshTokenExpiresAt.ToString());
                    }
                }
#pragma warning disable CA1031 /// Do not catch general exception types: Exception is logged and captured in AggregatException. We don't want one credential failure to prevent others from being refreshed.
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    individualCredentialRefreshExceptions.Add(ex);
                    errorCount++;

                    var revokedAt = tokenSet.RevokedAt.HasValue ? tokenSet.RevokedAt.Value.ToString() : "Not revoked";
                    logger.LogError(
                        ex,
                        "Error encountered while refreshingTokenSet. TokenSet ID: '{TokenSetId}', User ID: '{UserId}', OrgKey: '{OrgKey}', Revoked at (UTC): '{RevokedAt}', Refresh token expires at (UTC): '{RefreshTokenExpiresAt}'",
                        tokenSet.Id, tokenSet.UserId, tokenSet.OrgKey, revokedAt, tokenSet.RefreshTokenExpiresAt.ToString());
                }
            }

            if (totalTokenCount > 0)
            {
                logger.LogInformation(
                    "Finished processing {TotalTokenCount} tokens. Refreshed: {RefreshedCount}, skipped: {SkippedCount}, errored: {ErrorCount}.",
                    totalTokenCount, refreshedCount, skippedCount, errorCount);
            }
            else
            {
                logger.LogInformation("No tokens found that are close to expiry.");
            }

            if (individualCredentialRefreshExceptions.Count > 0)
            {
                // If there were any failures, throwing ensures that the TimerJob shows up as failed.
                throw new AggregateException("One or more refresh operations failed.", individualCredentialRefreshExceptions);
            }
        }