Skip to content

Commit

Permalink
Summarize needed license on shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
josephdecock committed Dec 4, 2024
1 parent d685b97 commit 444a2ac
Show file tree
Hide file tree
Showing 22 changed files with 305 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ public static IIdentityServerBuilder AddCoreServices(this IIdentityServerBuilder

builder.Services.AddSingleton<ILicenseAccessor, LicenseAccessor>();
builder.Services.AddSingleton<IProtocolRequestCounter, ProtocolRequestCounter>();
builder.Services.AddSingleton<IFeatureManager, FeatureManager>();
builder.Services.AddSingleton<ILicenseUsageService, LicenseUsageService>();
builder.Services.AddHostedService<UsageSummaryService>();

return builder;
}
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 Duende.IdentityServer.Licensing.v2;
using Duende.IdentityServer.Stores;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
Expand All @@ -20,22 +21,26 @@ public class PostConfigureApplicationCookieTicketStore : IPostConfigureOptions<C
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly string _scheme;
private readonly ILicenseUsageService _licenseUsage;
private readonly ILogger<PostConfigureApplicationCookieTicketStore> _logger;

/// <summary>
/// ctor
/// </summary>
/// <param name="httpContextAccessor"></param>
/// <param name="identityServerOptions"></param>
/// <param name="licenseUsage"></param>
/// <param name="options"></param>
/// <param name="logger"></param>
public PostConfigureApplicationCookieTicketStore(
IHttpContextAccessor httpContextAccessor,
IdentityServerOptions identityServerOptions,
ILicenseUsageService licenseUsage,
IOptions<Microsoft.AspNetCore.Authentication.AuthenticationOptions> options,
ILogger<PostConfigureApplicationCookieTicketStore> logger)
{
_httpContextAccessor = httpContextAccessor;
_licenseUsage = licenseUsage;
_logger = logger;

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

IdentityServerLicenseValidator.Instance.ValidateServerSideSessions();
_licenseUsage.UseFeature(LicenseFeature.ServerSideSessions);

var sessionStore = _httpContextAccessor.HttpContext!.RequestServices.GetService<IServerSideSessionStore>();
if (sessionStore is InMemoryServerSideSessionStore)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ internal static void Validate(this IApplicationBuilder app)
var options = serviceProvider.GetRequiredService<IdentityServerOptions>();
var env = serviceProvider.GetRequiredService<IHostEnvironment>();
IdentityServerLicenseValidator.Instance.Initialize(loggerFactory, options, env.IsDevelopment());
if (options.KeyManagement.Enabled)
{
var licenseUsage = serviceProvider.GetRequiredService<ILicenseUsageService>();
licenseUsage.UseFeature(LicenseFeature.KeyManagement);
}

TestService(serviceProvider, typeof(IPersistedGrantStore), logger, "No storage mechanism for grants specified. Use the 'AddInMemoryPersistedGrants' extension method to register a development version.");
TestService(serviceProvider, typeof(IClientStore), logger, "No storage mechanism for clients specified. Use the 'AddInMemoryClients' extension method to register a development version.");
Expand Down Expand Up @@ -111,8 +116,8 @@ private static void ValidateLicenseServices(IServiceProvider serviceProvider)
throw new InvalidOperationException("Detected a custom IProtocolRequestCounter implementation. The default IProtocolRequestCounter is required.");
}

var featureManager = serviceProvider.GetRequiredService<IFeatureManager>();
if (featureManager is not FeatureManager)
var featureManager = serviceProvider.GetRequiredService<ILicenseUsageService>();
if (featureManager is not LicenseUsageService)
{
throw new InvalidOperationException("Detected a custom IFeatureManager implementation. The default IFeatureManager is required.");
}
Expand Down
4 changes: 2 additions & 2 deletions src/IdentityServer/Endpoints/PushedAuthorizationEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ internal class PushedAuthorizationEndpoint : IEndpointHandler
private readonly IClientSecretValidator _clientValidator;
private readonly IPushedAuthorizationRequestValidator _parValidator;
private readonly IPushedAuthorizationResponseGenerator _responseGenerator;
private readonly IFeatureManager _features;
private readonly ILicenseUsageService _features;
private readonly IdentityServerOptions _options;
private readonly ILogger<PushedAuthorizationEndpoint> _logger;

public PushedAuthorizationEndpoint(
IClientSecretValidator clientValidator,
IPushedAuthorizationRequestValidator parValidator,
IPushedAuthorizationResponseGenerator responseGenerator,
IFeatureManager features,
ILicenseUsageService features,
IdentityServerOptions options,
ILogger<PushedAuthorizationEndpoint> logger
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ class DynamicAuthenticationSchemeProvider : IAuthenticationSchemeProvider
{
private readonly IAuthenticationSchemeProvider _inner;
private readonly DynamicProviderOptions _options;
private readonly IFeatureManager _features;
private readonly ILicenseUsageService _features;

private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<DynamicAuthenticationSchemeProvider> _logger;

public DynamicAuthenticationSchemeProvider(
Decorator<IAuthenticationSchemeProvider> inner,
DynamicProviderOptions options,
IFeatureManager features,
ILicenseUsageService features,
IHttpContextAccessor httpContextAccessor,
ILogger<DynamicAuthenticationSchemeProvider> logger)
{
Expand Down
10 changes: 7 additions & 3 deletions src/IdentityServer/Hosting/IdentityServerMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Duende.IdentityServer.Models;
using System.Linq;
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Licensing.v2;

namespace Duende.IdentityServer.Hosting;

Expand Down Expand Up @@ -44,6 +45,7 @@ public IdentityServerMiddleware(RequestDelegate next, ILogger<IdentityServerMidd
/// <param name="events">The event service.</param>
/// <param name="issuerNameService">The issuer name service</param>
/// <param name="sessionCoordinationService"></param>
/// <param name="licenseUsage"></param>
/// <returns></returns>
public async Task Invoke(
HttpContext context,
Expand All @@ -52,7 +54,8 @@ public async Task Invoke(
IUserSession userSession,
IEventService events,
IIssuerNameService issuerNameService,
ISessionCoordinationService sessionCoordinationService)
ISessionCoordinationService sessionCoordinationService,
ILicenseUsageService licenseUsage)
{
// this will check the authentication session and from it emit the check session
// cookie needed from JS-based signout clients.
Expand Down Expand Up @@ -97,8 +100,9 @@ public async Task Invoke(
using var activity = Tracing.BasicActivitySource.StartActivity("IdentityServerProtocolRequest");
activity?.SetTag(Tracing.Properties.EndpointType, endpointType);

// TODO - Consider how to use the new licensing system here
IdentityServerLicenseValidator.Instance.ValidateIssuer(await issuerNameService.GetCurrentAsync());
var issuer = await issuerNameService.GetCurrentAsync();
licenseUsage.UseIssuer(issuer);
IdentityServerLicenseValidator.Instance.ValidateIssuer(issuer);

_logger.LogInformation("Invoking IdentityServer endpoint: {endpointType} for {url}", endpointType, requestPath);

Expand Down
62 changes: 0 additions & 62 deletions src/IdentityServer/Licensing/v2/FeatureManager.cs

This file was deleted.

14 changes: 0 additions & 14 deletions src/IdentityServer/Licensing/v2/IFeatureManager.cs

This file was deleted.

42 changes: 42 additions & 0 deletions src/IdentityServer/Licensing/v2/ILicenseUsageService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

#nullable enable

using System.Collections.Generic;

namespace Duende.IdentityServer.Licensing.v2;

/// <summary>
/// Tracks the usage of the license.
/// </summary>
public interface ILicenseUsageService
{
/// <summary>
/// Gets the licensed features that have been used.
/// </summary>
HashSet<LicenseFeature> UsedFeatures { get; }
/// <summary>
/// Indicates that a licensed feature has been used.
/// </summary>
void UseFeature(LicenseFeature feature);

/// <summary>
/// Gets the client ids that have been used.
/// </summary>
HashSet<string> UsedClients { get; }
/// <summary>
/// Indicates that a client id has been used.
/// </summary>
void UseClient(string clientId);


/// <summary>
/// Gets the issuers that have been used.
/// </summary>
HashSet<string> UsedIssuers { get; }
/// <summary>
/// Indicates that an issuer has been used.
/// </summary>
void UseIssuer(string issuer);
}
1 change: 0 additions & 1 deletion src/IdentityServer/Licensing/v2/License.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#nullable enable

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand Down
2 changes: 1 addition & 1 deletion src/IdentityServer/Licensing/v2/LicenseFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public enum LicenseFeature : ulong
ISV = 256,

/// <summary>
/// Dedistribution
/// Redistribution
/// </summary>
[Description("redistribution")]
Redistribution = 512,
Expand Down
56 changes: 56 additions & 0 deletions src/IdentityServer/Licensing/v2/LicenseUsageService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

#nullable enable

using System.Collections.Generic;
using System.Linq;

namespace Duende.IdentityServer.Licensing.v2;

internal class LicenseUsageService : ILicenseUsageService
{
private void EnsureAdded<T>(ref HashSet<T> hashSet, object lockObject, T key)
{
// Lock free test first.
if (!hashSet.Contains(key))
{
lock (lockObject)
{
// Check again after lock, to quit early if another thread
// already did the job.
if (!hashSet.Contains(key))
{
// The HashSet is not thread safe. And we don't want to lock for every single
// time we use it. Our access pattern should be a lot of reads and a few writes
// so better to create a new copy every time we need to add a value.
var newSet = new HashSet<T>(hashSet)
{
key
};

// Reference assignment is atomic so non-locked readers will handle this.
hashSet = newSet;
}
}
}
}

// Features
private readonly object _featureLock = new();
private HashSet<LicenseFeature> _features = new();
public HashSet<LicenseFeature> UsedFeatures => _features;
public void UseFeature(LicenseFeature feature) => EnsureAdded(ref _features, _featureLock, feature);

// Clients
private readonly object _clientLock = new();
private HashSet<string> _clients = new();
public HashSet<string> UsedClients => _clients;
public void UseClient(string clientId) => EnsureAdded(ref _clients, _clientLock, clientId);

// Issuers
private readonly object _issuerLock = new();
private HashSet<string> _issuers = new();
public HashSet<string> UsedIssuers => _issuers;
public void UseIssuer(string issuer) => EnsureAdded(ref _issuers, _issuerLock, issuer);
}
28 changes: 28 additions & 0 deletions src/IdentityServer/Licensing/v2/LicenseUsageServiceExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

#nullable enable

using System.Collections.Generic;
using System.Linq;

namespace Duende.IdentityServer.Licensing.v2;

internal static class LicenseUsageServiceExtensions
{
internal static void UseResourceIndicator(this ILicenseUsageService licenseUsage, string? resourceIndicator)
{
if (!string.IsNullOrWhiteSpace(resourceIndicator))
{
licenseUsage.UseFeature(LicenseFeature.ResourceIsolation);
}
}

internal static void UseResourceIndicators(this ILicenseUsageService licenseUsage, IEnumerable<string> resourceIndicators)
{
if (resourceIndicators.Any())
{
licenseUsage.UseFeature(LicenseFeature.ResourceIsolation);
}
}
}
Loading

0 comments on commit 444a2ac

Please sign in to comment.