chris ~ $ 

software_developer devops_engineer ethical_hacker cheshire_uk

...

  Authentication & Authorization 

dev   security

Custom lifetime validation

Workaround for: AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/92

There is currently an issue with the default lifetime validation for a token, where if the token expires after 19/01/2038 12:00:00 AM it overflows the int value causing the DateTime recieved by the default LifetimeValidatier to be null.

The following is a custom LifetimeValidator method that can be used in TokenValidationParameters. It resolves the issue by wrapping the default LifetimeValidator provided in Microsoft.IdentityModel.Tokens and using the ValidTo property on the Security Token passed to the method if the criteria is met.

    public bool CustomLifetimeValidator(
        DateTime? notBefore, 
        DateTime? expires, 
        SecurityToken securityToken, 
        TokenValidationParameters validationParameters)
    {
        if (!expires.HasValue && validationParameters.RequireExpirationTime)
        {
            var overflowDate = DateTimeOffset.FromUnixTimeSeconds(int.MaxValue).DateTime;
            if (securityToken is not null && securityToken.ValidTo >= overflowDate)
                expires = securityToken.ValidTo;
        }
        
        // Prevents validation loop
        var newParameters = validationParameters.Clone();
        newParameters.LifetimeValidator = null;
        
        // Use the default validation logic with the new expiry time
        Validators.ValidateLifetime(notBefore, expires, securityToken, newParameters);

        return true;
    }

TenantId Attribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class TenantIdAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    private readonly string[] _ids;
    public TenantIdAttribute(params string[] validIds)
    {
        _ids = validIds;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var user = context.HttpContext.User;
        if (!user.Identity.IsAuthenticated)
        {
            context.Result = new ForbidResult();
            return;
        }

        foreach(var claim in _ids)
        {
            if(user.HasClaim("TenantId", claim.ToString()))
                return;
        }

        context.Result = new ForbidResult();
    }
}
[TenantId("c34c8a15-a93f-41c9-9325-35f20811651e")]
[Authorize]
[HttpGet]
[Route("results")]
public IActionResult GetResults()
{
    ...
    return Ok();
}