59 lines
2.8 KiB
C#

using AutoMapper;
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.RSAKey;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
namespace DigitalData.Core.Security
{
public class JwtSignatureHandler<TPrincipal> : JwtSecurityTokenHandler, IJwtSignatureHandler<TPrincipal>
{
private readonly ClaimDescriptor<TPrincipal> _claimDescriptor;
private readonly IMapper _mapper;
private readonly ICryptograph _cryptograph;
public JwtSignatureHandler(IOptions<ClaimDescriptor<TPrincipal>> claimDescriptorOptions, IMapper mapper, ICryptograph cryptograph)
{
_claimDescriptor = claimDescriptorOptions.Value;
_mapper = mapper;
_cryptograph = cryptograph;
}
public SecurityToken CreateToken(TPrincipal subject, RSAPrivateKey key)
{
if(key.TokenDescriptor is null)
throw new InvalidOperationException($"No descriptor found for issuer '{key.Issuer}' and audience '{key.Audience}'.");
var descriptor = _mapper.Map(key.TokenDescriptor);
descriptor.Claims = _claimDescriptor.CreateClaims?.Invoke(subject);
descriptor.Subject = _claimDescriptor.CreateSubject?.Invoke(subject);
return CreateToken(descriptor);
}
public SecurityToken CreateToken(TPrincipal subject, string issuer, string audience)
{
var key = _cryptograph.Decryptors?.Get(issuer: issuer, audience: audience)
?? throw new InvalidOperationException($"No or multiple token description found for issuer '{issuer}' and audience '{audience}'.");
return CreateToken(subject: subject, key: (RSAPrivateKey)key);
}
public SecurityToken CreateToken(TPrincipal subject, string apiRoute)
{
var key = _cryptograph.Decryptors.SingleOrDefault(key => ((RSAPrivateKey)key).TokenDescriptor?.ApiRoute == apiRoute)
?? throw new InvalidOperationException($"No or multiple token description found for api route '{apiRoute}'.");
return CreateToken(subject: subject, key: (RSAPrivateKey)key);
}
public string WriteToken(SecurityTokenDescriptor descriptor) => WriteToken(CreateToken(descriptor));
public string WriteToken(TPrincipal subject, RSAPrivateKey key) => WriteToken(CreateToken(subject: subject, key: key));
public string WriteToken(TPrincipal subject, string issuer, string audience) => WriteToken(CreateToken(subject: subject, issuer: issuer, audience: audience));
public string WriteToken(TPrincipal subject, string apiRoute) => WriteToken(CreateToken(subject: subject, apiRoute: apiRoute));
}
}