Agent messaging and execution abstraction (#107)

* Agent messaging and execution abstraction

Centralize functions to AuthJanitorService, which operates on other loaded services

* Formatting cleanup and license headers

* Documentation

* Finish splitting Data

Data is now an operationally separate entity which exists only for the sake of management convenience
This commit is contained in:
Anthony Turner 2020-12-30 18:35:37 -05:00 коммит произвёл GitHub
Родитель 92368a291a
Коммит 08d683afd0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
61 изменённых файлов: 905 добавлений и 381 удалений

Просмотреть файл

@ -78,9 +78,6 @@
case AuthJanitor.Integrity.IntegrityReportExtensibilityType.ExtensibilityTypes.CryptographicImplementation:
iconName = FontAwesomeIcons.Lock;
break;
case AuthJanitor.Integrity.IntegrityReportExtensibilityType.ExtensibilityTypes.DataStore:
iconName = FontAwesomeIcons.Database;
break;
case AuthJanitor.Integrity.IntegrityReportExtensibilityType.ExtensibilityTypes.EventSink:
iconName = FontAwesomeIcons.Bell;
break;

Просмотреть файл

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<!-- Copyright (c) Microsoft Corporation. -->
<!-- Licensed under the MIT license. -->
<html>

Просмотреть файл

@ -1,22 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrity;
using AuthJanitor.Providers;
using AuthJanitor.UI.Shared.MetaServices;
using Microsoft.Extensions.DependencyInjection;
namespace AuthJanitor.UI.Shared
{
public static class AuthJanitorServiceRegistration
{
public static void RegisterServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<EventDispatcherMetaService>();
serviceCollection.AddSingleton<TaskExecutionMetaService>();
serviceCollection.AddSingleton<SystemIntegrityService>();
serviceCollection.AddTransient<ProviderWorkflowActionLogger>();
serviceCollection.AddTransient(typeof(ProviderWorkflowActionLogger<>), typeof(ProviderWorkflowActionLogger<>));
}
}
}

Просмотреть файл

@ -1,14 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.DataStores;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AuthJanitor.Integrations.DataStores
namespace AuthJanitor.DataStores
{
public interface IDataStore<TStoredModel> : IAuthJanitorExtensibilityPoint
public interface IDataStore<TStoredModel>
where TStoredModel : IAuthJanitorModel
{
/// <summary>

Просмотреть файл

@ -14,6 +14,7 @@ namespace AuthJanitor.UI.Shared.Models
public string Description { get; set; }
public TaskConfirmationStrategies TaskConfirmationStrategies { get; set; } = TaskConfirmationStrategies.None;
public string ExecutingAgentId { get; set; } = "admin-service";
public DateTimeOffset LastChanged { get; set; } = DateTimeOffset.MinValue;
public TimeSpan ValidPeriod { get; set; }

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
using System;
namespace AuthJanitor.UI.Shared
namespace AuthJanitor
{
[Serializable]
[Flags]

Просмотреть файл

@ -1,250 +1,214 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;
using AuthJanitor.SecureStorage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace AuthJanitor.UI.Shared.MetaServices
{
public class TaskExecutionMetaService
{
private readonly IDataStore<ManagedSecret> _managedSecrets;
private readonly IDataStore<RekeyingTask> _rekeyingTasks;
private readonly IDataStore<Resource> _resources;
private readonly ISecureStorage _secureStorageProvider;
private readonly ILogger<TaskExecutionMetaService> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly ProviderManagerService _providerManagerService;
private readonly EventDispatcherMetaService _eventDispatcherMetaService;
private readonly IIdentityService _identityService;
public TaskExecutionMetaService(
ILogger<TaskExecutionMetaService> logger,
IServiceProvider serviceProvider,
EventDispatcherMetaService eventDispatcherMetaService,
IIdentityService identityService,
ProviderManagerService providerManagerService,
IDataStore<ManagedSecret> managedSecrets,
IDataStore<RekeyingTask> rekeyingTasks,
IDataStore<Resource> resources,
ISecureStorage secureStorageProvider)
{
_logger = logger;
_serviceProvider = serviceProvider;
_eventDispatcherMetaService = eventDispatcherMetaService;
_identityService = identityService;
_providerManagerService = providerManagerService;
_managedSecrets = managedSecrets;
_rekeyingTasks = rekeyingTasks;
_resources = resources;
_secureStorageProvider = secureStorageProvider;
}
public async Task CacheBackCredentialsForTaskIdAsync(Guid taskId, CancellationToken cancellationToken)
{
var task = await _rekeyingTasks.GetOne(taskId, cancellationToken);
if (task == null)
throw new KeyNotFoundException("Task not found");
if (task.ConfirmationType != TaskConfirmationStrategies.AdminCachesSignOff)
throw new InvalidOperationException("Task does not persist credentials");
if (_secureStorageProvider == null)
throw new NotSupportedException("Must register an ISecureStorageProvider");
var credentialId = await _identityService.GetAccessTokenOnBehalfOfCurrentUserAsync()
.ContinueWith(t => _secureStorageProvider.Persist(task.Expiry, t.Result))
.Unwrap();
task.PersistedCredentialId = credentialId;
task.PersistedCredentialUser = _identityService.UserName;
await _rekeyingTasks.Update(task, cancellationToken);
}
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;
}
}
private TProvider DuplicateProvider<TProvider>(TProvider provider)
where TProvider : IAuthJanitorProvider => _providerManagerService.GetProviderInstance(provider);
public async Task ExecuteTask(Guid taskId, CancellationToken cancellationToken)
{
// Prepare record
_logger.LogInformation("Retrieving task {TaskId}", taskId);
var task = await _rekeyingTasks.GetOne(taskId, cancellationToken);
task.RekeyingInProgress = true;
// Create task to perform regular updates to UI (every 15s)
_logger.LogInformation("Starting log update task");
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 the secret configuration and its resources
var secret = await _managedSecrets.GetOne(task.ManagedSecretId, cancellationToken);
_logger.LogInformation("Retrieving resources for secret {SecretId}", secret.ObjectId);
var resources = await _resources.Get(r => secret.ResourceIds.Contains(r.ObjectId), cancellationToken);
ProviderWorkflowActionCollection workflowCollection = null;
try
{
// Create configured providers for each resource
_logger.LogInformation("Getting providers for {ResourceCount} resources", resources.Count);
var providers = resources.Select(r => _providerManagerService.GetProviderInstance(
r.ProviderType,
r.ProviderConfiguration)).ToList();
// Generate a workflow collection from the configured providers
_logger.LogInformation("Creating workflow collection");
workflowCollection = _providerManagerService.CreateWorkflowCollection(
secret.ValidPeriod,
providers);
// Get the token credential for this task and embed it
_logger.LogInformation("Embedding credentials");
workflowCollection.EmbedCredentials(await GetTokenCredentialAsync(taskId, cancellationToken));
// TODO: Per-action credentialing will go here eventually
// For now, use the snippet above for all instances
//workflowCollection.Actions.ToList().ForEach(a =>
//{
// a.Instance.Credential = credential;
//});
try
{
// Update the UI with the data from this attempt
_logger.LogInformation("Adding workflow collection to task");
task.Attempts.Add(workflowCollection);
await _rekeyingTasks.Update(task, cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating task: {ex}", ex.ToString());
throw ex;
}
// Execute the workflow collection
_logger.LogInformation("Executing {ActionCount} actions", workflowCollection.Actions.Count);
try { await workflowCollection.Run(); }
catch (Exception ex)
{
_logger.LogError(ex, "Error executing action(s)");
await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error preparing workflow: {ex}", ex);
await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task);
}
// Update Task record
_logger.LogInformation("Completing task record");
task.RekeyingInProgress = false;
task.RekeyingCompleted = (workflowCollection?.HasBeenExecuted).GetValueOrDefault();
task.RekeyingCompleted = (workflowCollection?.HasBeenExecutedSuccessfully).GetValueOrDefault();
// End the regular update task and perform one final data update with the results
logUpdateCancellationTokenSource.Cancel();
await _rekeyingTasks.Update(task, cancellationToken);
// Run cleanup if Task is complete
if (!task.RekeyingFailed)
{
_logger.LogInformation("Performing cleanup");
try
{
secret.LastChanged = DateTimeOffset.UtcNow;
if (task.PersistedCredentialId != default && task.PersistedCredentialId != Guid.Empty)
{
await _secureStorageProvider.Destroy(task.PersistedCredentialId);
task.PersistedCredentialId = default;
task.PersistedCredentialUser = default;
}
await _rekeyingTasks.Update(task, cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting persisted credentials");
await _eventDispatcherMetaService.DispatchEvent(AuthJanitorSystemEvents.AnomalousEventOccurred, nameof(TaskExecutionMetaService.ExecuteTask),
"Failure to clean up persisted credentials");
}
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);
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
using AuthJanitor.Providers;
using AuthJanitor.SecureStorage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using AuthJanitor.DataStores;
namespace AuthJanitor
{
public class TaskExecutionMetaService
{
private readonly IDataStore<ManagedSecret> _managedSecrets;
private readonly IDataStore<RekeyingTask> _rekeyingTasks;
private readonly IDataStore<Resource> _resources;
private readonly ISecureStorage _secureStorageProvider;
private readonly ILogger<TaskExecutionMetaService> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly ProviderManagerService _providerManagerService;
private readonly EventDispatcherService _eventDispatcherService;
private readonly IIdentityService _identityService;
private readonly AuthJanitorService _authJanitorService;
public TaskExecutionMetaService(
ILogger<TaskExecutionMetaService> logger,
IServiceProvider serviceProvider,
EventDispatcherService eventDispatcherService,
IIdentityService identityService,
ProviderManagerService providerManagerService,
IDataStore<ManagedSecret> managedSecrets,
IDataStore<RekeyingTask> rekeyingTasks,
IDataStore<Resource> resources,
ISecureStorage secureStorageProvider,
AuthJanitorService authJanitorService)
{
_logger = logger;
_serviceProvider = serviceProvider;
_eventDispatcherService = eventDispatcherService;
_identityService = identityService;
_providerManagerService = providerManagerService;
_managedSecrets = managedSecrets;
_rekeyingTasks = rekeyingTasks;
_resources = resources;
_secureStorageProvider = secureStorageProvider;
_authJanitorService = authJanitorService;
}
public async Task CacheBackCredentialsForTaskIdAsync(Guid taskId, CancellationToken cancellationToken)
{
var task = await _rekeyingTasks.GetOne(taskId, cancellationToken);
if (task == null)
throw new KeyNotFoundException("Task not found");
if (task.ConfirmationType != TaskConfirmationStrategies.AdminCachesSignOff)
throw new InvalidOperationException("Task does not persist credentials");
if (_secureStorageProvider == null)
throw new NotSupportedException("Must register an ISecureStorageProvider");
var credentialId = await _identityService.GetAccessTokenOnBehalfOfCurrentUserAsync()
.ContinueWith(t => _secureStorageProvider.Persist(task.Expiry, t.Result))
.Unwrap();
task.PersistedCredentialId = credentialId;
task.PersistedCredentialUser = _identityService.UserName;
await _rekeyingTasks.Update(task, cancellationToken);
}
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 _eventDispatcherService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task);
throw ex;
}
}
private TProvider DuplicateProvider<TProvider>(TProvider provider)
where TProvider : IAuthJanitorProvider => _providerManagerService.GetProviderInstance(provider);
public async Task ExecuteTask(Guid taskId, CancellationToken cancellationToken)
{
// Prepare record
_logger.LogInformation("Retrieving task {TaskId}", taskId);
var task = await _rekeyingTasks.GetOne(taskId, cancellationToken);
task.RekeyingInProgress = true;
// Create task to perform regular updates to UI (every 15s)
_logger.LogInformation("Starting log update task");
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 the secret configuration and its resources
var secret = await _managedSecrets.GetOne(task.ManagedSecretId, cancellationToken);
_logger.LogInformation("Retrieving resources for secret {SecretId}", secret.ObjectId);
var resources = await _resources.Get(r => secret.ResourceIds.Contains(r.ObjectId), cancellationToken);
var workflowCollection = await _authJanitorService.ExecuteAsync(
secret.ValidPeriod,
async (pwac) =>
{
if (!task.Attempts.Any(a => a.StartedExecution == pwac.StartedExecution))
{
task.Attempts.Add(pwac);
await _rekeyingTasks.Update(task, cancellationToken);
}
},
resources.Select(r =>
{
TokenSources tokenSource = TokenSources.Unknown;
string tokenParameter = string.Empty;
switch (secret.TaskConfirmationStrategies)
{
case TaskConfirmationStrategies.AdminSignsOffJustInTime:
tokenSource = TokenSources.OBO;
break;
case TaskConfirmationStrategies.AdminCachesSignOff:
tokenSource = TokenSources.Persisted;
tokenParameter = task.PersistedCredentialId.ToString();
break;
case TaskConfirmationStrategies.AutomaticRekeyingAsNeeded:
case TaskConfirmationStrategies.AutomaticRekeyingScheduled:
case TaskConfirmationStrategies.ExternalSignal:
tokenSource = TokenSources.ServicePrincipal;
break;
}
return new ProviderExecutionParameters()
{
ProviderType = r.ProviderType,
ProviderConfiguration = r.ProviderConfiguration,
AgentId = secret.ExecutingAgentId,
TokenSource = tokenSource,
TokenParameter = tokenParameter
};
}).ToArray());
// Update Task record
_logger.LogInformation("Completing task record");
task.RekeyingInProgress = false;
task.RekeyingCompleted = (workflowCollection?.HasBeenExecuted).GetValueOrDefault();
task.RekeyingCompleted = (workflowCollection?.HasBeenExecutedSuccessfully).GetValueOrDefault();
await _rekeyingTasks.Update(task, cancellationToken);
if (workflowCollection.HasBeenExecutedSuccessfully)
{
if (task.ConfirmationType.UsesOBOTokens())
await _eventDispatcherService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskCompletedManually, nameof(TaskExecutionMetaService.ExecuteTask), task);
else
await _eventDispatcherService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskCompletedAutomatically, nameof(TaskExecutionMetaService.ExecuteTask), task);
}
else
await _eventDispatcherService.DispatchEvent(AuthJanitorSystemEvents.RotationTaskAttemptFailed, nameof(TaskExecutionMetaService.ExecuteTask), task);
}
}
}

Просмотреть файл

@ -2,7 +2,6 @@
// Licensed under the MIT license.
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.UI.Shared.ViewModels;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;
using Microsoft.Extensions.DependencyInjection;
using System;
@ -14,6 +13,7 @@ using System.Reflection;
using System.Threading;
using AuthJanitor.IdentityServices;
using AuthJanitor.Providers.Capabilities;
using AuthJanitor.DataStores;
namespace AuthJanitor.UI.Shared
{
@ -143,6 +143,7 @@ namespace AuthJanitor.UI.Shared
Name = secret.Name,
Description = secret.Description,
TaskConfirmationStrategies = secret.TaskConfirmationStrategies,
ExecutingAgentId = secret.ExecutingAgentId,
LastChanged = secret.LastChanged,
ValidPeriodMinutes = (int)secret.ValidPeriod.TotalMinutes,
Nonce = secret.Nonce,

Просмотреть файл

@ -21,6 +21,7 @@ namespace AuthJanitor.UI.Shared.ViewModels
}
public int TaskConfirmationStrategiesInt { get; set; }
public string ExecutingAgentId { get; set; }
public DateTimeOffset? LastChanged { get; set; }
public int ValidPeriodMinutes { get; set; }

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AuthJanitor.Agents
{
public class AgentMessageEnvelope
{
public DateTimeOffset Created { get; set; }
public string Originator { get; set; }
public string Target { get; set; }
public string MessageType { get; set; }
public byte[] Message { get; set; } = new byte[0];
public IAgentMessage MessageObject { get; set; } = null;
public byte[] Signature { get; set; }
public static async Task<AgentMessageEnvelope> Create(
ICryptographicImplementation cryptographicImplementation,
string originator,
string target,
IAgentMessage message)
{
var envelope = new AgentMessageEnvelope()
{
Created = DateTimeOffset.UtcNow,
Originator = originator,
Target = target,
MessageType = message.GetType().Name,
Message = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message))
};
envelope.Signature = await cryptographicImplementation.Sign(
await GetMessageEnvelopeHash(cryptographicImplementation, envelope));
return envelope;
}
public async Task<bool> VerifyAndUnpack(
ICryptographicImplementation cryptographicImplementation)
{
MessageObject = null;
if (!await Verify(cryptographicImplementation))
return false;
MessageObject = (IAgentMessage)JsonConvert.DeserializeObject(
Encoding.UTF8.GetString(Message),
Type.GetType(MessageType));
return true;
}
public async Task<bool> Verify(
ICryptographicImplementation cryptographicImplementation) =>
await cryptographicImplementation.Verify(
await GetMessageEnvelopeHash(cryptographicImplementation, this),
this.Signature);
private static Task<byte[]> GetMessageEnvelopeHash(
ICryptographicImplementation cryptographicImplementation,
AgentMessageEnvelope envelope) =>
cryptographicImplementation.Hash(
new byte[][] {
BitConverter.GetBytes(envelope.Created.Ticks),
Encoding.UTF8.GetBytes(envelope.Originator),
Encoding.UTF8.GetBytes(envelope.Target),
Encoding.UTF8.GetBytes(envelope.MessageType),
envelope.Message
}.SelectMany(a => a).ToArray());
}
}

Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Providers;
using System;
using System.Collections.Generic;
namespace AuthJanitor.Agents
{
public class AgentProviderCommandMessage : IAgentMessage
{
public List<ProviderExecutionParameters> Providers { get; set; } =
new List<ProviderExecutionParameters>();
public TimeSpan ValidPeriod { get; set; }
public string State { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Providers;
namespace AuthJanitor.Agents
{
public class AgentProviderStatusMessage : IAgentMessage
{
public string State { get; set; }
public ProviderWorkflowActionCollection WorkflowActionCollection { get; set; } =
new ProviderWorkflowActionCollection();
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
namespace AuthJanitor.Agents
{
public class AgentStatusMessage : IAgentMessage
{
public DateTimeOffset CurrentTime { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System.Threading.Tasks;
namespace AuthJanitor.Agents
{
public interface IAgentCommunicationProvider
{
Task Send(AgentMessageEnvelope envelop);
Task<AgentMessageEnvelope> TryReceive();
}
}

Просмотреть файл

@ -0,0 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace AuthJanitor.Agents
{
public interface IAgentMessage
{
}
}

Просмотреть файл

@ -7,6 +7,7 @@
<ItemGroup>
<PackageReference Include="AuthenticodeExaminer" Version="0.3.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Text.Json" Version="4.7.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />

Просмотреть файл

@ -0,0 +1,355 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Agents;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
using AuthJanitor.Integrity;
using AuthJanitor.Providers;
using AuthJanitor.SecureStorage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AuthJanitor
{
public class AuthJanitorServiceOptions
{
public string InstanceId { get; set; }
}
public static class AuthJanitorServiceExtensions
{
public static void AddAuthJanitorService(this IServiceCollection serviceCollection,
string instanceIdentity,
Type[] providerTypes)
{
serviceCollection.AddSingleton<EventDispatcherService>();
serviceCollection.AddSingleton<SystemIntegrityService>();
serviceCollection.AddSingleton<ProviderManagerService>((s) =>
new ProviderManagerService(s, providerTypes));
serviceCollection.Configure<AuthJanitorServiceOptions>((o) => o.InstanceId = instanceIdentity);
serviceCollection.AddSingleton<AuthJanitorService>();
serviceCollection.AddTransient<ProviderWorkflowActionLogger>();
serviceCollection.AddTransient(typeof(ProviderWorkflowActionLogger<>), typeof(ProviderWorkflowActionLogger<>));
}
}
public class AuthJanitorService
{
private readonly ILogger<AuthJanitorService> _logger;
private readonly ProviderManagerService _providerManagerService;
private readonly ICryptographicImplementation _cryptographicImplementation;
private readonly ISecureStorage _secureStorage;
private readonly IIdentityService _identityService;
private readonly EventDispatcherService _eventDispatcher;
private readonly IAgentCommunicationProvider _agentCommunicationProvider;
private readonly IOptions<AuthJanitorServiceOptions> _options;
public AuthJanitorService(
ILogger<AuthJanitorService> logger,
ProviderManagerService providerManagerService,
ICryptographicImplementation cryptographicImplementation,
ISecureStorage secureStorage,
IIdentityService identityService,
EventDispatcherService eventDispatcherService,
IAgentCommunicationProvider agentCommunicationProvider,
IOptions<AuthJanitorServiceOptions> options)
{
_logger = logger;
_providerManagerService = providerManagerService;
_cryptographicImplementation = cryptographicImplementation;
_secureStorage = secureStorage;
_identityService = identityService;
_eventDispatcher = eventDispatcherService;
_agentCommunicationProvider = agentCommunicationProvider;
_options = options;
}
/// <summary>
/// Process an incoming serialized message.
///
/// The message will be deserialized, its signature verified,
/// and it will be routed.
///
/// If the message is a command to execute, the execution will
/// run and the periodicUpdateFunction will be run regularly to
/// update the caller on the runtime status.
///
/// If the message is a status update, the periodicUpdateFunction
/// will be executed only once.
/// </summary>
/// <param name="serializedMessage">Serialized Agent message</param>
/// <param name="periodicUpdateFunction">Function which is invoked periodically to communicate runtime status</param>
/// <returns></returns>
public async Task ProcessMessageAsync(
string serializedMessage,
Func<ProviderWorkflowActionCollection, Task> periodicUpdateFunction)
{
var envelope = JsonConvert.DeserializeObject<AgentMessageEnvelope>(serializedMessage);
envelope.MessageObject = null;
if (envelope.Target != _options.Value.InstanceId)
return;
if (!await envelope.VerifyAndUnpack(_cryptographicImplementation))
{
await _eventDispatcher.DispatchEvent(
EventSinks.AuthJanitorSystemEvents.AnomalousEventOccurred,
nameof(AuthJanitorService.ProcessMessageAsync),
"Failed to verify agent message! This may indicate agent compromise.");
throw new Exception("Message verification failed!");
}
if (envelope.MessageObject is AgentProviderCommandMessage)
{
var message = envelope.MessageObject as AgentProviderCommandMessage;
await ExecuteAsync(message.ValidPeriod,
periodicUpdateFunction,
message.Providers.ToArray());
}
if (envelope.MessageObject is AgentProviderStatusMessage)
{
var message = envelope.MessageObject as AgentProviderStatusMessage;
var taskId = Guid.Parse(message.State);
await periodicUpdateFunction(message.WorkflowActionCollection);
}
}
/// <summary>
/// Stash the credentials for the current user in the preferred
/// secure storage, and return the Guid of the stashed object.
/// </summary>
/// <param name="expiry">When the credentials expire, if unused</param>
/// <returns>Guid of stashed object</returns>
public async Task<Guid> StashCredentialForCurrentUserAsync(DateTimeOffset expiry = default) =>
await StashCredentialAsync(
await _identityService.GetAccessTokenOnBehalfOfCurrentUserAsync(),
expiry);
/// <summary>
/// Stash the credentials for the application's identity in the preferred
/// secure storage, and return the Guid of the stashed object.
/// </summary>
/// <param name="expiry">When the credentials expire, if unused</param>
/// <returns>Guid of stashed object</returns>
public async Task<Guid> StashCredentialForCurrentAppAsync(DateTimeOffset expiry = default) =>
await StashCredentialAsync(
await _identityService.GetAccessTokenForApplicationAsync(),
expiry);
/// <summary>
/// Stash a given credentials object in the preferred
/// secure storage, and return the Guid of the stashed object.
/// </summary>
/// <param name="token">AccessTokenCredential to stash</param>
/// <param name="expiry">When the credentials expire, if unused</param>
/// <returns>Guid of stashed object</returns>
public async Task<Guid> StashCredentialAsync(
AccessTokenCredential token,
DateTimeOffset expiry = default)
{
if (expiry == default) expiry = DateTimeOffset.Now.AddDays(7);
return await _secureStorage.Persist(expiry, token);
}
/// <summary>
/// Process a given set of providerConfigurations and either
/// execute the workflow locally or dispatch a message to an Agent
/// to run the workflow.
///
/// The periodicUpdateFunction will be executed regularly throughout
/// the execution of the workflow.
///
/// When dispatching a message, the dispatchMessageState string will
/// be included to differentiate message sets
/// </summary>
/// <param name="secretValidPeriod">Secret's period of validity</param>
/// <param name="periodicUpdateFunction">Function which is invoked periodically to communicate runtime status</param>
/// <param name="dispatchMessageState">State included in any dispatched messages to group related messages</param>
/// <param name="providerConfigurations">Provider configurations</param>
/// <returns></returns>
public async Task DispatchOrExecuteAsync(
TimeSpan secretValidPeriod,
Func<ProviderWorkflowActionCollection, Task> periodicUpdateFunction,
string dispatchMessageState,
params ProviderExecutionParameters[] providerConfigurations)
{
if (providerConfigurations.Any(c => c.AgentId != _options.Value.InstanceId))
{
var agentId = providerConfigurations.FirstOrDefault(c => c.AgentId != _options.Value.InstanceId)?.AgentId;
await _agentCommunicationProvider.Send(
await AgentMessageEnvelope.Create(_cryptographicImplementation,
_options.Value.InstanceId,
agentId,
new AgentProviderCommandMessage()
{
State = dispatchMessageState,
ValidPeriod = secretValidPeriod,
Providers = providerConfigurations.Where(c => c.AgentId == agentId).ToList()
}));
}
if (providerConfigurations.Any(c => c.AgentId == _options.Value.InstanceId))
{
await ExecuteAsync(secretValidPeriod,
periodicUpdateFunction,
providerConfigurations.Where(c => c.AgentId == _options.Value.InstanceId).ToArray());
}
}
/// <summary>
/// Process a given set of providerConfigurations and execute the
/// workflow locally. If the Instance ID doesn't match the expected
/// Agent ID, this will return immediately.
///
/// The periodicUpdateFunction will be executed regularly throughout
/// the execution of the workflow.
/// </summary>
/// <param name="secretValidPeriod">Secret's period of validity</param>
/// <param name="periodicUpdateFunction">Function which is invoked periodically to communicate runtime status</param>
/// <param name="providerConfigurations">Provider configurations</param>
/// <returns></returns>
public async Task<ProviderWorkflowActionCollection> ExecuteAsync(
TimeSpan secretValidPeriod,
Func<ProviderWorkflowActionCollection, Task> periodicUpdateFunction,
params ProviderExecutionParameters[] providerConfigurations)
{
ProviderWorkflowActionCollection workflowCollection =
new ProviderWorkflowActionCollection();
try
{
var persisted = new Dictionary<Guid, AccessTokenCredential>();
if (providerConfigurations.Any(p => p.TokenSource == TokenSources.Persisted))
{
_logger.LogInformation("Downloading persisted tokens");
foreach (var item in providerConfigurations.Where(p => p.TokenSource == TokenSources.Persisted))
{
var guid = Guid.Parse(item.TokenParameter);
persisted[guid] = await _secureStorage.Retrieve<AccessTokenCredential>(guid);
}
}
AccessTokenCredential obo = null, msi = null;
if (providerConfigurations.Any(p => p.TokenSource == TokenSources.OBO))
{
_logger.LogInformation("Acquiring OBO token");
obo = await _identityService.GetAccessTokenOnBehalfOfCurrentUserAsync();
}
if (providerConfigurations.Any(p => p.TokenSource == TokenSources.ServicePrincipal))
{
_logger.LogInformation("Acquiring application token");
msi = await _identityService.GetAccessTokenForApplicationAsync();
}
_logger.LogInformation("Getting providers for {ResourceCount} resources", providerConfigurations.Count());
await Task.WhenAll(providerConfigurations.Select(async r =>
{
switch (r.TokenSource)
{
case TokenSources.Explicit:
r.AccessToken = JsonConvert.DeserializeObject<AccessTokenCredential>(r.TokenParameter);
break;
case TokenSources.OBO:
r.AccessToken = obo;
r.AccessToken.DisplayEmail = _identityService.UserEmail;
r.AccessToken.DisplayUserName = _identityService.UserName;
break;
case TokenSources.Persisted:
r.AccessToken = persisted[Guid.Parse(r.TokenParameter)];
r.AccessToken.DisplayEmail = r.AccessToken.Username;
r.AccessToken.DisplayUserName = r.AccessToken.Username;
break;
case TokenSources.ServicePrincipal:
r.AccessToken = msi;
break;
case TokenSources.Unknown:
default:
await _eventDispatcher.DispatchEvent(AuthJanitorSystemEvents.AnomalousEventOccurred,
nameof(AuthJanitorService.ExecuteAsync),
$"TokenSource was unknown for a provider! ({r.ProviderType})");
break;
}
return r;
}));
// --- end access token acquisition/embed ---
var providers = providerConfigurations.Select(r =>
{
var p = _providerManagerService.GetProviderInstance(
r.ProviderType,
r.ProviderConfiguration);
if (r.AccessToken != null)
p.Credential = r.AccessToken;
return p;
}).ToList();
workflowCollection = _providerManagerService.CreateWorkflowCollection(
secretValidPeriod,
providers);
_logger.LogInformation("Creating workflow execution task");
Task workflowCollectionRunTask = new Task(async () =>
{
try { await workflowCollection.Run(); }
catch (Exception ex)
{
_logger.LogError(ex, "Error executing action(s)");
throw ex;
}
});
_logger.LogInformation("Creating tracker task for workflow collection");
var logUpdateCancellationTokenSource = new CancellationTokenSource();
var periodicUpdateTask = Task.Run(async () =>
{
while (!workflowCollectionRunTask.IsCompleted &&
!workflowCollectionRunTask.IsCanceled)
{
await Task.Delay(5 * 1000);
await periodicUpdateFunction(workflowCollection);
}
}, logUpdateCancellationTokenSource.Token);
_logger.LogInformation("Executing {ActionCount} actions", workflowCollection.Actions.Count);
await workflowCollectionRunTask;
_logger.LogInformation("Execution complete", workflowCollection.Actions.Count);
logUpdateCancellationTokenSource.Cancel();
await periodicUpdateFunction(workflowCollection);
if (workflowCollection.HasBeenExecutedSuccessfully)
{
if (providerConfigurations.Any(p => p.TokenSource == TokenSources.Persisted))
{
_logger.LogInformation("Cleaning up persisted tokens");
foreach (var item in providerConfigurations.Where(p => p.TokenSource == TokenSources.Persisted))
await _secureStorage.Destroy(Guid.Parse(item.TokenParameter));
}
}
return workflowCollection;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error preparing workflow: {ex}", ex);
await _eventDispatcher.DispatchEvent(
AuthJanitorSystemEvents.RotationTaskAttemptFailed,
nameof(AuthJanitorService.ExecuteAsync),
"Error executing provider workflow");
return workflowCollection;
}
}
}
}

Просмотреть файл

@ -4,7 +4,7 @@ using System;
using System.Runtime.InteropServices;
using System.Security;
namespace AuthJanitor.Integrations.CryptographicImplementations
namespace AuthJanitor.CryptographicImplementations
{
public static class CryptographicImplementationExtensions
{

Просмотреть файл

@ -3,7 +3,7 @@
using System.Security;
using System.Threading.Tasks;
namespace AuthJanitor.Integrations.CryptographicImplementations
namespace AuthJanitor.CryptographicImplementations
{
public interface ICryptographicImplementation : IAuthJanitorExtensibilityPoint
{

Просмотреть файл

@ -1,24 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.EventSinks;
using AuthJanitor.Integrations.EventSinks;
using AuthJanitor.EventSinks;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AuthJanitor.UI.Shared.MetaServices
namespace AuthJanitor
{
public class EventDispatcherMetaService
public class EventDispatcherService
{
private readonly ILogger _logger;
private readonly IEnumerable<IEventSink> _eventSinks;
public EventDispatcherMetaService(
public EventDispatcherService(
ILoggerFactory loggerFactory,
IEnumerable<IEventSink> eventSinks)
{
_logger = loggerFactory.CreateLogger<EventDispatcherMetaService>();
_logger = loggerFactory.CreateLogger<EventDispatcherService>();
_eventSinks = eventSinks;
}

Просмотреть файл

@ -4,7 +4,7 @@ using AuthJanitor.EventSinks;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace AuthJanitor.Integrations.EventSinks
namespace AuthJanitor.EventSinks
{
public interface IEventSink : IAuthJanitorExtensibilityPoint
{

Просмотреть файл

@ -10,7 +10,6 @@ namespace AuthJanitor.Integrity
public enum ExtensibilityTypes
{
CryptographicImplementation,
DataStore,
EventSink,
Identity,
Provider,
@ -35,15 +34,11 @@ namespace AuthJanitor.Integrity
{
ExtensibilityType = ExtensibilityTypes.Identity;
}
else if (typeof(Integrations.CryptographicImplementations.ICryptographicImplementation).IsAssignableFrom(type))
else if (typeof(CryptographicImplementations.ICryptographicImplementation).IsAssignableFrom(type))
{
ExtensibilityType = ExtensibilityTypes.CryptographicImplementation;
}
else if (typeof(Integrations.DataStores.IDataStore<>).IsAssignableFrom(type))
{
ExtensibilityType = ExtensibilityTypes.DataStore;
}
else if (typeof(Integrations.EventSinks.IEventSink).IsAssignableFrom(type))
else if (typeof(EventSinks.IEventSink).IsAssignableFrom(type))
{
ExtensibilityType = ExtensibilityTypes.EventSink;
}

Просмотреть файл

@ -1,14 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthenticodeExaminer;
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace AuthJanitor.Integrity

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Providers;
using AuthJanitor.Providers.Capabilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -10,14 +11,13 @@ using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace AuthJanitor.Providers
namespace AuthJanitor
{
public class ProviderManagerService
{
private const int MAX_RETRIES = 5;
private const int DELAY_BETWEEN_ACTIONS_MS = 1000;
public static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions()
{
WriteIndented = false,
@ -50,13 +50,20 @@ namespace AuthJanitor.Providers
.AsReadOnly();
}
public static void ConfigureServices(IServiceCollection serviceCollection, params Type[] loadedProviderTypes)
{
serviceCollection.AddSingleton<ProviderManagerService>((s) => new ProviderManagerService(s, loadedProviderTypes));
}
/// <summary>
/// Check if a provider is loaded
/// </summary>
/// <param name="providerName">Provider type name</param>
/// <returns><c>TRUE</c> if the provider is loaded</returns>
public bool HasProvider(string providerName) => LoadedProviders.Any(p => p.ProviderTypeName == providerName);
/// <summary>
/// Get the metadata for a given Provider by its type name.
///
/// If the Provider is not found, an Exception is thrown.
/// </summary>
/// <param name="providerName">Provider type name</param>
/// <returns>Provider's metadata</returns>
public LoadedProviderMetadata GetProviderMetadata(string providerName)
{
if (!HasProvider(providerName))
@ -65,12 +72,27 @@ namespace AuthJanitor.Providers
return LoadedProviders.First(p => p.ProviderTypeName == providerName);
}
/// <summary>
/// Get an unconfigured instance of a given Provider by its type name.
///
/// If the Provider is not found, an Exception is thrown.
/// </summary>
/// <param name="providerName">Provider type name</param>
/// <returns>Unconfigured Provider instance</returns>
public IAuthJanitorProvider GetProviderInstance(string providerName)
{
var metadata = GetProviderMetadata(providerName);
return ActivatorUtilities.CreateInstance(_serviceProvider, metadata.ProviderType) as IAuthJanitorProvider;
}
/// <summary>
/// Get an instance of a given Provider by its type name.
/// The Provider will be configured with its defaults.
///
/// If the Provider is not found, an Exception is thrown.
/// </summary>
/// <param name="providerName">Provider type name</param>
/// <returns>Provider instance with defaults</returns>
public IAuthJanitorProvider GetProviderInstanceDefault(string providerName)
{
var instance = GetProviderInstance(providerName);
@ -78,6 +100,16 @@ namespace AuthJanitor.Providers
return instance;
}
/// <summary>
/// Get an instance of a given Provider by its type name.
/// The instance's configuration will be deserialized from
/// the given string.
///
/// If the Provider is not found, an Exception is thrown.
/// </summary>
/// <param name="providerName">Provider type name</param>
/// <param name="serializedProviderConfiguration">Serialized configuration</param>
/// <returns>Configured Provider instance</returns>
public IAuthJanitorProvider GetProviderInstance(string providerName, string serializedProviderConfiguration)
{
var instance = GetProviderInstance(providerName);
@ -85,20 +117,62 @@ namespace AuthJanitor.Providers
return instance;
}
/// <summary>
/// Create a duplicate of an existing Provider, including configuration.
///
/// If the Provider is not found, an Exception is thrown.
/// </summary>
/// <typeparam name="TProvider">Provider type</typeparam>
/// <param name="existingProviderToClone">Provider to clone</param>
/// <returns>Duplicate Provider instance</returns>
public TProvider GetProviderInstance<TProvider>(TProvider existingProviderToClone)
where TProvider : IAuthJanitorProvider =>
(TProvider)GetProviderInstance(existingProviderToClone.GetType().AssemblyQualifiedName, existingProviderToClone.SerializedConfiguration);
/// <summary>
/// Get the default configuration for a given Provider by its type name
/// </summary>
/// <param name="name">Provider type name</param>
/// <returns>Default configuration for Provider</returns>
public AuthJanitorProviderConfiguration GetProviderConfiguration(string name) => ActivatorUtilities.CreateInstance(_serviceProvider, GetProviderMetadata(name).ProviderConfigurationType) as AuthJanitorProviderConfiguration;
/// <summary>
/// Get the Provider configuration for a given Provider from
/// a serialized string
/// </summary>
/// <param name="name">Provider type name</param>
/// <param name="serializedConfiguration">Serialized configuration</param>
/// <returns>Provider configuration</returns>
public AuthJanitorProviderConfiguration GetProviderConfiguration(string name, string serializedConfiguration) => JsonSerializer.Deserialize(serializedConfiguration, GetProviderMetadata(name).ProviderConfigurationType, SerializerOptions) as AuthJanitorProviderConfiguration;
/// <summary>
/// Serialize a given Provider configuration
/// </summary>
/// <typeparam name="T">Configuration type</typeparam>
/// <param name="name">Provider type name</param>
/// <param name="configuration">Configuration object</param>
/// <returns>Serialized configuration</returns>
public string GetProviderConfiguration<T>(string name, T configuration) => JsonSerializer.Serialize(configuration, GetProviderMetadata(name).ProviderConfigurationType, SerializerOptions);
/// <summary>
/// Test a given serialized configuration with a given
/// Provider type name
/// </summary>
/// <param name="name">Provider type name</param>
/// <param name="serializedConfiguration">Serialized configuration to test</param>
/// <returns><c>TRUE</c> if the configuration is valid for this Provider</returns>
public bool TestProviderConfiguration(string name, string serializedConfiguration)
{
try { return GetProviderConfiguration(name, serializedConfiguration) != null; }
catch { return false; }
}
/// <summary>
/// Enumerate potential candidates for all loaded Provider modules using
/// a given AccessTokenCredential
/// </summary>
/// <param name="credential">Credentials to access cloud service to enumerate</param>
/// <returns>Collection of suggestions of Provider configurations based on existing services</returns>
public async Task<IEnumerable<ProviderResourceSuggestion>> EnumerateProviders(AccessTokenCredential credential)
{
var providers = (await Task.WhenAll(
@ -120,6 +194,13 @@ namespace AuthJanitor.Providers
return providers;
}
/// <summary>
/// Enumerate potential candidates for a given Provider module using
/// a given AccessTokenCredential
/// </summary>
/// <param name="credential">Credentials to access cloud service to enumerate</param>
/// <param name="provider">Provider to enumerate</param>
/// <returns>Collection of suggestions of Provider configurations based on existing services</returns>
public async Task<IEnumerable<ProviderResourceSuggestion>> EnumerateProviders(AccessTokenCredential credential, IAuthJanitorProvider provider)
{
provider.Credential = credential;
@ -148,6 +229,9 @@ namespace AuthJanitor.Providers
return new ProviderResourceSuggestion[0];
}
/// <summary>
/// Loaded Providers available to this runtime instance
/// </summary>
public IReadOnlyList<LoadedProviderMetadata> LoadedProviders { get; }
private TProvider DuplicateProvider<TProvider>(TProvider provider)
@ -155,6 +239,14 @@ namespace AuthJanitor.Providers
_serviceProvider.GetRequiredService<ProviderManagerService>()
.GetProviderInstance(provider);
/// <summary>
/// Create a Workflow Collection based on actions which need to
/// be taken to execute a given set of Providers. This includes
/// proper ordering of actions as required.
/// </summary>
/// <param name="validPeriod">Valid period for secret</param>
/// <param name="providers">Providers to generate workflow collection from</param>
/// <returns>Workflow collection</returns>
public ProviderWorkflowActionCollection CreateWorkflowCollection(
TimeSpan validPeriod,
IEnumerable<IAuthJanitorProvider> providers)

Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace AuthJanitor.Providers
{
public enum TokenSources
{
Unknown,
Explicit,
Persisted,
ServicePrincipal,
OBO
}
public class ProviderExecutionParameters
{
public string ProviderType { get; set; }
public string ProviderConfiguration { get; set; }
public TokenSources TokenSource { get; set; }
public string TokenParameter { get; set; }
public string AgentId { get; set; } = "admin-service";
public AccessTokenCredential AccessToken { get; set; }
}
}

Просмотреть файл

@ -47,12 +47,9 @@ namespace AuthJanitor.Providers
_serviceProvider.GetRequiredService<ProviderManagerService>()
.GetProviderInstance(provider);
private IAuthJanitorProvider CreateProvider(string providerType, string providerConfiguration) =>
_serviceProvider.GetRequiredService<ProviderManagerService>()
.GetProviderInstance(providerType, providerConfiguration);
public void EmbedCredentials(AccessTokenCredential credential) =>
_actions.ForEach(a => a.Instance.Credential = credential);
_actions.Where(a => a.Instance.Credential == null).ToList()
.ForEach(a => a.Instance.Credential = credential);
public void Add<TProvider>(params ProviderWorkflowActionWithoutResult<TProvider>[] actions)
where TProvider : IAuthJanitorProvider

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.DataStores;
using AuthJanitor.IdentityServices;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;

Просмотреть файл

@ -1,11 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.UI.Shared.ViewModels;
using Microsoft.AspNetCore.Http;
@ -15,6 +11,8 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.DataStores;
namespace AuthJanitor.Services
{
@ -28,7 +26,7 @@ namespace AuthJanitor.Services
private readonly IIdentityService _identityService;
private readonly ICryptographicImplementation _cryptographicImplementation;
private readonly ProviderManagerService _providerManager;
private readonly EventDispatcherMetaService _eventDispatcher;
private readonly EventDispatcherService _eventDispatcher;
private readonly IDataStore<ManagedSecret> _managedSecrets;
private readonly IDataStore<Resource> _resources;
@ -38,7 +36,7 @@ namespace AuthJanitor.Services
IOptions<AuthJanitorCoreConfiguration> configuration,
IIdentityService identityService,
ICryptographicImplementation cryptographicImplementation,
EventDispatcherMetaService eventDispatcher,
EventDispatcherService eventDispatcher,
ProviderManagerService providerManager,
IDataStore<ManagedSecret> managedSecretStore,
IDataStore<Resource> resourceStore,

Просмотреть файл

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.UI.Shared;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.UI.Shared.ViewModels;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
@ -26,7 +25,7 @@ namespace AuthJanitor.Services
{
private readonly IIdentityService _identityService;
private readonly ILogger _logger;
private readonly EventDispatcherMetaService _eventDispatcher;
private readonly EventDispatcherService _eventDispatcher;
private readonly ProviderManagerService _providerManager;
private readonly Func<AuthJanitorProviderConfiguration, ProviderConfigurationViewModel> _configViewModel;
@ -35,7 +34,7 @@ namespace AuthJanitor.Services
public ProvidersService(
IIdentityService identityService,
ILogger<ProvidersService> logger,
EventDispatcherMetaService eventDispatcher,
EventDispatcherService eventDispatcher,
ProviderManagerService providerManager,
Func<AuthJanitorProviderConfiguration, ProviderConfigurationViewModel> configViewModelDelegate,
Func<LoadedProviderMetadata, LoadedProviderViewModel> providerViewModelDelegate)

Просмотреть файл

@ -1,11 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.DataStores;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;
using AuthJanitor.UI.Shared;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.UI.Shared.ViewModels;
using Microsoft.AspNetCore.Http;
@ -29,7 +26,7 @@ namespace AuthJanitor.Services
private readonly IIdentityService _identityService;
private readonly TaskExecutionMetaService _taskExecutionMetaService;
private readonly ProviderManagerService _providerManager;
private readonly EventDispatcherMetaService _eventDispatcher;
private readonly EventDispatcherService _eventDispatcher;
private readonly IDataStore<ManagedSecret> _managedSecrets;
private readonly IDataStore<RekeyingTask> _rekeyingTasks;
@ -39,7 +36,7 @@ namespace AuthJanitor.Services
IOptions<AuthJanitorCoreConfiguration> configuration,
IIdentityService identityService,
TaskExecutionMetaService taskExecutionMetaService,
EventDispatcherMetaService eventDispatcher,
EventDispatcherService eventDispatcher,
ProviderManagerService providerManager,
IDataStore<ManagedSecret> managedSecretStore,
IDataStore<RekeyingTask> rekeyingTaskStore,

Просмотреть файл

@ -1,10 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.DataStores;
using AuthJanitor.EventSinks;
using AuthJanitor.IdentityServices;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.UI.Shared.ViewModels;
using Microsoft.AspNetCore.Http;
@ -25,14 +23,14 @@ namespace AuthJanitor.Services
{
private readonly IIdentityService _identityService;
private readonly ProviderManagerService _providerManager;
private readonly EventDispatcherMetaService _eventDispatcher;
private readonly EventDispatcherService _eventDispatcher;
private readonly IDataStore<Resource> _resources;
private readonly Func<Resource, ResourceViewModel> _resourceViewModel;
public ResourcesService(
IIdentityService identityService,
EventDispatcherMetaService eventDispatcher,
EventDispatcherService eventDispatcher,
ProviderManagerService providerManager,
IDataStore<Resource> resourceStore,
Func<Resource, ResourceViewModel> resourceViewModelDelegate)

Просмотреть файл

@ -1,10 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.DataStores;
using AuthJanitor.EventSinks;
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.Providers;
using AuthJanitor.UI.Shared;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.UI.Shared.Models;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
@ -21,7 +18,7 @@ namespace AuthJanitor.Services
{
private readonly AuthJanitorCoreConfiguration _configuration;
private readonly ProviderManagerService _providerManager;
private readonly EventDispatcherMetaService _eventDispatcherMetaService;
private readonly EventDispatcherService _eventDispatcherMetaService;
private readonly IDataStore<ManagedSecret> _managedSecrets;
private readonly IDataStore<Resource> _resources;
@ -29,7 +26,7 @@ namespace AuthJanitor.Services
public ScheduleRekeyingTasksService(
IOptions<AuthJanitorCoreConfiguration> configuration,
EventDispatcherMetaService eventDispatcherMetaService,
EventDispatcherService eventDispatcherMetaService,
ProviderManagerService providerManager,
IDataStore<ManagedSecret> managedSecretStore,
IDataStore<Resource> resourceStore,

Просмотреть файл

@ -89,9 +89,6 @@ namespace AuthJanitor
builder.Services.AddTransient<ProvidersService>();
builder.Services.AddTransient<ResourcesService>();
logger.LogDebug("Registering AuthJanitor MetaServices");
AuthJanitorServiceRegistration.RegisterServices(builder.Services);
// -----
logger.LogDebug("Registering DataStores");
@ -119,7 +116,7 @@ namespace AuthJanitor
logger.LogInformation("Found {ProviderCount} providers: {ProviderTypeNames}", providerTypes.Length, string.Join(" ", providerTypes.Select(t => t.Name)));
logger.LogInformation("Registering Provider Manager Service");
ProviderManagerService.ConfigureServices(builder.Services, providerTypes);
builder.Services.AddAuthJanitorService("admin-service", providerTypes);
}
}
}

Просмотреть файл

@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.DataStores;
using AuthJanitor.UI.Shared;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.DataStores;
using AuthJanitor.UI.Shared.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

Просмотреть файл

@ -1,15 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.UI.Shared;
using AuthJanitor.UI.Shared.MetaServices;
using AuthJanitor.UI.Shared.Models;
using AuthJanitor.Integrations.DataStores;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Threading;
using System.Threading.Tasks;
using AuthJanitor.DataStores;
namespace AuthJanitor
{

Просмотреть файл

@ -69,9 +69,6 @@ namespace AuthJanitor
o.VaultName = "vault";
});
logger.LogDebug("Registering AuthJanitor MetaServices");
AuthJanitorServiceRegistration.RegisterServices(builder.Services);
// -----
logger.LogDebug("Registering DataStores");
@ -98,8 +95,8 @@ namespace AuthJanitor
.ToArray();
logger.LogInformation("Found {ProviderCount} providers: {ProviderTypeNames}", providerTypes.Length, string.Join(" ", providerTypes.Select(t => t.Name)));
logger.LogInformation("Registering Provider Manager Service");
ProviderManagerService.ConfigureServices(builder.Services, providerTypes);
logger.LogInformation("Registering AuthJanitor Service");
builder.Services.AddAuthJanitorService("agent-abc123", providerTypes); // todo: change this to env var
}
}
}

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.IdentityServices;
using Azure.Security.KeyVault.Keys;
using Azure.Security.KeyVault.Keys.Cryptography;

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
namespace AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault
{

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
using Microsoft.Extensions.DependencyInjection;
using System;

Просмотреть файл

@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
using Microsoft.Extensions.Options;
using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
using Microsoft.Extensions.DependencyInjection;
using System;

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.EventSinks;
using Microsoft.Extensions.DependencyInjection;
using System;

Просмотреть файл

@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.IdentityServices;
using AuthJanitor.SecureStorage;
using Azure.Security.KeyVault.Secrets;
@ -9,7 +8,7 @@ using System;
using System.Text.Json;
using System.Threading.Tasks;
using System.Text;
using System.Buffers.Text;
using AuthJanitor.CryptographicImplementations;
namespace AuthJanitor.Integrations.SecureStorage.AzureKeyVault
{

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Microsoft.Azure.Management.AppService.Fluent;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Azure.Core;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Microsoft.Azure.Management.Maps;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;
@ -9,7 +9,6 @@ using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Azure.Management.Search.Fluent;
using Microsoft.Azure.Management.Search.Fluent.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

Просмотреть файл

@ -1,18 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Azure.Management.Search.Fluent;
using Microsoft.Azure.Management.Sql.Fluent;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace AuthJanitor.Providers.AzureSql

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;
@ -8,7 +8,6 @@ using Microsoft.Azure.Management.CosmosDB.Fluent;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;
@ -9,8 +9,6 @@ using Microsoft.Azure.Management.EventHub.Fluent.Models;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Azure.Management.Sql.Fluent;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Azure;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Azure;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Capabilities;
using Azure;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;
@ -9,7 +9,6 @@ using Microsoft.Azure.Management.Redis.Fluent;
using Microsoft.Azure.Management.Redis.Fluent.Models;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;
@ -9,7 +9,6 @@ using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Azure.Management.ServiceBus.Fluent;
using Microsoft.Azure.Management.ServiceBus.Fluent.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Providers.Azure;
using AuthJanitor.Providers.Azure.Workflows;
using AuthJanitor.Providers.Capabilities;
@ -9,7 +9,6 @@ using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.CollectionActions;
using Microsoft.Azure.Management.Storage.Fluent;
using Microsoft.Azure.Management.Storage.Fluent.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using AuthJanitor.CryptographicImplementations;
using AuthJanitor.Integrations.CryptographicImplementations;
using AuthJanitor.Integrations.CryptographicImplementations.Default;
using Microsoft.Extensions.Options;

Просмотреть файл

@ -67,7 +67,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthJanitor.Tests", "AuthJa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthJanitor.Integrations.DataStores.EntityFrameworkCore", "AuthJanitor.Integrations.DataStores.EntityFrameworkCore\AuthJanitor.Integrations.DataStores.EntityFrameworkCore.csproj", "{BCEC6AD5-4A69-4440-8643-AED247F45281}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault", "AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault\AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault.csproj", "{F5F9C392-D02D-4501-BE85-8DDAAC5D06F3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault", "AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault\AuthJanitor.Integrations.CryptographicImplementations.AzureKeyVault.csproj", "{F5F9C392-D02D-4501-BE85-8DDAAC5D06F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{C8572CCA-36EC-4AAB-A4C0-AF23B4B82B8C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -186,6 +188,7 @@ Global
{12CA268F-9E1F-403F-8428-C36F1F1C17E1} = {93A3274C-6CD8-4399-9C45-7D0A4077E4E0}
{1EB29D3F-A7E4-4038-9FA9-27CAD63213FA} = {93A3274C-6CD8-4399-9C45-7D0A4077E4E0}
{03A38E05-A6D4-4325-A3A4-6AE33D7E6718} = {93A3274C-6CD8-4399-9C45-7D0A4077E4E0}
{9C0E454F-146E-40FB-AFE5-F63DAACAB326} = {C8572CCA-36EC-4AAB-A4C0-AF23B4B82B8C}
{8DBA0BBC-F92B-456D-8342-0C42E39EB81E} = {4AB5E96D-1A78-44E0-A52B-5F1A7ABE3B40}
{F9DCAB83-056E-4F4B-A8CA-9DDBBCF08394} = {0E2B33F8-6CD0-43EE-AA35-337B6798B509}
{5BDB5B18-884B-4BB5-BF20-A06114C5C928} = {45A0E86E-0F1A-434E-B3F9-D9AE88C964E1}
@ -193,10 +196,12 @@ Global
{4AB5E96D-1A78-44E0-A52B-5F1A7ABE3B40} = {45A0E86E-0F1A-434E-B3F9-D9AE88C964E1}
{CC3E1903-9A04-4A14-8EDB-59444BB57E05} = {93A3274C-6CD8-4399-9C45-7D0A4077E4E0}
{0E2B33F8-6CD0-43EE-AA35-337B6798B509} = {45A0E86E-0F1A-434E-B3F9-D9AE88C964E1}
{07EE807A-D975-4B1D-B486-6633ED87B757} = {C8572CCA-36EC-4AAB-A4C0-AF23B4B82B8C}
{31D82FCB-3F22-482C-B7A4-F9D9D4A27EF6} = {07EE807A-D975-4B1D-B486-6633ED87B757}
{1E8E5F06-CF36-4CC8-95BD-B7E455D1737C} = {07EE807A-D975-4B1D-B486-6633ED87B757}
{367C9AAB-6A24-4DC8-A69C-A22039CC11C2} = {07EE807A-D975-4B1D-B486-6633ED87B757}
{03C30803-4304-4C01-B84B-3FFFA2AD57A1} = {07EE807A-D975-4B1D-B486-6633ED87B757}
{F103367D-F5FB-43A6-AA52-6B9A0DD66862} = {C8572CCA-36EC-4AAB-A4C0-AF23B4B82B8C}
{2ED2CBEF-1B5F-4D0D-ACF0-C41D59C69B7A} = {07EE807A-D975-4B1D-B486-6633ED87B757}
{A22F4B5A-10D8-4692-9C34-D7089108E4B5} = {93A3274C-6CD8-4399-9C45-7D0A4077E4E0}
{AF99E01C-3AB2-4AF6-8771-871B3F0E380E} = {93A3274C-6CD8-4399-9C45-7D0A4077E4E0}