Merge branch 'rel/2.0.0-preview1' into dev
This commit is contained in:
commit
d40a823675
|
|
@ -1,6 +1,6 @@
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26419.0
|
VisualStudioVersion = 15.0.26424.2
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -24,9 +24,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{192F
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "samples\SampleApp\SampleApp.csproj", "{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "samples\SampleApp\SampleApp.csproj", "{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppSettings", "samples\AppSettings\AppSettings.csproj", "{5009D7C8-6061-49CF-9A30-23B309BBEFB0}"
|
||||||
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.FunctionalTests", "test\Microsoft.AspNetCore.Tests\Microsoft.AspNetCore.FunctionalTests.csproj", "{C72A756A-D29D-44C7-83D4-821DBE82DBCA}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.FunctionalTests", "test\Microsoft.AspNetCore.FunctionalTests\Microsoft.AspNetCore.FunctionalTests.csproj", "{C72A756A-D29D-44C7-83D4-821DBE82DBCA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestSites", "TestSites", "{EC22261D-0DE1-47DE-8F7C-072675D6F5B4}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestSites", "TestSites", "{EC22261D-0DE1-47DE-8F7C-072675D6F5B4}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -38,6 +40,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartRequestDelegateUrlApp"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateDefaultBuilderApp", "test\TestSites\CreateDefaultBuilderApp\CreateDefaultBuilderApp.csproj", "{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateDefaultBuilderApp", "test\TestSites\CreateDefaultBuilderApp\CreateDefaultBuilderApp.csproj", "{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestArtifacts", "TestArtifacts", "{9BBA7A0A-109A-4AC8-B6EF-A52EA7CF1D90}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
test\TestArtifacts\testCert.pfx = test\TestArtifacts\testCert.pfx
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -56,6 +63,10 @@ Global
|
||||||
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5009D7C8-6061-49CF-9A30-23B309BBEFB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5009D7C8-6061-49CF-9A30-23B309BBEFB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5009D7C8-6061-49CF-9A30-23B309BBEFB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5009D7C8-6061-49CF-9A30-23B309BBEFB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C72A756A-D29D-44C7-83D4-821DBE82DBCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|
@ -85,11 +96,13 @@ Global
|
||||||
{CC8F551E-213A-45E8-AECA-507C4DB4F164} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
|
{CC8F551E-213A-45E8-AECA-507C4DB4F164} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
|
||||||
{F92CB7A1-C38E-408C-A7EC-A5C040D041E1} = {97D53BEB-A511-4FBE-B784-AB407D9A219F}
|
{F92CB7A1-C38E-408C-A7EC-A5C040D041E1} = {97D53BEB-A511-4FBE-B784-AB407D9A219F}
|
||||||
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2} = {192F583C-C4CA-43E5-B31C-D21B7806E274}
|
{AF5BB04E-92F7-4737-8B98-F86F6244FAB2} = {192F583C-C4CA-43E5-B31C-D21B7806E274}
|
||||||
|
{5009D7C8-6061-49CF-9A30-23B309BBEFB0} = {192F583C-C4CA-43E5-B31C-D21B7806E274}
|
||||||
{C72A756A-D29D-44C7-83D4-821DBE82DBCA} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
|
{C72A756A-D29D-44C7-83D4-821DBE82DBCA} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
|
||||||
{EC22261D-0DE1-47DE-8F7C-072675D6F5B4} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
|
{EC22261D-0DE1-47DE-8F7C-072675D6F5B4} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
|
||||||
{AB42054B-1801-4FEE-B5C3-8529C6D7BFDA} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
{AB42054B-1801-4FEE-B5C3-8529C6D7BFDA} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||||
{3A85FA52-F601-422E-A42E-9F187DB28492} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
{3A85FA52-F601-422E-A42E-9F187DB28492} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||||
{401C741B-6C7C-4E08-9F09-C3D43D22C0DE} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
{401C741B-6C7C-4E08-9F09-C3D43D22C0DE} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||||
{79CF58CE-B020-45D8-BDB5-2D8036BEAD14} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
{79CF58CE-B020-45D8-BDB5-2D8036BEAD14} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||||
|
{9BBA7A0A-109A-4AC8-B6EF-A52EA7CF1D90} = {9E49B5B9-9E72-42FB-B684-90CA1B1BCF9C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<Import Project="..\..\build\dependencies.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<UserSecretsId>aspnetcore-MetaPackagesAppSettings-20170421155031</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="testCert.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore\Microsoft.AspNetCore.csproj" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- TODO: restore reference when tools are working on netcoreapp2.0
|
||||||
|
<ItemGroup>
|
||||||
|
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="$(AspNetCoreVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace AppSettings
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
using (WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Running application: Press any key to shutdown...");
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:53434/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppSettings": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:53435"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"Kestrel": {
|
||||||
|
"EndPoints": {
|
||||||
|
"Http": {
|
||||||
|
"Address": "127.0.0.1",
|
||||||
|
"Port": 8081
|
||||||
|
},
|
||||||
|
"HttpV6": {
|
||||||
|
"Address": "::1",
|
||||||
|
"Port": 8081
|
||||||
|
},
|
||||||
|
// Add testCert.pfx to the current user's certificate store to enable this scenario.
|
||||||
|
//"HttpsInlineCertStore": {
|
||||||
|
// "Address": "127.0.0.1",
|
||||||
|
// "Port": 8082,
|
||||||
|
// "Certificate": {
|
||||||
|
// "Source": "Store",
|
||||||
|
// "Subject": "cn=localhost",
|
||||||
|
// "StoreName": "My",
|
||||||
|
// "StoreLocation": "CurrentUser",
|
||||||
|
// "AllowInvalid": "True"
|
||||||
|
// }
|
||||||
|
//},
|
||||||
|
"HttpsInlineCertFile": {
|
||||||
|
"Address": "127.0.0.1",
|
||||||
|
"Port": 8083,
|
||||||
|
"Certificate": {
|
||||||
|
"Source": "File",
|
||||||
|
"Path": "testCert.pfx",
|
||||||
|
// TODO: remove when dotnet user-secrets is working again
|
||||||
|
"Password": "testPassword",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Add testCert.pfx to the current user's certificate store to enable this scenario.
|
||||||
|
//"HttpsCertStore": {
|
||||||
|
// "Address": "127.0.0.1",
|
||||||
|
// "Port": 8084,
|
||||||
|
// "Certificate": "TestCertInStore"
|
||||||
|
//},
|
||||||
|
"HttpsCertFile": {
|
||||||
|
"Address": "127.0.0.1",
|
||||||
|
"Port": 8085,
|
||||||
|
"Certificate": "TestCert"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Certificates": {
|
||||||
|
"TestCert": {
|
||||||
|
"Source": "File",
|
||||||
|
"Path": "testCert.pfx",
|
||||||
|
// TODO: remove when dotnet user-secrets is working again
|
||||||
|
"Password": "testPassword"
|
||||||
|
},
|
||||||
|
// Add testCert.pfx to the current user's certificate store to enable this scenario.
|
||||||
|
//"TestCertInStore": {
|
||||||
|
// "Source": "Store",
|
||||||
|
// "Subject": "cn=localhost",
|
||||||
|
// "StoreName": "My",
|
||||||
|
// "StoreLocation": "CurrentUser",
|
||||||
|
// "AllowInvalid": "True"
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<Import Project="..\..\build\common.props" />
|
<Import Project="..\..\build\dependencies.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A helper class to load certificates from files and certificate stores based on <seealso cref="IConfiguration"/> data.
|
||||||
|
/// </summary>
|
||||||
|
public static class CertificateLoader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Loads one or more certificates from a single source.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="certificateConfiguration">An <seealso cref="IConfiguration"/> with information about a certificate source.</param>
|
||||||
|
/// <param name="password">The certificate password, in case it's being loaded from a file.</param>
|
||||||
|
/// <returns>The loaded certificates.</returns>
|
||||||
|
public static X509Certificate2 Load(IConfiguration certificateConfiguration, string password)
|
||||||
|
{
|
||||||
|
var sourceKind = certificateConfiguration.GetValue<string>("Source");
|
||||||
|
|
||||||
|
CertificateSource certificateSource;
|
||||||
|
switch (sourceKind.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "file":
|
||||||
|
certificateSource = new CertificateFileSource(password);
|
||||||
|
break;
|
||||||
|
case "store":
|
||||||
|
certificateSource = new CertificateStoreSource();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException($"Invalid certificate source kind: {sourceKind}");
|
||||||
|
}
|
||||||
|
|
||||||
|
certificateConfiguration.Bind(certificateSource);
|
||||||
|
return certificateSource.Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads all certificates specified in an <seealso cref="IConfiguration"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configurationRoot">The root <seealso cref="IConfiguration"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A dictionary mapping certificate names to loaded certificates.
|
||||||
|
/// </returns>
|
||||||
|
public static Dictionary<string, X509Certificate2> LoadAll(IConfiguration configurationRoot)
|
||||||
|
{
|
||||||
|
return configurationRoot.GetSection("Certificates").GetChildren()
|
||||||
|
.ToDictionary(
|
||||||
|
certificateSource => certificateSource.Key,
|
||||||
|
certificateSource => Load(certificateSource, certificateSource["Password"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class CertificateSource
|
||||||
|
{
|
||||||
|
public string Source { get; set; }
|
||||||
|
|
||||||
|
public abstract X509Certificate2 Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CertificateFileSource : CertificateSource
|
||||||
|
{
|
||||||
|
private readonly string _password;
|
||||||
|
|
||||||
|
public CertificateFileSource(string password)
|
||||||
|
{
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
public override X509Certificate2 Load()
|
||||||
|
{
|
||||||
|
var certificate = TryLoad(X509KeyStorageFlags.DefaultKeySet, out var error)
|
||||||
|
?? TryLoad(X509KeyStorageFlags.UserKeySet, out error)
|
||||||
|
#if NETCOREAPP2_0
|
||||||
|
?? TryLoad(X509KeyStorageFlags.EphemeralKeySet, out error)
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private X509Certificate2 TryLoad(X509KeyStorageFlags flags, out Exception exception)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var loadedCertificate = new X509Certificate2(Path, _password, flags);
|
||||||
|
exception = null;
|
||||||
|
return loadedCertificate;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
exception = e;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CertificateStoreSource : CertificateSource
|
||||||
|
{
|
||||||
|
public string Subject { get; set; }
|
||||||
|
public string StoreName { get; set; }
|
||||||
|
public string StoreLocation { get; set; }
|
||||||
|
public bool AllowInvalid { get; set; }
|
||||||
|
|
||||||
|
public override X509Certificate2 Load()
|
||||||
|
{
|
||||||
|
if (!Enum.TryParse(StoreLocation, ignoreCase: true, result: out StoreLocation storeLocation))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid store location: {StoreLocation}");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var store = new X509Store(StoreName, storeLocation))
|
||||||
|
{
|
||||||
|
X509Certificate2Collection storeCertificates = null;
|
||||||
|
X509Certificate2Collection foundCertificates = null;
|
||||||
|
X509Certificate2 foundCertificate = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
store.Open(OpenFlags.ReadOnly);
|
||||||
|
storeCertificates = store.Certificates;
|
||||||
|
foundCertificates = storeCertificates.Find(X509FindType.FindBySubjectDistinguishedName, Subject, validOnly: !AllowInvalid);
|
||||||
|
foundCertificate = foundCertificates
|
||||||
|
.OfType<X509Certificate2>()
|
||||||
|
.OrderByDescending(certificate => certificate.NotAfter)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (foundCertificate == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No certificate found for {Subject} in store {StoreName} in {StoreLocation}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundCertificate;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (foundCertificate != null)
|
||||||
|
{
|
||||||
|
storeCertificates.Remove(foundCertificate);
|
||||||
|
foundCertificates.Remove(foundCertificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposeCertificates(storeCertificates);
|
||||||
|
DisposeCertificates(foundCertificates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisposeCertificates(X509Certificate2Collection certificates)
|
||||||
|
{
|
||||||
|
if (certificates != null)
|
||||||
|
{
|
||||||
|
foreach (var certificate in certificates)
|
||||||
|
{
|
||||||
|
certificate.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Binds Kestrel configuration.
|
||||||
|
/// </summary>
|
||||||
|
public class KestrelServerOptionsSetup : IConfigureOptions<KestrelServerOptions>
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _configurationRoot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="KestrelServerOptionsSetup"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configurationRoot">The root <seealso cref="IConfiguration"/>.</param>
|
||||||
|
public KestrelServerOptionsSetup(IConfiguration configurationRoot)
|
||||||
|
{
|
||||||
|
_configurationRoot = configurationRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures a <seealso cref="KestrelServerOptions"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The <seealso cref="KestrelServerOptions"/> to configure.</param>
|
||||||
|
public void Configure(KestrelServerOptions options)
|
||||||
|
{
|
||||||
|
BindConfiguration(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindConfiguration(KestrelServerOptions options)
|
||||||
|
{
|
||||||
|
var certificates = CertificateLoader.LoadAll(_configurationRoot);
|
||||||
|
var endPoints = _configurationRoot.GetSection("Kestrel:EndPoints");
|
||||||
|
|
||||||
|
foreach (var endPoint in endPoints.GetChildren())
|
||||||
|
{
|
||||||
|
BindEndPoint(options, endPoint, certificates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindEndPoint(
|
||||||
|
KestrelServerOptions options,
|
||||||
|
IConfigurationSection endPoint,
|
||||||
|
Dictionary<string, X509Certificate2> certificates)
|
||||||
|
{
|
||||||
|
var addressValue = endPoint.GetValue<string>("Address");
|
||||||
|
var portValue = endPoint.GetValue<string>("Port");
|
||||||
|
|
||||||
|
IPAddress address;
|
||||||
|
if (!IPAddress.TryParse(addressValue, out address))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid IP address: {addressValue}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int port;
|
||||||
|
if (!int.TryParse(portValue, out port))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid port: {portValue}");
|
||||||
|
}
|
||||||
|
|
||||||
|
options.Listen(address, port, listenOptions =>
|
||||||
|
{
|
||||||
|
var certificateName = endPoint.GetValue<string>("Certificate");
|
||||||
|
|
||||||
|
X509Certificate2 endPointCertificate = null;
|
||||||
|
if (certificateName != null)
|
||||||
|
{
|
||||||
|
if (!certificates.TryGetValue(certificateName, out endPointCertificate))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No certificate named {certificateName} found in configuration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var certificate = endPoint.GetSection("Certificate");
|
||||||
|
|
||||||
|
if (certificate.GetChildren().Any())
|
||||||
|
{
|
||||||
|
endPointCertificate = CertificateLoader.Load(certificate, certificate["Password"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endPointCertificate != null)
|
||||||
|
{
|
||||||
|
listenOptions.UseHttps(endPointCertificate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="@(MetaPackagePackageReference)" />
|
<PackageReference Include="@(MetaPackagePackageReference)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore
|
namespace Microsoft.AspNetCore
|
||||||
{
|
{
|
||||||
|
|
@ -182,6 +184,7 @@ namespace Microsoft.AspNetCore
|
||||||
.ConfigureServices(services =>
|
.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
services.AddSingleton<IStartupFilter, WebHostStartupFilter>();
|
services.AddSingleton<IStartupFilter, WebHostStartupFilter>();
|
||||||
|
services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@
|
||||||
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
|
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\TestArtifacts\testCert.pfx" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore\Microsoft.AspNetCore.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore\Microsoft.AspNetCore.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
@ -17,4 +21,8 @@
|
||||||
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -4,9 +4,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
|
@ -74,6 +77,129 @@ namespace Microsoft.AspNetCore.Tests
|
||||||
}, setTestEnvVars: true);
|
}, setTestEnvVars: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("127.0.0.1", "127.0.0.1")]
|
||||||
|
[InlineData("::1", "[::1]")]
|
||||||
|
public async Task BindsKestrelHttpEndPointFromConfiguration(string endPointAddress, string requestAddress)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText("appsettings.json", @"
|
||||||
|
{
|
||||||
|
""Kestrel"": {
|
||||||
|
""EndPoints"": {
|
||||||
|
""EndPoint"": {
|
||||||
|
""Address"": """ + endPointAddress + @""",
|
||||||
|
""Port"": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
");
|
||||||
|
using (var webHost = WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
|
||||||
|
{
|
||||||
|
var port = GetWebHostPort(webHost);
|
||||||
|
|
||||||
|
Assert.NotEqual(0, port);
|
||||||
|
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
var response = await client.GetAsync($"http://{requestAddress}:{port}");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete("appsettings.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BindsKestrelHttpsEndPointFromConfiguration_ReferencedCertificateFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText("appsettings.json", @"
|
||||||
|
{
|
||||||
|
""Kestrel"": {
|
||||||
|
""EndPoints"": {
|
||||||
|
""EndPoint"": {
|
||||||
|
""Address"": ""127.0.0.1"",
|
||||||
|
""Port"": 0,
|
||||||
|
""Certificate"": ""TestCert""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
""Certificates"": {
|
||||||
|
""TestCert"": {
|
||||||
|
""Source"": ""File"",
|
||||||
|
""Path"": ""testCert.pfx"",
|
||||||
|
""Password"": ""testPassword""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
");
|
||||||
|
using (var webHost = WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
|
||||||
|
{
|
||||||
|
var port = GetWebHostPort(webHost);
|
||||||
|
|
||||||
|
Assert.NotEqual(0, port);
|
||||||
|
|
||||||
|
using (var client = new HttpClient(new HttpClientHandler { ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true }))
|
||||||
|
{
|
||||||
|
var response = await client.GetAsync($"https://127.0.0.1:{port}");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete("appsettings.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BindsKestrelHttpsEndPointFromConfiguration_InlineCertificateFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText("appsettings.json", @"
|
||||||
|
{
|
||||||
|
""Kestrel"": {
|
||||||
|
""EndPoints"": {
|
||||||
|
""EndPoint"": {
|
||||||
|
""Address"": ""127.0.0.1"",
|
||||||
|
""Port"": 0,
|
||||||
|
""Certificate"": {
|
||||||
|
""Source"": ""File"",
|
||||||
|
""Path"": ""testCert.pfx"",
|
||||||
|
""Password"": ""testPassword""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
");
|
||||||
|
using (var webHost = WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
|
||||||
|
{
|
||||||
|
var port = GetWebHostPort(webHost);
|
||||||
|
|
||||||
|
Assert.NotEqual(0, port);
|
||||||
|
|
||||||
|
using (var client = new HttpClient(new HttpClientHandler { ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true }))
|
||||||
|
{
|
||||||
|
var response = await client.GetAsync($"https://127.0.0.1:{port}");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete("appsettings.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ExecuteStartOrStartWithTest(Func<DeploymentResult, Task<HttpResponseMessage>> getResponse, string applicationName)
|
private async Task ExecuteStartOrStartWithTest(Func<DeploymentResult, Task<HttpResponseMessage>> getResponse, string applicationName)
|
||||||
{
|
{
|
||||||
await ExecuteTestApp(applicationName, async (deploymentResult, logger) =>
|
await ExecuteTestApp(applicationName, async (deploymentResult, logger) =>
|
||||||
|
|
@ -135,5 +261,10 @@ namespace Microsoft.AspNetCore.Tests
|
||||||
|
|
||||||
throw new Exception($"Solution root could not be found using {applicationBasePath}");
|
throw new Exception($"Solution root could not be found using {applicationBasePath}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetWebHostPort(IWebHost webHost)
|
||||||
|
=> webHost.ServerFeatures.Get<IServerAddressesFeature>().Addresses
|
||||||
|
.Select(serverAddress => new Uri(serverAddress).Port)
|
||||||
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
Loading…
Reference in New Issue