public async Task ExecuteTask(Guid taskId, CancellationToken cancellationToken) { // Prepare record var task = await _rekeyingTasks.GetOne(taskId, cancellationToken); task.RekeyingInProgress = true; var rekeyingAttemptLog = new RekeyingAttemptLogger(); task.Attempts.Add(rekeyingAttemptLog); await _rekeyingTasks.Update(task, cancellationToken); var logUpdateCancellationTokenSource = new CancellationTokenSource(); var logUpdateTask = Task.Run(async() => { while (task.RekeyingInProgress) { await Task.Delay(15 * 1000); await _rekeyingTasks.Update(task, cancellationToken); } }, logUpdateCancellationTokenSource.Token); // Retrieve credentials for Task AccessTokenCredential credential = null; try { if (task.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff) { if (task.PersistedCredentialId == default) { throw new KeyNotFoundException("Cached sign-off is preferred but no credentials were persisted!"); } if (_secureStorageProvider == null) { throw new NotSupportedException("Must register an ISecureStorageProvider"); } credential = await _secureStorageProvider.Retrieve <AccessTokenCredential>(task.PersistedCredentialId); } else if (task.ConfirmationType == TaskConfirmationStrategies.AdminSignsOffJustInTime) { credential = await _identityService.GetAccessTokenOnBehalfOfCurrentUserAsync(); } else if (task.ConfirmationType.UsesServicePrincipal()) { credential = await _identityService.GetAccessTokenForApplicationAsync(); } else { throw new NotSupportedException("No Access Tokens could be generated for this Task!"); } if (credential == null || string.IsNullOrEmpty(credential.AccessToken)) { throw new InvalidOperationException("Access Token was found, but was blank or invalid"); } } catch (Exception ex) { await EmbedException(task, ex, cancellationToken, "Exception retrieving Access Token"); await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task); return; } // Embed credential context in attempt log rekeyingAttemptLog.UserDisplayName = credential.Username; rekeyingAttemptLog.UserEmail = credential.Username; if (task.ConfirmationType.UsesOBOTokens()) { if (!string.IsNullOrEmpty(task.PersistedCredentialUser)) { rekeyingAttemptLog.UserDisplayName = task.PersistedCredentialUser; } else { rekeyingAttemptLog.UserDisplayName = _identityService.UserName; rekeyingAttemptLog.UserEmail = _identityService.UserEmail; } } // Retrieve targets var secret = await _managedSecrets.GetOne(task.ManagedSecretId, cancellationToken); rekeyingAttemptLog.LogInformation("Beginning rekeying of secret ID {SecretId}", task.ManagedSecretId); var resources = await _resources.Get(r => secret.ResourceIds.Contains(r.ObjectId), cancellationToken); await _rekeyingTasks.Update(task, cancellationToken); // Execute rekeying workflow try { var providers = resources.Select(r => _providerManagerService.GetProviderInstance( r.ProviderType, r.ProviderConfiguration)).ToList(); // Link in automation bindings from the outer flow providers.ForEach(p => p.Credential = credential); await _providerManagerService.ExecuteRekeyingWorkflow(rekeyingAttemptLog, secret.ValidPeriod, providers); } catch (Exception ex) { rekeyingAttemptLog.IsComplete = true; await EmbedException(task, ex, cancellationToken, "Error executing rekeying workflow!"); await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task); } // Update Task record task.RekeyingInProgress = false; task.RekeyingCompleted = rekeyingAttemptLog.IsSuccessfulAttempt; task.RekeyingFailed = !rekeyingAttemptLog.IsSuccessfulAttempt; logUpdateCancellationTokenSource.Cancel(); await _rekeyingTasks.Update(task, cancellationToken); // Run cleanup if Task is complete if (task.RekeyingCompleted) { try { secret.LastChanged = DateTimeOffset.UtcNow; await _managedSecrets.Update(secret, cancellationToken); if (task.PersistedCredentialId != default && task.PersistedCredentialId != Guid.Empty) { rekeyingAttemptLog.LogInformation("Destroying persisted credential"); await _secureStorageProvider.Destroy(task.PersistedCredentialId); task.PersistedCredentialId = default; task.PersistedCredentialUser = default; } rekeyingAttemptLog.LogInformation("Completed rekeying workflow for ManagedSecret '{ManagedSecretName}' (ID {ManagedSecretId})", secret.Name, secret.ObjectId); rekeyingAttemptLog.LogInformation("Rekeying task completed"); await _rekeyingTasks.Update(task, cancellationToken); } catch (Exception ex) { await EmbedException(task, ex, cancellationToken, "Error cleaning up after rekeying!"); } if (task.ConfirmationType.UsesOBOTokens()) { await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskCompletedManually, nameof(TaskExecutionMetaService.ExecuteTask), task); } else { await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskCompletedAutomatically, nameof(TaskExecutionMetaService.ExecuteTask), task); } } else { await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task); } }
public async Task <AccessTokenCredential> GetTokenCredentialAsync(Guid taskId, CancellationToken cancellationToken) { var task = await _rekeyingTasks.GetOne(taskId, cancellationToken); // Retrieve credentials for Task AccessTokenCredential credential = null; try { if (task.ConfirmationType == TaskConfirmationStrategies.AdminCachesSignOff) { if (task.PersistedCredentialId == default) { throw new KeyNotFoundException("Cached sign-off is preferred but no credentials were persisted!"); } if (_secureStorageProvider == null) { throw new NotSupportedException("Must register an ISecureStorageProvider"); } credential = await _secureStorageProvider.Retrieve <AccessTokenCredential>(task.PersistedCredentialId); } else if (task.ConfirmationType == TaskConfirmationStrategies.AdminSignsOffJustInTime) { credential = await _identityService.GetAccessTokenOnBehalfOfCurrentUserAsync(); } else if (task.ConfirmationType.UsesServicePrincipal()) { credential = await _identityService.GetAccessTokenForApplicationAsync(); } else { throw new NotSupportedException("No Access Tokens could be generated for this Task!"); } if (credential == null || string.IsNullOrEmpty(credential.AccessToken)) { throw new InvalidOperationException("Access Token was found, but was blank or invalid"); } credential.DisplayUserName = credential.Username; credential.DisplayEmail = credential.Username; if (task.ConfirmationType.UsesOBOTokens()) { if (!string.IsNullOrEmpty(task.PersistedCredentialUser)) { credential.DisplayUserName = task.PersistedCredentialUser; } else { credential.DisplayUserName = _identityService.UserName; credential.DisplayEmail = _identityService.UserEmail; } } return(credential); } catch (Exception ex) { await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task); throw ex; } }