From 4a05d5087852cb5a607d88fff7869265a6c00ee5 Mon Sep 17 00:00:00 2001 From: "olek.huang" Date: Sun, 15 May 2022 10:43:16 +0800 Subject: [PATCH] Create RSA Certificate For Signing Credential --- .../IdentityServerBuilderExtensions.cs | 77 ++++++++++++++++++- .../Helpers/StartupHelpers.cs | 24 +++--- ...koruba.IdentityServer4.STS.Identity.csproj | 1 + .../Startup.cs | 2 +- .../appsettings.json | 9 ++- .../Common/CertificateConfiguration.cs | 6 ++ 6 files changed, 102 insertions(+), 17 deletions(-) diff --git a/src/Skoruba.IdentityServer4.STS.Identity/Helpers/IdentityServerBuilderExtensions.cs b/src/Skoruba.IdentityServer4.STS.Identity/Helpers/IdentityServerBuilderExtensions.cs index 537808cfe..60dccb50c 100644 --- a/src/Skoruba.IdentityServer4.STS.Identity/Helpers/IdentityServerBuilderExtensions.cs +++ b/src/Skoruba.IdentityServer4.STS.Identity/Helpers/IdentityServerBuilderExtensions.cs @@ -1,7 +1,12 @@ using Microsoft.Extensions.DependencyInjection; using System; +using System.Collections.Generic; using System.IO; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using CertificateManager; +using CertificateManager.Models; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Skoruba.IdentityServer4.Shared.Configuration.Configuration.Common; using Skoruba.IdentityServer4.Shared.Configuration.Helpers; @@ -21,9 +26,10 @@ public static class IdentityServerBuilderExtensions /// Add custom signing certificate from certification store according thumbprint or from file /// /// + /// /// /// - public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentityServerBuilder builder, IConfiguration configuration) + public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentityServerBuilder builder, IWebHostEnvironment webHostEnvironment, IConfiguration configuration) { var certificateConfiguration = configuration.GetSection(nameof(CertificateConfiguration)).Get(); var azureKeyVaultConfiguration = configuration.GetSection(nameof(AzureKeyVaultConfiguration)).Get(); @@ -79,12 +85,17 @@ public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentitySe throw new Exception(SigningCertificatePathIsNotSpecified); } - if (File.Exists(certificateConfiguration.SigningCertificatePfxFilePath)) + string certificateFilePath = Path.Combine(webHostEnvironment.ContentRootPath, certificateConfiguration.SigningCertificatePfxFilePath); + if (!File.Exists(certificateFilePath) || certificateConfiguration.NeedToCreateNewOne) + { + CreateRsaCertificate(builder.Services, certificateConfiguration, certificateFilePath); + } + + if (File.Exists(certificateFilePath)) { - try { - builder.AddSigningCredential(new X509Certificate2(certificateConfiguration.SigningCertificatePfxFilePath, certificateConfiguration.SigningCertificatePfxFilePassword)); + builder.AddSigningCredential(new X509Certificate2(certificateFilePath, certificateConfiguration.SigningCertificatePfxFilePassword)); } catch (Exception e) { @@ -108,6 +119,64 @@ public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentitySe return builder; } + /// + /// Create RSA Certificate For Signing Credential - https://damienbod.com/2020/02/10/create-certificates-for-identityserver4-signing-using-net-core/ + /// + /// + /// + /// + private static void CreateRsaCertificate(IServiceCollection services, CertificateConfiguration certificateConfiguration, string certificateFilePath) + { + services.AddCertificateManager(); + var createCertificates = services.BuildServiceProvider().GetRequiredService(); + + var basicConstraints = new BasicConstraints + { + CertificateAuthority = false, + HasPathLengthConstraint = false, + PathLengthConstraint = 0, + Critical = false + }; + + var subjectAlternativeName = new SubjectAlternativeName + { + DnsName = new List + { + certificateConfiguration.DnsName + } + }; + + const X509KeyUsageFlags x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature; + + // only if certification authentication is used + var enhancedKeyUsages = new OidCollection + { + OidLookup.ClientAuthentication, + OidLookup.ServerAuthentication + }; + + var certificate = createCertificates.NewRsaSelfSignedCertificate( + new DistinguishedName { CommonName = certificateConfiguration.DnsName }, + basicConstraints, + new ValidityPeriod + { + ValidFrom = DateTimeOffset.UtcNow, + ValidTo = DateTimeOffset.UtcNow.AddYears(certificateConfiguration.ValidityPeriodInYear) + }, + subjectAlternativeName, + enhancedKeyUsages, + x509KeyUsageFlags, + new RsaConfiguration + { + KeySize = 2048, + HashAlgorithmName = HashAlgorithmName.SHA512 + }); + + var iec = services.BuildServiceProvider().GetRequiredService(); + var rsaCertPfxBytes = iec.ExportSelfSignedCertificatePfx(certificateConfiguration.SigningCertificatePfxFilePassword, certificate); + File.WriteAllBytes(certificateFilePath, rsaCertPfxBytes); + } + /// /// Add custom validation key for signing key rollover /// http://docs.identityserver.io/en/latest/topics/crypto.html#signing-key-rollover diff --git a/src/Skoruba.IdentityServer4.STS.Identity/Helpers/StartupHelpers.cs b/src/Skoruba.IdentityServer4.STS.Identity/Helpers/StartupHelpers.cs index aeb2a9d6e..7e48cb3e6 100644 --- a/src/Skoruba.IdentityServer4.STS.Identity/Helpers/StartupHelpers.cs +++ b/src/Skoruba.IdentityServer4.STS.Identity/Helpers/StartupHelpers.cs @@ -23,6 +23,7 @@ using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; using Skoruba.IdentityServer4.Admin.EntityFramework.Helpers; using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Identity.Web; using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration; @@ -40,6 +41,7 @@ public static class StartupHelpers /// Register services for MVC and localization including available languages /// /// + /// public static IMvcBuilder AddMvcWithLocalization(this IServiceCollection services, IConfiguration configuration) where TUser : IdentityUser where TKey : IEquatable @@ -48,10 +50,10 @@ public static IMvcBuilder AddMvcWithLocalization(this IServiceColle services.TryAddTransient(typeof(IGenericControllerLocalizer<>), typeof(GenericControllerLocalizer<>)); - var mvcBuilder = services.AddControllersWithViews(o => - { - o.Conventions.Add(new GenericControllerRouteConvention()); - }) + var mvcBuilder = services.AddControllersWithViews(o => + { + o.Conventions.Add(new GenericControllerRouteConvention()); + }) .AddViewLocalization( LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = ConfigurationConsts.ResourcesPath; }) @@ -76,7 +78,7 @@ public static IMvcBuilder AddMvcWithLocalization(this IServiceColle // If the default culture is specified use it, otherwise use CultureConfiguration.DefaultRequestCulture ("en") var defaultCultureCode = string.IsNullOrEmpty(cultureConfiguration?.DefaultCulture) ? - CultureConfiguration.DefaultRequestCulture : cultureConfiguration?.DefaultCulture; + CultureConfiguration.DefaultRequestCulture : cultureConfiguration.DefaultCulture; // If the default culture is not among the supported cultures, use the first supported culture as default if (!supportedCultureCodes.Contains(defaultCultureCode)) defaultCultureCode = supportedCultureCodes.FirstOrDefault(); @@ -186,6 +188,7 @@ public static void UseSecurityHeaders(this IApplicationBuilder app, IConfigurati /// /// /// + /// /// /// public static void RegisterDbContexts(this IServiceCollection services, IConfiguration configuration) @@ -224,6 +227,7 @@ public static void RegisterDbContexts /// /// + /// /// public static void RegisterDbContextsStaging( this IServiceCollection services) @@ -345,9 +349,10 @@ private static RegisterConfiguration GetRegistrationConfiguration(IConfiguration /// /// /// + /// /// public static IIdentityServerBuilder AddIdentityServer( - this IServiceCollection services, + this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration configuration) where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext @@ -360,7 +365,7 @@ public static IIdentityServerBuilder AddIdentityServer() .AddAspNetIdentity(); - builder.AddCustomSigningCredential(configuration); + builder.AddCustomSigningCredential(webHostEnvironment, configuration); builder.AddCustomValidationKey(configuration); builder.AddExtensionGrantValidator(); @@ -398,7 +403,7 @@ private static void AddExternalProviders(AuthenticationBuilder authenticationBui options.Instance = externalProviderConfiguration.AzureInstance; options.Domain = externalProviderConfiguration.AzureDomain; options.CallbackPath = externalProviderConfiguration.AzureAdCallbackPath; - }, cookieScheme: null); + }, cookieScheme: null); } } @@ -409,7 +414,8 @@ private static void AddExternalProviders(AuthenticationBuilder authenticationBui public static void UseMvcLocalizationServices(this IApplicationBuilder app) { var options = app.ApplicationServices.GetService>(); - app.UseRequestLocalization(options.Value); + if (options != null) + app.UseRequestLocalization(options.Value); } /// diff --git a/src/Skoruba.IdentityServer4.STS.Identity/Skoruba.IdentityServer4.STS.Identity.csproj b/src/Skoruba.IdentityServer4.STS.Identity/Skoruba.IdentityServer4.STS.Identity.csproj index 6c18c37b9..3e72cd222 100644 --- a/src/Skoruba.IdentityServer4.STS.Identity/Skoruba.IdentityServer4.STS.Identity.csproj +++ b/src/Skoruba.IdentityServer4.STS.Identity/Skoruba.IdentityServer4.STS.Identity.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Skoruba.IdentityServer4.STS.Identity/Startup.cs b/src/Skoruba.IdentityServer4.STS.Identity/Startup.cs index 38fb4ece0..3ba30522a 100644 --- a/src/Skoruba.IdentityServer4.STS.Identity/Startup.cs +++ b/src/Skoruba.IdentityServer4.STS.Identity/Startup.cs @@ -100,7 +100,7 @@ public virtual void RegisterDbContexts(IServiceCollection services) public virtual void RegisterAuthentication(IServiceCollection services) { services.AddAuthenticationServices(Configuration); - services.AddIdentityServer(Configuration); + services.AddIdentityServer(Environment, Configuration); } public virtual void RegisterAuthorization(IServiceCollection services) diff --git a/src/Skoruba.IdentityServer4.STS.Identity/appsettings.json b/src/Skoruba.IdentityServer4.STS.Identity/appsettings.json index d598dc54b..9c5339647 100644 --- a/src/Skoruba.IdentityServer4.STS.Identity/appsettings.json +++ b/src/Skoruba.IdentityServer4.STS.Identity/appsettings.json @@ -18,9 +18,12 @@ "UseSigningCertificateThumbprint": false, "SigningCertificateThumbprint": "", - "UseSigningCertificatePfxFile": false, - "SigningCertificatePfxFilePath": "", - "SigningCertificatePfxFilePassword": "", + "DnsName": "localhost", + "UseSigningCertificatePfxFile": true, + "SigningCertificatePfxFilePath": "certificate.pfx", + "SigningCertificatePfxFilePassword": "JrUZVzv05ZaYkSh%I)u", + "ValidityPeriodInYear": 5, + "NeedToCreateNewOne": false, "UseValidationCertificatePfxFile": false, "ValidationCertificatePfxFilePath": "", diff --git a/src/Skoruba.IdentityServer4.Shared.Configuration/Configuration/Common/CertificateConfiguration.cs b/src/Skoruba.IdentityServer4.Shared.Configuration/Configuration/Common/CertificateConfiguration.cs index 7a7df65fc..40f14698e 100644 --- a/src/Skoruba.IdentityServer4.Shared.Configuration/Configuration/Common/CertificateConfiguration.cs +++ b/src/Skoruba.IdentityServer4.Shared.Configuration/Configuration/Common/CertificateConfiguration.cs @@ -11,12 +11,18 @@ public class CertificateConfiguration public string SigningCertificateThumbprint { get; set; } + public string DnsName { get; set; } + public bool UseSigningCertificatePfxFile { get; set; } public string SigningCertificatePfxFilePath { get; set; } public string SigningCertificatePfxFilePassword { get; set; } + public int ValidityPeriodInYear { get; set; } + + public bool NeedToCreateNewOne { get; set; } + public bool UseValidationCertificateThumbprint { get; set; } public string ValidationCertificateThumbprint { get; set; }