Skip to content

Commit

Permalink
License updates
Browse files Browse the repository at this point in the history
- Make services private
- Add public LicenseSummary
- Show how to use LicenseSummary in main host
- Remove license usage hosted service
- Track used license features by minimum license level that supports them
  • Loading branch information
josephdecock committed Dec 4, 2024
1 parent bb04af5 commit 87c30c6
Show file tree
Hide file tree
Showing 22 changed files with 247 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"name": "host: main (dotnet 8)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-host-main",
"preLaunchTask": "build-host-main-8",
"program": "${workspaceFolder}/hosts/main/bin/Debug/net8.0/Host.Main.dll",
"args": [],
"cwd": "${workspaceFolder}/hosts/main",
Expand Down
14 changes: 14 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,26 @@
//-------
// Hosts
//-------
{
"label": "build-host-main-8",
"type": "process",
"command": "dotnet",
"args": [
"build",
"--framework=net8.0",
"${workspaceFolder}/hosts/main/Host.Main.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-host-main",
"type": "process",
"command": "dotnet",
"args": [
"build",
"--framework=net9.0",
"${workspaceFolder}/hosts/main/Host.Main.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
Expand Down
5 changes: 3 additions & 2 deletions hosts/main/IdentityServerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicatio
UseX509Certificate = true
});
})
//.AddServerSideSessions()
.AddServerSideSessions()
.AddInMemoryClients(Clients.Get().ToList())
.AddInMemoryIdentityResources(Resources.IdentityResources)
.AddInMemoryApiScopes(Resources.ApiScopes)
Expand All @@ -64,7 +64,8 @@ internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicatio
ResponseType = "id_token",
Scope = "openid profile"
}
]);
])
.AddLicenseSummary();


builder.Services.AddDistributedMemoryCache();
Expand Down
5 changes: 5 additions & 0 deletions hosts/main/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

using Duende.IdentityServer.Licensing.v2;
using IdentityServerHost;
using Serilog;
using Serilog.Events;
Expand Down Expand Up @@ -36,7 +37,11 @@
.ConfigureServices()
.ConfigurePipeline();

var license = app.Services.GetRequiredService<ILicenseSummary>();

app.Run();

Console.Write(license.Summary);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ public static IIdentityServerBuilder AddCoreServices(this IIdentityServerBuilder
builder.Services.AddSingleton<ILicenseAccessor, LicenseAccessor>();
builder.Services.AddSingleton<IProtocolRequestCounter, ProtocolRequestCounter>();
builder.Services.AddSingleton<ILicenseUsageService, LicenseUsageService>();
builder.Services.AddHostedService<UsageSummaryService>();

return builder;
}
Expand Down Expand Up @@ -398,6 +397,15 @@ public static IIdentityServerBuilder AddDefaultSecretValidators(this IIdentitySe
return builder;
}

/// <summary>
/// Adds the license summary, which provides information about the current license usage.
/// </summary>
public static IIdentityServerBuilder AddLicenseSummary(this IIdentityServerBuilder builder)
{
builder.Services.AddSingleton<ILicenseSummary, LicenseSummary>();
return builder;
}

internal static void AddTransientDecorator<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,16 @@ public class PostConfigureApplicationCookieTicketStore : IPostConfigureOptions<C
/// </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;
_licenseUsage = httpContextAccessor.HttpContext?.RequestServices.GetRequiredService<ILicenseUsageService>();
_logger = logger;

_scheme = identityServerOptions.Authentication.CookieAuthenticationScheme ??
Expand Down
6 changes: 3 additions & 3 deletions src/IdentityServer/Hosting/IdentityServerMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Linq;
using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Licensing.v2;
using Microsoft.Extensions.DependencyInjection;

namespace Duende.IdentityServer.Hosting;

Expand Down Expand Up @@ -45,7 +46,6 @@ 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 @@ -54,8 +54,7 @@ public async Task Invoke(
IUserSession userSession,
IEventService events,
IIssuerNameService issuerNameService,
ISessionCoordinationService sessionCoordinationService,
ILicenseUsageService licenseUsage)
ISessionCoordinationService sessionCoordinationService)
{
// this will check the authentication session and from it emit the check session
// cookie needed from JS-based signout clients.
Expand Down Expand Up @@ -101,6 +100,7 @@ public async Task Invoke(
activity?.SetTag(Tracing.Properties.EndpointType, endpointType);

var issuer = await issuerNameService.GetCurrentAsync();
var licenseUsage = context.RequestServices.GetRequiredService<ILicenseUsageService>();
licenseUsage.UseIssuer(issuer);
IdentityServerLicenseValidator.Instance.ValidateIssuer(issuer);

Expand Down
2 changes: 1 addition & 1 deletion src/IdentityServer/Licensing/v2/ILicenseAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Duende.IdentityServer.Licensing.v2;
/// <summary>
/// Provides access to the current License.
/// </summary>
public interface ILicenseAccessor
internal interface ILicenseAccessor
{
/// <summary>
/// Gets the current IdentityServer license.
Expand Down
49 changes: 49 additions & 0 deletions src/IdentityServer/Licensing/v2/ILicenseSummary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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>
/// Summarizes the usage of IdentityServer
/// </summary>
public interface ILicenseSummary
{
/// <summary>
/// Summarizes the usage of IdentityServer, including licensed features, clients, and issuers.
/// </summary>
public string Summary { get; }

/// <summary>
/// Gets the license edition.
/// </summary>
public string LicenseEdition { get; }

/// <summary>
/// Gets the licensed enterprise edition features that have been used.
/// </summary>
IEnumerable<string> EnterpriseFeaturesUsed { get; }

/// <summary>
/// Gets the licensed business edition features that have been used.
/// </summary>
IEnumerable<string> BusinessFeaturesUsed { get; }

/// <summary>
/// Gets other licensed features that have been used.
/// </summary>
IEnumerable<string> OtherFeaturesUsed { get; }

/// <summary>
/// Gets the client ids that have been used.
/// </summary>
IEnumerable<string> UsedClients { get; }

/// <summary>
/// Gets the issuers that have been used.
/// </summary>
IEnumerable<string> UsedIssuers { get; }
}
17 changes: 14 additions & 3 deletions src/IdentityServer/Licensing/v2/ILicenseUsageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,23 @@ namespace Duende.IdentityServer.Licensing.v2;
/// <summary>
/// Tracks the usage of the license.
/// </summary>
public interface ILicenseUsageService
internal interface ILicenseUsageService
{
/// <summary>
/// Gets the licensed features that have been used.
/// Gets the licensed business edition features that have been used.
/// </summary>
HashSet<LicenseFeature> UsedFeatures { get; }
HashSet<LicenseFeature> BusinessFeaturesUsed { get; }

/// <summary>
/// Gets the licensed enterprise edition features that have been used.
/// </summary>
HashSet<LicenseFeature> EnterpriseFeaturesUsed { get; }

/// <summary>
/// Gets other licensed features that have been used.
/// </summary>
HashSet<LicenseFeature> OtherFeaturesUsed { get; }

/// <summary>
/// Indicates that a licensed feature has been used.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/IdentityServer/Licensing/v2/License.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Duende.IdentityServer.Licensing.v2;
/// <summary>
/// Models a Duende commercial license.
/// </summary>
public sealed class License
internal class License // TODO - make this internal, and consider a public type that constrains what we show externally
{

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/IdentityServer/Licensing/v2/LicenseEdition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Duende.IdentityServer.Licensing.v2;
/// <summary>
/// The editions of our license, which give access to different features.
/// </summary>
public enum LicenseEdition
internal enum LicenseEdition
{
/// <summary>
/// Enterprise license edition
Expand Down
4 changes: 2 additions & 2 deletions src/IdentityServer/Licensing/v2/LicenseFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Duende.IdentityServer.Licensing.v2;
/// <summary>
/// The features of IdentityServer that can be enabled or disabled through the License.
/// </summary>
public enum LicenseFeature : ulong
internal enum LicenseFeature : ulong
{
/// <summary>
/// Automatic Key Management
Expand Down Expand Up @@ -48,7 +48,7 @@ public enum LicenseFeature : ulong
ServerSideSessions = 32,

/// <summary>
/// Demonstrating Proof of Possesion
/// Demonstrating Proof of Possession
/// </summary>
[Description("dpop")]
DPoP = 64,
Expand Down
51 changes: 51 additions & 0 deletions src/IdentityServer/Licensing/v2/LicenseSummary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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;
using System.Text;

namespace Duende.IdentityServer.Licensing.v2;

internal class LicenseSummary(ILicenseAccessor license, ILicenseUsageService usage) : ILicenseSummary
{
public string Summary
{
get
{
var sb = new StringBuilder();
sb.AppendLine("IdentityServer Usage Summary:");
sb.AppendLine($"\tLicense: {LicenseEdition}");

AppendSummary(sb, "Client Ids Used", usage.UsedClients);
AppendSummary(sb, "Business Edition Features Used", usage.BusinessFeaturesUsed);
AppendSummary(sb, "Enterprise Edition Features Used", usage.EnterpriseFeaturesUsed);
AppendSummary(sb, "Other Features Used", usage.OtherFeaturesUsed);
AppendSummary(sb, "Issuers Used", usage.UsedIssuers);

return sb.ToString();
}
}

private void AppendSummary<T>(StringBuilder sb, string label, IReadOnlyCollection<T> items)
{
if (items.Count == 1)
{
sb.AppendLine($"\t{label}: {items.Single()}");
}
else if (items.Count > 1)
{
sb.AppendLine($"\t{label}s: {string.Join(", ", items)}");
}
}

public string LicenseEdition => license.Current.Edition?.ToString() ?? "None";
public IEnumerable<string> UsedClients => usage.UsedClients;
public IEnumerable<string> UsedIssuers => usage.UsedIssuers;

public IEnumerable<string> EnterpriseFeaturesUsed => usage.EnterpriseFeaturesUsed.Select(f => f.ToString());
public IEnumerable<string> BusinessFeaturesUsed => usage.BusinessFeaturesUsed.Select(f => f.ToString());
public IEnumerable<string> OtherFeaturesUsed => usage.OtherFeaturesUsed.Select(f => f.ToString());
}
33 changes: 29 additions & 4 deletions src/IdentityServer/Licensing/v2/LicenseUsageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#nullable enable

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

namespace Duende.IdentityServer.Licensing.v2;

Expand Down Expand Up @@ -38,9 +37,34 @@ private void EnsureAdded<T>(ref HashSet<T> hashSet, object lockObject, T key)

// 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);
private HashSet<LicenseFeature> _otherFeatures = new();
private HashSet<LicenseFeature> _businessFeatures = new();
private HashSet<LicenseFeature> _enterpriseFeatures = new();
public HashSet<LicenseFeature> BusinessFeaturesUsed => _businessFeatures;
public HashSet<LicenseFeature> EnterpriseFeaturesUsed => _enterpriseFeatures;
public HashSet<LicenseFeature> OtherFeaturesUsed => _otherFeatures;
public void UseFeature(LicenseFeature feature)
{
switch (feature)
{
case LicenseFeature.ResourceIsolation:
case LicenseFeature.DynamicProviders:
case LicenseFeature.CIBA:
case LicenseFeature.DPoP:
EnsureAdded(ref _enterpriseFeatures, _featureLock, feature);
break;
case LicenseFeature.KeyManagement:
case LicenseFeature.PAR:
case LicenseFeature.ServerSideSessions:
case LicenseFeature.DCR:
EnsureAdded(ref _businessFeatures, _featureLock, feature);
break;
case LicenseFeature.ISV:
case LicenseFeature.Redistribution:
EnsureAdded(ref _otherFeatures, _featureLock, feature);
break;
}
}

// Clients
private readonly object _clientLock = new();
Expand All @@ -52,5 +76,6 @@ private void EnsureAdded<T>(ref HashSet<T> hashSet, object lockObject, T key)
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);
}
Loading

0 comments on commit 87c30c6

Please sign in to comment.