diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs b/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs index 914c33768b..b9868dd9e7 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs @@ -61,7 +61,13 @@ internal static void CreateClaimFromObject(List claims, string claimType, else if (value is long l) claims.Add(new Claim(claimType, l.ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Integer64, issuer, issuer)); else if (value is bool b) - claims.Add(new Claim(claimType, b.ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Boolean, issuer, issuer)); + { + // Can't just use ToString or bools will get encoded as True/False instead of true/false. + if (b) + claims.Add(new Claim(claimType, "true", ClaimValueTypes.Boolean, issuer, issuer)); + else + claims.Add(new Claim(claimType, "false", ClaimValueTypes.Boolean, issuer, issuer)); + } else if (value is double d) claims.Add(new Claim(claimType, d.ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Double, issuer, issuer)); else if (value is DateTime dt) @@ -108,9 +114,9 @@ internal static Claim CreateClaimFromJsonElement(string claimType, string issuer else if (jsonElement.ValueKind == JsonValueKind.Object) return new Claim(claimType, jsonElement.ToString(), JsonClaimValueTypes.Json, issuer, issuer); else if (jsonElement.ValueKind == JsonValueKind.False) - return new Claim(claimType, "False", ClaimValueTypes.Boolean, issuer, issuer); + return new Claim(claimType, "false", ClaimValueTypes.Boolean, issuer, issuer); else if (jsonElement.ValueKind == JsonValueKind.True) - return new Claim(claimType, "True", ClaimValueTypes.Boolean, issuer, issuer); + return new Claim(claimType, "true", ClaimValueTypes.Boolean, issuer, issuer); else if (jsonElement.ValueKind == JsonValueKind.Number) { if (jsonElement.TryGetInt32(out int i)) diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs b/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs index 32efc9e3e1..d89bf96874 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtPayload.cs @@ -543,6 +543,14 @@ public virtual IEnumerable Claims } else if (keyValuePair.Value is DateTime dateTime) claims.Add(new Claim(keyValuePair.Key, dateTime.ToString("o", CultureInfo.InvariantCulture), ClaimValueTypes.DateTime, issuer, issuer)); + else if (keyValuePair.Value is bool boolValue) + { + // Can't just use ToString or bools will get encoded as True/False instead of true/false. + if (boolValue) + claims.Add(new Claim(keyValuePair.Key, "true", ClaimValueTypes.Boolean, issuer, issuer)); + else + claims.Add(new Claim(keyValuePair.Key, "false", ClaimValueTypes.Boolean, issuer, issuer)); + } else if (keyValuePair.Value != null) claims.Add(new Claim(keyValuePair.Key, keyValuePair.Value.ToString(), GetClaimValueType(keyValuePair.Value), issuer, issuer)); } @@ -557,6 +565,13 @@ private void AddListofObjects(string key, IEnumerable objects, List c.Type == "testClaim"); + Assert.Equal("true", testClaim.Value); + + var testClaim2 = claimSet.First(c => c.Type == "testClaim2"); + Assert.Equal("true", testClaim2.Value); + } + [Fact] public void DateTime2038Issue() { diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs index 90b5f3a5e1..9798607dc5 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtPayloadTest.cs @@ -256,8 +256,8 @@ public static TheoryData, JwtPayload, JwtPayload> PayloadDat new List { new Claim("ClaimValueTypes.String", "ClaimValueTypes.String.Value", ClaimValueTypes.String), - new Claim("ClaimValueTypes.Boolean.true", "True", ClaimValueTypes.Boolean), - new Claim("ClaimValueTypes.Boolean.false", "False", ClaimValueTypes.Boolean), + new Claim("ClaimValueTypes.Boolean.true", "true", ClaimValueTypes.Boolean), + new Claim("ClaimValueTypes.Boolean.false", "false", ClaimValueTypes.Boolean), new Claim("ClaimValueTypes.Double", "123.4", ClaimValueTypes.Double), new Claim("ClaimValueTypes.int.MaxValue", intMaxValue, ClaimValueTypes.Integer32), new Claim("ClaimValueTypes.int.MinValue", intMinValue, ClaimValueTypes.Integer32), @@ -300,8 +300,8 @@ public static TheoryData, JwtPayload, JwtPayload> PayloadDat new Claim("ClaimValueTypes", longValue, ClaimValueTypes.Integer64), new Claim("ClaimValueTypes", "132.64", ClaimValueTypes.Double), new Claim("ClaimValueTypes", "-132.64", ClaimValueTypes.Double), - new Claim("ClaimValueTypes", "True", ClaimValueTypes.Boolean), - new Claim("ClaimValueTypes", "False", ClaimValueTypes.Boolean), + new Claim("ClaimValueTypes", "true", ClaimValueTypes.Boolean), + new Claim("ClaimValueTypes", "false", ClaimValueTypes.Boolean), new Claim("ClaimValueTypes", "2019-11-15T14:31:21.6101326Z", ClaimValueTypes.DateTime), new Claim("ClaimValueTypes", "2019-11-15", ClaimValueTypes.String), new Claim("ClaimValueTypes", @"{""name3.1"":""value3.1""}", JsonClaimValueTypes.Json), diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenTests.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenTests.cs index 629fb694df..c53fcb5144 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenTests.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Linq; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Logging; @@ -13,6 +14,30 @@ namespace System.IdentityModel.Tokens.Jwt.Tests { public class JwtSecurityTokenTests { + [Fact] + public void BoolClaimsEncodedAsExpected() + { + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(new string('a', 128))); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + + var claims = new[] { new Claim("testClaim", "true", ClaimValueTypes.Boolean), new Claim("testClaim2", "True", ClaimValueTypes.Boolean) }; + var token = new JwtSecurityToken( + issuer: "issuer.contoso.com", + audience: "audience.contoso.com", + claims: claims, + expires: (new DateTime(2038, 1, 20)).ToUniversalTime(), + signingCredentials: creds); + + var claimSet = token.Claims; + + // Will throw if can't find. + var testClaim = claimSet.First(c => c.Type == "testClaim"); + Assert.Equal("true", testClaim.Value); + + var testClaim2 = claimSet.First(c => c.Type == "testClaim2"); + Assert.Equal("true", testClaim2.Value); + } + [Fact] public void DateTime2038Issue() {