diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f86a62b..16510f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,13 @@ jobs: steps: - uses: actions/checkout@af513c7a016048ae468971c52ed77d9562c7c819 - - name: Setup net6 + - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: '6.0.x' + dotnet-version: | + 6.0.x + 7.0.x + 8.0.x - run: dotnet --info diff --git a/IdentityModel.OidcClient.sln b/IdentityModel.OidcClient.sln index cf52a7e..ac54fb3 100644 --- a/IdentityModel.OidcClient.sln +++ b/IdentityModel.OidcClient.sln @@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DPoPTests", "test\DPoPTests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClientWithBrowserAndDPoP", "clients\ConsoleClientWithBrowserAndDPoP\ConsoleClientWithBrowserAndDPoP.csproj", "{7DDDA872-49C0-43F0-8B88-2531BF828DDE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrimmableAnalysis", "test\TrimmableAnalysis\TrimmableAnalysis.csproj", "{672FE4E9-9071-4C59-95FC-F265DF6B2FF5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -63,6 +65,10 @@ Global {7DDDA872-49C0-43F0-8B88-2531BF828DDE}.Debug|Any CPU.Build.0 = Debug|Any CPU {7DDDA872-49C0-43F0-8B88-2531BF828DDE}.Release|Any CPU.ActiveCfg = Release|Any CPU {7DDDA872-49C0-43F0-8B88-2531BF828DDE}.Release|Any CPU.Build.0 = Release|Any CPU + {672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -76,6 +82,7 @@ Global {56EC3A58-33FE-4DCD-9D64-2A985DC58C2C} = {0B7CC363-CF34-4B40-A769-7E928A6B25AF} {0E1807AF-4142-4A3D-925C-BBA019E4E777} = {3DEB81D4-5B40-4D20-AC50-66D1CD6EA24A} {7DDDA872-49C0-43F0-8B88-2531BF828DDE} = {A4154BEB-4B4A-4A48-B75D-B52432304F36} + {672FE4E9-9071-4C59-95FC-F265DF6B2FF5} = {3DEB81D4-5B40-4D20-AC50-66D1CD6EA24A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {66951C2E-691F-408C-9283-F2455F390A9A} diff --git a/build/Program.cs b/build/Program.cs index 258d37b..bf3cb86 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -21,6 +21,7 @@ private static class Targets public const string Pack = "pack"; public const string SignBinary = "sign-binary"; public const string SignPackage = "sign-package"; + public const string TrimmableAnalysis = "trimmable-analysis"; } static async Task Main(string[] args) @@ -65,9 +66,14 @@ static async Task Main(string[] args) SignNuGet(); }); - Target("default", DependsOn(Targets.Test, Targets.Pack)); + Target(Targets.TrimmableAnalysis, () => + { + Run("dotnet", "publish test/TrimmableAnalysis -c Release -r win-x64"); + }); + + Target("default", DependsOn(Targets.Test, Targets.Pack, Targets.TrimmableAnalysis)); - Target("sign", DependsOn(Targets.Test, Targets.SignPackage)); + Target("sign", DependsOn(Targets.Test, Targets.SignPackage, Targets.TrimmableAnalysis)); await RunTargetsAndExitAsync(args, ex => ex is SimpleExec.ExitCodeException || ex.Message.EndsWith(envVarMissing)); } diff --git a/src/DPoP/DPoP.csproj b/src/DPoP/DPoP.csproj index f50f344..a0fe34d 100644 --- a/src/DPoP/DPoP.csproj +++ b/src/DPoP/DPoP.csproj @@ -39,7 +39,7 @@ - + diff --git a/src/OidcClient/Infrastructure/LogSerializer.cs b/src/OidcClient/Infrastructure/LogSerializer.cs index 0ed85a7..d70fb1e 100644 --- a/src/OidcClient/Infrastructure/LogSerializer.cs +++ b/src/OidcClient/Infrastructure/LogSerializer.cs @@ -1,9 +1,13 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +#if NET6_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +#endif using System.Text.Json; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace IdentityModel.OidcClient.Infrastructure { @@ -14,7 +18,7 @@ public static class LogSerializer { /// /// Allows log serialization to be disabled, for example, for platforms - /// that don't support serialization of arbitarary objects to JSON. + /// that don't support serialization of arbitrary objects to JSON. /// public static bool Enabled = true; @@ -34,9 +38,27 @@ static LogSerializer() /// /// The object. /// +#if NET6_0_OR_GREATER + [RequiresUnreferencedCode("The log serializer uses reflection in a way that is incompatible with trimming")] +#endif public static string Serialize(object logObject) { return Enabled ? JsonSerializer.Serialize(logObject, JsonOptions) : "Logging has been disabled"; } + + internal static string Serialize(OidcClientOptions opts) => Serialize(opts); + internal static string Serialize(AuthorizeState state) => Serialize(state); + + /// + /// Serializes the specified object. + /// + /// The object. + /// + private static string Serialize(T logObject) + { + return Enabled ? + JsonSerializer.Serialize(logObject, (JsonTypeInfo)SourceGenerationContext.Default.GetTypeInfo(typeof(T))) : + "Logging has been disabled"; + } } } \ No newline at end of file diff --git a/src/OidcClient/NoValidationIdentityTokenValidator.cs b/src/OidcClient/NoValidationIdentityTokenValidator.cs index 22c550f..3f053c4 100644 --- a/src/OidcClient/NoValidationIdentityTokenValidator.cs +++ b/src/OidcClient/NoValidationIdentityTokenValidator.cs @@ -2,6 +2,7 @@ using System.Security.Claims; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using IdentityModel.OidcClient.Results; @@ -26,10 +27,9 @@ public Task ValidateAsync(string identityToken, O } var payload = Encoding.UTF8.GetString((Base64Url.Decode(parts[1]))); + var values = JsonSerializer.Deserialize( + payload, SourceGenerationContext.Default.DictionaryStringJsonElement); - var values = - JsonSerializer.Deserialize>(payload); - var claims = new List(); foreach (var element in values) { @@ -43,7 +43,6 @@ public Task ValidateAsync(string identityToken, O else { claims.Add(new Claim(element.Key, element.Value.ToString())); - } } diff --git a/src/OidcClient/OidcClient.csproj b/src/OidcClient/OidcClient.csproj index 518b18b..6c4da54 100644 --- a/src/OidcClient/OidcClient.csproj +++ b/src/OidcClient/OidcClient.csproj @@ -4,14 +4,15 @@ IdentityModel.OidcClient IdentityModel.OidcClient IdentityModel.OidcClient - - netstandard2.0 - + + netstandard2.0;net6.0 + latest + OAuth2;OAuth 2.0;OpenID Connect;Security;Identity;IdentityServer RFC8252 compliant and certified OpenID Connect and OAuth 2.0 client library for native applications Dominick Baier;Brock Allen icon.jpg - + Apache-2.0 true @@ -24,12 +25,14 @@ embedded + + true + True - + ../../key.snk true true - @@ -37,11 +40,19 @@ - + + + + + + + + + \ No newline at end of file diff --git a/src/OidcClient/ResponseProcessor.cs b/src/OidcClient/ResponseProcessor.cs index 9980d45..4cb7fa9 100644 --- a/src/OidcClient/ResponseProcessor.cs +++ b/src/OidcClient/ResponseProcessor.cs @@ -1,15 +1,12 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - using IdentityModel.Client; using IdentityModel.OidcClient.Infrastructure; using IdentityModel.OidcClient.Results; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.Net; -using System.Security.Claims; using System.Threading; using System.Threading.Tasks; diff --git a/src/OidcClient/SourceGenerationContext.cs b/src/OidcClient/SourceGenerationContext.cs new file mode 100644 index 0000000..f42be6d --- /dev/null +++ b/src/OidcClient/SourceGenerationContext.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace IdentityModel.OidcClient +{ + [JsonSourceGenerationOptions( + WriteIndented = false, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + GenerationMode = JsonSourceGenerationMode.Metadata, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] + [JsonSerializable(typeof(AuthorizeState))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(OidcClientOptions))] + internal partial class SourceGenerationContext : JsonSerializerContext + { + } +} \ No newline at end of file diff --git a/test/DPoPTests/DPoPTests.csproj b/test/DPoPTests/DPoPTests.csproj index 5d1a056..ce0c530 100644 --- a/test/DPoPTests/DPoPTests.csproj +++ b/test/DPoPTests/DPoPTests.csproj @@ -1,7 +1,7 @@  - net6.0 + net6.0;net7.0;net8.0 diff --git a/test/JwtValidationTests/JwtValidationTests.csproj b/test/JwtValidationTests/JwtValidationTests.csproj index 25c74e0..e7822e7 100644 --- a/test/JwtValidationTests/JwtValidationTests.csproj +++ b/test/JwtValidationTests/JwtValidationTests.csproj @@ -1,7 +1,7 @@ - net6.0 + net6.0;net7.0;net8.0 diff --git a/test/OidcClient.Tests/LogSerializerTests.cs b/test/OidcClient.Tests/LogSerializerTests.cs new file mode 100644 index 0000000..646c10a --- /dev/null +++ b/test/OidcClient.Tests/LogSerializerTests.cs @@ -0,0 +1,28 @@ +// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +using FluentAssertions; +using System; +using Xunit; +using IdentityModel.OidcClient.Infrastructure; + +namespace IdentityModel.OidcClient.Tests +{ + public class LogSerializerTests + { + [Fact] + // This test exists to make sure that the public api for the log + // serializer can serialize types that aren't part of the source + // generation context. There is an internal api that does use the source + // generation context types. We should always use that other serialize + // method internally in order to be trimmable. The overload in this test + // exists to avoid a breaking change. + public void LogSerializer_should_serialize_arbitrary_types() + { + // We instantiate the test class as an example of a class that is + // not (and won't ever be) in the generation context. + var act = () => LogSerializer.Serialize(new LogSerializerTests()); + act.Should().NotThrow(); + } + } +} \ No newline at end of file diff --git a/test/TrimmableAnalysis/Program.cs b/test/TrimmableAnalysis/Program.cs new file mode 100644 index 0000000..3751555 --- /dev/null +++ b/test/TrimmableAnalysis/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/test/TrimmableAnalysis/README.md b/test/TrimmableAnalysis/README.md new file mode 100644 index 0000000..5199b0e --- /dev/null +++ b/test/TrimmableAnalysis/README.md @@ -0,0 +1,3 @@ +This project exists to facilitate analysis of trimmable warnings. + +See https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming \ No newline at end of file diff --git a/test/TrimmableAnalysis/TrimmableAnalysis.csproj b/test/TrimmableAnalysis/TrimmableAnalysis.csproj new file mode 100644 index 0000000..ea08cd2 --- /dev/null +++ b/test/TrimmableAnalysis/TrimmableAnalysis.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + enable + true + false + true + + + + + + + +