Skip to content

Commit

Permalink
fix: update UseServerCertificateSelector to call the original selector (
Browse files Browse the repository at this point in the history
  • Loading branch information
natemcmaster authored Mar 30, 2024
1 parent ba32cda commit dbe32b5
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</PropertyGroup>

<PropertyGroup>
<VersionPrefix>1.3.0</VersionPrefix>
<VersionPrefix>1.3.1</VersionPrefix>
<VersionSuffix>beta</VersionSuffix>
<IncludePreReleaseLabelInPackageVersion Condition="'$(IS_STABLE_BUILD)' != 'true'">true</IncludePreReleaseLabelInPackageVersion>
<BuildNumber Condition=" '$(BuildNumber)' == '' ">$([MSBuild]::ValueOrDefault($(BUILD_NUMBER), 0))</BuildNumber>
Expand Down
9 changes: 8 additions & 1 deletion src/Kestrel.Certificates/KestrelHttpsOptionsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ public static HttpsConnectionAdapterOptions UseServerCertificateSelector(
this HttpsConnectionAdapterOptions httpsOptions,
IServerCertificateSelector certificateSelector)
{
httpsOptions.ServerCertificateSelector = certificateSelector.Select!;
var fallbackSelector = httpsOptions.ServerCertificateSelector;
httpsOptions.ServerCertificateSelector = (connectionContext, domainName) =>
{
var primaryCert = certificateSelector.Select(connectionContext!, domainName);
// fallback to the original selector if the injected selector fails to find a certificate.
return primaryCert ?? fallbackSelector?.Invoke(connectionContext, domainName);
};

return httpsOptions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Nate McMaster.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Security.Cryptography.X509Certificates;
using McMaster.AspNetCore.Kestrel.Certificates;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Moq;
using Xunit;

namespace LettuceEncrypt.UnitTests;

using SelectorFunc = Func<ConnectionContext, string, X509Certificate2>;

public class KestrelHttpsOptionsExtensionsTests
{
[Fact]
public void UseServerCertificateSelectorFallsbackToOriginalSelector()
{
var injectedSelector = new Mock<IServerCertificateSelector>();
injectedSelector
.Setup(c => c.Select(It.IsAny<ConnectionContext>(), It.IsAny<string>()))
.Returns(() => null);

var originalSelectorWasCalled = false;
SelectorFunc originalSelector = (_, __) => { originalSelectorWasCalled = true; return null; };

var options = new HttpsConnectionAdapterOptions
{
ServerCertificateSelector = originalSelector
};

KestrelHttpsOptionsExtensions.UseServerCertificateSelector(options, injectedSelector.Object);
options.ServerCertificateSelector(null, null);

Assert.NotSame(options.ServerCertificateSelector, originalSelector);
Assert.True(originalSelectorWasCalled);
injectedSelector.VerifyAll();
}

[Fact]
public void UseServerCertificateSelectorDoesNotCallFallback()
{
var injectedSelector = new Mock<IServerCertificateSelector>();
injectedSelector
.Setup(c => c.Select(It.IsAny<ConnectionContext>(), It.IsAny<string>()))
.Returns(() => TestUtils.CreateTestCert("foo.test"));

var originalSelectorWasCalled = false;
SelectorFunc originalSelector = (_, __) => { originalSelectorWasCalled = true; return null; };

var options = new HttpsConnectionAdapterOptions
{
ServerCertificateSelector = originalSelector
};

KestrelHttpsOptionsExtensions.UseServerCertificateSelector(options, injectedSelector.Object);
options.ServerCertificateSelector(null, null);

Assert.NotSame(options.ServerCertificateSelector, originalSelector);
Assert.False(originalSelectorWasCalled);
injectedSelector.VerifyAll();
}
}

0 comments on commit dbe32b5

Please sign in to comment.