diff --git a/identity-server/src/IdentityServer/Configuration/DependencyInjection/BuilderExtensions/Core.cs b/identity-server/src/IdentityServer/Configuration/DependencyInjection/BuilderExtensions/Core.cs index d64d082ed..7511256d4 100644 --- a/identity-server/src/IdentityServer/Configuration/DependencyInjection/BuilderExtensions/Core.cs +++ b/identity-server/src/IdentityServer/Configuration/DependencyInjection/BuilderExtensions/Core.cs @@ -217,6 +217,7 @@ public static IIdentityServerBuilder AddCoreServices(this IIdentityServerBuilder builder.Services.AddSingleton(new ServiceCollectionAccessor(builder.Services)); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); diff --git a/identity-server/src/IdentityServer/Licensing/V2/Diagnostics/DiagnosticEntries/DataProtectionDiagnosticEntry.cs b/identity-server/src/IdentityServer/Licensing/V2/Diagnostics/DiagnosticEntries/DataProtectionDiagnosticEntry.cs new file mode 100644 index 000000000..571e47e61 --- /dev/null +++ b/identity-server/src/IdentityServer/Licensing/V2/Diagnostics/DiagnosticEntries/DataProtectionDiagnosticEntry.cs @@ -0,0 +1,23 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using System.Text.Json; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.DataProtection.KeyManagement; +using Microsoft.Extensions.Options; + +namespace Duende.IdentityServer.Licensing.V2.Diagnostics.DiagnosticEntries; + +internal class DataProtectionDiagnosticEntry(IOptions dataProtectionOptions, IOptions keyManagementOptions) : IDiagnosticEntry +{ + public Task WriteAsync(Utf8JsonWriter writer) + { + writer.WriteStartObject("DataProtectionConfiguration"); + writer.WriteString("ApplicationDiscriminator", dataProtectionOptions?.Value?.ApplicationDiscriminator ?? "Not Configured"); + writer.WriteString("XmlEncryptor", keyManagementOptions?.Value.XmlEncryptor?.GetType().FullName ?? "Not Configured"); + writer.WriteString("XmlRepository", keyManagementOptions?.Value.XmlRepository?.GetType().FullName ?? "Not Configured"); + writer.WriteEndObject(); + + return Task.CompletedTask; + } +} diff --git a/identity-server/test/IdentityServer.UnitTests/Licensing/v2/DiagnosticEntries/DataProtectionDiagnosticEntryTests.cs b/identity-server/test/IdentityServer.UnitTests/Licensing/v2/DiagnosticEntries/DataProtectionDiagnosticEntryTests.cs new file mode 100644 index 000000000..094440197 --- /dev/null +++ b/identity-server/test/IdentityServer.UnitTests/Licensing/v2/DiagnosticEntries/DataProtectionDiagnosticEntryTests.cs @@ -0,0 +1,66 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using System.Xml.Linq; +using Duende.IdentityServer.Licensing.V2.Diagnostics.DiagnosticEntries; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.DataProtection.KeyManagement; +using Microsoft.AspNetCore.DataProtection.Repositories; +using Microsoft.AspNetCore.DataProtection.XmlEncryption; +using Microsoft.Extensions.Options; + +namespace IdentityServer.UnitTests.Licensing.V2.DiagnosticEntries; + +public class DataProtectionDiagnosticEntryTests +{ + [Fact] + public async Task WriteAsync_WithConfiguredOptions_ShouldWriteCorrectValues() + { + var dataProtectionOptions = Options.Create(new DataProtectionOptions + { + ApplicationDiscriminator = "TestApplication" + }); + var keyManagementOptions = Options.Create(new KeyManagementOptions + { + XmlEncryptor = new TestXmlEncryptor(), + XmlRepository = new TestXmlRepository() + }); + var subject = new DataProtectionDiagnosticEntry(dataProtectionOptions, keyManagementOptions); + + var result = await DiagnosticEntryTestHelper.WriteEntryToJson(subject); + + var dataProtectionConfiguration = result.RootElement.GetProperty("DataProtectionConfiguration"); + dataProtectionConfiguration.GetProperty("ApplicationDiscriminator").GetString().ShouldBe("TestApplication"); + dataProtectionConfiguration.GetProperty("XmlEncryptor").GetString().ShouldBe(typeof(TestXmlEncryptor).FullName); + dataProtectionConfiguration.GetProperty("XmlRepository").GetString().ShouldBe(typeof(TestXmlRepository).FullName); + } + + [Fact] + public async Task WriteAsync_WithDefaultOptions_ShouldWriteDefaultValues() + { + var subject = new DataProtectionDiagnosticEntry( + Options.Create(new DataProtectionOptions()), + Options.Create(new KeyManagementOptions())); + + var result = await DiagnosticEntryTestHelper.WriteEntryToJson(subject); + + var dataProtectionConfiguration = result.RootElement.GetProperty("DataProtectionConfiguration"); + dataProtectionConfiguration.GetProperty("ApplicationDiscriminator").GetString().ShouldBe("Not Configured"); + dataProtectionConfiguration.GetProperty("XmlEncryptor").GetString().ShouldBe("Not Configured"); + dataProtectionConfiguration.GetProperty("XmlRepository").GetString().ShouldBe("Not Configured"); + } + + private class TestXmlEncryptor : IXmlEncryptor + { + public EncryptedXmlInfo Encrypt(XElement plaintextElement) => new EncryptedXmlInfo(plaintextElement, typeof(TestXmlEncryptor)); + } + + private class TestXmlRepository : IXmlRepository + { + public IReadOnlyCollection GetAllElements() => Array.Empty(); + + public void StoreElement(XElement element, string friendlyName) + { + } + } +}