Ejemplo n.º 1
0
        public async Task RetrieveCertificateAsync()
        {
            #region Snippet:RetrieveCertificate
            CertificateWithPolicy certificateWithPolicy = await client.GetCertificateAsync("MyCertificate");

            #endregion

            #region Snippet:GetCertificate
            Certificate certificate = await client.GetCertificateVersionAsync(certificateWithPolicy.Name, certificateWithPolicy.Properties.Version);

            #endregion
        }
        private async Task GetCertificateFromKeyVault()
        {
            try
            {
                string keyVaultUri    = KeyVaultOptions.Value.KeyVaultUri;
                string tenantId       = KeyVaultOptions.Value.TenantId;
                string clientId       = KeyVaultOptions.Value.ClientId;
                string clientSecret   = KeyVaultOptions.Value.ClientSecret;
                string certificateUrl = KeyVaultOptions.Value.CertificateUrl;

                var          credential   = new ClientSecretCredential(tenantId, clientId, clientSecret);
                SecretClient secretClient = new SecretClient(new Uri(keyVaultUri), credential);

                KeyVaultSecret keyVaultCertificatePfx = await secretClient.GetSecretAsync(certificateUrl);

                CertificateClient             certificateClient      = new CertificateClient(new Uri(keyVaultUri), credential);
                KeyVaultCertificateWithPolicy keyVaultCertificateCer = await certificateClient.GetCertificateAsync(certificateUrl.Replace("/secrets/", "/certificates/", StringComparison.OrdinalIgnoreCase));

                DecryptionCertificate        = keyVaultCertificatePfx.Value;
                this.EncryptionCertificate   = Convert.ToBase64String(keyVaultCertificateCer.Cer);
                this.EncryptionCertificateId = keyVaultCertificatePfx.Properties.Version;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
Ejemplo n.º 3
0
        private async Task <X509Certificate2?> GetCertificateAsync(string domain, CancellationToken token)
        {
            _logger.LogInformation("Searching for certificate in KeyVault for {Domain}", domain);

            try
            {
                var normalizedName = NormalizeHostName(domain);
                var certificate    = await _client.GetCertificateAsync(normalizedName, token);

                return(new X509Certificate2(certificate.Value.Cer));
            }
            catch (RequestFailedException ex) when(ex.Status == 404)
            {
                _logger.LogWarning("Could not find certificate for {Domain} in Azure KeyVault", domain);
            }
            catch (CredentialUnavailableException ex)
            {
                _logger.LogError(ex, "Could not retrieve credentials for Azure Key Vault");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Unexpected error attempting to retrieve certificate for {Domain} from Azure KeyVault. Verify settings and try again.", domain);
            }

            return(null);
        }
Ejemplo n.º 4
0
        public async Task <bool> SignAsync(string packagePath,
                                           string outputPath,
                                           string timestampUrl,
                                           HashAlgorithmName signatureHashAlgorithm,
                                           HashAlgorithmName timestampHashAlgorithm,
                                           SignatureType signatureType,
                                           bool overwrite,
                                           Uri v3ServiceIndexUrl,
                                           IReadOnlyList <string> packageOwners,
                                           string keyVaultCertificateName,
                                           Uri keyVaultUrl,
                                           TokenCredential credential,
                                           CancellationToken cancellationToken = default)
        {
            var client = new CertificateClient(keyVaultUrl, credential);
            // We call this here to verify it's a valid cert
            // It also implicitly validates the access token or credentials
            var kvcert = await client.GetCertificateAsync(keyVaultCertificateName, cancellationToken)
                         .ConfigureAwait(false);

            var publicCertificate = new X509Certificate2(kvcert.Value.Cer);


            var rsa = RSAFactory.Create(credential, kvcert.Value.KeyId, publicCertificate);

            return(await SignAsync(packagePath, outputPath, timestampUrl, v3ServiceIndexUrl, packageOwners, signatureType, signatureHashAlgorithm, timestampHashAlgorithm, overwrite, publicCertificate, rsa, cancellationToken));
        }
        public static async Task <AzureKeyVaultMaterializedConfiguration> Materialize(AzureKeyVaultSignConfigurationSet configuration, CryptographyClientOptions options = null)
        {
            TokenCredential credential = configuration.ManagedIdentity switch
            {
                true => new DefaultAzureCredential(),
                false => new ClientSecretCredential(configuration.AzureTenantId, configuration.AzureClientId, configuration.AzureClientSecret)
            };

            if (configuration.Mode == KeyVaultMode.Certificate)
            {
                var certificateClient = new CertificateClient(configuration.AzureKeyVaultUrl, credential);
                var cert = await certificateClient.GetCertificateAsync(configuration.AzureKeyVaultKeyName).ConfigureAwait(false);

                var x509Certificate = new X509Certificate2(cert.Value.Cer);
                var keyId           = cert.Value.KeyId;

                return(new AzureKeyVaultMaterializedConfiguration(credential, keyId, publicCertificate: x509Certificate, options: options));
            }
            else if (configuration.Mode == KeyVaultMode.Key)
            {
                var keyClient = new KeyClient(configuration.AzureKeyVaultUrl, credential);
                var key       = await keyClient.GetKeyAsync(configuration.AzureKeyVaultKeyName).ConfigureAwait(false);

                return(new AzureKeyVaultMaterializedConfiguration(credential, key.Value.Id, key.Value.Key, options: options));
            }
            throw new ArgumentOutOfRangeException(nameof(configuration));
        }
    }
Ejemplo n.º 6
0
        private async Task GetCertificateFromKeyVault()
        {
            try
            {
                string clientId     = KeyVaultOptions.Value.ClientId;
                string clientSecret = KeyVaultOptions.Value.ClientSecret;
                string tenantId     = KeyVaultOptions.Value.TenantId;
                Uri    keyVaultUrl  = KeyVaultOptions.Value.KeyVaultUrl;
                string keyName      = KeyVaultOptions.Value.KeyName;

                ClientSecretCredential credential        = new ClientSecretCredential(tenantId, clientId, clientSecret);
                SecretClient           secretClient      = new SecretClient(keyVaultUrl, credential);
                CertificateClient      certificateClient = new CertificateClient(keyVaultUrl, credential);


                KeyVaultSecret keyVaultCertificatePfx = await secretClient.GetSecretAsync(keyName).ConfigureAwait(false);

                KeyVaultCertificate keyVaultCertificateCer = await certificateClient.GetCertificateAsync(keyName).ConfigureAwait(false);

                DecryptionCertificate        = keyVaultCertificatePfx.Value;
                this.EncryptionCertificate   = Convert.ToBase64String(keyVaultCertificateCer.Cer);
                this.EncryptionCertificateId = keyVaultCertificatePfx.Properties.Version;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
Ejemplo n.º 7
0
    private static async Task <int> RunAsync(
        Uri vaultUri,
        string certificateName,
        string message,
        IConsole console)
    {
        CancellationToken cancellationToken = s_cancellationTokenSource.Token;

        // Allow only credentials appropriate for this interactive tool sample.
        DefaultAzureCredential credential = new DefaultAzureCredential(
            new DefaultAzureCredentialOptions
        {
            ExcludeEnvironmentCredential     = true,
            ExcludeManagedIdentityCredential = true,
        });

        // Get the certificate to use for encrypting and decrypting.
        CertificateClient             certificateClient = new CertificateClient(vaultUri, credential);
        KeyVaultCertificateWithPolicy certificate       = await certificateClient.GetCertificateAsync(certificateName, cancellationToken : cancellationToken);

        // Make sure the private key is exportable.
        if (certificate.Policy?.Exportable != true)
        {
            console.Error.WriteLine($@"Error: certificate ""{certificateName}"" is not exportable.");
            return(1);
        }
        else if (certificate.Policy?.KeyType != CertificateKeyType.Rsa)
        {
            console.Error.WriteLine($@"Error: certificate type ""{certificate.Policy?.KeyType}"" cannot be used to locally encrypt and decrypt.");
            return(1);
        }

        // Get the managed secret which contains the public and private key (if exportable).
        string secretName = ParseSecretName(certificate.SecretId);

        SecretClient   secretClient = new SecretClient(vaultUri, credential);
        KeyVaultSecret secret       = await secretClient.GetSecretAsync(secretName, cancellationToken : cancellationToken);

        // Get a certificate pair from the secret value.
        X509Certificate2 pfx = ParseCertificate(secret);

        // Decode and encrypt the message.
        byte[] plaintext = Encoding.UTF8.GetBytes(message);

        using RSA encryptor = (RSA)pfx.PublicKey.Key;
        byte[] ciphertext = encryptor.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256);

        console.Out.WriteLine($"Encrypted message: {Convert.ToBase64String(ciphertext)}");

        // Decrypt and encode the message.
        using RSA decryptor = (RSA)pfx.PrivateKey;
        plaintext           = decryptor.Decrypt(ciphertext, RSAEncryptionPadding.OaepSHA256);

        message = Encoding.UTF8.GetString(plaintext);
        console.Out.WriteLine($"Decrypted message: {message}");

        return(0);
    }
        /// <summary>
        /// Downloads the certificate from the key vault store.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="flags"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        async Task <X509Certificate2> LoadCertifcateAsync(string name, X509KeyStorageFlags flags, CancellationToken cancellationToken)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException(nameof(name));
            }

            // download certificate from key vault
            logger.LogInformation("Loading certificate {CertificateName}.", name);
            var crt = await certificateClient.GetCertificateAsync(name, cancellationToken);

            if (crt.Value == null)
            {
                throw new InvalidOperationException($"Unable to load Key Vault certificate '{name}'.");
            }

            var sid = new KeyVaultSecretIdentifier(crt.Value.SecretId);

            if (sid.VaultUri != certificateClient.VaultUri)
            {
                throw new Exception("Certificate secret not from the same vault as the certificate.");
            }

            logger.LogInformation("Loading secret {SecretId}.", sid);
            var key = await secretClient.GetSecretAsync(sid.Name, cancellationToken : cancellationToken);

            if (key.Value == null)
            {
                throw new InvalidOperationException($"Unable to load Key Vault secret from '{sid}'.");
            }

            // load private key
            var pfx = new X509Certificate2(
                Convert.FromBase64String(key.Value.Value),
                (string)null,
                flags);

            // log certificate information
            if (logger.IsEnabled(LogLevel.Information))
            {
                logger.LogInformation("Loaded certificate from {Id}: {@Certificate}.", crt.Value.Id, new
                {
                    pfx.FriendlyName,
                    pfx.Issuer,
                    pfx.SerialNumber,
                    pfx.Subject,
                    pfx.Thumbprint
                });
            }

            // return first certificate in collection
            return(pfx);
        }
Ejemplo n.º 9
0
 public async Task <X509Certificate2> GetCertificateAsync()
 {
     if (certificate == null)
     {
         var cert = (await client.GetCertificateAsync(CertificateInfo.CertificateName).ConfigureAwait(false)).Value;
         certificate   = new X509Certificate2(cert.Cer);
         keyIdentifier = cert.KeyId;
     }
     return(certificate);
 }
        public async Task HelloWorldAsync()
        {
            // Environment variable with the Key Vault endpoint.
            string keyVaultUrl = TestEnvironment.KeyVaultUrl;

            // Instantiate a certificate client that will be used to call the service. Notice that the client is using
            // default Azure credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID',
            // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials.
            CertificateClient client = new CertificateClient(new Uri(keyVaultUrl), new DefaultAzureCredential());

            // Let's create a self-signed certificate using the default policy. If the certificate
            // already exists in the Key Vault, then a new version of the key is created.
            string certName = $"defaultCert-{Guid.NewGuid()}";

            CertificateOperation certOp = await client.StartCreateCertificateAsync(certName, CertificatePolicy.Default);

            // Next, let's wait on the certificate operation to complete. Note that certificate creation can last an indeterministic
            // amount of time, so applications should only wait on the operation to complete in the case the issuance time is well
            // known and within the scope of the application lifetime. In this case we are creating a self-signed certificate which
            // should be issued in a relatively short amount of time.
            Response <KeyVaultCertificateWithPolicy> certificateResponse = await certOp.WaitForCompletionAsync();

            KeyVaultCertificateWithPolicy certificate = certificateResponse.Value;

            // At some time later we could get the created certificate along with its policy from the Key Vault.
            certificate = await client.GetCertificateAsync(certName);

            Debug.WriteLine($"Certificate was returned with name {certificate.Name} which expires {certificate.Properties.ExpiresOn}");

            // We find that the certificate has been compromised and we want to disable it so applications will no longer be able
            // to access the compromised version of the certificate.
            CertificateProperties certificateProperties = certificate.Properties;

            certificateProperties.Enabled = false;

            Response <KeyVaultCertificate> updatedCertResponse = await client.UpdateCertificatePropertiesAsync(certificateProperties);

            Debug.WriteLine($"Certificate enabled set to '{updatedCertResponse.Value.Properties.Enabled}'");

            // We need to create a new version of the certificate that applications can use to replace the compromised certificate.
            // Creating a certificate with the same name and policy as the compromised certificate will create another version of the
            // certificate with similar properties to the original certificate
            CertificateOperation newCertOp = await client.StartCreateCertificateAsync(certificate.Name, certificate.Policy);

            KeyVaultCertificateWithPolicy newCert = await newCertOp.WaitForCompletionAsync();

            // The certificate is no longer needed, need to delete it from the Key Vault.
            DeleteCertificateOperation operation = await client.StartDeleteCertificateAsync(certName);

            // You only need to wait for completion if you want to purge or recover the certificate.
            await operation.WaitForCompletionAsync();

            // If the keyvault is soft-delete enabled, then for permanent deletion, the deleted key needs to be purged.
            await client.PurgeDeletedCertificateAsync(certName);
        }
Ejemplo n.º 11
0
        public async Task DownloadCertificateAsync()
        {
            // Environment variable with the Key Vault endpoint.
            string keyVaultUrl = TestEnvironment.KeyVaultUrl;

            CertificateClient client = new CertificateClient(new Uri(keyVaultUrl), new DefaultAzureCredential());

            string certificateName         = $"rsa-{Guid.NewGuid()}";
            CertificateOperation operation = await client.StartCreateCertificateAsync(certificateName, CertificatePolicy.Default);

            await operation.WaitForCompletionAsync();

            using SHA256 sha = SHA256.Create();
            byte[] data = Encoding.UTF8.GetBytes("test");
            byte[] hash = sha.ComputeHash(data);

            #region Snippet:CertificatesSample4DownloadCertificateAsync
            X509KeyStorageFlags keyStorageFlags = X509KeyStorageFlags.MachineKeySet;
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                keyStorageFlags |= X509KeyStorageFlags.EphemeralKeySet;
            }

            DownloadCertificateOptions options = new DownloadCertificateOptions
            {
                KeyStorageFlags = keyStorageFlags
            };

            using X509Certificate2 certificate = await client.DownloadCertificateAsync(certificateName, options : options);

            using RSA key = certificate.GetRSAPrivateKey();

            byte[] signature = key.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            Debug.WriteLine($"Signature: {Convert.ToBase64String(signature)}");
            #endregion

            Response <KeyVaultCertificateWithPolicy> certificateResponse = await client.GetCertificateAsync(certificateName);

            using X509Certificate2 publicCertificate = new X509Certificate2(certificateResponse.Value.Cer);
            using RSA publicKey = publicCertificate.GetRSAPublicKey();

            bool verified = publicKey.VerifyHash(hash, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            Debug.WriteLine($"Signature verified: {verified}");

            Assert.IsTrue(verified);

            DeleteCertificateOperation deleteOperation = await client.StartDeleteCertificateAsync(certificateName);

            await deleteOperation.WaitForCompletionAsync();

            client.PurgeDeletedCertificate(certificateName);
        }
Ejemplo n.º 12
0
        public async Task <ICertificate> GetCertificateAsync(CancellationToken cancellationToken)
        {
            try
            {
                var cert = await _certificateClient.GetCertificateAsync(_certificateName, cancellationToken);

                return(new CertificateInfo(cert.Value, this));
            }
            catch (RequestFailedException ex) when(ex.Status == 404)
            {
                return(null);
            }
        }
Ejemplo n.º 13
0
        public async Task <IReadOnlyList <CertificateItem> > GetExpiringCertificates([ActivityTrigger] DateTime currentDateTime)
        {
            var certificates = _certificateClient.GetPropertiesOfCertificatesAsync();

            var result = new List <CertificateItem>();

            await foreach (var certificate in certificates)
            {
                if (!certificate.TagsFilter(IssuerName, _options.Endpoint))
                {
                    continue;
                }

                if ((certificate.ExpiresOn.Value - currentDateTime).TotalDays > 30)
                {
                    continue;
                }

                result.Add((await _certificateClient.GetCertificateAsync(certificate.Name)).Value.ToCertificateItem());
            }

            return(result);
        }
    public async virtual Task <string> GenerateHttpsCertificateAsync(
        AcmeOptions options,
        CancellationToken cancellationToken)
    {
        const string certName = "acme-https-cert";
        var          certs    = new CertificateClient(options.KeyVaultUrl, _credential);

        try
        {
            var cert = await certs.GetCertificateAsync(certName, cancellationToken);

            var thumbprint = Convert.ToHexString(cert.Value.Properties.X509Thumbprint);
            if (cert.Value.Properties.ExpiresOn > DateTimeOffset.UtcNow.AddDays(30) && (cert.Value.Properties.Enabled ?? false))
            {
                _logger.LogInformation("Existing valid HTTPS certificate has been found with thumbprint {}", thumbprint);
                return(cert.Value.Name);
            }

            _logger.LogWarning("HTTPS certificate {} is expiring soon, automatically generating a new one", thumbprint);
        }
        catch (RequestFailedException)
        {
            _logger.LogInformation("No existing HTTPS certificate has been found, generating a new one");
        }

        const string accountKeySecretName = "acme-accountkey-pem";
        AcmeContext  acme;

        try
        {
            var secrets    = new SecretClient(options.KeyVaultUrl, _credential);
            var accountKey = await secrets.GetSecretAsync(accountKeySecretName, cancellationToken : cancellationToken);

            acme = new AcmeContext(options.DirectoryUrl, KeyFactory.FromPem(accountKey.Value.Value));
            _logger.LogDebug("Found existing ACME account");
        }
        catch
        {
            _logger.LogInformation("Creating new ACME account at {} with email {}", options.DirectoryUrl, options.AccountEmail);
            acme = new AcmeContext(options.DirectoryUrl);
            await acme.NewAccount(options.AccountEmail, termsOfServiceAgreed : true);
        }

        string orderIdentifier;
        string acmeChallengeRecord;

        if (options.Subdomain is { Length : > 0 })
Ejemplo n.º 15
0
 public async Task <DateTimeOffset?> GetCertificateExpiryAsync(string certificateName)
 {
     try
     {
         return((await certificateClient.GetCertificateAsync(certificateName)).Value.Properties.ExpiresOn);
     }
     catch (RequestFailedException e)
     {
         if (e.Status == 404)
         {
             return(null);
         }
         else
         {
             throw;
         }
     }
 }
        public async Task <ErrorOr <AzureKeyVaultMaterializedConfiguration> > Materialize(AzureKeyVaultSignConfigurationSet configuration)
        {
            TokenCredential credential;

            if (configuration.ManagedIdentity)
            {
                credential = new DefaultAzureCredential();
            }
            else if (!string.IsNullOrWhiteSpace(configuration.AzureAccessToken))
            {
                credential = new AccessTokenCredential(configuration.AzureAccessToken);
            }
            else
            {
                credential = new ClientSecretCredential(configuration.AzureTenantId, configuration.AzureClientId, configuration.AzureClientSecret);
            }


            X509Certificate2 certificate;
            KeyVaultCertificateWithPolicy azureCertificate;

            try
            {
                var certClient = new CertificateClient(configuration.AzureKeyVaultUrl, credential);

                _logger.LogTrace($"Retrieving certificate {configuration.AzureKeyVaultCertificateName}.");
                azureCertificate = (await certClient.GetCertificateAsync(configuration.AzureKeyVaultCertificateName).ConfigureAwait(false)).Value;
                _logger.LogTrace($"Retrieved certificate {configuration.AzureKeyVaultCertificateName}.");

                certificate = new X509Certificate2(azureCertificate.Cer);
            }
            catch (Exception e)
            {
                _logger.LogError($"Failed to retrieve certificate {configuration.AzureKeyVaultCertificateName} from Azure Key Vault. Please verify the name of the certificate and the permissions to the certificate. Error message: {e.Message}.");
                _logger.LogTrace(e.ToString());

                return(e);
            }
            var keyId = azureCertificate.KeyId;

            return(new AzureKeyVaultMaterializedConfiguration(credential, certificate, keyId));
        }
        public async Task <CertInfo?> GetCertInfo(string identifier)
        {
            try
            {
                var cert = await certClient.GetCertificateAsync(identifier);

                var x509 = new X509Certificate2(cert.Value.Cer);

                return(new CertInfo(identifier, x509));
            }
            catch (RequestFailedException e)
            {
                if (e.Status != 404)
                {
                    throw;
                }
            }

            return(null);
        }
Ejemplo n.º 18
0
        public async Task <KeyVaultCertificateWithPolicy> GetCertificateAsync(string name, Uri keyVaultUri)
        {
            var client = new CertificateClient(keyVaultUri, azureCredential);

            try
            {
                var cert = (await client.GetCertificateAsync(name)).Value;

                logger.LogInformation("Found certificate: {certInfo}", new {
                    cert.Properties.Name, cert.Properties.ExpiresOn,
                    Thumbprint = BitConverter.ToString(cert.Properties.X509Thumbprint).Replace("-", "")
                });

                return(cert);
            }
            catch (Azure.RequestFailedException e) when(e.Status == (int)HttpStatusCode.NotFound)
            {
                logger.LogWarning("Certificate {certName} not found!", name);
                return(null);
            }
        }
Ejemplo n.º 19
0
        public async Task <X509Certificate2> GetCertAsync(string name)
        {
            var client = new CertificateClient(_kvUri, _cred);

            return(new X509Certificate2((await client.GetCertificateAsync(name)).Value.Cer));
        }
Ejemplo n.º 20
0
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton <ILocalizationProvider, StorageLocalizationProvider>();
            services.AddTextLocalization(options =>
            {
                options.ReturnOnlyKeyIfNotFound = !_environment.IsDevelopment();
                options.FallBackNeutralCulture  = !_environment.IsDevelopment();
            }).Configure <RequestLocalizationOptions>(options =>
            {
                options.DefaultRequestCulture = new RequestCulture(Settings.SupportedCultures[0]);
                options.AddSupportedCultures(Settings.SupportedCultures);
                options.AddSupportedUICultures(Settings.SupportedCultures);
            });

            services.AddScoped <LazyAssemblyLoader>();

            var dataProtectionBuilder = services.AddDataProtection().SetApplicationName(projectName);

            services.RegisterStorage(Configuration);

            services.Configure <ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });

            services.AddIdentity <ApplicationUser, ApplicationRole>()
            .AddRoles <ApplicationRole>()
            .AddEntityFrameworkStores <ApplicationDbContext>()
            .AddDefaultTokenProviders()
            .AddErrorDescriber <LocalizedIdentityErrorDescriber>();

            services.AddScoped <IUserClaimsPrincipalFactory <ApplicationUser>,
                                AdditionalUserClaimsPrincipalFactory>();

            var authAuthority = Configuration[$"{projectName}:IS4ApplicationUrl"].TrimEnd('/');

            // Adds IdentityServer https://identityserver4.readthedocs.io/en/latest/reference/options.html
            var identityServerBuilder = services.AddIdentityServer(options =>
            {
                options.IssuerUri = authAuthority;
                options.Events.RaiseErrorEvents       = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents     = true;
                options.Events.RaiseSuccessEvents     = true;
                options.UserInteraction.ErrorUrl      = "/identityserver/error";
            })
                                        .AddIdentityServerStores(Configuration)
                                        .AddAspNetIdentity <ApplicationUser>(); //https://identityserver4.readthedocs.io/en/latest/reference/aspnet_identity.html

            X509Certificate2 cert = null;

            var keysLocalFolder = Path.Combine(_environment.ContentRootPath, "Keys");

            if (_environment.IsDevelopment())
            {
                // The AddDeveloperSigningCredential extension creates temporary key material tempkey.jwk for signing tokens.
                // This might be useful to get started, but needs to be replaced by some persistent key material for production scenarios.
                // See http://docs.identityserver.io/en/release/topics/crypto.html#refcrypto for more information.
                // https://stackoverflow.com/questions/42351274/identityserver4-hosting-in-iis

                identityServerBuilder.AddDeveloperSigningCredential();

                dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysLocalFolder));
            }
            else
            {
                // Running on Azure Web App service - read the setup doc at blazor-boilerplate.readthedocs.io

                // appsettings.json parameters used:
                //  "RunsOnAzure": true,
                //  "RunningAsAppService": true,
                //  "RunningAsDocker": false, // not implemented yet
                //  "AzureKeyVault": {
                //      "UsingKeyVault": true,
                //      "UseManagedAppIdentity": true,
                //      "AppKey": "", // not implemented yet.
                //      "AppSecret": "",
                //      "KeyVaultURI": "https://YOURVAULTNAMEHERE.vault.azure.net/",
                //      "CertificateIdentifier": "https://YOURVAULTNAMEHERE.vault.azure.net/certificates/BBAUTH/<HEX_VERSION_STRING_HERE>",
                //      "CertificateName": "BBAUTH",
                //      "StorageAccountBlobBaseUrl": "https://<YOUR_STORAGE_ACCOUNT_NAME_HERE>.blob.core.windows.net",
                //      "ContainerName": "blazor-boilerplate-keys",
                //      "KeysBlobName": "keys.xml"
                if (Convert.ToBoolean(Configuration["HostingOnAzure:RunsOnAzure"]) == true)
                {
                    if (Convert.ToBoolean(Configuration["HostingOnAzure:AzureKeyVault:UsingKeyVault"]) == true)
                    {
                        if (Convert.ToBoolean(Configuration["HostingOnAzure:AzurekeyVault:UseManagedAppIdentity"]) == true)
                        {
                            //https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview

                            // In production environment we have already configured Managed Identity (blazor-boilerplate) using Azure Portal for our app to access Key Vault and Blob Storage.

                            // Set up TokenCredential options for production and development environments
                            bool isDeployed        = !_environment.IsDevelopment();
                            var  credentialOptions = new DefaultAzureCredentialOptions
                            {
                                ExcludeEnvironmentCredential        = isDeployed,
                                ExcludeManagedIdentityCredential    = false, // we only use this one in production
                                ExcludeSharedTokenCacheCredential   = isDeployed,
                                ExcludeVisualStudioCredential       = isDeployed,
                                ExcludeVisualStudioCodeCredential   = isDeployed,
                                ExcludeAzureCliCredential           = isDeployed,
                                ExcludeInteractiveBrowserCredential = isDeployed,
                            };

                            // In development environment DefaultAzureCredential() will use the shared token credential from the IDE. In Visual Studio this is under Options - Azure Service Authentication.
                            if (_environment.IsDevelopment())
                            {
                                // credentialOptions.SharedTokenCacheUsername = "******"; // specify user name to use if more than one Azure username is configured in IDE.
                                // var defaultTenantId = "?????-????-????-????-????????"; // specify AAD tenant to authenticate against (from Azure Portal - AAD - Tenant ID)
                                // credentialOptions.SharedTokenCacheTenantId = defaultTenantId;
                                // credentialOptions.VisualStudioCodeTenantId = defaultTenantId;
                                // credentialOptions.VisualStudioTenantId = defaultTenantId;
                            }

                            TokenCredential tokenCredential = new DefaultAzureCredential(credentialOptions);

                            // The Azure Storage Container (blazor-boilerplate-keys) Access Control must grant blazor-boilerplate the following roles:
                            // - Storage Blob Data Contributor

                            var blobServiceClient = new BlobServiceClient(
                                new Uri(Configuration["HostingOnAzure:AzureKeyVault:StorageAccountBlobBaseUrl"]),
                                tokenCredential);

                            BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(Configuration["HostingOnAzure:AzureKeyVault:ContainerName"]);
                            BlobClient          blobClient          = blobContainerClient.GetBlobClient(Configuration["HostingOnAzure:AzureKeyVault:KeysBlobName"]);

                            var certificateIdentifier = Configuration["HostingOnAzure:AzureKeyVault:CertificateIdentifier"];

                            dataProtectionBuilder.PersistKeysToAzureBlobStorage(blobClient);
                            // 1. Remove the call to ProtectKeysWithAzureKeyVault below for the first run to create the keys.xml blob in place.
                            // 2. Add the call to ProtectKeysWithAzureKeyVault for subsequent runs.so that keys.xml gets created - see the setup doc for more information
                            dataProtectionBuilder.ProtectKeysWithAzureKeyVault(new Uri(certificateIdentifier), tokenCredential);

                            // Azure Key Vault Access Policy must grant the following permissions to the blazor-boilerplate app:
                            // - Secret Permissions: Get
                            // - Certificate Permissions: Get

                            // Retrieve the certificate and extract the secret so that we can build the new X509 certificate for later use by Identity Server
                            var certificateClient = new CertificateClient(vaultUri: new Uri(Configuration["HostingOnAzure:AzureKeyVault:KeyVaultUri"]), credential: new DefaultAzureCredential());
                            var secretClient      = new SecretClient(vaultUri: new Uri(Configuration["HostingOnAzure:AzureKeyVault:KeyVaultUri"]), credential: new DefaultAzureCredential());
                            KeyVaultCertificateWithPolicy certificateWithPolicy = certificateClient.GetCertificateAsync(Configuration["HostingOnAzure:AzureKeyVault:CertificateName"]).GetAwaiter().GetResult(); // retrieves latest version of certificate
                            KeyVaultSecretIdentifier      secretIdentifier      = new KeyVaultSecretIdentifier(certificateWithPolicy.SecretId);
                            KeyVaultSecret secret          = secretClient.GetSecretAsync(secretIdentifier.Name, secretIdentifier.Version).GetAwaiter().GetResult();
                            byte[]         privateKeyBytes = Convert.FromBase64String(secret.Value);

                            cert = new X509Certificate2(privateKeyBytes, (string)null, X509KeyStorageFlags.MachineKeySet);
                        }
                    }
                    else // if app id and app secret are used
                    {
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysLocalFolder));
                }

                //TODO this implementation does not consider certificate expiration
                if (Convert.ToBoolean(Configuration[$"{projectName}:UseLocalCertStore"]) == true)
                {
                    var certificateThumbprint = Configuration[$"{projectName}:CertificateThumbprint"];

                    var storeLocation = StoreLocation.LocalMachine;

                    dynamic storeName = "WebHosting";

                    if (OperatingSystem.IsLinux())
                    {
                        storeLocation = StoreLocation.CurrentUser;
                        storeName     = StoreName.My;
                    }

                    using X509Store store = new(storeName, storeLocation);
                    store.Open(OpenFlags.ReadOnly);
                    var certs = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
                    if (certs.Count > 0)
                    {
                        cert = certs[0];
                    }
                    else
                    {
                        var certPath = Path.Combine(_environment.ContentRootPath, "AuthSample.pfx");

                        if (File.Exists(certPath))
                        {
                            string certificatePassword = Configuration[$"{projectName}:CertificatePassword"] ?? "Admin123";
                            cert = new X509Certificate2(certPath, certificatePassword,
                                                        X509KeyStorageFlags.MachineKeySet |
                                                        X509KeyStorageFlags.PersistKeySet |
                                                        X509KeyStorageFlags.Exportable);
                        }
                    }

                    store.Close();
                }

                // pass the resulting certificate to Identity Server
                if (cert != null)
                {
                    identityServerBuilder.AddSigningCredential(cert);
                    Log.Logger.Information($"Added certificate {cert.Subject} to Identity Server");
                }
                else if (OperatingSystem.IsWindows())
                {
                    Log.Logger.Debug("Trying to use WebHosting Certificate for Identity Server");
                    identityServerBuilder.AddWebHostingCertificate();
                }
                else
                {
                    throw new Exception("Missing Certificate for Identity Server");
                }
            }

            var authBuilder = services.AddAuthentication(options =>
            {
                options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
            })
                              .AddIdentityServerAuthentication(options =>
            {
                options.Authority            = authAuthority;
                options.SupportedTokens      = SupportedTokens.Jwt;
                options.RequireHttpsMetadata = _environment.IsProduction();
                options.ApiName = IdentityServerConfig.LocalApiName;
                options.Events  = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];

                        // If the request is for our hub...
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                            (path.StartsWithSegments("/chathub")))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return(Task.CompletedTask);
                    }
                };
            });

            #region ExternalAuthProviders
            //https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/samples/SocialSample/Startup.cs
            //https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins
            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Google:Enabled"] ?? "false"))
            {
                authBuilder.AddGoogle(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ClientId     = Configuration["ExternalAuthProviders:Google:ClientId"];
                    options.ClientSecret = Configuration["ExternalAuthProviders:Google:ClientSecret"];

                    options.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response
                    options.AccessType             = "offline";
                    options.SaveTokens             = true;
                    options.Events = new OAuthEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                    options.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url");
                    options.ClaimActions.Remove(ClaimTypes.GivenName);
                });
            }

            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Facebook:Enabled"] ?? "false"))
            {
                // You must first create an app with Facebook and add its ID and Secret to your user-secrets.
                // https://developers.facebook.com/apps/
                // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login
                authBuilder.AddFacebook(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.AppId     = Configuration["ExternalAuthProviders:Facebook:AppId"];
                    options.AppSecret = Configuration["ExternalAuthProviders:Facebook:AppSecret"];

                    options.Scope.Add("email");
                    options.Fields.Add("name");
                    options.Fields.Add("email");
                    options.SaveTokens = true;
                    options.Events     = new OAuthEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                });
            }

            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Twitter:Enabled"] ?? "false"))
            {
                // You must first create an app with Twitter and add its key and Secret to your user-secrets.
                // https://apps.twitter.com/
                // https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token
                authBuilder.AddTwitter(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ConsumerKey    = Configuration["ExternalAuthProviders:Twitter:ConsumerKey"];
                    options.ConsumerSecret = Configuration["ExternalAuthProviders:Twitter:ConsumerSecret"];

                    // http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370
                    // http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1
                    options.RetrieveUserDetails = true;
                    options.SaveTokens          = true;
                    options.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
                    options.Events = new TwitterEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                });
            }

            //https://github.com/xamarin/Essentials/blob/master/Samples/Sample.Server.WebAuthenticator/Startup.cs
            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Apple:Enabled"] ?? "false"))
            {
                authBuilder.AddApple(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ClientId = Configuration["ExternalAuthProviders:Apple:ClientId"];
                    options.KeyId    = Configuration["ExternalAuthProviders:Apple:KeyId"];
                    options.TeamId   = Configuration["ExternalAuthProviders:Apple:TeamId"];

                    options.UsePrivateKey(keyId
                                          => _environment.ContentRootFileProvider.GetFileInfo($"AuthKey_{keyId}.p8"));
                    options.SaveTokens = true;
                });
            }

            // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
            // https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Microsoft:Enabled"] ?? "false"))
            {
                authBuilder.AddMicrosoftAccount(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ClientId     = Configuration["ExternalAuthProviders:Microsoft:ClientId"];
                    options.ClientSecret = Configuration["ExternalAuthProviders:Microsoft:ClientSecret"];

                    options.SaveTokens = true;
                    options.Scope.Add("offline_access");
                    options.Events = new OAuthEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                });
            }
            #endregion

            #region Authorization
            //Add Policies / Claims / Authorization - https://identityserver4.readthedocs.io/en/latest/topics/add_apis.html#advanced
            services.AddScoped <EntityPermissions>();
            services.AddSingleton <IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
            services.AddTransient <IAuthorizationHandler, DomainRequirementHandler>();
            services.AddTransient <IAuthorizationHandler, PermissionRequirementHandler>();
            #endregion

            services.Configure <IdentityOptions>(options =>
            {
                // Password settings
                options.Password.RequireDigit           = RequireDigit;
                options.Password.RequiredLength         = RequiredLength;
                options.Password.RequireNonAlphanumeric = RequireNonAlphanumeric;
                options.Password.RequireUppercase       = RequireUppercase;
                options.Password.RequireLowercase       = RequireLowercase;
                //options.Password.RequiredUniqueChars = 6;

                // Lockout settings
                options.Lockout.DefaultLockoutTimeSpan  = TimeSpan.FromMinutes(30);
                options.Lockout.MaxFailedAccessAttempts = 10;
                options.Lockout.AllowedForNewUsers      = true;

                // Require Confirmed Email User settings
                if (Convert.ToBoolean(Configuration[$"{projectName}:RequireConfirmedEmail"] ?? "false"))
                {
                    options.User.RequireUniqueEmail      = true;
                    options.SignIn.RequireConfirmedEmail = true;
                }
            });

            #region Cookies
            // cookie policy to deal with temporary browser incompatibilities
            services.AddSameSiteCookiePolicy();

            //https://docs.microsoft.com/en-us/aspnet/core/security/gdpr
            services.Configure <CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential
                // cookies is needed for a given request.
                options.CheckConsentNeeded = context => false; //consent not required
                // requires using Microsoft.AspNetCore.Http;
                //options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //services.ConfigureExternalCookie(options =>
            // {
            // macOS login fix
            //options.Cookie.SameSite = SameSiteMode.None;
            //});

            services.ConfigureApplicationCookie(options =>
            {
                options.Cookie.IsEssential  = true;
                options.Cookie.HttpOnly     = true;
                options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                options.ExpireTimeSpan      = TimeSpan.FromDays(Convert.ToDouble(Configuration[$"{projectName}:CookieExpireTimeSpanDays"] ?? "30"));
                options.LoginPath           = Constants.Settings.LoginPath;
                //options.AccessDeniedPath = "/Identity/Account/AccessDenied";
                // ReturnUrlParameter requires
                //using Microsoft.AspNetCore.Authentication.Cookies;
                options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
                options.SlidingExpiration  = true;

                // Suppress redirect on API URLs in ASP.NET Core -> https://stackoverflow.com/a/56384729/54159
                options.Events = new CookieAuthenticationEvents()
                {
                    OnRedirectToAccessDenied = context =>
                    {
                        if (context.Request.Path.StartsWithSegments("/api"))
                        {
                            context.Response.StatusCode = Status403Forbidden;
                        }

                        return(Task.CompletedTask);
                    },
                    OnRedirectToLogin = context =>
                    {
                        context.Response.StatusCode = Status401Unauthorized;
                        return(Task.CompletedTask);
                    }
                };
            });
            #endregion

            services.AddMvc().AddNewtonsoftJson(opt =>
            {
                // Set Breeze defaults for entity serialization
                var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings);
                if (ss.ContractResolver is DefaultContractResolver resolver)
                {
                    resolver.NamingStrategy = null;  // remove json camelCasing; names are converted on the client.
                }
                if (_environment.IsDevelopment())
                {
                    ss.Formatting = Newtonsoft.Json.Formatting.Indented; // format JSON for debugging
                }
            })                                                           // Add Breeze exception filter to send errors back to the client
            .AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); })
            .AddViewLocalization().AddDataAnnotationsLocalization(options =>
            {
                options.DataAnnotationLocalizerProvider = (type, factory) =>
                {
                    return(factory.Create(typeof(Global)));
                };
            }).AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining <LocalizationRecordValidator>());

            services.AddServerSideBlazor().AddCircuitOptions(o =>
            {
                if (_environment.IsDevelopment())
                {
                    o.DetailedErrors = true;
                }
            }).AddHubOptions(o =>
            {
                o.MaximumReceiveMessageSize = 131072;
            });

            services.AddSignalR();

            if (_enableAPIDoc)
            {
                services.AddOpenApiDocument(document =>
                {
                    document.Title   = "BlazorBoilerplate API";
                    document.Version = typeof(Startup).GetTypeInfo().Assembly.GetName().Version.ToString();
                    document.AddSecurity("bearer", Enumerable.Empty <string>(), new OpenApiSecurityScheme
                    {
                        Type             = OpenApiSecuritySchemeType.OAuth2,
                        Description      = "Local Identity Server",
                        OpenIdConnectUrl = $"{authAuthority}/.well-known/openid-configuration", //not working
                        Flow             = OpenApiOAuth2Flow.AccessCode,
                        Flows            = new OpenApiOAuthFlows()
                        {
                            AuthorizationCode = new OpenApiOAuthFlow()
                            {
                                Scopes = new Dictionary <string, string>
                                {
                                    { LocalApi.ScopeName, IdentityServerConfig.LocalApiName }
                                },
                                AuthorizationUrl = $"{authAuthority}/connect/authorize",
                                TokenUrl         = $"{authAuthority}/connect/token"
                            },
                        }
                    });;

                    document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
                    //      new OperationSecurityScopeProcessor("bearer"));
                });
            }

            services.AddScoped <IUserSession, UserSession>();

            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();

            services.Add(ServiceDescriptor.Scoped(typeof(ITenantSettings <>), typeof(TenantSettingsManager <>)));

            services.AddTransient <IEmailFactory, EmailFactory>();

            services.AddTransient <IAccountManager, AccountManager>();
            services.AddTransient <IAdminManager, AdminManager>();
            services.AddTransient <IEmailManager, EmailManager>();
            services.AddTransient <IExternalAuthManager, ExternalAuthManager>();

            #region Automapper
            //Automapper to map DTO to Models https://www.c-sharpcorner.com/UploadFile/1492b1/crud-operations-using-automapper-in-mvc-application/
            var automapperConfig = new MapperConfiguration(configuration =>
            {
                configuration.AddProfile(new MappingProfile());
            });

            var autoMapper = automapperConfig.CreateMapper();

            services.AddSingleton(autoMapper);
            #endregion

            /* ServerSideBlazor */
            services.AddScoped <IAccountApiClient, AccountApiClient>();
            services.AddScoped <AppState>();

            // setup HttpClient for server side in a client side compatible fashion ( with auth cookie )
            // if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
            // {
            services.AddScoped(s =>
            {
                // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
                var navigationManager   = s.GetRequiredService <NavigationManager>();
                var httpContextAccessor = s.GetRequiredService <IHttpContextAccessor>();
                var cookies             = httpContextAccessor.HttpContext.Request.Cookies;
                var httpClientHandler   = new HttpClientHandler()
                {
                    UseCookies = false
                };
                if (_environment.IsDevelopment())
                {
                    // Return 'true' to allow certificates that are untrusted/invalid
                    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return(true); };
                }
                var client = new HttpClient(httpClientHandler);
                if (cookies.Any())
                {
                    var cks = new List <string>();

                    foreach (var cookie in cookies)
                    {
                        cks.Add($"{cookie.Key}={cookie.Value}");
                    }

                    client.DefaultRequestHeaders.Add("Cookie", string.Join(';', cks));
                }

                client.BaseAddress = new Uri(navigationManager.BaseUri);

                return(client);
            });
            // }

            services.AddScoped <ILocalizationApiClient, LocalizationApiClient>();
            services.AddScoped <IApiClient, ApiClient>();

            // Authentication providers
            Log.Logger.Debug("Removing AuthenticationStateProvider...");
            var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(AuthenticationStateProvider));
            if (serviceDescriptor != null)
            {
                services.Remove(serviceDescriptor);
            }

            Log.Logger.Debug("Adding AuthenticationStateProvider...");
            services.AddScoped <AuthenticationStateProvider, IdentityAuthenticationStateProvider>();
            /**********************/

            services.AddModules();

            if (Log.Logger.IsEnabled(Serilog.Events.LogEventLevel.Debug))
            {
                Log.Logger.Debug($"Total Services Registered: {services.Count}");
                foreach (var service in services)
                {
                    Log.Logger.Debug($"\n\tService: {service.ServiceType.FullName}\n\tLifetime: {service.Lifetime}\n\tInstance: {service.ImplementationType?.FullName}");
                }
            }
        }
        public async Task <byte[]> GetCertificateBytesAsync(string certName)
        {
            KeyVaultCertificateWithPolicy certificateWithPolicy = await _certClient.GetCertificateAsync(certName);

            return(certificateWithPolicy.Cer);
        }
Ejemplo n.º 22
0
        public async Task <ActionResult> Secrets()
        {
            // Via App Service reference
            // See https://docs.microsoft.com/bs-cyrl-ba/azure/app-service/app-service-key-vault-references
            // For example:
            //     @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)
            //     or
            //     @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/)
            //     if you only care about the latest version of that secret
            ViewBag.ViaRef = ConfigurationManager.AppSettings["secret1"];

            // Via Key Vault SDK
            string keyVaultInstance = "https://alice.vault.azure.net";
            // Retry policy
            // https://docs.microsoft.com/en-us/azure/key-vault/general/overview-throttling
            SecretClientOptions options = new SecretClientOptions()
            {
                Retry =
                {
                    Delay      = TimeSpan.FromSeconds(2),
                    MaxDelay   = TimeSpan.FromSeconds(16),
                    MaxRetries =                        5,
                    Mode       = RetryMode.Exponential
                }
            };
            // Instantiate client with retry policy (options)
            SecretClient   secretClient = new SecretClient(new Uri(keyVaultInstance), new DefaultAzureCredential(), options);
            KeyVaultSecret secret       = await secretClient.GetSecretAsync("secret1");

            ViewBag.ViaSDK = secret.Value;

            // Via configBuilder (see web.config)
            ViewBag.ViaBuilder = ConfigurationManager.AppSettings["secret1"];

            // Manual REST API calls
            AzureServiceTokenProvider tokenProvider = new AzureServiceTokenProvider();
            // Resource URI for Key Vault is always https://vault.azure.net,
            // irrespective of the name of your Key Vault
            string accessToken = await tokenProvider.GetAccessTokenAsync("https://vault.azure.net");

            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
            // Response is a JSON object, the secret value is returned as response["value"] and looks like this -
            //  {
            //      "value": "TH3 VALU3 0F THE S3CRE7",
            //      "contentType": "this_property_is/completely_arbitrary",
            //      "id": "https://<YOUR-VAULT-NAME>.vault.azure.net/secrets/<NAME-OF-YOUR-SECRET>/d96492d7b6d744a085a37c812badb3e4",
            //      "attributes": {
            //          "enabled": true,
            //          "created": 1526314127,
            //          "updated": 1526314127,
            //          "recoveryLevel": "Purgeable"
            //      }
            //  }
            string secretOverRest = await httpClient.GetStringAsync("https://alice.vault.azure.net/secrets/secret1?api-version=7.0");

            ViewBag.ViaRest = secretOverRest;


            // Get certificate from Key Vault
            CertificateClient   certClient = new CertificateClient(new Uri(keyVaultInstance), new DefaultAzureCredential());
            KeyVaultCertificate cert       = await certClient.GetCertificateAsync("Joes-Crab-Shack-RSA");

            X509Certificate2 x509cert = new X509Certificate2(cert.Cer);

            ViewBag.CertSubject = x509cert.Subject;
            ViewBag.CertId      = cert.Id;
            ViewBag.CertName    = cert.Name;

            return(View());
        }
Ejemplo n.º 23
0
        private async Task MigrationGuide()
        {
            #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_Create
            CertificateClient client = new CertificateClient(
                new Uri("https://myvault.vault.azure.net"),
                new DefaultAzureCredential());
            #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_Create

            #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions
            using (HttpClient httpClient = new HttpClient())
            {
                CertificateClientOptions options = new CertificateClientOptions
                {
                    Transport = new HttpClientTransport(httpClient)
                };

                //@@CertificateClient client = new CertificateClient(
                /*@@*/ CertificateClient _ = new CertificateClient(
                    new Uri("https://myvault.vault.azure.net"),
                    new DefaultAzureCredential(),
                    options);
            }
            #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions

            #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCustomPolicy
            CertificatePolicy policy = new CertificatePolicy("issuer-name", "CN=customdomain.com")
            {
                ContentType = CertificateContentType.Pkcs12,
                KeyType     = CertificateKeyType.Rsa,
                ReuseKey    = true,
                KeyUsage    =
                {
                    CertificateKeyUsage.CrlSign,
                    CertificateKeyUsage.DataEncipherment,
                    CertificateKeyUsage.DigitalSignature,
                    CertificateKeyUsage.KeyEncipherment,
                    CertificateKeyUsage.KeyAgreement,
                    CertificateKeyUsage.KeyCertSign
                },
                ValidityInMonths = 12,
                LifetimeActions  =
                {
                    new LifetimeAction(CertificatePolicyAction.AutoRenew)
                    {
                        DaysBeforeExpiry = 90,
                    }
                }
            };
            #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy

            #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy
            //@@CertificatePolicy policy = CertificatePolicy.Default;
            /*@@*/ policy = CertificatePolicy.Default;
            #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy

            {
                #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate
                // Start certificate creation.
                // Depending on the policy and your business process, this could even take days for manual signing.
                CertificateOperation createOperation = await client.StartCreateCertificateAsync("certificate-name", policy);

                KeyVaultCertificateWithPolicy certificate = await createOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(20), CancellationToken.None);

                // If you need to restart the application you can recreate the operation and continue awaiting.
                createOperation = new CertificateOperation(client, "certificate-name");
                certificate     = await createOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(20), CancellationToken.None);

                #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate
            }

            {
                #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate
                byte[] cer = File.ReadAllBytes("certificate.pfx");
                ImportCertificateOptions importCertificateOptions = new ImportCertificateOptions("certificate-name", cer)
                {
                    Policy = policy
                };

                KeyVaultCertificateWithPolicy certificate = await client.ImportCertificateAsync(importCertificateOptions);

                #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate
            }

            {
                #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates
                // List all certificates asynchronously.
                await foreach (CertificateProperties item in client.GetPropertiesOfCertificatesAsync())
                {
                    KeyVaultCertificateWithPolicy certificate = await client.GetCertificateAsync(item.Name);
                }

                // List all certificates synchronously.
                foreach (CertificateProperties item in client.GetPropertiesOfCertificates())
                {
                    KeyVaultCertificateWithPolicy certificate = client.GetCertificate(item.Name);
                }
                #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates
            }

            {
                #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate
                // Delete the certificate.
                DeleteCertificateOperation deleteOperation = await client.StartDeleteCertificateAsync("certificate-name");

                // Purge or recover the deleted certificate if soft delete is enabled.
                if (deleteOperation.Value.RecoveryId != null)
                {
                    // Deleting a certificate does not happen immediately. Wait for the certificate to be deleted.
                    DeletedCertificate deletedCertificate = await deleteOperation.WaitForCompletionAsync();

                    // Purge the deleted certificate.
                    await client.PurgeDeletedCertificateAsync(deletedCertificate.Name);

                    // You can also recover the deleted certificate using StartRecoverDeletedCertificateAsync,
                    // which returns RecoverDeletedCertificateOperation you can await like DeleteCertificateOperation above.
                }
                #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate
            }
        }