DfwForSale
DfwForSale

Reputation: 374

Enforcing a ClaimType on ClaimsIdentity

I am working on a new app and am using ASP.NET Identity and was wondering if there was a way to enforce a specific claim type be present on the ClaimsIdentity. Here is what I have so far.. It works but it seems there this is something that would / should be built in and maybe I am just not finding it.

 public void SignIn(IUserIdentity user, string authenticationType, bool isPersistent)
    {
        if (user == null)
        {
            string msg = "UserIdentity or UserIdentity is null";
            _logger.Error(msg);
            throw new NullReferenceException(msg);
        }
        List<Claim> claims = _claimService.GetClaims(user.UserId);

        var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
        if (claims.Any() && claims.Single(c => c.Type == ClaimTypes.Name).Value != null)
        {
            _owinContext.Authentication.SignIn(new AuthenticationProperties
            {
                IsPersistent = isPersistent
            }, identity);
        }
        else
        {
            throw new SecurityException("Invalid or null Name Claim");    
        }

    }

Upvotes: 3

Views: 1373

Answers (1)

LostInComputer
LostInComputer

Reputation: 15420

I am not aware of any built-in way to assert that a claim exist.

Edit:

You are right. My original solution is over-engineered. I think your solution is the only way to go.

The validation is incorrect though for two reasons:

  • an exception is throw if the claim isn't found since .Single is used
  • Claim's value can never be null since it's constructor prevents it

It should be:

List<Claim> claims = _claimService.GetClaims(user.UserId);
if (claims.Any(i => i.Type == ClaimTypes.Name)
{
    var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);

Or

var claims = _claimService.GetClaims(user.UserId);
var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
if (identity.Name != null)
{

Original:

How I would do it is to separate authentication and authorization.

Authentication - verifies the user

Authorization - verifies what the user is authorized to do.

public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
    public string[] ClaimTypes { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null) { throw new ArgumentNullException("httpContext"); }

        var principal = httpContext.User as ClaimsPrincipal;
        return principal != null && HasAllClaimTypes(principal) && base.AuthorizeCore(httpContext);
    }

    private bool HasAllClaimTypes(ClaimsPrincipal principal)
    {
        return ClaimTypes == null || ClaimTypes.All(claimType => principal.HasClaim(claim => claim.Type == claimType));
    }
}

Enforce claim types that all controllers require in global filters like so:

filters.Add(new ClaimsAuthorizeAttribute { ClaimTypes = new[]{ ClaimTypes.Name } });

When a claim type is not present, the user is redirected to the log in page. (you may want to change this behavior though)

See this article too http://leastprivilege.com/2012/10/26/using-claims-based-authorization-in-mvc-and-web-api/

Upvotes: 3

Related Questions