Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Claims cannot be deserialized #22

Open
dominikfoldi opened this issue May 22, 2018 · 3 comments
Open

Claims cannot be deserialized #22

dominikfoldi opened this issue May 22, 2018 · 3 comments

Comments

@dominikfoldi
Copy link

If I create a user without claims it can log in without any errors.
If I add some claims to the user upon registration then the user cannot log in.

The error is thrown when the DocumentDbUserStore FindByNameAsync or FindByEmailAsync actions try to read the user data.

The problem is that the Document DB SDK does not respect the JsonConver.DefaultSettings. You wrote in a comment that this is a workaround but it is not the case.

 // TODO: Until DocumentDB SDK exposes it's JSON.NET settings, we need to hijack the global settings to serialize claims
JsonConvert.DefaultSettings = () =>
{
    return new JsonSerializerSettings()
    {
        Converters = new List<JsonConverter>() { new JsonClaimConverter(), new JsonClaimsPrincipalConverter(), new JsonClaimsIdentityConverter() }
    };
};

I forked the repository and I get the following error message:

{Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type System.Security.Claims.Claim. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'claims[0].Type', line 1, position 503.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Microsoft.Azure.Documents.QueryResult.Convert(Type type)
   at Microsoft.Azure.Documents.QueryResult.AsType[T]()
   at Microsoft.Azure.Documents.Client.FeedResponseBinder.Convert[T](FeedResponse`1 dynamicFeed)
   at Microsoft.Azure.Documents.Linq.DocumentQuery`1.<GetEnumerator>d__31.MoveNext()
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at AspNetCore.Identity.DocumentDb.Stores.DocumentDbUserStore`2.FindByNameAsync(String normalizedUserName, CancellationToken cancellationToken)
@dominikfoldi dominikfoldi changed the title Claims cannot be serialized Claims cannot be deserialized May 22, 2018
@vindemi
Copy link

vindemi commented Aug 15, 2018

I have the same problem. Is there any work around how to resolve that issue?

@dominikfoldi
Copy link
Author

@vindemi I have not found any solutions for this issue. If I am not mistaken, Microsoft is working to support JsonConvert.DefaultSettings but I do not have any idea when will they finish it.

Our solution was to not use Claims but Roles instead. The serialization of Roles is not a problem.

But soon we will move to Identity Server with SQL Server because this library is not maintained and it has this issue, also it does not support partitioning so I do not think that it is production ready.

@jpmtl
Copy link

jpmtl commented Aug 15, 2018

I'm also using IdentityServer4 and have it running fine against the
AspNetCore.Identity.DocumentDb . Partitioning is definitely an issue and I'll probably have to go with a Mongo implementation without it. I used this to fix the convert issue.

`public class JsonClaimConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Claim));
}

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        IList<Claim> claims = new List<Claim>();
        JToken jt = JObject.ReadFrom(reader);
        for (int i = 0; i < jt.Count(); i++)
        {
            string type = jt.Values<string>("Type").ElementAtOrDefault(i);
            string value = jt.Values<string>("Value").ElementAtOrDefault(i);
            string valueType = jt.Values<string>("ValueType").ElementAtOrDefault(i);
            string issuer = jt.Values<string>("Issuer").ElementAtOrDefault(i);
            string originalIssuer = jt.Values<string>("OriginalIssuer").ElementAtOrDefault(i);
            claims.Add(new Claim(type, value, valueType, issuer, originalIssuer));

        }
        return claims;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

        var claim = (Claim)value;
        JObject jo = new JObject
        {
            { "Type", claim.Type },
            { "Value", claim.Value },
            { "ValueType", claim.ValueType },
            { "Issuer", claim.Issuer },
            { "OriginalIssuer", claim.OriginalIssuer }
        };
        jo.WriteTo(writer);

    }
}`

I also added this to the DocumentDBUserStore for the FindBy... issues.

IQueryable<TUser> IQueryableUserStore<TUser>.Users => documentClient.CreateDocumentQuery<TUser>(collectionUri) .Where(u => u.DocumentType == typeof(TUser).Name) .AsQueryable();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants