public async Task Run([TimerTrigger("0 */2 * * * *")] TimerInfo myTimer, ILogger log)
        {
            _ = myTimer; // unused but required for attribute

            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            var toRekey = await _rekeyingTasks.Get(t =>
                                                   (t.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff ||
                                                    t.ConfirmationType == TaskConfirmationStrategies.AutomaticRekeyingAsNeeded ||
                                                    t.ConfirmationType == TaskConfirmationStrategies.AutomaticRekeyingScheduled) &&
                                                   DateTimeOffset.UtcNow + TimeSpan.FromHours(_configuration.AutomaticRekeyableJustInTimeLeadTimeHours) > t.Expiry);

            foreach (var task in toRekey)
            {
                await _taskExecutionMetaService.ExecuteTask(task.ObjectId);
            }
        }
Esempio n. 2
0
        public async Task <IActionResult> Approve([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "tasks/{taskId:guid}/approve")] HttpRequest req,
                                                  Guid taskId)
        {
            _ = req;

            if (!_identityService.CurrentUserHasRole(AuthJanitorRoles.ServiceOperator))
            {
                return(new UnauthorizedResult());
            }

            var toRekey = await _rekeyingTasks.GetOne(t => t.ObjectId == taskId);

            if (toRekey == null)
            {
                await _eventDispatcher.DispatchEvent(AuthJanitorSystemEvents.AnomalousEventOccurred, nameof(RekeyingTasks.Delete), "Rekeying Task not found");

                return(new NotFoundResult());
            }
            if (!toRekey.ConfirmationType.UsesOBOTokens())
            {
                await _eventDispatcher.DispatchEvent(AuthJanitorSystemEvents.AnomalousEventOccurred, nameof(RekeyingTasks.Approve), "Rekeying Task does not support Administrator approval");

                return(new BadRequestErrorMessageResult("Task does not support Administrator approval"));
            }

            // Just cache credentials if no workflow action is required
            if (toRekey.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff)
            {
                await _taskExecutionMetaService.CacheBackCredentialsForTaskIdAsync(toRekey.ObjectId);
            }
            else
            {
                await _taskExecutionMetaService.ExecuteTask(toRekey.ObjectId);
            }

            return(new OkResult());
        }
Esempio n. 3
0
        public async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "secrets/{managedSecretId:guid}/{nonce}")] HttpRequest req,
            Guid managedSecretId,
            string nonce,
            ILogger log,
            CancellationToken cancellationToken)
        {
            _ = req; // unused but required for attribute

            log.LogInformation("External signal called to check ManagedSecret ID {ManagedSecretId} against nonce {Nonce}", managedSecretId, nonce);

            var secret = await _managedSecrets.GetOne(managedSecretId, cancellationToken);

            if (secret == null)
            {
                return(new BadRequestErrorMessageResult("Invalid ManagedSecret ID"));
            }
            if (!secret.TaskConfirmationStrategies.HasFlag(TaskConfirmationStrategies.ExternalSignal))
            {
                return(new BadRequestErrorMessageResult("This ManagedSecret cannot be used with External Signals"));
            }

            if ((await _rekeyingTasks.Get(t => t.ManagedSecretId == secret.ObjectId, cancellationToken))
                .Any(t => t.RekeyingInProgress))
            {
                return(new OkObjectResult(RETURN_RETRY_SHORTLY));
            }

            if ((secret.IsValid && secret.TimeRemaining <= TimeSpan.FromHours(_configuration.ExternalSignalRekeyableLeadTimeHours)) || !secret.IsValid)
            {
                var executeRekeyingTask = Task.Run(async() =>
                {
                    var rekeyingTask = new RekeyingTask()
                    {
                        ManagedSecretId    = secret.ObjectId,
                        Expiry             = secret.Expiry,
                        Queued             = DateTimeOffset.UtcNow,
                        RekeyingInProgress = true
                    };

                    await _rekeyingTasks.Create(rekeyingTask, cancellationToken).ConfigureAwait(false);

                    await _taskExecutionMetaService.ExecuteTask(rekeyingTask.ObjectId, cancellationToken).ConfigureAwait(false);
                });

                var timeout = TimeSpan.FromSeconds(MAX_EXECUTION_SECONDS_BEFORE_RETRY);
                var timeoutCancellationTokenSource = new CancellationTokenSource();
                var timeoutTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);

                var completedTask = await Task.WhenAny(executeRekeyingTask, timeoutTask);

                // If the task that completed first was the timeout task we need to let the caller know it's still running
                if (completedTask == timeoutTask)
                {
                    log.LogInformation("Rekeying workflow was started but exceeded the maximum request time! ({MaxExecutionRequestTime})", timeout);
                    return(new OkObjectResult(RETURN_RETRY_SHORTLY));
                }
                else
                {
                    // Signal that the timeout task can be canceled
                    timeoutCancellationTokenSource.Cancel();

                    // The rekeying task completed in time, let the caller know
                    log.LogInformation("Completed rekeying workflow within maximum time! ({MaxExecutionRequestTime})", timeout);
                    return(new OkObjectResult(RETURN_CHANGE_OCCURRED));
                }
            }
            return(new OkObjectResult(RETURN_NO_CHANGE));
        }