refactor(DigitalData.Core.Security.RSAKey.Base): Ordnerverzeichnisse und Namespaces geordnet

This commit is contained in:
Developer 02 2025-03-14 12:32:40 +01:00
parent 9ec9bcd474
commit 192a93d153
40 changed files with 371 additions and 372 deletions

View File

@ -0,0 +1,23 @@
namespace DigitalData.Core.Abstractions.Security.Common;
/// <summary>
/// Represents a unique security context that identifies an issuer and an audience.
/// </summary>
public interface IUniqueSecurityContext
{
/// <summary>
/// Gets the issuer identifier for this security context.
/// </summary>
/// <remarks>
/// The issuer typically represents the entity that issues a token or a cryptographic key.
/// </remarks>
string Issuer { get; }
/// <summary>
/// Gets the audience identifier for this security context.
/// </summary>
/// <remarks>
/// The audience typically represents the intended recipient or target of a token or cryptographic operation.
/// </remarks>
string Audience { get; }
}

View File

@ -0,0 +1,64 @@
using DigitalData.Core.Abstractions.Security.Common;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Abstractions.Security.Services;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace DigitalData.Core.Abstractions.Security.Extensions;
public static class SecurityExtensions
{
#region Unique Security Context
public static IEnumerable<TUniqueSecurityContext> GetByIssuer<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string issuer) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Where(c => c.Issuer == issuer);
public static IEnumerable<TUniqueSecurityContext> GetByAudience<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string audience) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Where(c => c.Audience == audience);
public static TUniqueSecurityContext Get<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string issuer, string audience) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Where(c => c.Issuer == issuer && c.Audience == audience).SingleOrDefault()
?? throw new InvalidOperationException($"Exactly one {typeof(TUniqueSecurityContext).Name} must exist with Issuer: '{issuer}' and Audience: '{audience}'.");
public static bool TryGet<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string issuer, string audience, out TUniqueSecurityContext context) where TUniqueSecurityContext : IUniqueSecurityContext
{
#pragma warning disable CS8601 // Possible null reference assignment.
context = contextes.SingleOrDefault(c => c.Issuer == issuer && c.Audience == audience);
#pragma warning restore CS8601 // Possible null reference assignment.
return context is not null;
}
public static TUniqueSecurityContext Match<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, IUniqueSecurityContext lookupContext) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Get(lookupContext.Issuer, lookupContext.Audience);
public static bool TryMatch<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, IUniqueSecurityContext lookupContext, out TUniqueSecurityContext context) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.TryGet(lookupContext.Issuer, lookupContext.Audience, out context);
#endregion Unique Security Context
#region De/serilization
internal static byte[] Base64ToByte(this string base64String) => Convert.FromBase64String(base64String);
internal static string BytesToString(this byte[] bytes) => Encoding.UTF8.GetString(bytes);
internal static string ToBase64String(this byte[] bytes) => Convert.ToBase64String(bytes);
internal static byte[] ToBytes(this string str) => Encoding.UTF8.GetBytes(str);
public static string Decrypt(this IAsymmetricDecryptor decryptor, string data) => decryptor
.Decrypt(data.Base64ToByte()).BytesToString();
#endregion De/serilization
#region Asymmetric Encryptor
public static string Encrypt(this IAsymmetricEncryptor encryptor, string data) => encryptor.Encrypt(data.ToBytes()).ToBase64String();
#endregion Asymmetric Encryptor
#region Jwt Signature Handler
public static string WriteToken<TPrincipal>(this IJwtSignatureHandler<TPrincipal> handler, SecurityTokenDescriptor descriptor)
=> handler.WriteToken(handler.CreateToken(descriptor));
public static string WriteToken<TPrincipal>(this IJwtSignatureHandler<TPrincipal> handler, TPrincipal subject, IAsymmetricTokenDescriptor descriptor)
=> handler.WriteToken(handler.CreateToken(subject: subject, descriptor: descriptor));
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));
#endregion Jwt Signature Handler
}

View File

@ -1,9 +0,0 @@
namespace DigitalData.Core.Abstractions.Security
{
public interface IAsymmetricDecryptor : IAsymmetricPrivateKey
{
byte[] Decrypt(byte[] data);
IAsymmetricEncryptor Encryptor { get; }
}
}

View File

@ -1,7 +0,0 @@
namespace DigitalData.Core.Abstractions.Security
{
public interface IAsymmetricEncryptor : IAsymmetricPublicKey
{
byte[] Encrypt(byte[] data);
}
}

View File

@ -1,9 +0,0 @@
namespace DigitalData.Core.Abstractions.Security
{
public interface IAsymmetricKey
{
string? Id { get; }
string Content { get; }
}
}

View File

@ -1,9 +0,0 @@
namespace DigitalData.Core.Abstractions.Security
{
public interface IAsymmetricPrivateKey : IAsymmetricKey
{
bool IsEncrypted { get; }
IAsymmetricPublicKey PublicKey { get; }
}
}

View File

@ -1,6 +0,0 @@
namespace DigitalData.Core.Abstractions.Security
{
public interface IAsymmetricPublicKey : IAsymmetricKey
{
}
}

View File

@ -1,74 +0,0 @@
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Abstractions.Security
{
/// <summary>
/// Contains some information which used to create a security token. Designed to abstract <see cref="SecurityTokenDescriptor"/>
/// </summary>
public interface IAsymmetricTokenDescriptor : IAsymmetricPrivateKey, IUniqueSecurityContext
{
IAsymmetricTokenValidator Validator { get; }
TimeSpan Lifetime { get; init; }
#region SecurityTokenDescriptor Map
/// <summary>
/// Defines the compression algorithm that will be used to compress the JWT token payload.
/// </summary>
string CompressionAlgorithm { get; }
/// <summary>
/// Gets or sets the <see cref="EncryptingCredentials"/> used to create a encrypted security token.
/// </summary>
EncryptingCredentials EncryptingCredentials { get; }
/// <summary>
/// Gets or sets the value of the 'expiration' claim. This value should be in UTC.
/// </summary>
DateTime? Expires { get; }
/// <summary>
/// Gets or sets the time the security token was issued. This value should be in UTC.
/// </summary>
DateTime? IssuedAt { get; }
/// <summary>
/// Gets or sets the notbefore time for the security token. This value should be in UTC.
/// </summary>
DateTime? NotBefore { get; }
/// <summary>
/// Gets or sets the token type.
/// <remarks> If provided, this will be added as the value for the 'typ' header parameter. In the case of a JWE, this will be added to both the inner (JWS) and the outer token (JWE) header. By default, the value used is 'JWT'.
/// If <see cref="AdditionalHeaderClaims"/> also contains 'typ' header claim value, it will override the TokenType provided here.
/// This value is used only for JWT tokens and not for SAML/SAML2 tokens</remarks>
/// </summary>
string TokenType { get; }
/// <summary>
/// Gets or sets the <see cref="Dictionary{TKey, TValue}"/> which contains any custom header claims that need to be added to the JWT token header.
/// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the <see cref="SigningCredentials"/>,
/// <see cref="EncryptingCredentials"/>, and/or <see cref="CompressionAlgorithm"/> provided and SHOULD NOT be included in this dictionary as this
/// will result in an exception being thrown.
/// <remarks> These claims are only added to the outer header (in case of a JWE).</remarks>
/// </summary>
IDictionary<string, object> AdditionalHeaderClaims { get; }
/// <summary>
/// Gets or sets the <see cref="Dictionary{TKey, TValue}"/> which contains any custom header claims that need to be added to the inner JWT token header.
/// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the <see cref="SigningCredentials"/>,
/// <see cref="EncryptingCredentials"/>, and/or <see cref="CompressionAlgorithm"/> provided and SHOULD NOT be included in this dictionary as this
/// will result in an exception being thrown.
/// <remarks>
/// For JsonWebTokenHandler, these claims are merged with <see cref="AdditionalHeaderClaims"/> while adding to the inner JWT header.
/// </remarks>
/// </summary>
IDictionary<string, object> AdditionalInnerHeaderClaims { get; }
/// <summary>
/// Gets or sets the <see cref="SigningCredentials"/> used to create a security token.
/// </summary>
SigningCredentials SigningCredentials { get; }
#endregion SecurityTokenDescriptor
}
}

View File

@ -1,9 +0,0 @@
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Abstractions.Security
{
public interface IAsymmetricTokenValidator : IAsymmetricPublicKey
{
SecurityKey SecurityKey { get; }
}
}

View File

@ -1,24 +0,0 @@
namespace DigitalData.Core.Abstractions.Security
{
/// <summary>
/// Represents a unique security context that identifies an issuer and an audience.
/// </summary>
public interface IUniqueSecurityContext
{
/// <summary>
/// Gets the issuer identifier for this security context.
/// </summary>
/// <remarks>
/// The issuer typically represents the entity that issues a token or a cryptographic key.
/// </remarks>
string Issuer { get; }
/// <summary>
/// Gets the audience identifier for this security context.
/// </summary>
/// <remarks>
/// The audience typically represents the intended recipient or target of a token or cryptographic operation.
/// </remarks>
string Audience { get; }
}
}

View File

@ -0,0 +1,8 @@
namespace DigitalData.Core.Abstractions.Security.Key;
public interface IAsymmetricDecryptor : IAsymmetricPrivateKey
{
byte[] Decrypt(byte[] data);
IAsymmetricEncryptor Encryptor { get; }
}

View File

@ -0,0 +1,6 @@
namespace DigitalData.Core.Abstractions.Security.Key;
public interface IAsymmetricEncryptor : IAsymmetricPublicKey
{
byte[] Encrypt(byte[] data);
}

View File

@ -0,0 +1,8 @@
namespace DigitalData.Core.Abstractions.Security.Key;
public interface IAsymmetricKey
{
string? Id { get; }
string Content { get; }
}

View File

@ -0,0 +1,8 @@
namespace DigitalData.Core.Abstractions.Security.Key;
public interface IAsymmetricPrivateKey : IAsymmetricKey
{
bool IsEncrypted { get; }
IAsymmetricPublicKey PublicKey { get; }
}

View File

@ -0,0 +1,5 @@
namespace DigitalData.Core.Abstractions.Security.Key;
public interface IAsymmetricPublicKey : IAsymmetricKey
{
}

View File

@ -0,0 +1,74 @@
using DigitalData.Core.Abstractions.Security.Common;
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Abstractions.Security.Key;
/// <summary>
/// Contains some information which used to create a security token. Designed to abstract <see cref="SecurityTokenDescriptor"/>
/// </summary>
public interface IAsymmetricTokenDescriptor : IAsymmetricPrivateKey, IUniqueSecurityContext
{
IAsymmetricTokenValidator Validator { get; }
TimeSpan Lifetime { get; init; }
#region SecurityTokenDescriptor Map
/// <summary>
/// Defines the compression algorithm that will be used to compress the JWT token payload.
/// </summary>
string CompressionAlgorithm { get; }
/// <summary>
/// Gets or sets the <see cref="EncryptingCredentials"/> used to create a encrypted security token.
/// </summary>
EncryptingCredentials EncryptingCredentials { get; }
/// <summary>
/// Gets or sets the value of the 'expiration' claim. This value should be in UTC.
/// </summary>
DateTime? Expires { get; }
/// <summary>
/// Gets or sets the time the security token was issued. This value should be in UTC.
/// </summary>
DateTime? IssuedAt { get; }
/// <summary>
/// Gets or sets the notbefore time for the security token. This value should be in UTC.
/// </summary>
DateTime? NotBefore { get; }
/// <summary>
/// Gets or sets the token type.
/// <remarks> If provided, this will be added as the value for the 'typ' header parameter. In the case of a JWE, this will be added to both the inner (JWS) and the outer token (JWE) header. By default, the value used is 'JWT'.
/// If <see cref="AdditionalHeaderClaims"/> also contains 'typ' header claim value, it will override the TokenType provided here.
/// This value is used only for JWT tokens and not for SAML/SAML2 tokens</remarks>
/// </summary>
string TokenType { get; }
/// <summary>
/// Gets or sets the <see cref="Dictionary{TKey, TValue}"/> which contains any custom header claims that need to be added to the JWT token header.
/// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the <see cref="SigningCredentials"/>,
/// <see cref="EncryptingCredentials"/>, and/or <see cref="CompressionAlgorithm"/> provided and SHOULD NOT be included in this dictionary as this
/// will result in an exception being thrown.
/// <remarks> These claims are only added to the outer header (in case of a JWE).</remarks>
/// </summary>
IDictionary<string, object> AdditionalHeaderClaims { get; }
/// <summary>
/// Gets or sets the <see cref="Dictionary{TKey, TValue}"/> which contains any custom header claims that need to be added to the inner JWT token header.
/// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the <see cref="SigningCredentials"/>,
/// <see cref="EncryptingCredentials"/>, and/or <see cref="CompressionAlgorithm"/> provided and SHOULD NOT be included in this dictionary as this
/// will result in an exception being thrown.
/// <remarks>
/// For JsonWebTokenHandler, these claims are merged with <see cref="AdditionalHeaderClaims"/> while adding to the inner JWT header.
/// </remarks>
/// </summary>
IDictionary<string, object> AdditionalInnerHeaderClaims { get; }
/// <summary>
/// Gets or sets the <see cref="SigningCredentials"/> used to create a security token.
/// </summary>
SigningCredentials SigningCredentials { get; }
#endregion SecurityTokenDescriptor
}

View File

@ -0,0 +1,8 @@
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Abstractions.Security.Key;
public interface IAsymmetricTokenValidator : IAsymmetricPublicKey
{
SecurityKey SecurityKey { get; }
}

View File

@ -1,62 +0,0 @@
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace DigitalData.Core.Abstractions.Security
{
public static class SecurityExtensions
{
#region Unique Security Context
public static IEnumerable<TUniqueSecurityContext> GetByIssuer<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string issuer) where TUniqueSecurityContext: IUniqueSecurityContext
=> contextes.Where(c => c.Issuer == issuer);
public static IEnumerable<TUniqueSecurityContext> GetByAudience<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string audience) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Where(c => c.Audience == audience);
public static TUniqueSecurityContext Get<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string issuer, string audience) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Where(c => c.Issuer == issuer && c.Audience == audience).SingleOrDefault()
?? throw new InvalidOperationException($"Exactly one {typeof(TUniqueSecurityContext).Name} must exist with Issuer: '{issuer}' and Audience: '{audience}'.");
public static bool TryGet<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, string issuer, string audience, out TUniqueSecurityContext context) where TUniqueSecurityContext : IUniqueSecurityContext
{
#pragma warning disable CS8601 // Possible null reference assignment.
context = contextes.SingleOrDefault(c => c.Issuer == issuer && c.Audience == audience);
#pragma warning restore CS8601 // Possible null reference assignment.
return context is not null;
}
public static TUniqueSecurityContext Match<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, IUniqueSecurityContext lookupContext) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.Get(lookupContext.Issuer, lookupContext.Audience);
public static bool TryMatch<TUniqueSecurityContext>(this IEnumerable<TUniqueSecurityContext> contextes, IUniqueSecurityContext lookupContext, out TUniqueSecurityContext context) where TUniqueSecurityContext : IUniqueSecurityContext
=> contextes.TryGet(lookupContext.Issuer, lookupContext.Audience, out context);
#endregion Unique Security Context
#region De/serilization
internal static byte[] Base64ToByte(this string base64String) => Convert.FromBase64String(base64String);
internal static string BytesToString(this byte[] bytes) => Encoding.UTF8.GetString(bytes);
internal static string ToBase64String(this byte[] bytes) => Convert.ToBase64String(bytes);
internal static byte[] ToBytes(this string str) => System.Text.Encoding.UTF8.GetBytes(str);
public static string Decrypt(this IAsymmetricDecryptor decryptor, string data) => decryptor
.Decrypt(data.Base64ToByte()).BytesToString();
#endregion De/serilization
#region Asymmetric Encryptor
public static string Encrypt(this IAsymmetricEncryptor encryptor, string data) => encryptor.Encrypt(data.ToBytes()).ToBase64String();
#endregion Asymmetric Encryptor
#region Jwt Signature Handler
public static string WriteToken<TPrincipal>(this IJwtSignatureHandler<TPrincipal> handler, SecurityTokenDescriptor descriptor)
=> handler.WriteToken(handler.CreateToken(descriptor));
public static string WriteToken<TPrincipal>(this IJwtSignatureHandler<TPrincipal> handler, TPrincipal subject, IAsymmetricTokenDescriptor descriptor)
=> handler.WriteToken(handler.CreateToken(subject: subject, descriptor: descriptor));
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));
#endregion Jwt Signature Handler
}
}

View File

@ -1,6 +1,7 @@
using System.Security.Cryptography;
using DigitalData.Core.Abstractions.Security.Key;
namespace DigitalData.Core.Abstractions.Security;
namespace DigitalData.Core.Abstractions.Security.Services;
public interface IAsymmetricKeyFactory
{

View File

@ -1,4 +1,6 @@
namespace DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
namespace DigitalData.Core.Abstractions.Security.Services;
public interface IAsymmetricKeyPool : IAsymmetricKeyFactory
{

View File

@ -1,6 +1,7 @@
using Microsoft.IdentityModel.Tokens;
using DigitalData.Core.Abstractions.Security.Key;
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Abstractions.Security
namespace DigitalData.Core.Abstractions.Security.Services
{
public interface IJwtSignatureHandler<TPrincipal>
{

View File

@ -1,11 +1,10 @@
using System.Security.Claims;
namespace DigitalData.Core.Security.Config
{
public class ClaimDescriptor<TPrincipal>
{
public Func<TPrincipal, IDictionary<string, object>>? CreateClaims { get; init; }
namespace DigitalData.Core.Security.Config;
public Func<TPrincipal, ClaimsIdentity>? CreateSubject { get; init; }
}
public class ClaimDescriptor<TPrincipal>
{
public Func<TPrincipal, IDictionary<string, object>>? CreateClaims { get; init; }
public Func<TPrincipal, ClaimsIdentity>? CreateSubject { get; init; }
}

View File

@ -1,14 +1,13 @@
using AutoMapper;
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Security.Config
namespace DigitalData.Core.Security.Config;
public class MappingProfile : Profile
{
public class MappingProfile : Profile
public MappingProfile()
{
public MappingProfile()
{
CreateMap<IAsymmetricTokenDescriptor, SecurityTokenDescriptor>();
}
CreateMap<IAsymmetricTokenDescriptor, SecurityTokenDescriptor>();
}
}

View File

@ -1,37 +0,0 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Security.Claims;
namespace DigitalData.Core.Security
{
public static class DIExtensions
{
/// <summary>
/// Registers a custom asym crypt service with specified parameters from the given configuration section.
/// </summary>
/// <param name="services"></param>
/// <param name="section"></param>
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
public static IServiceCollection AddCryptoFactory(this IServiceCollection services, IConfiguration configuration) => services
.Configure<RSAParams>(configuration)
.AddAutoMapper(typeof(MappingProfile).Assembly)
.AddSingleton<IAsymmetricKeyPool, RSAPool>()
.AddSingleton<IAsymmetricKeyFactory, RSAFactory>()
.AddHostedService<PemFileInitalizer>();
public static IServiceCollection AddJwtSignatureHandler<TPrincipal>(this IServiceCollection services,
Func<TPrincipal, IDictionary<string, object>>? claimsMapper = null,
Func<TPrincipal, ClaimsIdentity>? subjectMapper = null)
=> services
.AddSingleton<IJwtSignatureHandler<TPrincipal>, JwtSignatureHandler<TPrincipal>>()
.AddSingleton(sp => Options.Create(new ClaimDescriptor<TPrincipal>
{
CreateClaims = claimsMapper,
CreateSubject = subjectMapper
}));
}
}

View File

@ -34,7 +34,6 @@
<ItemGroup>
<ProjectReference Include="..\DigitalData.Core.Abstractions.Security\DigitalData.Core.Abstractions.Security.csproj" />
<ProjectReference Include="..\DigitalData.Core.Abstractions\DigitalData.Core.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@ -1,89 +0,0 @@
using AutoMapper;
using DigitalData.Core.Abstractions.Security;
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Security
{
internal static class Extension
{
/// <summary>
/// Converts a <see cref="DateTime"/> to a formatted string based on the specified format string.
/// <br />
/// - If the format contains the symbol “//”, the method divides the numeric value obtained from the left side of the format
/// by one minus the numeric value obtained from the right side of the format string and adds one. For instance:
/// <br />
/// - If the date is 02.03.2024 and the format is "MM//2", it extracts the month (02), subtracts one (3), divides it by 2,
/// rounds down the outgoing number (1), adds one to the number (resulting in 2).
/// <br />
/// - If the format does not contain "//", the method uses the default <see cref="DateTime.ToString"/> format.
/// <br />
/// </summary>
/// <param name="date">The <see cref="DateTime"/> value to be formatted.</param>
/// <param name="format">The format string that dictates the formatting of the date. If the format includes the "//" symbol,
/// it splits the string at "//" and divides the left-side value by the right-side value. The format string can include standard
/// <see cref="DateTime.ToString"/> format patterns.</param>
/// <returns>A string representation of the formatted date, or the result of the division operation if "//" is present in the format.</returns>
/// <exception cref="ArgumentException">Thrown if the format string is invalid, such as having an incorrect number of parts after "//".</exception>
/// <exception cref="DivideByZeroException">Thrown if the right side of the "//" contains a zero, resulting in division by zero.</exception>
/// <exception cref="FormatException">Thrown if either the left-side or right-side value of "//" cannot be parsed as an integer.</exception>
internal static string ToTag(this DateTime date, string format)
{
if (format is not null && format.Contains("//"))
{
var subStrings = format.Split("//");
if (subStrings.Length != 2)
throw new ArgumentException($"Date tag format {format} is invalid. It must contain exactly one '//' separator.", nameof(format));
var formattedLeft = date.ToString(subStrings[0]);
if (!int.TryParse(formattedLeft, out var dateValue))
throw new FormatException($"The left-side value ({formattedLeft}) of the format could not be parsed to an integer.");
if (!int.TryParse(subStrings[1], out var divisor))
throw new FormatException($"The right-side value ({divisor}) of the format could not be parsed to an integer.");
if (divisor == 0)
throw new DivideByZeroException($"Date tag format {format} includes division by zero, which is not allowed.");
var result = (dateValue - 1) / divisor + 1;
return result.ToString();
}
return date.ToString(format);
}
/// <summary>
/// Converts a <see cref="DateTime"/> to a formatted string based on the specified format string.
/// <br />
/// - If the format contains the symbol “//”, the method divides the numeric value obtained from the left side of the format
/// by one minus the numeric value obtained from the right side of the format string and adds one. For instance:
/// <br />
/// - If the date is 02.03.2024 and the format is "MM//2", it extracts the month (02), subtracts one (3), divides it by 2,
/// rounds down the outgoing number (1), adds one to the number (resulting in 2).
/// <br />
/// - If the format does not contain "//", the method uses the default <see cref="DateTime.ToString"/> format.
/// <br />
/// This method provides a way to format the date based on typical or customized rules, including mathematical operations like division.
/// </summary>
/// <param name="date">The <see cref="DateOnly"/> value to be formatted. It will convert to DateTime to use the method shared with DateTime.</param>
/// <param name="format">The format string that dictates the formatting of the date. If the format includes the "//" symbol,
/// it splits the string at "//" and divides the left-side value by the right-side value. The format string can include standard
/// <see cref="DateTime.ToString"/> format patterns.</param>
/// <returns>A string representation of the formatted date, or the result of the division operation if "//" is present in the format.</returns>
/// <exception cref="ArgumentException">Thrown if the format string is invalid, such as having an incorrect number of parts after "//".</exception>
/// <exception cref="DivideByZeroException">Thrown if the right side of the "//" contains a zero, resulting in division by zero.</exception>
/// <exception cref="FormatException">Thrown if either the left-side or right-side value of "//" cannot be parsed as an integer.</exception>
internal static string ToTag(this DateOnly date, string format) => date.ToDateTime(new()).ToTag(format);
/// <summary>
/// Maps a <see cref="RSATokenDescriptor"/> to a <see cref="SecurityTokenDescriptor"/>.
/// </summary>
/// <param name="mapper">The <see cref="IMapper"/> instance used for mapping.</param>
/// <param name="description">The <see cref="RSATokenDescriptor"/> instance to be mapped.</param>
/// <returns>A <see cref="SecurityTokenDescriptor"/> instance populated with the mapped values.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="mapper"/> or <paramref name="description"/> is <c>null</c>.</exception>
internal static SecurityTokenDescriptor Map(this IMapper mapper, IAsymmetricTokenDescriptor description)
=> mapper.Map(description, new SecurityTokenDescriptor());
}
}

View File

@ -0,0 +1,36 @@
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Security.Claims;
namespace DigitalData.Core.Security.Extensions;
public static class DIExtensions
{
/// <summary>
/// Registers a custom asym crypt service with specified parameters from the given configuration section.
/// </summary>
/// <param name="services"></param>
/// <param name="section"></param>
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
public static IServiceCollection AddCryptoFactory(this IServiceCollection services, IConfiguration configuration) => services
.Configure<RSAParams>(configuration)
.AddAutoMapper(typeof(MappingProfile).Assembly)
.AddSingleton<IAsymmetricKeyPool, RSAPool>()
.AddSingleton<IAsymmetricKeyFactory, RSAFactory>()
.AddHostedService<PemFileInitalizer>();
public static IServiceCollection AddJwtSignatureHandler<TPrincipal>(this IServiceCollection services,
Func<TPrincipal, IDictionary<string, object>>? claimsMapper = null,
Func<TPrincipal, ClaimsIdentity>? subjectMapper = null)
=> services
.AddSingleton<IJwtSignatureHandler<TPrincipal>, JwtSignatureHandler<TPrincipal>>()
.AddSingleton(sp => Options.Create(new ClaimDescriptor<TPrincipal>
{
CreateClaims = claimsMapper,
CreateSubject = subjectMapper
}));
}

View File

@ -0,0 +1,88 @@
using AutoMapper;
using DigitalData.Core.Abstractions.Security.Key;
using Microsoft.IdentityModel.Tokens;
namespace DigitalData.Core.Security.Extensions;
internal static class Extension
{
/// <summary>
/// Converts a <see cref="DateTime"/> to a formatted string based on the specified format string.
/// <br />
/// - If the format contains the symbol “//”, the method divides the numeric value obtained from the left side of the format
/// by one minus the numeric value obtained from the right side of the format string and adds one. For instance:
/// <br />
/// - If the date is 02.03.2024 and the format is "MM//2", it extracts the month (02), subtracts one (3), divides it by 2,
/// rounds down the outgoing number (1), adds one to the number (resulting in 2).
/// <br />
/// - If the format does not contain "//", the method uses the default <see cref="DateTime.ToString"/> format.
/// <br />
/// </summary>
/// <param name="date">The <see cref="DateTime"/> value to be formatted.</param>
/// <param name="format">The format string that dictates the formatting of the date. If the format includes the "//" symbol,
/// it splits the string at "//" and divides the left-side value by the right-side value. The format string can include standard
/// <see cref="DateTime.ToString"/> format patterns.</param>
/// <returns>A string representation of the formatted date, or the result of the division operation if "//" is present in the format.</returns>
/// <exception cref="ArgumentException">Thrown if the format string is invalid, such as having an incorrect number of parts after "//".</exception>
/// <exception cref="DivideByZeroException">Thrown if the right side of the "//" contains a zero, resulting in division by zero.</exception>
/// <exception cref="FormatException">Thrown if either the left-side or right-side value of "//" cannot be parsed as an integer.</exception>
internal static string ToTag(this DateTime date, string format)
{
if (format is not null && format.Contains("//"))
{
var subStrings = format.Split("//");
if (subStrings.Length != 2)
throw new ArgumentException($"Date tag format {format} is invalid. It must contain exactly one '//' separator.", nameof(format));
var formattedLeft = date.ToString(subStrings[0]);
if (!int.TryParse(formattedLeft, out var dateValue))
throw new FormatException($"The left-side value ({formattedLeft}) of the format could not be parsed to an integer.");
if (!int.TryParse(subStrings[1], out var divisor))
throw new FormatException($"The right-side value ({divisor}) of the format could not be parsed to an integer.");
if (divisor == 0)
throw new DivideByZeroException($"Date tag format {format} includes division by zero, which is not allowed.");
var result = (dateValue - 1) / divisor + 1;
return result.ToString();
}
return date.ToString(format);
}
/// <summary>
/// Converts a <see cref="DateTime"/> to a formatted string based on the specified format string.
/// <br />
/// - If the format contains the symbol “//”, the method divides the numeric value obtained from the left side of the format
/// by one minus the numeric value obtained from the right side of the format string and adds one. For instance:
/// <br />
/// - If the date is 02.03.2024 and the format is "MM//2", it extracts the month (02), subtracts one (3), divides it by 2,
/// rounds down the outgoing number (1), adds one to the number (resulting in 2).
/// <br />
/// - If the format does not contain "//", the method uses the default <see cref="DateTime.ToString"/> format.
/// <br />
/// This method provides a way to format the date based on typical or customized rules, including mathematical operations like division.
/// </summary>
/// <param name="date">The <see cref="DateOnly"/> value to be formatted. It will convert to DateTime to use the method shared with DateTime.</param>
/// <param name="format">The format string that dictates the formatting of the date. If the format includes the "//" symbol,
/// it splits the string at "//" and divides the left-side value by the right-side value. The format string can include standard
/// <see cref="DateTime.ToString"/> format patterns.</param>
/// <returns>A string representation of the formatted date, or the result of the division operation if "//" is present in the format.</returns>
/// <exception cref="ArgumentException">Thrown if the format string is invalid, such as having an incorrect number of parts after "//".</exception>
/// <exception cref="DivideByZeroException">Thrown if the right side of the "//" contains a zero, resulting in division by zero.</exception>
/// <exception cref="FormatException">Thrown if either the left-side or right-side value of "//" cannot be parsed as an integer.</exception>
internal static string ToTag(this DateOnly date, string format) => date.ToDateTime(new()).ToTag(format);
/// <summary>
/// Maps a <see cref="RSATokenDescriptor"/> to a <see cref="SecurityTokenDescriptor"/>.
/// </summary>
/// <param name="mapper">The <see cref="IMapper"/> instance used for mapping.</param>
/// <param name="description">The <see cref="RSATokenDescriptor"/> instance to be mapped.</param>
/// <returns>A <see cref="SecurityTokenDescriptor"/> instance populated with the mapped values.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="mapper"/> or <paramref name="description"/> is <c>null</c>.</exception>
internal static SecurityTokenDescriptor Map(this IMapper mapper, IAsymmetricTokenDescriptor description)
=> mapper.Map(description, new SecurityTokenDescriptor());
}

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Security.RSAKey.Base;
using Microsoft.IdentityModel.Tokens;

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Security.RSAKey.Base;
using Microsoft.IdentityModel.Tokens;

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using System.Security.Cryptography;
namespace DigitalData.Core.Security.RSAKey.Base;

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using System.Security.Cryptography;
namespace DigitalData.Core.Security.RSAKey.Base;

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
namespace DigitalData.Core.Security.RSAKey.Base;

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Security.RSAKey.Base;
using System.Reflection;
using System.Security.Cryptography;

View File

@ -1,4 +1,4 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Security.RSAKey.Base;
using System.Reflection;
using System.Security.Cryptography;

View File

@ -1,14 +1,13 @@
using System.Text.Json.Serialization;
namespace DigitalData.Core.Security
namespace DigitalData.Core.Security;
public static class Secrets
{
public static class Secrets
{
public static readonly DateTime CreationDate = new (2024, 11, 19);
public static readonly DateTime CreationDate = new (2024, 11, 19);
public static readonly Version Version = new (1, 0);
public static readonly Version Version = new (1, 0);
[JsonIgnore]
internal static readonly string PBE_PASSWORD = "9mk@i/$QY&Mw@_--dI^ahlXpNKEtv_U-,V-46b19_-Z6-U_*89_n1_-5-r-_+_$_IY_mYQl-";
}
[JsonIgnore]
internal static readonly string PBE_PASSWORD = "9mk@i/$QY&Mw@_--dI^ahlXpNKEtv_U-,V-46b19_-Z6-U_*89_n1_-5-r-_+_$_IY_mYQl-";
}

View File

@ -1,6 +1,9 @@
using AutoMapper;
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Extensions;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

View File

@ -1,4 +1,5 @@
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Extensions;
using DigitalData.Core.Security.RSAKey.Auth;
using DigitalData.Core.Security.RSAKey.Base;
using Microsoft.Extensions.Hosting;

View File

@ -1,4 +1,5 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.RSAKey.Crypto;
using System.Security.Cryptography;

View File

@ -1,4 +1,5 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Security.Config;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;