Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex Claim Values in .NET Framework with System.Security.Claims

I'm developing a web app with Asp.Net 5 MVC, Owin and Oauth2 bearer token as auth type.

Following this guide that adds a custom complex claim Json serialized to an instance of Microsoft.IdentityModel.Claims.ClaimsIdentity with success, I've tried to replicate the same example using the ClaimsIdentity on the System.Security.Claims namespace.

Unluckily, it seems that adding a complexClaim to the ClaimsIdentity instance, the derived class type information is lost, and the claim is stored as a System.Security.Claims.Claim.

var complexClaim = new ComplexClaim<UKPassport>(@"http://it.test/currentpassport", passport);
var claims = new List<Claim>() { complexClaim };
identity.AddClaims(claims);

When I try to get back the claim from identity, casting it to to a ComplexClaim<UKPassport> Type results in a null value.

var passportClaim = identity.Claims.FirstOrDefault<Claim>(c=>c.Type == @"http://it.test/currentpassport") as ComplexClaim<UKPassport>;

The same example works perfectly using Microsoft.IdentityModel.Claims.

Any hints?

Here is the complete ported code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Security.Claims;

namespace ConsoleApplication1
{
    class Program {
    private static ClaimsIdentity identity = new ClaimsIdentity();

    static void Main(string[] args)
    {
        var oldPassport = CreatePassport();
        identity.AddPassport(oldPassport);

        var britishCitizen = identity.IsBritishCitizen();
        var hasExpired = identity.IsCurrentPassportExpired();
        Console.WriteLine(hasExpired); 
        Console.ReadLine();
    }

    private static UKPassport CreatePassport()
    {
        var passport = new UKPassport(
            code: PassportCode.GBR, 
            number: 123456789,
            expiryDate: DateTime.Now);

        return passport;
    }
}

    public static class ClaimsIdentityExtensions {
    public static void AddPassport(this ClaimsIdentity identity, UKPassport passport)
    {
        var complexClaim = new ComplexClaim<UKPassport>(@"http://it.test/currentpassport", passport);

        var claims = new List<Claim>() { complexClaim };
        identity.AddClaims(claims);
    }

    public static bool IsCurrentPassportExpired(this ClaimsIdentity identity)
    {
        var passport = GetPassport(identity, @"http://it.test/currentpassport");
        return DateTime.Now > passport.ExpiryDate;
    }

    public static bool IsBritishCitizen(this ClaimsIdentity identity)
    {
        var passport = GetPassport(identity, @"http://it.test/currentpassport");
        return passport.Code == PassportCode.GBR;
    }

    private static UKPassport GetPassport(this ClaimsIdentity identity, string passportType)
    {
        var passportClaim = identity.Claims.FirstOrDefault<Claim>(c=>c.Type == @"http://it.test/currentpassport") as ComplexClaim<UKPassport>;
        return passportClaim.Value;
    }
}

    public enum PassportCode
    {
        GBR,

        GBD,

        GBO,

        GBS,

        GBP,

        GBN
    }


    public class ComplexClaim<T> : Claim where T : ClaimValue
    {
        public ComplexClaim(string claimType, T claimValue)
            : this(claimType, claimValue, string.Empty)
        {
        }

        public ComplexClaim(string claimType, T claimValue, string issuer)
            : this(claimType, claimValue, issuer, string.Empty)
        {
        }

        public ComplexClaim(string claimType, T claimValue, string issuer, string originalIssuer)
            : base(claimType, claimValue.ToString(), claimValue.ValueType(), issuer, originalIssuer)
        {
        }

        public new T Value
        {
            get
            {
                return JsonConvert.DeserializeObject<T>(base.Value);
            }
        }
    }

    public class UKPassport : ClaimValue
    {
        public const string Name = "UKPassport";

        private readonly PassportCode code;
        private readonly int number;
        private readonly DateTime expiryDate;

        public UKPassport(PassportCode code, int number, DateTime expiryDate)
        {
            this.code = code;
            this.number = number;
            this.expiryDate = expiryDate;
        }

        public PassportCode Code { get { return this.code; } }
        public int Number { get { return this.number; } }
        public DateTime ExpiryDate { get { return this.expiryDate; } }

        public override string ValueType()
        {
            return @"http://it.test/currentpassport";
        }
    }    

public abstract class ClaimValue {
    public abstract string ValueType();

    public override string ToString()
    {
        return JsonConvert.SerializeObject(this);
    }
}
}
like image 243
systempuntoout Avatar asked Jul 17 '14 21:07

systempuntoout


People also ask

How would you implement claims based authentication in .NET core?

The claims-based authorization works by checking if the user has a claim to access an URL. In ASP.NET Core we create policies to implement the Claims-Based Authorization. The policy defines what claims that user must process to satisfy the policy. We apply the policy on the Controller, action method, razor page, etc.

What is claims in security?

Claims are pieces of information about a user that have been packaged, signed into security tokens and sent by an issuer or identity provider to relying party applications through a security token service (STS).

What is ClaimsIdentity in ASP.NET Core?

In . NET Core, the ClaimsIdentity class represents a user in your application. It helps describe who they are and helps manage the list of claims which describe what they can do.

What is claim based authentication in ASP NET?

Claim based authorization checks are declarative - the developer embeds them within their code, against a controller or an action within a controller, specifying claims which the current user must possess, and optionally the value the claim must hold to access the requested resource.


1 Answers

The cast in GetPassport tries to convert from base type Claim to derived type ComplexClaim<UKPassport> which will result in null. You need to write a cast operator to convert from Claim to UKPassport

public static explicit operator UKPassport(Claim c)
{
     return (c == null ? null:JsonConvert.DeserializeObject<UKPassport> (c.Value));
}       

and GetPassport will be

private static UKPassport GetPassport(this ClaimsIdentity identity, string passportType)
{
   return (UKPassport)identity.Claims.FirstOrDefault<Claim>(c => c.Type == @"http://it.test/currentpassport");
}
like image 58
Ahmed Bahtity Avatar answered Oct 02 '22 20:10

Ahmed Bahtity