Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit 37b20c2

Browse files
committed
Listen on https by default if the cert is present
1 parent 6a3a365 commit 37b20c2

File tree

7 files changed

+73
-12
lines changed

7 files changed

+73
-12
lines changed

src/Kestrel.Core/CoreStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,4 +465,7 @@
465465
<data name="UnableToConfigureHttpsBindings" xml:space="preserve">
466466
<value>Unable to configure default https bindings because no IDefaultHttpsProvider service was provided.</value>
467467
</data>
468+
<data name="BindingToDefaultAddresses" xml:space="preserve">
469+
<value>No listening endpoints were configured. Binding to {address0} and {address1} by default.</value>
470+
</data>
468471
</root>

src/Kestrel.Core/Internal/AddressBinder.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Linq;
88
using System.Net;
9+
using System.Security.Cryptography.X509Certificates;
910
using System.Threading.Tasks;
1011
using Microsoft.AspNetCore.Builder;
1112
using Microsoft.AspNetCore.Hosting.Server.Features;
@@ -163,12 +164,33 @@ private class DefaultAddressStrategy : IStrategy
163164
{
164165
public async Task BindAsync(AddressBindContext context)
165166
{
166-
context.Logger.LogDebug(CoreStrings.BindingToDefaultAddress, Constants.DefaultServerAddress);
167-
168167
var options = ParseAddress(Constants.DefaultServerAddress, out var https);
169168
options.KestrelServerOptions = context.ServerOptions;
170169
context.ServerOptions.EndpointDefaults(options);
171170
await options.BindAsync(context).ConfigureAwait(false);
171+
172+
// Conditional https default, only if a cert is available
173+
options = ParseAddress(Constants.DefaultServerHttpsAddress, out https);
174+
options.KestrelServerOptions = context.ServerOptions;
175+
context.ServerOptions.EndpointDefaults(options);
176+
177+
if (!options.ConnectionAdapters.Any(f => f.IsHttps))
178+
{
179+
try
180+
{
181+
context.DefaultHttpsProvider.ConfigureHttps(options);
182+
}
183+
catch (Exception)
184+
{
185+
// No default cert is available
186+
context.Logger.LogDebug(CoreStrings.BindingToDefaultAddress, Constants.DefaultServerAddress);
187+
return;
188+
}
189+
}
190+
191+
context.Logger.LogDebug(CoreStrings.BindingToDefaultAddresses,
192+
Constants.DefaultServerAddress, Constants.DefaultServerHttpsAddress);
193+
await options.BindAsync(context).ConfigureAwait(false);
172194
}
173195
}
174196

@@ -260,6 +282,8 @@ private UnconfiguredDefaultHttpsProvider()
260282
{
261283
}
262284

285+
public X509Certificate2 Certificate => null;
286+
263287
public void ConfigureHttps(ListenOptions listenOptions)
264288
{
265289
// We have to throw here. If this is called, it's because the user asked for "https" binding but for some
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Security.Cryptography.X509Certificates;
5+
46
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
57
{
68
public interface IDefaultHttpsProvider
79
{
10+
/// <summary>
11+
/// Returns the default certificate, if available, otherwise null.
12+
/// </summary>
13+
X509Certificate2 Certificate { get; }
14+
15+
/// <summary>
16+
/// Adds the https connection adapter using the default certificate. This throws if the certificate is not available.
17+
/// </summary>
18+
/// <param name="listenOptions"></param>
819
void ConfigureHttps(ListenOptions listenOptions);
920
}
1021
}

src/Kestrel.Core/Internal/Infrastructure/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ internal static class Constants
1313
/// The IPEndPoint Kestrel will bind to if nothing else is specified.
1414
/// </summary>
1515
public static readonly string DefaultServerAddress = "http://localhost:5000";
16+
public static readonly string DefaultServerHttpsAddress = "https://localhost:5001";
1617

1718
/// <summary>
1819
/// Prefix of host name used to specify Unix sockets in the configuration.

src/Kestrel.Core/Properties/CoreStrings.Designer.cs

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Kestrel/Internal/DefaultHttpsProvider.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,37 @@ public DefaultHttpsProvider(ILogger<DefaultHttpsProvider> logger)
2323
_logger = logger;
2424
}
2525

26+
public X509Certificate2 Certificate => GetDefaultCert();
27+
2628
public void ConfigureHttps(ListenOptions listenOptions)
2729
{
28-
var certificate = GetDefaultCert();
30+
listenOptions.UseHttps(options =>
31+
{
32+
// ConfigureHttpsDefaults may have set the default cert.
33+
if (options.ServerCertificate == null)
34+
{
35+
options.ServerCertificate = GetDefaultCert();
36+
if (options.ServerCertificate == null)
37+
{
38+
throw new InvalidOperationException(KestrelStrings.HttpsUrlProvidedButNoDevelopmentCertificateFound);
39+
}
40+
}
41+
});
42+
}
43+
44+
private X509Certificate2 GetDefaultCert()
45+
{
46+
var certificate = _certificateManager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true)
47+
.FirstOrDefault();
2948
if (certificate != null)
3049
{
3150
_logger.LocatedDevelopmentCertificate(certificate);
32-
listenOptions.UseHttps(certificate);
3351
}
3452
else
3553
{
3654
_logger.UnableToLocateDevelopmentCertificate();
37-
throw new InvalidOperationException(KestrelStrings.HttpsUrlProvidedButNoDevelopmentCertificateFound);
3855
}
39-
}
40-
41-
internal static X509Certificate2 GetDefaultCert()
42-
{
43-
return _certificateManager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true)
44-
.FirstOrDefault();
56+
return certificate;
4557
}
4658
}
4759
}

src/Kestrel/KestrelConfigBuilder.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ public void Build()
7979
}
8080
else if (certInfo.IsStoreCert)
8181
{
82+
// TODO: Throw if the cert cannot be loaded, FileCert does.
8283
httpsOptions.ServerCertificate = LoadFromStoreCert(certInfo);
8384
}
8485
else if (httpsOptions.ServerCertificate == null)
8586
{
86-
httpsOptions.ServerCertificate = DefaultHttpsProvider.GetDefaultCert();
87+
var provider = Options.ApplicationServices.GetRequiredService<IDefaultHttpsProvider>();
88+
httpsOptions.ServerCertificate = provider.Certificate; // May be null
8789
}
8890
}
8991

0 commit comments

Comments
 (0)