How do correctly rollover to a new signing certificate with IdentityServer 4?

Viewed 166

We have multiple applications that use a single sign on identity provider application. These are all Asp.NetCore 2.1 apps. The Idp app uses IdentityServer 4 and all are hosted on Windows Server in IIS. The signing certificate for the Idp is just a self-signed server authentication cert created in IIS.

After our old signing certificate expired and our app rolled over to the new certificate we no longer could reach the discovery document.

I have had both certificates added with the respective middleware about a week before the rollover. This is the relevant code from the Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    var identityServerConnectionString = Configuration.GetConnectionString("IdentityServerDataDbConnectionString");
    services.AddIdentityServer()
                .AddSigningCredential(LoadCertificateFromStore(Configuration["CurrentKeySubject"]))
                .AddValidationKey(LoadCertificateFromStore(Configuration["NextKeySubject"]))
                .AddUserStore()
                .AddConfigurationStore(builder =>
                {
                    builder.ConfigureDbContext = (context) => context.UseSqlServer(identityServerConnectionString);
                })
                .AddOperationalStore(builder =>
                {
                    builder.ConfigureDbContext = (context) => context.UseSqlServer(identityServerConnectionString);
                    builder.EnableTokenCleanup = true;
                    builder.TokenCleanupInterval = 3600;
                    builder.TokenCleanupBatchSize = 100;
                });

    public X509Certificate2 LoadCertificateFromStore(string value)
        {
            using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
            {
                store.Open(OpenFlags.ReadOnly);
                var certCollection = store.Certificates.Find(X509FindType.FindBySubjectName,
                    value, true);
                if (certCollection.Count == 0)
                {
                    throw new Exception("The specified certificate wasn't found. Check the specified identifier.");
                }
                return certCollection[0];
            }
        }
}

It wasn't until I deleted the records from the PersistentGrants table in the database that it started working again.

I have updated this certificate every year for about 4 years and this has not "seemed" to happen before. This is the first year that the app has had more than a couple users though so rollover and caching could have been a problem but never noticed.

Is this normal to have to remove the token references from the persistent grant store for this to work? If this is pure caching involved, how do I fix it? Should I have had a reference to both certs in the discovery document more than a week in advance?

IDX20803: Unable to obtain configuration from: 'https://oursite.com/ouridp/.well-known/openid-configuration'.

at Microsoft.IdentityModel.Protocols.ConfigurationManager1.GetConfigurationAsync(CancellationToken cancel) at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsync(AuthenticationProperties properties) at Microsoft.AspNetCore.Authentication.AuthenticationHandler1.ChallengeAsync(AuthenticationProperties properties) at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties) at Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAlwaysRunResultFilters() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

0 Answers
Related