Include the developer certificate by default, make it noop when environment != development
This commit is contained in:
parent
45f9780d32
commit
63f7f9a62c
|
|
@ -44,15 +44,20 @@ namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
var credentialsProvider = context.RequestServices.GetRequiredService<ISigningCredentialsPolicyProvider>();
|
|
||||||
var openIdOptionsCache = context.RequestServices.GetRequiredService<IOptionsCache<OpenIdConnectOptions>>();
|
|
||||||
|
|
||||||
|
var credentialsProvider = context.RequestServices.GetService<DeveloperCertificateSigningCredentialsSource>();
|
||||||
|
if (credentialsProvider == null)
|
||||||
|
{
|
||||||
|
await _next(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var openIdOptionsCache = context.RequestServices.GetRequiredService<IOptionsCache<OpenIdConnectOptions>>();
|
||||||
if (_environment.IsDevelopment() &&
|
if (_environment.IsDevelopment() &&
|
||||||
context.Request.Path.Equals(_options.Value.ListeningEndpoint))
|
context.Request.Path.Equals(_options.Value.ListeningEndpoint))
|
||||||
{
|
{
|
||||||
if (context.Request.Method.Equals(HttpMethods.Get))
|
if (context.Request.Method.Equals(HttpMethods.Get))
|
||||||
{
|
{
|
||||||
var credentials = await credentialsProvider.GetAllCredentialsAsync();
|
var credentials = await credentialsProvider.GetCredentials();
|
||||||
bool hasDevelopmentCertificate = await IsDevelopmentCertificateConfiguredAndValid();
|
bool hasDevelopmentCertificate = await IsDevelopmentCertificateConfiguredAndValid();
|
||||||
var foundDeveloperCertificate = FoundDeveloperCertificate();
|
var foundDeveloperCertificate = FoundDeveloperCertificate();
|
||||||
if (!foundDeveloperCertificate || !hasDevelopmentCertificate)
|
if (!foundDeveloperCertificate || !hasDevelopmentCertificate)
|
||||||
|
|
@ -102,7 +107,6 @@ namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
store.Open(OpenFlags.ReadWrite);
|
store.Open(OpenFlags.ReadWrite);
|
||||||
store.Add(imported);
|
store.Add(imported);
|
||||||
store.Close();
|
store.Close();
|
||||||
_identityServiceOptionsCache.TryRemove(Options.DefaultName);
|
|
||||||
openIdOptionsCache.TryRemove(OpenIdConnectDefaults.AuthenticationScheme);
|
openIdOptionsCache.TryRemove(OpenIdConnectDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
context.Response.StatusCode = StatusCodes.Status204NoContent;
|
context.Response.StatusCode = StatusCodes.Status204NoContent;
|
||||||
|
|
@ -131,7 +135,7 @@ namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
|
||||||
async Task<bool> IsDevelopmentCertificateConfiguredAndValid()
|
async Task<bool> IsDevelopmentCertificateConfiguredAndValid()
|
||||||
{
|
{
|
||||||
var certificates = await credentialsProvider.GetAllCredentialsAsync();
|
var certificates = await credentialsProvider.GetCredentials();
|
||||||
return certificates.Any(
|
return certificates.Any(
|
||||||
c => _timeStampManager.IsValidPeriod(c.NotBefore, c.Expires) &&
|
c => _timeStampManager.IsValidPeriod(c.NotBefore, c.Expires) &&
|
||||||
c.Credentials.Key is X509SecurityKey key &&
|
c.Credentials.Key is X509SecurityKey key &&
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DeveloperCertificateSigningCredentialsSource : ISigningCredentialsSource
|
||||||
|
{
|
||||||
|
private readonly IHostingEnvironment _environment;
|
||||||
|
private readonly ITimeStampManager _timeStampManager;
|
||||||
|
|
||||||
|
public DeveloperCertificateSigningCredentialsSource(
|
||||||
|
IHostingEnvironment environment,
|
||||||
|
ITimeStampManager timeStampManager)
|
||||||
|
{
|
||||||
|
_environment = environment;
|
||||||
|
_timeStampManager = timeStampManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<SigningCredentialsDescriptor>> GetCredentials()
|
||||||
|
{
|
||||||
|
if (!_environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
return Task.FromResult(Enumerable.Empty<SigningCredentialsDescriptor>());
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
|
||||||
|
{
|
||||||
|
store.Open(OpenFlags.ReadOnly);
|
||||||
|
var cert = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, "CN=IdentityService.Development", validOnly: false);
|
||||||
|
var valid = cert.OfType<X509Certificate2>().FirstOrDefault(c => _timeStampManager.IsValidPeriod(c.NotBefore, c.NotAfter));
|
||||||
|
store.Close();
|
||||||
|
|
||||||
|
if (valid != null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<IEnumerable<SigningCredentialsDescriptor>>(new[] { CreateDescriptor(valid) });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Task.FromResult(Enumerable.Empty<SigningCredentialsDescriptor>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SigningCredentialsDescriptor CreateDescriptor(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
CryptographyHelpers.ValidateRsaKeyLength(certificate);
|
||||||
|
var credentials = new SigningCredentials(new X509SecurityKey(certificate), CryptographyHelpers.FindAlgorithm(certificate));
|
||||||
|
return new SigningCredentialsDescriptor(
|
||||||
|
credentials,
|
||||||
|
CryptographyHelpers.GetAlgorithm(credentials),
|
||||||
|
certificate.NotBefore,
|
||||||
|
certificate.NotAfter,
|
||||||
|
GetMetadata());
|
||||||
|
|
||||||
|
IDictionary<string, string> GetMetadata()
|
||||||
|
{
|
||||||
|
var rsaParameters = CryptographyHelpers.GetRSAParameters(credentials);
|
||||||
|
return new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
[JsonWebKeyParameterNames.E] = Base64UrlEncoder.Encode(rsaParameters.Exponent),
|
||||||
|
[JsonWebKeyParameterNames.N] = Base64UrlEncoder.Encode(rsaParameters.Modulus),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Microsoft.AspNetCore.Identity.Service.Core;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
|
@ -56,6 +58,20 @@ namespace Microsoft.AspNetCore.Identity.Service
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IIdentityServiceBuilder DisableDeveloperCertificate(this IIdentityServiceBuilder builder)
|
||||||
|
{
|
||||||
|
var services = builder.Services;
|
||||||
|
foreach (var service in services.ToList())
|
||||||
|
{
|
||||||
|
if (service.ImplementationType == typeof(DeveloperCertificateSigningCredentialsSource))
|
||||||
|
{
|
||||||
|
services.Remove(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
public static IIdentityServiceBuilder AddSigningCertificate(this IIdentityServiceBuilder builder, Func<X509Certificate2> func)
|
public static IIdentityServiceBuilder AddSigningCertificate(this IIdentityServiceBuilder builder, Func<X509Certificate2> func)
|
||||||
{
|
{
|
||||||
var cert = func();
|
var cert = func();
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.AddSingleton<ITokenClaimsProvider, TimestampsTokenClaimsProvider>();
|
services.AddSingleton<ITokenClaimsProvider, TimestampsTokenClaimsProvider>();
|
||||||
services.AddSingleton<ITokenClaimsProvider, TokenHashTokenClaimsProvider>();
|
services.AddSingleton<ITokenClaimsProvider, TokenHashTokenClaimsProvider>();
|
||||||
services.AddSingleton<ProtocolErrorProvider>();
|
services.AddSingleton<ProtocolErrorProvider>();
|
||||||
|
services.AddSingleton<ISigningCredentialsSource, DeveloperCertificateSigningCredentialsSource>();
|
||||||
|
services.AddSingleton<DeveloperCertificateSigningCredentialsSource>();
|
||||||
|
|
||||||
services.AddSingleton<IPasswordHasher<TApplication>, PasswordHasher<TApplication>>();
|
services.AddSingleton<IPasswordHasher<TApplication>, PasswordHasher<TApplication>>();
|
||||||
services.AddScoped<ISigningCredentialsPolicyProvider, DefaultSigningCredentialsPolicyProvider>();
|
services.AddScoped<ISigningCredentialsPolicyProvider, DefaultSigningCredentialsPolicyProvider>();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue