Compare commits
10 Commits
211064d44e
...
feat/secur
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad8d15314f | ||
|
|
f1efbae6a4 | ||
|
|
051567aa0a | ||
|
|
287871ddc6 | ||
|
|
a0ad8d732d | ||
|
|
3ad08e2a86 | ||
|
|
b90a52412c | ||
|
|
39091ff5cf | ||
|
|
22040cf1e7 | ||
|
|
af4b7d5438 |
@@ -9,7 +9,7 @@
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>DigitalData.Core.Abstractions</Product>
|
||||
<Description>This package contains abstractions for the DigitalData.Core.Abstractions library, developed according to the principles of Clean Architecture. It promotes separation of concerns and enables independent core logic.</Description>
|
||||
<Description>This package contains abstractions for the DigitalData.Core library, developed according to the principles of Clean Architecture. It promotes separation of concerns and enables independent core logic.</Description>
|
||||
<PackageTags>digital data core abstractions clean architecture</PackageTags>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Copyright>Copyright 2024</Copyright>
|
||||
@@ -17,9 +17,9 @@
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
|
||||
<PackAsTool>False</PackAsTool>
|
||||
<PackageIcon>core_icon.png</PackageIcon>
|
||||
<Version>3.0.0</Version>
|
||||
<AssemblyVersion>3.0.0</AssemblyVersion>
|
||||
<FileVersion>3.0.0</FileVersion>
|
||||
<Version>3.1.0</Version>
|
||||
<AssemblyVersion>3.1.0</AssemblyVersion>
|
||||
<FileVersion>3.1.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IAsymmetricKey
|
||||
{
|
||||
string Id { get; }
|
||||
string? Id { get; }
|
||||
|
||||
string Content { get; }
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace DigitalData.Core.Abstractions.Security
|
||||
/// </summary>
|
||||
public interface IAsymmetricTokenDescriptor : IAsymmetricPrivateKey, IUniqueSecurityContext
|
||||
{
|
||||
string? ApiRoute { get; }
|
||||
IAsymmetricTokenValidator Validator { get; }
|
||||
|
||||
TimeSpan Lifetime { get; init; }
|
||||
|
||||
#region SecurityTokenDescriptor Map
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace DigitalData.Core.Abstractions.Security
|
||||
{
|
||||
public interface IAsymmetricTokenValidator : IAsymmetricPublicKey
|
||||
{
|
||||
SecurityKey SecurityKey { get; }
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,6 @@ namespace DigitalData.Core.Abstractions.Security
|
||||
|
||||
SecurityToken CreateToken(TPrincipal subject, string issuer, string audience);
|
||||
|
||||
SecurityToken CreateToken(TPrincipal subject, string apiRoute);
|
||||
|
||||
string WriteToken(SecurityToken token);
|
||||
}
|
||||
}
|
||||
@@ -57,9 +57,6 @@ namespace DigitalData.Core.Abstractions.Security
|
||||
|
||||
public static string WriteToken<TPrincipal>(this IJwtSignatureHandler<TPrincipal> handler, TPrincipal subject, string issuer, string audience)
|
||||
=> handler.WriteToken(handler.CreateToken(subject: subject, issuer: issuer, audience: audience));
|
||||
|
||||
public static string WriteToken<TPrincipal>(this IJwtSignatureHandler<TPrincipal> handler, TPrincipal subject, string apiRoute)
|
||||
=> handler.WriteToken(handler.CreateToken(subject: subject, apiRoute: apiRoute));
|
||||
#endregion Jwt Signature Handler
|
||||
}
|
||||
}
|
||||
@@ -47,13 +47,6 @@ namespace DigitalData.Core.Security.Config
|
||||
|
||||
public CryptoFactoryParams()
|
||||
{
|
||||
// set defaults
|
||||
if (VaultDecryptor is not null)
|
||||
VaultDecryptor.Id = "vault";
|
||||
|
||||
foreach (var descriptor in TokenDescriptors)
|
||||
descriptor.IdSeparator = FileNameSeparator;
|
||||
|
||||
// init decryptors
|
||||
AfterCreate += () =>
|
||||
{
|
||||
@@ -72,7 +65,17 @@ namespace DigitalData.Core.Security.Config
|
||||
// set default path
|
||||
if (privateKey.IsPemNull)
|
||||
{
|
||||
var file_name_params = new List<object> { privateKey.Id, KeySizeInBits, DateTime.Now.ToTag(DateTagFormat) };
|
||||
// file name
|
||||
var file_name_params = new List<object>();
|
||||
|
||||
if (privateKey.Id is not null)
|
||||
file_name_params.Add(privateKey.Id);
|
||||
else if (privateKey is RSATokenDescriptor descriptor)
|
||||
file_name_params.Add(descriptor.Issuer);
|
||||
|
||||
file_name_params.Add(KeySizeInBits);
|
||||
file_name_params.Add(DateTime.Now.ToTag(DateTagFormat));
|
||||
|
||||
if (privateKey.IsEncrypted)
|
||||
file_name_params.Add(Secrets.Version);
|
||||
|
||||
|
||||
@@ -4,8 +4,28 @@
|
||||
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>DigitalData.Core.Security</PackageId>
|
||||
<Version>1.0.0</Version>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>Digital Data GmbH</Product>
|
||||
<Description>This package provides RSA-based security functionalities as an implementation of the DigitalData.Core.Abstractions.Security library. It supports robust encryption and decryption operations, as well as JWT signing and validation for secure authentication and data integrity.</Description>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Copyright>Copyright 2025</Copyright>
|
||||
<PackageProjectUrl></PackageProjectUrl>
|
||||
<PackageIcon>core_icon.png</PackageIcon>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
|
||||
<PackageTags>digital data core security</PackageTags>
|
||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\..\nuget-package-icons\core_icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||
|
||||
@@ -36,13 +36,5 @@ namespace DigitalData.Core.Security
|
||||
?? throw new InvalidOperationException($"No or multiple token description found for issuer '{issuer}' and audience '{audience}'.");
|
||||
return CreateToken(subject: subject, descriptor: descriptor);
|
||||
}
|
||||
|
||||
public SecurityToken CreateToken(TPrincipal subject, string apiRoute)
|
||||
{
|
||||
var desc = _cryptoFactory.TokenDescriptors.SingleOrDefault(desc => desc.ApiRoute == apiRoute)
|
||||
?? throw new InvalidOperationException($"No or multiple token description found for api route '{apiRoute}'.");
|
||||
|
||||
return CreateToken(subject: subject, descriptor: desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,10 @@ namespace DigitalData.Core.Security.RSAKey
|
||||
{
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public virtual string Content { get; init; }
|
||||
|
||||
public virtual string Id { get; internal set; }
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
public string? Id { get; init; }
|
||||
|
||||
protected virtual RSA RSA { get; } = RSA.Create();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using DigitalData.Core.Abstractions.Security;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace DigitalData.Core.Security.RSAKey
|
||||
@@ -24,16 +23,16 @@ namespace DigitalData.Core.Security.RSAKey
|
||||
|
||||
public bool IsEncrypted { get; init; }
|
||||
|
||||
private readonly Lazy<IAsymmetricPublicKey> _lazyPublicKey;
|
||||
protected TPublicKey CreatePublicKey<TPublicKey>() where TPublicKey : RSAPublicKey, new()
|
||||
=> new() { Content = RSA.ExportRSAPublicKeyPem() };
|
||||
|
||||
private readonly Lazy<RSAPublicKey> _lazyPublicKey;
|
||||
|
||||
public IAsymmetricPublicKey PublicKey => _lazyPublicKey.Value;
|
||||
|
||||
public RSAPrivateKey()
|
||||
{
|
||||
_lazyPublicKey = new(() => new RSAPublicKey()
|
||||
{
|
||||
Content = RSA.ExportRSAPublicKeyPem()
|
||||
});
|
||||
_lazyPublicKey = new(CreatePublicKey<RSAPublicKey>);
|
||||
}
|
||||
|
||||
internal void SetPem(string pem)
|
||||
|
||||
@@ -8,13 +8,11 @@ namespace DigitalData.Core.Security.RSAKey
|
||||
/// </summary>
|
||||
public class RSATokenDescriptor : RSAPrivateKey, IAsymmetricTokenDescriptor
|
||||
{
|
||||
internal string IdSeparator { get; set; } = "_-_";
|
||||
private readonly Lazy<RSATokenValidator> _lazyTokenValidator;
|
||||
|
||||
private string? _id;
|
||||
public IAsymmetricTokenValidator Validator => _lazyTokenValidator.Value;
|
||||
|
||||
public override string Id { get => _id ?? $"{Issuer}{IdSeparator}{Audience}"; internal set => _id = value; }
|
||||
|
||||
public string? ApiRoute { get; init; }
|
||||
public required TimeSpan Lifetime { get; init; }
|
||||
|
||||
#region SecurityTokenDescriptor Map
|
||||
/// <summary>
|
||||
@@ -34,8 +32,9 @@ namespace DigitalData.Core.Security.RSAKey
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the 'expiration' claim. This value should be in UTC.
|
||||
/// The expiration time is the sum of DateTime.Now and LifeTime.
|
||||
/// </summary>
|
||||
public DateTime? Expires { get; set; }
|
||||
public DateTime? Expires => DateTime.Now.AddTicks(Lifetime.Ticks);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the issuer of this <see cref="SecurityTokenDescriptor"/>.
|
||||
@@ -108,6 +107,8 @@ namespace DigitalData.Core.Security.RSAKey
|
||||
public RSATokenDescriptor()
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
{
|
||||
_lazyTokenValidator = new(CreatePublicKey<RSATokenValidator>);
|
||||
|
||||
_lazyRsaSecurityKey = new(() => new RsaSecurityKey(RSA));
|
||||
|
||||
_lazySigningCredentials = new(() => SigningDigest is null
|
||||
|
||||
17
DigitalData.Core.Security/RSAKey/RSATokenValidator.cs
Normal file
17
DigitalData.Core.Security/RSAKey/RSATokenValidator.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using DigitalData.Core.Abstractions.Security;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace DigitalData.Core.Security.RSAKey
|
||||
{
|
||||
public class RSATokenValidator : RSAPublicKey, IAsymmetricTokenValidator
|
||||
{
|
||||
private readonly Lazy<RsaSecurityKey> _lazyRsaSecurityKey;
|
||||
|
||||
public SecurityKey SecurityKey => _lazyRsaSecurityKey.Value;
|
||||
|
||||
public RSATokenValidator()
|
||||
{
|
||||
_lazyRsaSecurityKey = new(() => new RsaSecurityKey(RSA));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Security",
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Terminal", "DigitalData.Core.Terminal\DigitalData.Core.Terminal.csproj", "{0FA93730-8084-4907-B172-87D610323796}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Tests.API", "DigitalData.Core.Tests.API\DigitalData.Core.Tests.API.csproj", "{9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Tests.API", "DigitalData.Core.Tests.API\DigitalData.Core.Tests.API.csproj", "{9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -68,8 +68,8 @@ Global
|
||||
{E009A053-A9F4-48F2-984F-EF5C376A9B14}.Debug|Any CPU.Build.0 = Release|Any CPU
|
||||
{E009A053-A9F4-48F2-984F-EF5C376A9B14}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E009A053-A9F4-48F2-984F-EF5C376A9B14}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47D80C65-74A2-4EB8-96A5-D571A9108FB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{47D80C65-74A2-4EB8-96A5-D571A9108FB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47D80C65-74A2-4EB8-96A5-D571A9108FB3}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47D80C65-74A2-4EB8-96A5-D571A9108FB3}.Debug|Any CPU.Build.0 = Release|Any CPU
|
||||
{47D80C65-74A2-4EB8-96A5-D571A9108FB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47D80C65-74A2-4EB8-96A5-D571A9108FB3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0FA93730-8084-4907-B172-87D610323796}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
||||
Reference in New Issue
Block a user