Skip to content

Commit

Permalink
fix(is): service resolution from HttpContext
Browse files Browse the repository at this point in the history
Fix service resolution in PostConfigureApplicationCookieTicketStore so that it can be
constructed without an http context available.
  • Loading branch information
josephdecock committed Jan 5, 2025
1 parent 5c68cf3 commit d8fadf9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public class PostConfigureApplicationCookieTicketStore : IPostConfigureOptions<C
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly string _scheme;
private readonly LicenseUsageTracker _licenseUsage;
private readonly ILogger<PostConfigureApplicationCookieTicketStore> _logger;

/// <summary>
Expand All @@ -38,7 +37,6 @@ public PostConfigureApplicationCookieTicketStore(
ILogger<PostConfigureApplicationCookieTicketStore> logger)
{
_httpContextAccessor = httpContextAccessor;
_licenseUsage = httpContextAccessor.HttpContext?.RequestServices.GetRequiredService<LicenseUsageTracker>();
_logger = logger;

_scheme = identityServerOptions.Authentication.CookieAuthenticationScheme ??
Expand Down Expand Up @@ -69,6 +67,7 @@ public void PostConfigure(string name, CookieAuthenticationOptions options)
}

IdentityServerLicenseValidator.Instance.ValidateServerSideSessions();
var _licenseUsage = _httpContextAccessor.HttpContext?.RequestServices.GetRequiredService<LicenseUsageTracker>();
_licenseUsage.FeatureUsed(LicenseFeature.ServerSideSessions);

var sessionStore = _httpContextAccessor.HttpContext!.RequestServices.GetService<IServerSideSessionStore>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See LICENSE in the project root for license information.


using System;
using Duende.IdentityServer;
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Models;
Expand All @@ -24,7 +25,8 @@ public MockHttpContextAccessor(
IdentityServerOptions options = null,
IUserSession userSession = null,
IMessageStore<LogoutNotificationContext> endSessionStore = null,
IServerUrls urls = null)
IServerUrls urls = null,
Action<ServiceCollection> configureServices = null)
{
options = options ?? TestIdentityServerOptions.Create();

Expand Down Expand Up @@ -63,6 +65,11 @@ public MockHttpContextAccessor(
services.AddSingleton<IServerUrls>(urls);
}

if (configureServices != null)
{
configureServices(services);
}

_context.RequestServices = services.BuildServiceProvider();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Licensing.V2;
using FluentAssertions;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using UnitTests.Common;
using Xunit;

namespace UnitTests.Configuration.DependencyInjection;

public class PostConfigureApplicationCookieTicketStoreTests
{

[Fact]
public void can_be_constructed_without_httpcontext_and_used_later_with_httpcontext()
{
// Register the dependencies of the usage tracker so that we can resolve it in PostConfigure
var httpContextAccessor = new MockHttpContextAccessor(configureServices: sp =>
{
sp.AddSingleton(TestLogger.Create<LicenseAccessor>());
sp.AddSingleton<LicenseAccessor>();
sp.AddSingleton<LicenseUsageTracker>();
});

// The mock http context has a convenient HttpContext, but initially we
// simulate not having it by stashing it away and setting the accessor
// to null.
var savedContext = httpContextAccessor.HttpContext;
httpContextAccessor.HttpContext = null;

var sut = new PostConfigureApplicationCookieTicketStore(
httpContextAccessor,
new IdentityServerOptions
{
Authentication = new AuthenticationOptions
{
// This is needed so that we operate on the correct scheme
CookieAuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme
}
},
Options.Create<Microsoft.AspNetCore.Authentication.AuthenticationOptions>(new()),
TestLogger.Create<PostConfigureApplicationCookieTicketStore>()
);

// Now that we've constructed, we can bring back the http context and run PostConfigure
httpContextAccessor.HttpContext = savedContext;
var cookieOpts = new CookieAuthenticationOptions();
sut.PostConfigure(CookieAuthenticationDefaults.AuthenticationScheme, cookieOpts);

cookieOpts.SessionStore.Should().BeOfType<TicketStoreShim>();
}
}

0 comments on commit d8fadf9

Please sign in to comment.