using AutoMapper; using DigitalData.Core.Abstractions.Security; using DigitalData.Core.Security.Config; 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 TokenParams _params; private readonly ICryptograph _cryptograph; public JwtSignatureHandler(IOptions> claimDescriptorOptions, IMapper mapper, IOptions tokenParamOptions, ICryptograph cryptograph) { _claimDescriptor = claimDescriptorOptions.Value; _mapper = mapper; _params = tokenParamOptions.Value; _cryptograph = cryptograph; } public SecurityToken CreateToken(TPrincipal subject, TokenDescription description) { var descriptor = _mapper.Map(description); 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 description = _params.Descriptions?.Get(issuer: issuer, audience: audience) ?? throw new InvalidOperationException($"No or multiple token description found for issuer '{issuer}' and audience '{audience}'."); description.SigningCredentials = _cryptograph.PrivateKeys .Get(issuer: issuer, audience: audience) .CreateSigningCredentials(algorithm: description.SigningAlgorithm, digest: description.SigningDigest); return CreateToken(subject: subject, description: description); } public SecurityToken CreateToken(TPrincipal subject, string apiRoute) { var description = _params.Descriptions.SingleOrDefault(description => description.ApiRoute == apiRoute) ?? throw new InvalidOperationException($"No or multiple token description found for api route '{apiRoute}'."); description.SigningCredentials = _cryptograph.PrivateKeys .Get(issuer: description.Issuer, audience: description.Audience) .CreateSigningCredentials(algorithm: description.SigningAlgorithm, digest: description.SigningDigest); return CreateToken(subject: subject, description: description); } public string WriteToken(SecurityTokenDescriptor descriptor) => WriteToken(CreateToken(descriptor)); public string WriteToken(TPrincipal subject, TokenDescription description) => WriteToken(CreateToken(subject: subject, description: description)); 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)); } }