Compare commits
5 Commits
0235f81003
...
74444d301d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74444d301d | ||
|
|
2378b93579 | ||
|
|
85a047467e | ||
|
|
106d31b068 | ||
|
|
48f5c69c91 |
@@ -1,14 +0,0 @@
|
|||||||
using DigitalData.Core.Abstractions.Security;
|
|
||||||
|
|
||||||
namespace DigitalData.Auth.Client;
|
|
||||||
|
|
||||||
public class AsymmetricPublicKey : IUniqueSecurityContext, IAsymmetricPublicKey
|
|
||||||
{
|
|
||||||
public required string Issuer { get; init; }
|
|
||||||
|
|
||||||
public required string Audience { get; init; }
|
|
||||||
|
|
||||||
public string? Id { get; init; }
|
|
||||||
|
|
||||||
public string Content { get; internal set; } = string.Empty;
|
|
||||||
}
|
|
||||||
@@ -34,7 +34,7 @@ public class AuthClient : IAuthClient, IAsyncDisposable
|
|||||||
|
|
||||||
public bool IsConnected { get; private set; } = false;
|
public bool IsConnected { get; private set; } = false;
|
||||||
|
|
||||||
public IEnumerable<AsymmetricPublicKey> PublicKeys => _params.PublicKeys;
|
public IEnumerable<ClientPublicKey> PublicKeys => _params.PublicKeys;
|
||||||
|
|
||||||
public async Task StartAsync()
|
public async Task StartAsync()
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ public class AuthClient : IAuthClient, IAsyncDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ReceivePublicKeyAsync(string issuer, string audience, string message) => Task.Run(() => _params.TriggerOnMessageReceived(this, issuer, audience, message, _logger));
|
public Task ReceivePublicKeyAsync(string issuer, string audience, string message) => Task.Run(() => _params.TriggerOnPublicReceivedEvent(this, issuer, audience, message, _logger));
|
||||||
|
|
||||||
public Task SendPublicKeyAsync(string issuer, string audience, string message) => _connection.InvokeAsync(nameof(SendPublicKeyAsync), issuer, audience, message);
|
public Task SendPublicKeyAsync(string issuer, string audience, string message) => _connection.InvokeAsync(nameof(SendPublicKeyAsync), issuer, audience, message);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public static class ClientEvents
|
|||||||
public static readonly ClientEvent UpdatePublicKeys = (client, issuer, audience, content, logger) =>
|
public static readonly ClientEvent UpdatePublicKeys = (client, issuer, audience, content, logger) =>
|
||||||
{
|
{
|
||||||
if(client.PublicKeys.TryGet(issuer, audience, out var publicKey))
|
if(client.PublicKeys.TryGet(issuer, audience, out var publicKey))
|
||||||
publicKey.Content = content;
|
publicKey.UpdateContent(content);
|
||||||
else
|
else
|
||||||
logger?.LogWarning(
|
logger?.LogWarning(
|
||||||
"Failed to update public key: No matching key found. Issuer: {Issuer}, Audience: {Audience}. Ensure the key exists before attempting an update.", issuer, audience);
|
"Failed to update public key: No matching key found. Issuer: {Issuer}, Audience: {Audience}. Ensure the key exists before attempting an update.", issuer, audience);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using DigitalData.Auth.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace DigitalData.Auth.Client;
|
namespace DigitalData.Auth.Client;
|
||||||
@@ -25,10 +24,10 @@ public class ClientParams
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan? RetryDelay { get; set; }
|
public TimeSpan? RetryDelay { get; set; }
|
||||||
|
|
||||||
public event ClientEvent OnMessageReceived = ClientEvents.UpdatePublicKeys;
|
public event ClientEvent OnPublicKeyReceived = ClientEvents.UpdatePublicKeys;
|
||||||
|
|
||||||
internal void TriggerOnMessageReceived(AuthClient client, string issuer, string audience, string key, ILogger? logger = null)
|
internal void TriggerOnPublicReceivedEvent(AuthClient client, string issuer, string audience, string key, ILogger? logger = null)
|
||||||
=> OnMessageReceived(client, issuer, audience, key, logger);
|
=> OnPublicKeyReceived(client, issuer, audience, key, logger);
|
||||||
|
|
||||||
public ClientParams()
|
public ClientParams()
|
||||||
{
|
{
|
||||||
@@ -42,5 +41,5 @@ public class ClientParams
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AsymmetricPublicKey> PublicKeys { get; init; } = new();
|
public List<ClientPublicKey> PublicKeys { get; set; } = new();
|
||||||
}
|
}
|
||||||
39
DigitalData.Auth.Client/ClientPublicKey.cs
Normal file
39
DigitalData.Auth.Client/ClientPublicKey.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using DigitalData.Core.Abstractions.Security;
|
||||||
|
using DigitalData.Core.Security.RSAKey;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace DigitalData.Auth.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a public RSA key, allowing dynamic updates and PEM import functionality.
|
||||||
|
/// </summary>
|
||||||
|
public class ClientPublicKey : RSAKeyBase, IAsymmetricTokenValidator, IUniqueSecurityContext
|
||||||
|
{
|
||||||
|
public required string Issuer { get; init; }
|
||||||
|
|
||||||
|
public required string Audience { get; init; }
|
||||||
|
|
||||||
|
private string _content = string.Empty;
|
||||||
|
|
||||||
|
public override string Content
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _content;
|
||||||
|
}
|
||||||
|
init
|
||||||
|
{
|
||||||
|
UpdateContent(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateContent(string content)
|
||||||
|
{
|
||||||
|
_content = content;
|
||||||
|
RSA.ImportFromPem(content);
|
||||||
|
SecurityKey = new RsaSecurityKey(RSA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityKey SecurityKey { get; private set; } = new RsaSecurityKey(RSA.Create());
|
||||||
|
}
|
||||||
@@ -1,16 +1,20 @@
|
|||||||
using DigitalData.Auth.Abstractions;
|
using DigitalData.Auth.Abstractions;
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace DigitalData.Auth.Client;
|
namespace DigitalData.Auth.Client;
|
||||||
|
|
||||||
public static class DIExtensions
|
public static class DIExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddAuthHubClient(this IServiceCollection services, Action<ClientParams> options)
|
public static IServiceCollection AddAuthHubClient(this IServiceCollection services, IConfiguration? configuration = null, Action<ClientParams>? options = null)
|
||||||
{
|
{
|
||||||
|
var clientParams = configuration?.GetSection(nameof(ClientParams)).Get<ClientParams>() ?? new ClientParams();
|
||||||
|
options?.Invoke(clientParams);
|
||||||
services
|
services
|
||||||
.Configure(options)
|
.AddSingleton(Options.Create(clientParams))
|
||||||
.AddSingleton<IAuthClient, AuthClient>()
|
.AddSingleton<IAuthClient, AuthClient>()
|
||||||
.TryAddSingleton<HubConnectionBuilder>();
|
.TryAddSingleton<HubConnectionBuilder>();
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PackageId>DigitalData.Auth.Client</PackageId>
|
<PackageId>DigitalData.Auth.Client</PackageId>
|
||||||
<Version>1.1.0</Version>
|
<Version>1.1.4.1</Version>
|
||||||
<Description>DigitalData.Auth.Client is a SignalR-based authentication client that enables applications to connect to a central authentication hub for real-time message exchange. It provides seamless connection management, automatic reconnection (RetryPolicy), and event-driven communication (ClientEvents). The package includes dependency injection support via DIExtensions, allowing easy integration into ASP.NET Core applications. With built-in retry policies and secure message handling, it ensures a reliable and scalable authentication client for real-time authentication workflows.</Description>
|
<Description>DigitalData.Auth.Client is a SignalR-based authentication client that enables applications to connect to a central authentication hub for real-time message exchange. It provides seamless connection management, automatic reconnection (RetryPolicy), and event-driven communication (ClientEvents). The package includes dependency injection support via DIExtensions, allowing easy integration into ASP.NET Core applications. With built-in retry policies and secure message handling, it ensures a reliable and scalable authentication client for real-time authentication workflows.</Description>
|
||||||
<Company>Digital Data GmbH</Company>
|
<Company>Digital Data GmbH</Company>
|
||||||
<Product>Digital Data GmbH</Product>
|
<Product>Digital Data GmbH</Product>
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
<PackageIcon>auth_icon.png</PackageIcon>
|
<PackageIcon>auth_icon.png</PackageIcon>
|
||||||
<RepositoryUrl>http://git.dd:3000/AppStd/DigitalData.Auth</RepositoryUrl>
|
<RepositoryUrl>http://git.dd:3000/AppStd/DigitalData.Auth</RepositoryUrl>
|
||||||
<PackageTags>Digital Data Auth Authorization Authentication</PackageTags>
|
<PackageTags>Digital Data Auth Authorization Authentication</PackageTags>
|
||||||
<AssemblyVersion>1.1.0</AssemblyVersion>
|
<AssemblyVersion>1.1.4.1</AssemblyVersion>
|
||||||
<FileVersion>1.1.0</FileVersion>
|
<FileVersion>1.1.4.1</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="3.3.0" />
|
<PackageReference Include="DigitalData.Core.Abstractions" Version="3.3.0" />
|
||||||
|
<PackageReference Include="DigitalData.Core.Security" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class AuthHubTests
|
|||||||
Build = options =>
|
Build = options =>
|
||||||
{
|
{
|
||||||
var provider = new ServiceCollection()
|
var provider = new ServiceCollection()
|
||||||
.AddAuthHubClient(options)
|
.AddAuthHubClient(options: options)
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
|
|
||||||
_disposableAsync.Enqueue(provider);
|
_disposableAsync.Enqueue(provider);
|
||||||
@@ -98,7 +98,7 @@ public class AuthHubTests
|
|||||||
var provider_receiver = Build(opt =>
|
var provider_receiver = Build(opt =>
|
||||||
{
|
{
|
||||||
opt.Url = _hubUrl;
|
opt.Url = _hubUrl;
|
||||||
opt.OnMessageReceived += (client, issuer, audience, key, logger) =>
|
opt.OnPublicKeyReceived += (client, issuer, audience, key, logger) =>
|
||||||
{
|
{
|
||||||
rcv_issuer = issuer;
|
rcv_issuer = issuer;
|
||||||
rcv_audience = audience;
|
rcv_audience = audience;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class AuthClientTests
|
|||||||
Build = options =>
|
Build = options =>
|
||||||
{
|
{
|
||||||
var provider = new ServiceCollection()
|
var provider = new ServiceCollection()
|
||||||
.AddAuthHubClient(options)
|
.AddAuthHubClient(options: options)
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
|
|
||||||
_disposableAsync.Enqueue(provider);
|
_disposableAsync.Enqueue(provider);
|
||||||
@@ -143,7 +143,7 @@ public class AuthClientTests
|
|||||||
var provider_receiver = Build(opt =>
|
var provider_receiver = Build(opt =>
|
||||||
{
|
{
|
||||||
opt.Url = _hubUrl;
|
opt.Url = _hubUrl;
|
||||||
opt.OnMessageReceived += (client, issuer, audience, key, logger) =>
|
opt.OnPublicKeyReceived += (client, issuer, audience, key, logger) =>
|
||||||
{
|
{
|
||||||
rcv_issuer = issuer;
|
rcv_issuer = issuer;
|
||||||
rcv_audience = audience;
|
rcv_audience = audience;
|
||||||
@@ -180,7 +180,7 @@ public class AuthClientTests
|
|||||||
var provider = Build(opt =>
|
var provider = Build(opt =>
|
||||||
{
|
{
|
||||||
opt.Url = _hubUrl;
|
opt.Url = _hubUrl;
|
||||||
opt.OnMessageReceived += (client, issuer, audience, key, logger) => publicKey = key;
|
opt.OnPublicKeyReceived += (client, issuer, audience, key, logger) => publicKey = key;
|
||||||
});
|
});
|
||||||
var client = provider.GetRequiredService<IAuthClient>();
|
var client = provider.GetRequiredService<IAuthClient>();
|
||||||
await client.StartAsync();
|
await client.StartAsync();
|
||||||
@@ -206,7 +206,7 @@ public class AuthClientTests
|
|||||||
public async Task StartAsync_ShouldUpdateAllPublicKey()
|
public async Task StartAsync_ShouldUpdateAllPublicKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var publicKey = new AsymmetricPublicKey() { Issuer = "Foo", Audience = "Bar" };
|
var publicKey = new ClientPublicKey() { Issuer = "Foo", Audience = "Bar" };
|
||||||
var provider = Build(opt =>
|
var provider = Build(opt =>
|
||||||
{
|
{
|
||||||
opt.Url = _hubUrl;
|
opt.Url = _hubUrl;
|
||||||
@@ -229,7 +229,7 @@ public class AuthClientTests
|
|||||||
public async Task Reconnected_ShouldUpdateAllPublicKey()
|
public async Task Reconnected_ShouldUpdateAllPublicKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var publicKey = new AsymmetricPublicKey() { Issuer = "Foo", Audience = "Bar" };
|
var publicKey = new ClientPublicKey() { Issuer = "Foo", Audience = "Bar" };
|
||||||
var provider = Build(opt =>
|
var provider = Build(opt =>
|
||||||
{
|
{
|
||||||
opt.Url = _hubUrl;
|
opt.Url = _hubUrl;
|
||||||
|
|||||||
Reference in New Issue
Block a user