Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored the use of ClaimLite and ClaimsRecord into a single type. #1756

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bff/migrations/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<Import Project="../../samples.props" />
</Project>
4 changes: 2 additions & 2 deletions bff/migrations/UserSessionDb/UserSessionDb.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" >
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion bff/samples/Apis/Api.DPoP/Api.DPoP.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFrameworks>net9.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion bff/samples/Bff/Bff.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFrameworks>net9.0</TargetFrameworks>
<RootNamespace>Bff</RootNamespace>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
19 changes: 19 additions & 0 deletions bff/samples/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<!-- This line is needed because:

Aspire needs a single target framework
(until this is resolved: https://github.com/dotnet/aspire/issues/2962)

When you add <TargetFrameworks>net9.0</TargetFrameworks> then aspire thinks there are more than
one framework. But this causes a problem for the Directory.Packages.props file.

In the Directory.Packages.props where we check for $(TargetFramework) == 'net9.0',
which is ONLY set if you use <TargetFrameworks>net9.0</TargetFrameworks> in the csproj file, not
if you set <TargetFramework>.

Now normally it's not recommended to set both, however, since this is only for samples, AND
we do need this check, we're setting it here as well.

-->
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<Import Project="../../samples.props" />
</Project>
2 changes: 1 addition & 1 deletion bff/samples/Hosts.Tests/Hosts.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFrameworks>net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
Expand Down
41 changes: 41 additions & 0 deletions bff/src/Duende.Bff.Blazor.Client/ClaimRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Text.Json.Serialization;

namespace Duende.Bff;

/// <summary>
/// Serialization friendly claim.
///
/// Note, this is a copy of the ClaimRecord class from Duende.Bff, but since we can't create a reference to it, we need to copy it here.
/// We also can't link to it (as we do with the extensions) because the other ClaimRecord class is public and this one is intentionally internal.
/// </summary>
josephdecock marked this conversation as resolved.
Show resolved Hide resolved
internal class ClaimRecord()
{
/// <summary>
/// Serialization friendly claim
/// </summary>
/// <param name="type">The type</param>
/// <param name="value">The Value</param>
internal ClaimRecord(string type, object value) : this()
{
Type = type;
Value = value;
}

/// <summary>
/// The type
/// </summary>
[JsonPropertyName("type")]
public string Type { get; init; } = default!;

/// <summary>
/// The value
/// </summary>
[JsonPropertyName("value")]
public object Value { get; init; } = default!;

/// <summary>
/// The value type
/// </summary>
[JsonPropertyName("valueType")]
public string? ValueType { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="..\Duende.Bff\Shared\ClaimLite.cs" Link="Shared\ClaimLite.cs" />
<Compile Include="..\Duende.Bff\Shared\ClaimsLiteExtensions.cs" Link="Shared\ClaimsLiteExtensions.cs" />
<Compile Include="..\Duende.Bff\Shared\ClaimsPrincipalLite.cs" Link="Shared\ClaimsPrincipalLite.cs" />
<Compile Include="..\Duende.Bff\Shared\ClaimRecordExtensions.cs" Link="Shared\ClaimRecordExtensions.cs" />
<Compile Include="..\Duende.Bff\Shared\ClaimsPrincipalRecord.cs" Link="Shared\ClaimsPrincipalRecord.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ public async ValueTask<ClaimsPrincipal> GetUserAsync(bool useCache = true)
return _cachedUser;
}

// TODO - Consider using ClaimLite instead here
record ClaimRecord(string Type, object Value);

internal async Task<ClaimsPrincipal> FetchUser()
{
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal class PersistentUserService(PersistentComponentState state, ILogger<Per
/// <inheritdoc />
public ClaimsPrincipal GetPersistedUser()
{
if (!state.TryTakeFromJson<ClaimsPrincipalLite>(nameof(ClaimsPrincipalLite), out var lite) || lite is null)
if (!state.TryTakeFromJson<ClaimsPrincipalRecord>(nameof(ClaimsPrincipalRecord), out var lite) || lite is null)
{
logger.LogDebug("Failed to load persisted user.");
return new ClaimsPrincipal(new ClaimsIdentity());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ private async Task OnPersistingAsync()
var authenticationState = await _authenticationStateTask;

var claims = authenticationState.User.Claims
.Select(c => new ClaimLite
.Select(c => new ClaimRecord
{
Type = c.Type,
Value = c.Value?.ToString() ?? string.Empty,
ValueType = c.ValueType == ClaimValueTypes.String ? null : c.ValueType
}).ToArray();

var principal = new ClaimsPrincipalLite
var principal = new ClaimsPrincipalRecord
{
AuthenticationType = authenticationState.User.Identity!.AuthenticationType,
NameClaimType = authenticationState.User.Identities.First().NameClaimType,
Expand All @@ -90,7 +90,7 @@ private async Task OnPersistingAsync()

_logger.LogDebug("Persisting Authentication State");

_state.PersistAsJson(nameof(ClaimsPrincipalLite), principal);
_state.PersistAsJson(nameof(ClaimsPrincipalRecord), principal);
}


Expand Down
16 changes: 1 addition & 15 deletions bff/src/Duende.Bff/EndpointServices/User/DefaultUserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
Expand Down Expand Up @@ -134,20 +135,5 @@ protected virtual Task<IEnumerable<ClaimRecord>> GetManagementClaimsAsync(HttpCo

return Task.FromResult((IEnumerable<ClaimRecord>)claims);
}

/// <summary>
/// Serialization-friendly claim
/// </summary>
/// <param name="Type"></param>
/// <param name="Value"></param>
protected record ClaimRecord(string Type, object Value)
{
/// <summary></summary>
[JsonPropertyName("type")]
public string Type { get; init; } = Type;

/// <summary></summary>
[JsonPropertyName("value")]
public object Value { get; init; } = Value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ internal class AuthenticationTicketLite
/// <summary>
/// The user
/// </summary>
public ClaimsPrincipalLite User { get; set; } = default!;
public ClaimsPrincipalRecord User { get; set; } = default!;

/// <summary>
/// The items
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

using System.Text.Json.Serialization;

namespace Duende.Bff;

/// <summary>
/// Serialization friendly claim
/// </summary>
internal class ClaimLite
public class ClaimRecord()
{
/// <summary>
///
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
public ClaimRecord(string type, object value) : this()
{
Type = type;
Value = value;
}

/// <summary>
/// The type
/// </summary>
[JsonPropertyName("type")]
public string Type { get; init; } = default!;

/// <summary>
/// The value
/// </summary>
public string Value { get; init; } = default!;
[JsonPropertyName("value")]
public object Value { get; init; } = default!;

/// <summary>
/// The value type
/// </summary>
[JsonPropertyName("valueType")]
public string? ValueType { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

using System.Linq;
using System.Security.Claims;

namespace Duende.Bff;

internal static class ClaimsLiteExtensions
internal static class ClaimRecordExtensions
{
/// <summary>
/// Converts a ClaimsPrincipalLite to ClaimsPrincipal
/// </summary>
public static ClaimsPrincipal ToClaimsPrincipal(this ClaimsPrincipalLite principal)
public static ClaimsPrincipal ToClaimsPrincipal(this ClaimsPrincipalRecord principal)
{
var claims = principal.Claims.Select(x => new Claim(x.Type, x.Value, x.ValueType ?? ClaimValueTypes.String))
var claims = principal.Claims.Select(x => new Claim(x.Type, x.Value.ToString() ?? string.Empty, x.ValueType ?? ClaimValueTypes.String))
.ToArray();
var id = new ClaimsIdentity(claims, principal.AuthenticationType, principal.NameClaimType,
principal.RoleClaimType);
Expand All @@ -24,17 +23,17 @@ public static ClaimsPrincipal ToClaimsPrincipal(this ClaimsPrincipalLite princip
/// <summary>
/// Converts a ClaimsPrincipal to ClaimsPrincipalLite
/// </summary>
public static ClaimsPrincipalLite ToClaimsPrincipalLite(this ClaimsPrincipal principal)
public static ClaimsPrincipalRecord ToClaimsPrincipalLite(this ClaimsPrincipal principal)
{
var claims = principal.Claims.Select(
x => new ClaimLite
x => new ClaimRecord
{
Type = x.Type,
Value = x.Value,
ValueType = x.ValueType == ClaimValueTypes.String ? null : x.ValueType
}).ToArray();

return new ClaimsPrincipalLite
return new ClaimsPrincipalRecord
{
AuthenticationType = principal.Identity!.AuthenticationType,
NameClaimType = principal.Identities.First().NameClaimType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Duende.Bff;
/// <summary>
/// Serialization friendly ClaimsPrincipal
/// </summary>
internal class ClaimsPrincipalLite
internal class ClaimsPrincipalRecord
{
/// <summary>
/// The authentication type
Expand All @@ -26,5 +26,5 @@ internal class ClaimsPrincipalLite
/// <summary>
/// The claims
/// </summary>
public ClaimLite[] Claims { get; init; } = default!;
public ClaimRecord[] Claims { get; init; } = default!;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Security.Cryptography;
using System.Text.Json;
using System.Threading.Tasks;
using Duende.Bff.Tests.TestFramework;
using Duende.Bff.Tests.TestHosts;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
Expand Down Expand Up @@ -35,10 +36,10 @@
[Fact]
public async Task test_dpop()
{
var apiResult = await BffHost.BrowserClient.CallBffHostApi(
ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi(
url: BffHost.Url("/api_client/test")
);

Check failure on line 42 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 42 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 42 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 42 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)
apiResult.RequestHeaders["DPoP"].First().ShouldNotBeNullOrEmpty();

Check failure on line 43 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 43 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 43 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 43 in bff/test/Duende.Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

'TestBrowserClient.BffHostResponse' does not contain a definition for 'RequestHeaders' and no accessible extension method 'RequestHeaders' accepting a first argument of type 'TestBrowserClient.BffHostResponse' could be found (are you missing a using directive or an assembly reference?)
apiResult.RequestHeaders["Authorization"].First().StartsWith("DPoP ").ShouldBeTrue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@

using Duende.Bff.Tests.TestFramework;
using Duende.Bff.Tests.TestHosts;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
using System.Text.Json;
using Xunit.Abstractions;

namespace Duende.Bff.Tests.Endpoints
Expand Down Expand Up @@ -313,5 +308,5 @@

response.Content.Headers.Select(x => x.Key).ShouldNotContain("added-by-custom-default-transform",
"a custom transform doesn't run the defaults");
}

Check failure on line 311 in bff/test/Duende.Bff.Tests/Endpoints/RemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

The name 'JsonSerializer' does not exist in the current context

Check failure on line 311 in bff/test/Duende.Bff.Tests/Endpoints/RemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

The name 'JsonSerializer' does not exist in the current context

Check failure on line 311 in bff/test/Duende.Bff.Tests/Endpoints/RemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

The name 'JsonSerializer' does not exist in the current context

Check failure on line 311 in bff/test/Duende.Bff.Tests/Endpoints/RemoteEndpointTests.cs

View workflow job for this annotation

GitHub Actions / Build

The name 'JsonSerializer' does not exist in the current context
}
Expand Down
9 changes: 0 additions & 9 deletions bff/test/Duende.Bff.Tests/TestFramework/Records.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,4 @@ public record JsonRecord(string Type, JsonElement Value)
[JsonPropertyName("value")]
public JsonElement Value { get; } = Value;
}

public record ClaimRecord(string Type, string Value)
{
[JsonPropertyName("type")]
public string Type { get; } = Type;

[JsonPropertyName("value")]
public string Value { get; } = Value;
}
}
Loading