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!")); } }
protected async Task <RekeyingAttemptLogger> ExecuteRekeyingWorkflow(RekeyingTask task, RekeyingAttemptLogger log = null) { if (log == null) { log = new RekeyingAttemptLogger(); } MultiCredentialProvider.CredentialType credentialType; if (task.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff) { if (task.PersistedCredentialId == default) { log.LogError("Cached sign-off is preferred but no credentials were persisted!"); throw new Exception("Cached sign-off is preferred but no credentials were persisted!"); } var token = await SecureStorageProvider.Retrieve <Azure.Core.AccessToken>(task.PersistedCredentialId); CredentialProvider.Register( MultiCredentialProvider.CredentialType.CachedCredential, token.Token, token.ExpiresOn); credentialType = MultiCredentialProvider.CredentialType.CachedCredential; } else if (task.ConfirmationType == TaskConfirmationStrategies.AdminSignsOffJustInTime) { credentialType = MultiCredentialProvider.CredentialType.UserCredential; } else { credentialType = MultiCredentialProvider.CredentialType.AgentServicePrincipal; } log.LogInformation("Using credential type {0} to access resources", credentialType); var secret = await ManagedSecrets.GetAsync(task.ManagedSecretId); log.LogInformation("Beginning rekeying for ManagedSecret '{0}' (ID {1})", secret.Name, secret.ObjectId); var resources = await Resources.GetAsync(r => secret.ResourceIds.Contains(r.ObjectId)); var workflow = new ProviderActionWorkflow(log, resources.Select(r => GetProvider(log, r.ProviderType, r.ProviderConfiguration, credentialType))); try { await workflow.InvokeAsync(secret.ValidPeriod); secret.LastChanged = DateTimeOffset.UtcNow; await ManagedSecrets.UpdateAsync(secret); log.LogInformation("Completed rekeying workflow for ManagedSecret '{0}' (ID {1})", secret.Name, secret.ObjectId); if (credentialType == MultiCredentialProvider.CredentialType.CachedCredential) { log.LogInformation("Destroying persisted credential"); await SecureStorageProvider.Destroy(task.PersistedCredentialId); } log.LogInformation("Rekeying task completed"); } catch (Exception ex) { log.LogCritical(ex, "Error running rekeying task!"); log.LogCritical(ex.Message); log.LogCritical(ex.StackTrace); log.OuterException = JsonConvert.SerializeObject(ex, Formatting.Indented); } return(log); }