Skip to content

Commit

Permalink
Do not crash when User.Locale and UserInfo.Locale are an object (#699)
Browse files Browse the repository at this point in the history
  • Loading branch information
frederikprijck authored Jan 10, 2024
1 parent 020e3fc commit 5d6efd2
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Auth0.AuthenticationApi/Models/UserInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using Auth0.Core.Serialization;

namespace Auth0.AuthenticationApi.Models
{
Expand Down Expand Up @@ -158,6 +159,7 @@ public class UserInfo
/// ISO 3166-1 Alpha-2 country code in uppercase, separated by a dash.
/// </remarks>
[JsonProperty("locale")]
[JsonConverter(typeof(StringOrObjectAsStringConverter))]
public string Locale { get; set; }

/// <summary>
Expand Down
37 changes: 37 additions & 0 deletions src/Auth0.Core/Serialization/StringOrObjectAsStringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Auth0.Core.Serialization
{
internal class StringOrObjectAsStringConverter : JsonConverter
{
public override bool CanWrite => false;

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override bool CanConvert(Type objectType)
{
return true;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var instance = "";

if (reader.TokenType == JsonToken.String)
{
instance = reader.Value?.ToString();
}
else if (reader.TokenType == JsonToken.StartObject)
{
instance = JObject.Load(reader).ToString();
}

return instance;
}
}
}
2 changes: 2 additions & 0 deletions src/Auth0.ManagementApi/Models/User.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Auth0.Core.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

Expand Down Expand Up @@ -47,6 +48,7 @@ public class User : UserBase
/// Returned for the Facebook, Google, and Microsoft social providers.
/// </remarks>
[JsonProperty("locale")]
[JsonConverter(typeof(StringOrObjectAsStringConverter))]
public string Locale { get; set; }

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,25 @@ public void Can_read_standard_claims()
userInfo.UpdatedAt.Should().Be(new DateTime(2009, 1, 29, 12, 48, 53));
}

[Fact]
public void Can_read_custom_locale_claim()
{
var jsonPayload = @"{
'sub': '123456',
'locale': {
'country': 'US',
'language': 'en'
},
'updated_at': 1233233333
}";
var userInfo = GetUserInfoFromJsonPayload(jsonPayload);

userInfo.UserId.Should().Be("123456");
userInfo.Locale.Should().NotBeNull();
JObject.Parse(userInfo.Locale).GetValue("country")!.Value<string>().Should().Be("US");
JObject.Parse(userInfo.Locale).GetValue("language")!.Value<string>().Should().Be("en");
}

[Fact]
public void Missing_values_are_null()
{
Expand Down
44 changes: 44 additions & 0 deletions tests/Auth0.Core.UnitTests/StringOrObjectAsStringConverterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Auth0.Core.Serialization;
using Newtonsoft.Json;
using Xunit;

namespace Auth0.Core.UnitTests;

public class StringOrObjectAsStringConverterTests
{
internal class StringOrObjectAsStringConverterData
{
[JsonProperty("value")]
[JsonConverter(typeof(StringOrObjectAsStringConverter))]
public string Value { get; set; }
}
[Fact]
public void Should_deserialize_string()
{
var content = "{ 'value': 'test' }";

var parsed = JsonConvert.DeserializeObject<StringOrObjectAsStringConverterData>(content);

Assert.Equal("test", parsed.Value);
}

[Fact]
public void Should_deserialize_object_as_string()
{
var content = "{ 'value': { 'innerValue': 'test' } }";

var parsed = JsonConvert.DeserializeObject<StringOrObjectAsStringConverterData>(content);

Assert.Equal("{\n \"innerValue\": \"test\"\n}", parsed.Value);
}

[Fact]
public void Should_deserialize_when_omitted()
{
var content = "{}";

var parsed = JsonConvert.DeserializeObject<StringOrObjectAsStringConverterData>(content);

Assert.Null(parsed.Value);
}
}

0 comments on commit 5d6efd2

Please sign in to comment.