private async Task CreateAndNotify(IEnumerable <RekeyingTask> tasks)
        {
            if (!tasks.Any())
            {
                return;
            }
            await Task.WhenAll(tasks.Select(t => RekeyingTasks.CreateAsync(t)));

            foreach (var task in tasks)
            {
                var secret = await ManagedSecrets.GetAsync(task.ManagedSecretId);

                if (task.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff ||
                    task.ConfirmationType == TaskConfirmationStrategies.AdminSignsOffJustInTime)
                {
                    await NotificationProvider.DispatchNotification_AdminApprovalRequiredTaskCreated(
                        secret.AdminEmails.ToArray(), task);
                }
                else if (task.ConfirmationType == TaskConfirmationStrategies.AutomaticRekeyingAsNeeded ||
                         task.ConfirmationType == TaskConfirmationStrategies.AutomaticRekeyingScheduled)
                {
                    await NotificationProvider.DispatchNotification_AutoRekeyingTaskCreated(
                        secret.AdminEmails.ToArray(), task);
                }
            }
        }
Exemple #2
0
        public async Task <IActionResult> List(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "tasks")] HttpRequest req,
            ILogger log)
        {
            if (!req.IsValidUser())
            {
                return(new UnauthorizedResult());
            }

            log.LogInformation("List all Tasks.");

            return(new OkObjectResult((await RekeyingTasks.ListAsync()).Select(t => GetViewModel(t))));
        }
Exemple #3
0
        public async Task <IActionResult> Get(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "tasks/{taskId:guid}")] HttpRequest req,
            Guid taskId,
            ILogger log)
        {
            if (!req.IsValidUser())
            {
                return(new UnauthorizedResult());
            }

            log.LogInformation("Preview Actions for Task ID {0}.", taskId);

            return(new OkObjectResult(GetViewModel((await RekeyingTasks.GetAsync(taskId)))));
        }
        private async Task <List <ManagedSecret> > GetSecretsForRekeyingTask(
            TaskConfirmationStrategies taskConfirmationStrategies,
            int leadTimeHours)
        {
            var secretsToRotate = await ManagedSecrets.GetAsync(s =>
                                                                s.TaskConfirmationStrategies.HasFlag(taskConfirmationStrategies) &&
                                                                s.Expiry < DateTimeOffset.UtcNow + TimeSpan.FromHours(leadTimeHours));

            var rekeyingTasks = await RekeyingTasks.ListAsync();

            return(secretsToRotate
                   .Where(s => !rekeyingTasks.Any(t =>
                                                  t.ManagedSecretId == s.ObjectId &&
                                                  !t.RekeyingCompleted))
                   .ToList());
        }
Exemple #5
0
        public async Task <IActionResult> Delete(
            [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "tasks/{taskId:guid}")] HttpRequest req,
            Guid taskId,
            ILogger log)
        {
            if (!req.IsValidUser(AuthJanitorRoles.ServiceOperator, AuthJanitorRoles.GlobalAdmin))
            {
                return(new UnauthorizedResult());
            }

            log.LogInformation("Deleting Task ID {0}.", taskId);

            if (!await RekeyingTasks.ContainsIdAsync(taskId))
            {
                return(new BadRequestErrorMessageResult("Task not found!"));
            }

            await RekeyingTasks.DeleteAsync(taskId);

            return(new OkResult());
        }
Exemple #6
0
        public async Task <IActionResult> Create(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "tasks")] string secretId,
            HttpRequest req,
            ILogger log)
        {
            if (!req.IsValidUser(AuthJanitorRoles.ServiceOperator, AuthJanitorRoles.GlobalAdmin))
            {
                return(new UnauthorizedResult());
            }

            log.LogInformation("Creating new Task.");

            if (!await ManagedSecrets.ContainsIdAsync(Guid.Parse(secretId)))
            {
                return(new BadRequestErrorMessageResult("Invalid Managed Secret ID"));
            }

            var secret = await ManagedSecrets.GetAsync(Guid.Parse(secretId));

            if (!secret.TaskConfirmationStrategies.HasFlag(TaskConfirmationStrategies.AdminCachesSignOff) &&
                !secret.TaskConfirmationStrategies.HasFlag(TaskConfirmationStrategies.AdminSignsOffJustInTime))
            {
                return(new BadRequestErrorMessageResult("Managed Secret does not support administrator approval!"));
            }

            RekeyingTask newTask = new RekeyingTask()
            {
                Queued          = DateTimeOffset.UtcNow,
                Expiry          = secret.Expiry,
                ManagedSecretId = secret.ObjectId
            };

            await RekeyingTasks.CreateAsync(newTask);

            return(new OkObjectResult(newTask));
        }
Exemple #7
0
        public async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "dashboard")] HttpRequest req,
            ClaimsPrincipal claimsPrincipal,
            ILogger log)
        {
            if (!req.IsValidUser())
            {
                return(new UnauthorizedResult());
            }

            log.LogInformation("Requested Dashboard metrics");

            var allSecrets = await ManagedSecrets.ListAsync();

            var allResources = await Resources.ListAsync();

            var allTasks = await RekeyingTasks.ListAsync();

            var expiringInNextWeek = allSecrets.Where(s => DateTimeOffset.UtcNow.AddDays(7) < (s.LastChanged + s.ValidPeriod));
            var expired            = allSecrets.Where(s => !s.IsValid);

            var metrics = new DashboardMetricsViewModel()
            {
                SignedInName =
                    claimsPrincipal.FindFirst(ClaimTypes.GivenName)?.Value +
                    " " +
                    claimsPrincipal.FindFirst(ClaimTypes.Surname)?.Value,
                SignedInEmail        = claimsPrincipal.FindFirst(ClaimTypes.Email)?.Value,
                SignedInRole         = AuthJanitorRoleExtensions.GetUserRole(req),
                TotalResources       = allResources.Count,
                TotalSecrets         = allSecrets.Count,
                TotalPendingApproval = allTasks.Where(t =>
                                                      t.ConfirmationType.HasFlag(TaskConfirmationStrategies.AdminCachesSignOff) ||
                                                      t.ConfirmationType.HasFlag(TaskConfirmationStrategies.AdminSignsOffJustInTime)).Count(),
                TotalExpiringSoon = expiringInNextWeek.Count(),
                TotalExpired      = expired.Count(),
                ExpiringSoon      = expiringInNextWeek.Select(s => GetViewModel(s)),
                PercentExpired    = (int)((double)expired.Count() / allSecrets.Count) * 100,
                TasksInError      = allTasks.Count(t => t.RekeyingFailed)
            };

            foreach (var secret in allSecrets)
            {
                var riskScore = 0;
                foreach (var resourceId in secret.ResourceIds)
                {
                    var resource = allResources.FirstOrDefault(r => r.ObjectId == resourceId);
                    var provider = GetProvider(new RekeyingAttemptLogger(log), resource.ProviderType, resource.ProviderConfiguration);
                    riskScore += provider.GetRisks(secret.ValidPeriod).Sum(r => r.Score);
                }
                if (riskScore > 85)
                {
                    metrics.RiskOver85++;
                }
                else if (riskScore > 60)
                {
                    metrics.Risk85++;
                }
                else if (riskScore > 35)
                {
                    metrics.Risk60++;
                }
                else if (riskScore > 0)
                {
                    metrics.Risk35++;
                }
                else if (riskScore == 0)
                {
                    metrics.Risk0++;
                }
            }

            return(new OkObjectResult(metrics));
        }
Exemple #8
0
        public async Task <IActionResult> Approve(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "tasks/{taskId:guid}/approve")] HttpRequest req,
            Guid taskId,
            ClaimsPrincipal claimsPrincipal,
            ILogger log)
        {
            if (!req.IsValidUser(AuthJanitorRoles.ServiceOperator, AuthJanitorRoles.GlobalAdmin))
            {
                return(new UnauthorizedResult());
            }

            log.LogInformation("Administrator approved Task ID {0}", taskId);

            var task = await RekeyingTasks.GetAsync(taskId);

            log.LogInformation("Registering incoming user credential...");
            try { await RegisterUserCredential(req); }
            catch (Exception ex)
            {
                var logger = new RekeyingAttemptLogger();
                logger.LogCritical(ex, "Error registering user credential!");
                task.Attempts.Add(logger);
                await RekeyingTasks.UpdateAsync(task);

                return(new BadRequestErrorMessageResult(ex.Message));
            }

            if (task.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff)
            {
                var credential = CredentialProvider.Get(MultiCredentialProvider.CredentialType.UserCredential);
                var persisted  = await SecureStorageProvider.Persist <Azure.Core.AccessToken>(
                    credential.Expiry,
                    new Azure.Core.AccessToken(credential.AccessToken, credential.Expiry));

                task.PersistedCredentialId   = persisted;
                task.PersistedCredentialUser = credential.Username;
                await RekeyingTasks.UpdateAsync(task);

                return(new OkResult());
            }
            else if (task.ConfirmationType == TaskConfirmationStrategies.AdminSignsOffJustInTime)
            {
                task.RekeyingInProgress = true;
                await RekeyingTasks.UpdateAsync(task);

                var aggregatedStringLogger = new RekeyingAttemptLogger(log)
                {
                    UserDisplayName =
                        claimsPrincipal.FindFirst(ClaimTypes.GivenName)?.Value +
                        " " +
                        claimsPrincipal.FindFirst(ClaimTypes.Surname)?.Value,
                    UserEmail = claimsPrincipal.FindFirst(ClaimTypes.Email)?.Value
                };
                try
                {
                    await ExecuteRekeyingWorkflow(task, aggregatedStringLogger);

                    task.RekeyingInProgress = false;
                    task.RekeyingCompleted  = aggregatedStringLogger.IsSuccessfulAttempt;
                    task.RekeyingFailed     = !aggregatedStringLogger.IsSuccessfulAttempt;
                }
                catch (Exception ex)
                {
                    task.RekeyingInProgress = false;
                    task.RekeyingCompleted  = false;
                    task.RekeyingFailed     = true;
                    if (aggregatedStringLogger.OuterException == null)
                    {
                        aggregatedStringLogger.OuterException = JsonConvert.SerializeObject(ex, Formatting.Indented);
                    }
                }

                task.Attempts.Add(aggregatedStringLogger);
                await RekeyingTasks.UpdateAsync(task);

                if (task.RekeyingFailed)
                {
                    return(new BadRequestErrorMessageResult(aggregatedStringLogger.OuterException));
                }
                else
                {
                    return(new OkResult());
                }
            }
            else
            {
                log.LogError("Task does not support an Administrator's approval!");
                return(new BadRequestErrorMessageResult("Task does not support an Administrator's approval!"));
            }
        }