/// <summary> /// Configures the data protection system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="sasUri">The full URI where the key file should be stored. /// The URI must contain the SAS token as a query string parameter.</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="blobSasUri"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, Uri blobSasUri) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (blobSasUri == null) { throw new ArgumentNullException(nameof(blobSasUri)); } var uriBuilder = new BlobUriBuilder(blobSasUri); BlobClient client; // The SAS token is present in the query string. if (uriBuilder.Sas == null) { throw new ArgumentException($"{nameof(blobSasUri)} is expected to be a SAS URL.", nameof(blobSasUri)); } else { client = new BlobClient(blobSasUri); } return(PersistKeysToAzureBlobStorage(builder, client)); }
/// <summary> /// Configures the key rotation system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="blobUri">The full URI where the key file should be stored. /// The URI must contain the SAS token as a query string parameter.</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="blobUri"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, Uri blobUri) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (blobUri == null) { throw new ArgumentNullException(nameof(blobUri)); } var uriBuilder = new UriBuilder(blobUri); // The SAS token is present in the query string. if (string.IsNullOrEmpty(uriBuilder.Query)) { throw new ArgumentException( message: "URI does not have a SAS token in the query string.", paramName: nameof(blobUri)); } var credentials = new StorageCredentials(uriBuilder.Query); uriBuilder.Query = null; // no longer needed var blobAbsoluteUri = uriBuilder.Uri; return(PersistKeystoAzureBlobStorageInternal(builder, () => new CloudBlockBlob(blobAbsoluteUri, credentials))); }
/// <summary> /// Configures the key rotation system to persist keys to a RavenDb datasstore /// </summary> /// <param name="builder">The <see cref="IDataProtectionBuilder" /> instance to modify.</param> /// <param name="getSession">The get session.</param> /// <returns> /// The value <paramref name="builder" />. /// </returns> /// <exception cref="ArgumentNullException">builder</exception> public static IKeyRotationBuilder PersistKeysToRavenDb(this IKeyRotationBuilder builder, Func <IServiceProvider, IDocumentSession> getSession = null) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (getSession == null) { getSession = p => { var store = p.GetRequiredService <IDocumentStore>(); return(store.OpenSession()); }; } builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { var loggerFactory = services.GetService <ILoggerFactory>() ?? NullLoggerFactory.Instance; return(new ConfigureOptions <KeyRotationOptions>(options => { options.XmlRepository = new RavenDbXmlRepository <Aguacongas.IdentityServer.KeysRotation.RavenDb.KeyRotationKey>(services, loggerFactory); })); }) .AddTransient(p => new DocumentSessionWrapper(getSession(p))); return(builder); }
/// <summary> /// Configures keys to be encrypted to a given certificate before being persisted to storage. /// </summary> /// <param name="builder">The <see cref="IDataProtectionBuilder"/>.</param> /// <param name="certificate">The certificate to use when encrypting keys.</param> /// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder ProtectKeysWithCertificate(this IKeyRotationBuilder builder, X509Certificate2 certificate) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { var loggerFactory = services.GetService <ILoggerFactory>() ?? NullLoggerFactory.Instance; return(new ConfigureOptions <KeyRotationOptions>(options => { options.XmlEncryptor = new CertificateXmlEncryptor(certificate, loggerFactory); })); }); builder.Services.Configure <XmlKeyDecryptionOptions>(o => o.AddKeyDecryptionCertificate(certificate)); return(builder); }
/// <summary> /// Configures the key rotation system to protect keys with specified key in Azure KeyVault. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="client">The <see cref="KeyVaultClient"/> to use for KeyVault access.</param> /// <param name="keyIdentifier">The Azure KeyVault key identifier used for key encryption.</param> /// <returns>The value <paramref name="builder"/>.</returns> public static IKeyRotationBuilder ProtectKeysWithAzureKeyVault(this IKeyRotationBuilder builder, KeyVaultClient client, string keyIdentifier) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (client == null) { throw new ArgumentNullException(nameof(client)); } if (string.IsNullOrEmpty(keyIdentifier)) { throw new ArgumentNullException(nameof(keyIdentifier)); } var vaultClientWrapper = new KeyVaultClientWrapper(client); builder.Services.AddSingleton <IKeyVaultWrappingClient>(vaultClientWrapper); builder.Services.Configure <KeyRotationOptions>(options => { options.XmlEncryptor = new AzureKeyVaultXmlEncryptor(vaultClientWrapper, keyIdentifier); }); return(builder); }
/// <summary> /// Configures keys to be encrypted to a given certificate before being persisted to storage. /// </summary> /// <param name="builder">The <see cref="IDataProtectionBuilder"/>.</param> /// <param name="thumbprint">The thumbprint of the certificate to use when encrypting keys.</param> /// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder ProtectKeysWithCertificate(this IKeyRotationBuilder builder, string thumbprint) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (thumbprint == null) { throw new ArgumentNullException(nameof(thumbprint)); } // Make sure the thumbprint corresponds to a valid certificate. if (new AspNetCore.DataProtection.XmlEncryption.CertificateResolver().ResolveCertificate(thumbprint) == null) { throw new InvalidOperationException($"A certificate with the thumbprint '{thumbprint}' could not be found."); } // ICertificateResolver is necessary for this type to work correctly, so register it // if it doesn't already exist. builder.Services.TryAddSingleton <AspNetCore.DataProtection.XmlEncryption.ICertificateResolver, AspNetCore.DataProtection.XmlEncryption.CertificateResolver>(); builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { var loggerFactory = services.GetService <ILoggerFactory>() ?? NullLoggerFactory.Instance; var certificateResolver = services.GetRequiredService <AspNetCore.DataProtection.XmlEncryption.ICertificateResolver>(); return(new ConfigureOptions <KeyRotationOptions>(options => { options.XmlEncryptor = new CertificateXmlEncryptor(thumbprint, certificateResolver, loggerFactory); })); }); return(builder); }
/// <summary> /// Configures the key rotation system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="storageAccount">The <see cref="CloudStorageAccount"/> which /// should be utilized.</param> /// <param name="relativePath">A relative path where the key file should be /// stored, generally specified as "/containerName/[subDir/]keys.xml".</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="relativePath"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, CloudStorageAccount storageAccount, string relativePath) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (storageAccount == null) { throw new ArgumentNullException(nameof(storageAccount)); } if (relativePath == null) { throw new ArgumentNullException(nameof(relativePath)); } // Simply concatenate the root storage endpoint with the relative path, // which includes the container name and blob name. var uriBuilder = new UriBuilder(storageAccount.BlobEndpoint); uriBuilder.Path = $"{uriBuilder.Path.TrimEnd('/')}/{relativePath.TrimStart('/')}"; // We can create a CloudBlockBlob from the storage URI and the creds. var blobAbsoluteUri = uriBuilder.Uri; var credentials = storageAccount.Credentials; return(PersistKeystoAzureBlobStorageInternal(builder, () => new CloudBlockBlob(blobAbsoluteUri, credentials))); }
private static IKeyRotationBuilder PersistKeysToStackExchangeRedisInternal(IKeyRotationBuilder builder, Func <IDatabase> databaseFactory, RedisKey key) { builder.Services.Configure <KeyRotationOptions>(options => { options.XmlRepository = new RedisXmlRepository(databaseFactory, key); }); return(builder); }
// important: the Func passed into this method must return a new instance with each call private static IKeyRotationBuilder PersistKeystoAzureBlobStorageInternal(IKeyRotationBuilder builder, Func <CloudBlockBlob> blobRefFactory) { builder.Services.Configure <KeyRotationOptions>(options => { options.XmlRepository = new AzureBlobXmlRepository(blobRefFactory); }); return(builder); }
/// <summary> /// Configures the key rotation system to persist keys to the specified key in Redis database /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="connectionMultiplexer">The <see cref="IConnectionMultiplexer"/> for database access.</param> /// <param name="key">The <see cref="RedisKey"/> used to store key list.</param> /// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder PersistKeysToStackExchangeRedis(this IKeyRotationBuilder builder, IConnectionMultiplexer connectionMultiplexer, RedisKey key) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (connectionMultiplexer == null) { throw new ArgumentNullException(nameof(connectionMultiplexer)); } return(PersistKeysToStackExchangeRedisInternal(builder, () => connectionMultiplexer.GetDatabase(), key)); }
/// <summary> /// Configures the key rotation system to persist keys to specified key in Redis database /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="databaseFactory">The delegate used to create <see cref="IDatabase"/> instances.</param> /// <param name="key">The <see cref="RedisKey"/> used to store key list.</param> /// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder PersistKeysToStackExchangeRedis(this IKeyRotationBuilder builder, Func <IDatabase> databaseFactory, RedisKey key) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (databaseFactory == null) { throw new ArgumentNullException(nameof(databaseFactory)); } return(PersistKeysToStackExchangeRedisInternal(builder, databaseFactory, key)); }
/// <summary> /// Configures the key rotation system to protect keys with specified key in Azure KeyVault. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="keyIdentifier">The Azure KeyVault key identifier used for key encryption.</param> /// <param name="clientId">The application client id.</param> /// <param name="clientSecret">The client secret to use for authentication.</param> /// <returns>The value <paramref name="builder"/>.</returns> public static IKeyRotationBuilder ProtectKeysWithAzureKeyVault(this IKeyRotationBuilder builder, string keyIdentifier, string clientId, string clientSecret) { if (string.IsNullOrEmpty(clientId)) { throw new ArgumentNullException(nameof(clientId)); } if (string.IsNullOrEmpty(clientSecret)) { throw new ArgumentNullException(nameof(clientSecret)); } Task <string> callback(string authority, string resource, string scope) => GetTokenFromClientSecretAsync(authority, resource, clientId, clientSecret); return(ProtectKeysWithAzureKeyVault(builder, new KeyVaultClient(callback), keyIdentifier)); }
/// <summary> /// Configures the key rotation system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="container">The <see cref="CloudBlobContainer"/> in which the /// key file should be stored.</param> /// <param name="blobName">The name of the key file, generally specified /// as "[subdir/]keys.xml"</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="container"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, CloudBlobContainer container, string blobName) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (container == null) { throw new ArgumentNullException(nameof(container)); } if (blobName == null) { throw new ArgumentNullException(nameof(blobName)); } return(PersistKeystoAzureBlobStorageInternal(builder, () => container.GetBlockBlobReference(blobName))); }
/// <summary> /// Configures the data protection system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="blobClient">The <see cref="BlobClient"/> in which the /// key file should be stored.</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The blob referenced by <paramref name="blobClient"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, BlobClient blobClient) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (blobClient == null) { throw new ArgumentNullException(nameof(blobClient)); } builder.Services.Configure <KeyRotationOptions>(options => { options.XmlRepository = new AzureBlobXmlRepository(blobClient); }); return(builder); }
/// <summary> /// Configures the key rotation system to persist keys to an EntityFrameworkCore datastore /// </summary> /// <param name="builder">The <see cref="IDataProtectionBuilder"/> instance to modify.</param> /// <returns>The value <paramref name="builder"/>.</returns> public static IKeyRotationBuilder PersistKeysToDbContext <TContext>(this IKeyRotationBuilder builder) where TContext : DbContext, IKeyRotationContext { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { var loggerFactory = services.GetService <ILoggerFactory>() ?? NullLoggerFactory.Instance; return(new ConfigureOptions <KeyRotationOptions>(options => { options.XmlRepository = new EntityFrameworkCoreXmlRepository <TContext>(services, loggerFactory); })); }); return(builder); }
/// <summary> /// Configures the data protection system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="blobUri">The full URI where the key file should be stored. /// The URI must contain the SAS token as a query string parameter.</param> /// <param name="sharedKeyCredential">The credentials to connect to the blob.</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="blobUri"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, Uri blobUri, StorageSharedKeyCredential sharedKeyCredential) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (blobUri == null) { throw new ArgumentNullException(nameof(blobUri)); } if (sharedKeyCredential == null) { throw new ArgumentNullException(nameof(sharedKeyCredential)); } var client = new BlobClient(blobUri, sharedKeyCredential); return(PersistKeysToAzureBlobStorage(builder, client)); }
/// <summary> /// Configures the key rotation system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="blobReference">The <see cref="CloudBlockBlob"/> where the /// key file should be stored.</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="blobReference"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, CloudBlockBlob blobReference) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (blobReference == null) { throw new ArgumentNullException(nameof(blobReference)); } // We're basically just going to make a copy of this blob. // Use (container, blobName) instead of (storageuri, creds) since the container // is tied to an existing service client, which contains user-settable defaults // like retry policy and secondary connection URIs. var container = blobReference.Container; var blobName = blobReference.Name; return(PersistKeystoAzureBlobStorageInternal(builder, () => container.GetBlockBlobReference(blobName))); }
/// <summary> /// Configures the key management options for the key rotation system. /// </summary> /// <param name="builder">The <see cref="IKeyRotationBuilder"/>.</param> /// <param name="setupAction">An <see cref="Action{RsaEncryptorConfiguration}"/> to configure the provided <see cref="RsaEncryptorConfiguration"/>.</param> /// <returns>A reference to the <see cref="IKeyRotationBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder AddRsaEncryptorConfiguration(this IKeyRotationBuilder builder, Action <RsaEncryptorConfiguration> setupAction) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (setupAction == null) { throw new ArgumentNullException(nameof(setupAction)); } builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { return(new ConfigureOptions <KeyRotationOptions>(options => { setupAction(options.AuthenticatedEncryptorConfiguration as RsaEncryptorConfiguration); })); }); return(builder); }
/// <summary> /// Configures the key rotation system to persist keys to the specified directory. /// This path may be on the local machine or may point to a UNC share. /// </summary> /// <param name="builder">The <see cref="IDataProtectionBuilder"/>.</param> /// <param name="directory">The directory in which to store keys.</param> /// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder PersistKeysToFileSystem(this IKeyRotationBuilder builder, DirectoryInfo directory) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (directory == null) { throw new ArgumentNullException(nameof(directory)); } builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { var loggerFactory = services.GetService <ILoggerFactory>() ?? NullLoggerFactory.Instance; return(new ConfigureOptions <KeyRotationOptions>(options => { options.XmlRepository = new FileSystemXmlRepository(directory, loggerFactory); })); }); return(builder); }
/// <summary> /// Configures the data protection system to persist keys to the specified path /// in Azure Blob Storage. /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="connectionString">A connection string includes the authentication information /// required for your application to access data in an Azure Storage /// account at runtime. /// </param> /// <param name="containerName">The container name to use.</param> /// <param name="blobName">The blob name to use.</param> /// <returns>The value <paramref name="builder"/>.</returns> /// <remarks> /// The container referenced by <paramref name="containerName"/><paramref name="blobName"/> must already exist. /// </remarks> public static IKeyRotationBuilder PersistKeysToAzureBlobStorage(this IKeyRotationBuilder builder, string connectionString, string containerName, string blobName) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (connectionString == null) { throw new ArgumentNullException(nameof(connectionString)); } if (containerName == null) { throw new ArgumentNullException(nameof(containerName)); } if (blobName == null) { throw new ArgumentNullException(nameof(blobName)); } var client = new BlobServiceClient(connectionString).GetBlobContainerClient(containerName).GetBlobClient(blobName); return(PersistKeysToAzureBlobStorage(builder, client)); }
/// <summary> /// Configures the key rotation system to persist keys to a MongoDb datasstore /// </summary> /// <param name="builder">The <see cref="IDataProtectionBuilder" /> instance to modify.</param> /// <param name="getSession">The get session.</param> /// <returns> /// The value <paramref name="builder" />. /// </returns> /// <exception cref="ArgumentNullException">builder</exception> public static IKeyRotationBuilder PersistKeysToMongoDb(this IKeyRotationBuilder builder, Func <IServiceProvider, IMongoCollection <mongoDb.KeyRotationKey> > getCollection = null) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (getCollection == null) { getCollection = p => p.GetRequiredService <IMongoDatabase>().GetCollection <mongoDb.KeyRotationKey>(nameof(mongoDb.KeyRotationKey)); } builder.Services.AddSingleton <IConfigureOptions <KeyRotationOptions> >(services => { var loggerFactory = services.GetService <ILoggerFactory>() ?? NullLoggerFactory.Instance; return(new ConfigureOptions <KeyRotationOptions>(options => { options.XmlRepository = new mongoDb.MongoDbXmlRepository <mongoDb.KeyRotationKey>(services, loggerFactory); })); }) .AddTransient(p => new mongoDb.MongoCollectionWrapper <mongoDb.KeyRotationKey>(getCollection(p))); return(builder); }
/// <summary> /// Configures the key rotation system to persist keys to the default key ('DataProtection-Keys') in Redis database /// </summary> /// <param name="builder">The builder instance to modify.</param> /// <param name="connectionMultiplexer">The <see cref="IConnectionMultiplexer"/> for database access.</param> /// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns> public static IKeyRotationBuilder PersistKeysToStackExchangeRedis(this IKeyRotationBuilder builder, IConnectionMultiplexer connectionMultiplexer) { return(PersistKeysToStackExchangeRedis(builder, connectionMultiplexer, KeyRotationKeysName)); }