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 : JwtSecurityTokenHandler, IJwtSignatureHandler { private readonly ClaimDescriptor _claimDescriptor; private readonly IMapper _mapper; private readonly ICryptograph _cryptograph; public JwtSignatureHandler(IOptions> 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)); } }