jsonservicestackjson-deserializationservicestack-textservicestack-auth

Why does UserAuthExtensions.PopulateFromMap(session, jwtPayload) does not deserialize json values with escape correctly in ServiceStack.Auth?


We want to get the UserName from the ServiceStack session, but we find that the backslashes in the UserName are not deserialized as expected. The UserName has this format 'domainname\username' and serialized in a jwt token this looks like:

{
  "typ": "JWT",
  "alg": "HS256"
}.{
  "iss": "ssjwt",
  "iat": 1635952233,
  "exp": 1635955833,
  "name": "Robin Doe",
  "preferred_username": "domainname\\robindoe"
}.[Signature]

After calling:

var sessionFromJwt = JwtAuthProviderReader.CreateSessionFromJwt(req);
userName = sessionFromJwt.UserName;

The userName variable contains the value 'domainname\\robindoe' instead of 'domainname\robindoe'.

After digging in the ServiceStack code, we pin this down to the PopulateFromMap() method in https://github.com/ServiceStack/ServiceStack/blob/36df74a8b1ba7bf06f85262c1155e1425c082906/src/ServiceStack/Auth/UserAuth.cs#L388.

To demonstrate this problem we have written a small program to prove the point:

    class Program
        {
            static void Main(string[] args)
            {
                var jwtPayload = JsonObject.Parse(@"{
      ""iss"": ""ssjwt"",
      ""iat"": 1635952233,
      ""exp"": 1635955833,
      ""name"": ""John Doe"",
      ""preferred_username"": ""domainname\\username""
    }");
    
                var session = new AuthUserSession();
    
                // The PopulateFromMap implementation does not deserialize the json values according to json standards
                 UserAuthExtensions.PopulateFromMap(session, jwtPayload);
    
                // Notice that the session.UserName still has the escape character 'domainname\\username' instead of the expected 'domainname\username'
                Console.WriteLine(session.UserName);
    
                // The PopulateFromMap should deserialize also the values, like in test Can_dynamically_parse_JSON_with_escape_chars()
                Can_dynamically_parse_JSON_with_escape_chars();
            }
    
            private const string JsonCentroid = @"{""place"":{ ""woeid"":12345, ""placeTypeName"":""St\\a\/te"" } }";
    
// Source: https://github.com/ServiceStack/ServiceStack.Text/blob/master/tests/ServiceStack.Text.Tests/JsonObjectTests.cs
            public static void Can_dynamically_parse_JSON_with_escape_chars()
            {
                var placeTypeName = JsonObject.Parse(JsonCentroid).Object("place").Get("placeTypeName");
                if (placeTypeName != "St\\a/te")
                    throw new InvalidCastException(placeTypeName + " != St\\a/te");
    
                placeTypeName = JsonObject.Parse(JsonCentroid).Object("place").Get<string>("placeTypeName");
                if (placeTypeName != "St\\a/te")
                    throw new InvalidCastException(placeTypeName + " != St\\a/te");
            }
    
        }

Why does UserAuthExtensions.PopulateFromMap(session, jwtPayload) does not deserialize json values with escape correctly in ServiceStack.Auth?


Solution

  • The issue is due to enumerating a JsonObject didn't return the same escaped string value as indexing it which has been resolved from this commit.

    This change is available from v5.12.1+ that's now available on MyGet.