Skip to content

Commit

Permalink
Refactored the use of ClaimsLite and ClaimsRecord into a single type
Browse files Browse the repository at this point in the history
  • Loading branch information
Erwinvandervalk committed Feb 4, 2025
1 parent 68ef1f8 commit 56ee30f
Show file tree
Hide file tree
Showing 16 changed files with 103 additions and 46 deletions.
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 we had to make it public.
/// </summary>
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 @@ -7,9 +7,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
3 changes: 0 additions & 3 deletions bff/src/Duende.Bff.Blazor.Client/Internals/GetUserService.cs
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!;
}
2 changes: 1 addition & 1 deletion bff/test/Duende.Bff.Tests/TestHosts/ApiHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private void Configure(IApplicationBuilder app)
Path: context.Request.Path.Value ?? "/",
Sub: context.User.FindFirst("sub")?.Value,
ClientId: context.User.FindFirst("client_id")?.Value,
Claims: context.User.Claims.Select(x => new ClaimRecord(x.Type, x.Value)).ToArray())
Claims: context.User.Claims.Select(x => new TestFramework.ClaimRecord(x.Type, x.Value)).ToArray())
{
Body = body,
RequestHeaders = requestHeaders
Expand Down
10 changes: 5 additions & 5 deletions bff/test/Duende.Bff.Tests/TestHosts/BffHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private void Configure(IApplicationBuilder app)
context.Request.Path.Value ?? "/",
context.User.FindFirst("sub")?.Value,
context.User.FindFirst("client_id")?.Value,
context.User.Claims.Select(x => new ClaimRecord(x.Type, x.Value)).ToArray())
context.User.Claims.Select(x => new TestFramework.ClaimRecord(x.Type, x.Value)).ToArray())
{
Body = body,
RequestHeaders = requestHeaders
Expand Down Expand Up @@ -209,7 +209,7 @@ private void Configure(IApplicationBuilder app)
context.Request.Path.Value ?? "/",
context.User.FindFirst("sub")?.Value,
context.User.FindFirst("client_id")?.Value,
context.User.Claims.Select(x => new ClaimRecord(x.Type, x.Value)).ToArray())
context.User.Claims.Select(x => new TestFramework.ClaimRecord(x.Type, x.Value)).ToArray())
{
Body = body,
RequestHeaders = requestHeaders
Expand Down Expand Up @@ -263,7 +263,7 @@ private void Configure(IApplicationBuilder app)
context.Request.Path.Value ?? "/",
context.User.FindFirst("sub")?.Value,
context.User.FindFirst("client_id")?.Value,
context.User.Claims.Select(x => new ClaimRecord(x.Type, x.Value)).ToArray())
context.User.Claims.Select(x => new TestFramework.ClaimRecord(x.Type, x.Value)).ToArray())
{
Body = body,
RequestHeaders = requestHeaders
Expand Down Expand Up @@ -313,7 +313,7 @@ private void Configure(IApplicationBuilder app)
context.Request.Path.Value ?? "/",
sub,
context.User.FindFirst("client_id")?.Value,
context.User.Claims.Select(x => new ClaimRecord(x.Type, x.Value)).ToArray())
context.User.Claims.Select(x => new TestFramework.ClaimRecord(x.Type, x.Value)).ToArray())
{
Body = body
};
Expand Down Expand Up @@ -360,7 +360,7 @@ private void Configure(IApplicationBuilder app)
context.Request.Path.Value ?? "/",
sub,
context.User.FindFirst("client_id")?.Value,
context.User.Claims.Select(x => new ClaimRecord(x.Type, x.Value)).ToArray())
context.User.Claims.Select(x => new TestFramework.ClaimRecord(x.Type, x.Value)).ToArray())
{
Body = body
};
Expand Down

0 comments on commit 56ee30f

Please sign in to comment.