Skip to content

Add CertificateAuthentication #9756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
Jun 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
a2ea84d
Initial snapshot of CertAuth (tests pass)
HaoK Apr 25, 2019
609c678
Fix sample remove commented tests
HaoK Apr 25, 2019
4ac7474
Use built in GetCertHashString
HaoK Apr 25, 2019
df15031
Update Microsoft.AspNetCore.Authentication.Certificate.netcoreapp3.0.cs
HaoK Apr 26, 2019
245c478
Skip failing self signing cert tests on linux
HaoK Apr 29, 2019
ec39624
Initial snapshot of CertAuth (tests pass)
HaoK Apr 25, 2019
242616d
Stuff
HaoK May 7, 2019
60762fb
Use right header
HaoK May 16, 2019
83a9560
Move CertForwarderMiddleware to HttpOverrides
HaoK May 17, 2019
9c006c8
Collapse null checks
HaoK May 17, 2019
ed02704
Delete Cert validator
HaoK May 17, 2019
95508f0
remove no warn
HaoK May 20, 2019
da2dc36
Update src/Middleware/HttpOverrides/src/CertificateForwarderExtension…
HaoK May 20, 2019
8ead62b
Update src/Middleware/HttpOverrides/src/CertificateForwarderExtension…
HaoK May 20, 2019
d079170
Add doc comments
HaoK May 20, 2019
758d1af
Update src/Middleware/HttpOverrides/src/CertificateForwarderOptions.cs
HaoK May 21, 2019
b222348
Update src/Middleware/HttpOverrides/src/CertificateForwarderOptions.cs
HaoK May 21, 2019
6806957
Update src/Security/Authentication/Certificate/samples/Certificate.Sa…
HaoK May 21, 2019
e3bb3d0
Update src/Security/Authentication/Certificate/samples/Certificate.Sa…
HaoK May 21, 2019
1f7e8a6
Update src/Security/Authentication/Certificate/samples/Certificate.Sa…
HaoK May 21, 2019
8650102
Update src/Security/Authentication/Certificate/samples/Certificate.Sa…
HaoK May 21, 2019
c57c2fc
Update src/Security/Authentication/Certificate/samples/Certificate.Sa…
HaoK May 21, 2019
44b87eb
Update MessagePack-CSharp
HaoK May 21, 2019
23b8d88
Update self signed certs to CertSign key usage
HaoK May 17, 2019
460ede1
Add some tests for CertificateForwarderMiddleware
HaoK May 21, 2019
07e9971
Doc comments galore, add tests, PR feedback
HaoK May 21, 2019
a616c13
Update Microsoft.AspNetCore.Authentication.Certificate.csproj
HaoK May 21, 2019
93afcbd
Update SharedFramework.Local.props
HaoK May 21, 2019
254606d
Fix sample
HaoK May 21, 2019
1893a9c
Update Program.cs
HaoK May 22, 2019
3e8b045
Update Program.cs
HaoK May 22, 2019
1dde847
Update CertificateAuthenticationHandler.cs
HaoK May 22, 2019
5b92b6f
Update CertificateTypes.cs
HaoK May 22, 2019
10b5eda
Fix typo
HaoK May 22, 2019
91c1663
Update Microsoft.AspNetCore.Authentication.Certificate.netcoreapp3.0.cs
HaoK May 23, 2019
d6e41eb
Add TlsConnectionFeature for cert forward header
HaoK May 25, 2019
33ac70d
Switch to span sequence equals
HaoK May 28, 2019
b6febd2
Add structured logging
HaoK May 28, 2019
f0f66f8
Fix sample
HaoK May 28, 2019
a957b88
PR feedback
HaoK May 28, 2019
18f9296
Switch default header to X-Client-Cert for forwarder
HaoK May 29, 2019
908fb39
Create principal earlier for event
HaoK May 29, 2019
6943636
Code review feedback
HaoK May 29, 2019
8b3a435
Update src/Security/Authentication/Certificate/src/Microsoft.AspNetCo…
HaoK May 29, 2019
0eaa6fb
Add logging
HaoK May 29, 2019
a20c0c1
Merge branch 'security-cert' of https://github.com/aspnet/AspNetCore …
HaoK May 29, 2019
c592bc5
Feedback updates
HaoK May 29, 2019
22350cf
Fix tests
HaoK May 30, 2019
633edb2
Fix refs
HaoK May 30, 2019
3c8f335
Update src/Security/Authentication/Certificate/src/CertificateAuthent…
HaoK May 31, 2019
cae80fd
Renames
HaoK May 31, 2019
3d8510b
Update Microsoft.AspNetCore.HttpOverrides.netcoreapp3.0.cs
HaoK May 31, 2019
5e64221
Update Microsoft.AspNetCore.Authentication.Certificate.netcoreapp3.0.cs
HaoK May 31, 2019
7235295
Update Microsoft.AspNetCore.HttpOverrides.netcoreapp3.0.cs
HaoK May 31, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eng/ProjectReferences.props
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Abstractions\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Abstractions\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Libuv\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Libuv\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Sockets\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Certificate" ProjectPath="$(RepoRoot)src\Security\Authentication\Certificate\src\Microsoft.AspNetCore.Authentication.Certificate.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Certificate\ref\Microsoft.AspNetCore.Authentication.Certificate.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Cookies" ProjectPath="$(RepoRoot)src\Security\Authentication\Cookies\src\Microsoft.AspNetCore.Authentication.Cookies.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Cookies\ref\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication" ProjectPath="$(RepoRoot)src\Security\Authentication\Core\src\Microsoft.AspNetCore.Authentication.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Core\ref\Microsoft.AspNetCore.Authentication.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Facebook" ProjectPath="$(RepoRoot)src\Security\Authentication\Facebook\src\Microsoft.AspNetCore.Authentication.Facebook.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Facebook\ref\Microsoft.AspNetCore.Authentication.Facebook.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

namespace Microsoft.AspNetCore.Builder
{
public static partial class CertificateForwardingBuilderExtensions
{
public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseCertificateForwarding(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) { throw null; }
}
public static partial class ForwardedHeadersExtensions
{
public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseForwardedHeaders(this Microsoft.AspNetCore.Builder.IApplicationBuilder builder) { throw null; }
Expand Down Expand Up @@ -37,6 +41,17 @@ public HttpMethodOverrideOptions() { }
}
namespace Microsoft.AspNetCore.HttpOverrides
{
public partial class CertificateForwardingMiddleware
{
public CertificateForwardingMiddleware(Microsoft.AspNetCore.Http.RequestDelegate next, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.HttpOverrides.CertificateForwardingOptions> options) { }
public System.Threading.Tasks.Task Invoke(Microsoft.AspNetCore.Http.HttpContext httpContext) { throw null; }
}
public partial class CertificateForwardingOptions
{
public System.Func<string, System.Security.Cryptography.X509Certificates.X509Certificate2> HeaderConverter;
public CertificateForwardingOptions() { }
public string CertificateHeader { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
[System.FlagsAttribute]
public enum ForwardedHeaders
{
Expand Down Expand Up @@ -75,3 +90,10 @@ public IPNetwork(System.Net.IPAddress prefix, int prefixLength) { }
public bool Contains(System.Net.IPAddress address) { throw null; }
}
}
namespace Microsoft.Extensions.DependencyInjection
{
public static partial class CertificateForwardingServiceExtensions
{
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddCertificateForwarding(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.AspNetCore.HttpOverrides.CertificateForwardingOptions> configure) { throw null; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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;
using Microsoft.AspNetCore.HttpOverrides;

namespace Microsoft.AspNetCore.Builder
{
/// <summary>
/// Extension methods for using certificate fowarding.
/// </summary>
public static class CertificateForwardingBuilderExtensions
{
/// <summary>
/// Adds a middleware to the pipeline that will look for a certificate in a request header
/// decode it, and updates HttpContext.Connection.ClientCertificate.
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseCertificateForwarding(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}

return app.UseMiddleware<CertificateForwardingMiddleware>();
}
}
}
51 changes: 51 additions & 0 deletions src/Middleware/HttpOverrides/src/CertificateForwardingFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;

namespace Microsoft.AspNetCore.HttpOverrides
{
internal class CertificateForwardingFeature : ITlsConnectionFeature
{
private ILogger _logger;
private StringValues _header;
private CertificateForwardingOptions _options;
private X509Certificate2 _certificate;

public CertificateForwardingFeature(ILogger logger, StringValues header, CertificateForwardingOptions options)
{
_logger = logger;
_options = options;
_header = header;
}

public X509Certificate2 ClientCertificate
{
get
{
if (_certificate == null)
{
try
{
_certificate = _options.HeaderConverter(_header);
}
catch (Exception e)
{
_logger.NoCertificate(e);
}
}
return _certificate;
}
set => _certificate = value;
}

public Task<X509Certificate2> GetClientCertificateAsync(CancellationToken cancellationToken)
=> Task.FromResult(ClientCertificate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;

namespace Microsoft.AspNetCore.HttpOverrides
{
/// <summary>
/// Middleware that converts a forward header into a client certificate if found.
/// </summary>
public class CertificateForwardingMiddleware
{
private readonly RequestDelegate _next;
private readonly CertificateForwardingOptions _options;
private readonly ILogger _logger;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="next"></param>
/// <param name="loggerFactory"></param>
/// <param name="options"></param>
public CertificateForwardingMiddleware(
RequestDelegate next,
ILoggerFactory loggerFactory,
IOptions<CertificateForwardingOptions> options)
{
_next = next ?? throw new ArgumentNullException(nameof(next));

if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}

if (options == null)
{
throw new ArgumentNullException(nameof(options));
}

_options = options.Value;
_logger = loggerFactory.CreateLogger<CertificateForwardingMiddleware>();
}

/// <summary>
/// Looks for the presence of a <see cref="CertificateForwardingOptions.CertificateHeader"/> header in the request,
/// if found, converts this header to a ClientCertificate set on the connection.
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/>.</param>
/// <returns>A <see cref="Task"/>.</returns>
public Task Invoke(HttpContext httpContext)
{
var header = httpContext.Request.Headers[_options.CertificateHeader];
if (!StringValues.IsNullOrEmpty(header))
{
httpContext.Features.Set<ITlsConnectionFeature>(new CertificateForwardingFeature(_logger, header, _options));
}
return _next(httpContext);
}
}
}
30 changes: 30 additions & 0 deletions src/Middleware/HttpOverrides/src/CertificateForwardingOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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;
using System.Security.Cryptography.X509Certificates;

namespace Microsoft.AspNetCore.HttpOverrides
{
/// <summary>
/// Used to configure the <see cref="CertificateForwardingMiddleware"/>.
/// </summary>
public class CertificateForwardingOptions
{
/// <summary>
/// The name of the header containing the client certificate.
/// </summary>
/// <remarks>
/// This defaults to X-Client-Cert
/// </remarks>
public string CertificateHeader { get; set; } = "X-Client-Cert";

/// <summary>
/// The function used to convert the header to an instance of <see cref="X509Certificate2"/>.
/// </summary>
/// <remarks>
/// This defaults to a conversion from a base64 encoded string.
/// </remarks>
public Func<string, X509Certificate2> HeaderConverter = (headerValue) => new X509Certificate2(Convert.FromBase64String(headerValue));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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;
using Microsoft.AspNetCore.HttpOverrides;

namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extension methods for using certificate fowarding.
/// </summary>
public static class CertificateForwardingServiceExtensions
{
/// <summary>
/// Adds certificate forwarding to the specified <see cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="configure">An action delegate to configure the provided <see cref="CertificateForwardingOptions"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection AddCertificateForwarding(
this IServiceCollection services,
Action<CertificateForwardingOptions> configure)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}

if (configure == null)
{
throw new ArgumentNullException(nameof(configure));
}

services.AddOptions<CertificateForwardingOptions>().Validate(o => !string.IsNullOrEmpty(o.CertificateHeader), "CertificateForwarderOptions.CertificateHeader cannot be null or empty.");
return services.Configure(configure);
}
}
}
25 changes: 25 additions & 0 deletions src/Middleware/HttpOverrides/src/LoggingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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;

namespace Microsoft.Extensions.Logging
{
internal static class LoggingExtensions
{
private static Action<ILogger, Exception> _noCertificate;

static LoggingExtensions()
{
_noCertificate = LoggerMessage.Define(
eventId: new EventId(0, "NoCertificate"),
logLevel: LogLevel.Warning,
formatString: "Could not read certificate from header.");
}

public static void NoCertificate(this ILogger logger, Exception exception)
{
_noCertificate(logger, exception);
}
}
}
Loading