Skip to content

Commit 76aa676

Browse files
Brent Schmaltzbrentschmaltz
authored andcommitted
Add support for IList<string>, ICollection<string>
1 parent f602540 commit 76aa676

File tree

3 files changed

+335
-2
lines changed

3 files changed

+335
-2
lines changed

src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,20 +241,54 @@ internal T GetValue<T>(string key, bool throwEx, out bool found)
241241
if (objType == typeof(string))
242242
return (T)(object)new string[] { (string)obj };
243243

244+
if (objType == typeof(DateTime))
245+
return (T)(object)new string[] { ((DateTime)obj).ToString("o", CultureInfo.InvariantCulture) };
246+
244247
return (T)(object)new string[] { obj.ToString() };
245248
}
246249
else if (typeof(T) == typeof(List<string>))
247250
{
248251
if (objType == typeof(string))
249252
return (T)(object)new List<string> { (string)obj };
250253

254+
if (objType == typeof(DateTime))
255+
return (T)(object)new List<string> { ((DateTime)obj).ToString("o", CultureInfo.InvariantCulture) };
256+
251257
return (T)(object)new List<string> { obj.ToString() };
252258
}
253259
else if (typeof(T) == typeof(Collection<string>))
254260
{
255261
if (objType == typeof(string))
256262
return (T)(object)new Collection<string> { (string)obj };
257263

264+
if (objType == typeof(DateTime))
265+
return (T)(object)new Collection<string> { ((DateTime)obj).ToString("o", CultureInfo.InvariantCulture) };
266+
267+
return (T)(object)new Collection<string> { obj.ToString() };
268+
}
269+
// we could have added an OR condition to List<string>
270+
// but we have set an order of preference for the return types: Collection<string> is preferred over IList<string>
271+
else if (typeof(T) == typeof(IList<string>))
272+
{
273+
if (objType == typeof(string))
274+
return (T)(object)new List<string> { (string)obj };
275+
276+
if (objType == typeof(DateTime))
277+
return (T)(object)new List<string> { ((DateTime)obj).ToString("o", CultureInfo.InvariantCulture) };
278+
279+
return (T)(object)new List<string> { obj.ToString() };
280+
}
281+
// we could have added an OR condition to Collection<string>
282+
// but we have set an order of preference for the return types:
283+
// string[], List<string>, Collection<string>, IList<string>, ICollection<string>
284+
else if (typeof(T) == typeof(ICollection<string>))
285+
{
286+
if (objType == typeof(string))
287+
return (T)(object)new Collection<string> { (string)obj };
288+
289+
if (objType == typeof(DateTime))
290+
return (T)(object)new Collection<string> { ((DateTime)obj).ToString("o", CultureInfo.InvariantCulture) };
291+
258292
return (T)(object)new Collection<string> { obj.ToString() };
259293
}
260294
else if (typeof(T) == typeof(object[]))

src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,35 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
344344
t = (T)(object)items;
345345
return true;
346346
}
347+
// we could have added an OR condition to List<string>
348+
// but we have set an order of preference for the return types: Collection<string> is preferred over IList<string>
349+
else if (typeof(T) == typeof(IList<string>))
350+
{
351+
List<string> items = new();
352+
foreach (JsonElement j in jsonElement.EnumerateArray())
353+
if (j.ValueKind == JsonValueKind.String)
354+
items.Add(j.GetString());
355+
else
356+
items.Add(j.GetRawText());
357+
358+
t = (T)(object)items;
359+
return true;
360+
}
361+
// we could have added an OR condition to Collection<string>
362+
// but we have set an order of preference for the return types:
363+
// string[], List<string>, Collection<string>, IList<string>, ICollection<string>
364+
else if (typeof(T) == typeof(ICollection<string>))
365+
{
366+
Collection<string> items = new();
367+
foreach (JsonElement j in jsonElement.EnumerateArray())
368+
if (j.ValueKind == JsonValueKind.String)
369+
items.Add(j.GetString());
370+
else
371+
items.Add(j.GetRawText());
372+
373+
t = (T)(object)items;
374+
return true;
375+
}
347376
else if (typeof(T) == typeof(object[]))
348377
{
349378
int numItems = 0;

test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs

Lines changed: 272 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public void CompareJwtSecurityTokenWithJsonSecurityTokenMultipleAudiences()
241241

242242
// This test ensures that TryGetPayloadValue does not throw
243243
// No need to check for equal as GetPayloadValue does that
244-
[Theory, MemberData(nameof(GetPayloadValueTheoryData))]
244+
[Theory, MemberData(nameof(GetPayloadValueTheoryData), DisableDiscoveryEnumeration = true)]
245245
public void TryGetPayloadValue(GetPayloadValueTheoryData theoryData)
246246
{
247247
CompareContext context = TestUtilities.WriteHeader($"{this}.TryGetPayloadValue", theoryData);
@@ -264,7 +264,7 @@ public void TryGetPayloadValue(GetPayloadValueTheoryData theoryData)
264264
}
265265

266266
// This test ensures that our roundtripping works as expected.
267-
[Theory, MemberData(nameof(GetPayloadValueTheoryData))]
267+
[Theory, MemberData(nameof(GetPayloadValueTheoryData), DisableDiscoveryEnumeration = true)]
268268
public void GetPayloadValue(GetPayloadValueTheoryData theoryData)
269269
{
270270
CompareContext context = TestUtilities.WriteHeader($"{this}.GetPayloadValue", theoryData);
@@ -484,6 +484,260 @@ public static TheoryData<GetPayloadValueTheoryData> GetPayloadValueTheoryData
484484
});
485485
#endregion
486486

487+
#region collection of strings form simple types
488+
489+
#region string[]
490+
theoryData.Add(new GetPayloadValueTheoryData("string[]dateTime")
491+
{
492+
PropertyName = "dateTime",
493+
PropertyType = typeof(string[]),
494+
PropertyValue = new string[] {dateTime.ToString("o", CultureInfo.InvariantCulture)},
495+
Json = JsonUtilities.CreateUnsignedToken("dateTime", dateTime)
496+
});
497+
498+
theoryData.Add(new GetPayloadValueTheoryData("string[]true")
499+
{
500+
PropertyName = "true",
501+
PropertyType = typeof(string[]),
502+
PropertyValue = new string[] { "True" },
503+
Json = JsonUtilities.CreateUnsignedToken("true", true)
504+
});
505+
506+
theoryData.Add(new GetPayloadValueTheoryData("string[]double")
507+
{
508+
PropertyName = "double",
509+
PropertyType = typeof(string[]),
510+
PropertyValue = new string[] { "422.101" },
511+
Json = JsonUtilities.CreateUnsignedToken("double", 422.101)
512+
});
513+
514+
theoryData.Add(new GetPayloadValueTheoryData("string[]integer")
515+
{
516+
PropertyName = "integer",
517+
PropertyType = typeof(string[]),
518+
PropertyValue = new string[] { "42" },
519+
Json = JsonUtilities.CreateUnsignedToken("integer", 42)
520+
});
521+
522+
theoryData.Add(new GetPayloadValueTheoryData("string[]ulong")
523+
{
524+
PropertyName = "ulong",
525+
PropertyType = typeof(string[]),
526+
PropertyValue = new string[] { "42" },
527+
Json = JsonUtilities.CreateUnsignedToken("ulong", 42)
528+
});
529+
530+
theoryData.Add(new GetPayloadValueTheoryData("string[]string")
531+
{
532+
PropertyName = "string",
533+
PropertyType = typeof(string[]),
534+
PropertyValue = new string[] { "property" },
535+
Json = JsonUtilities.CreateUnsignedToken("string", "property")
536+
});
537+
#endregion
538+
539+
#region List:string
540+
theoryData.Add(new GetPayloadValueTheoryData("List<string>dateTime")
541+
{
542+
PropertyName = "dateTime",
543+
PropertyType = typeof(List<string>),
544+
PropertyValue = new List<string> { dateTime.ToString("o", CultureInfo.InvariantCulture) },
545+
Json = JsonUtilities.CreateUnsignedToken("dateTime", dateTime)
546+
});
547+
548+
theoryData.Add(new GetPayloadValueTheoryData("List<string>true")
549+
{
550+
PropertyName = "true",
551+
PropertyType = typeof(List<string>),
552+
PropertyValue = new List<string> { "True" },
553+
Json = JsonUtilities.CreateUnsignedToken("true", true)
554+
});
555+
556+
theoryData.Add(new GetPayloadValueTheoryData("List<string>double")
557+
{
558+
PropertyName = "double",
559+
PropertyType = typeof(List<string>),
560+
PropertyValue = new List<string> { "422.101" },
561+
Json = JsonUtilities.CreateUnsignedToken("double", 422.101)
562+
});
563+
564+
theoryData.Add(new GetPayloadValueTheoryData("List<string>integer")
565+
{
566+
PropertyName = "integer",
567+
PropertyType = typeof(List<string>),
568+
PropertyValue = new List<string> { "42" },
569+
Json = JsonUtilities.CreateUnsignedToken("integer", 42)
570+
});
571+
572+
theoryData.Add(new GetPayloadValueTheoryData("List<string>ulong")
573+
{
574+
PropertyName = "ulong",
575+
PropertyType = typeof(List<string>),
576+
PropertyValue = new List<string> { "42" },
577+
Json = JsonUtilities.CreateUnsignedToken("ulong", 42)
578+
});
579+
580+
theoryData.Add(new GetPayloadValueTheoryData("List<string>string")
581+
{
582+
PropertyName = "string",
583+
PropertyType = typeof(List<string>),
584+
PropertyValue = new List<string> { "property" },
585+
Json = JsonUtilities.CreateUnsignedToken("string", "property")
586+
});
587+
#endregion
588+
589+
#region Collection:string
590+
theoryData.Add(new GetPayloadValueTheoryData("Collection<string>dateTime")
591+
{
592+
PropertyName = "dateTime",
593+
PropertyType = typeof(Collection<string>),
594+
PropertyValue = new Collection<string> { dateTime.ToString("o", CultureInfo.InvariantCulture) },
595+
Json = JsonUtilities.CreateUnsignedToken("dateTime", dateTime)
596+
});
597+
598+
theoryData.Add(new GetPayloadValueTheoryData("Collection<string>true")
599+
{
600+
PropertyName = "true",
601+
PropertyType = typeof(Collection<string>),
602+
PropertyValue = new Collection<string> { "True" },
603+
Json = JsonUtilities.CreateUnsignedToken("true", true)
604+
});
605+
606+
theoryData.Add(new GetPayloadValueTheoryData("Collection<string>double")
607+
{
608+
PropertyName = "double",
609+
PropertyType = typeof(Collection<string>),
610+
PropertyValue = new Collection<string> { "422.101" },
611+
Json = JsonUtilities.CreateUnsignedToken("double", 422.101)
612+
});
613+
614+
theoryData.Add(new GetPayloadValueTheoryData("Collection<string>integer")
615+
{
616+
PropertyName = "integer",
617+
PropertyType = typeof(Collection<string>),
618+
PropertyValue = new Collection<string> { "42" },
619+
Json = JsonUtilities.CreateUnsignedToken("integer", 42)
620+
});
621+
622+
theoryData.Add(new GetPayloadValueTheoryData("Collection<string>ulong")
623+
{
624+
PropertyName = "ulong",
625+
PropertyType = typeof(Collection<string>),
626+
PropertyValue = new Collection<string> { "42" },
627+
Json = JsonUtilities.CreateUnsignedToken("ulong", 42)
628+
});
629+
630+
theoryData.Add(new GetPayloadValueTheoryData("Collection<string>string")
631+
{
632+
PropertyName = "string",
633+
PropertyType = typeof(Collection<string>),
634+
PropertyValue = new Collection<string> { "property" },
635+
Json = JsonUtilities.CreateUnsignedToken("string", "property")
636+
});
637+
#endregion
638+
639+
#region IList:string
640+
theoryData.Add(new GetPayloadValueTheoryData("IList<string>dateTime")
641+
{
642+
PropertyName = "dateTime",
643+
PropertyType = typeof(IList<string>),
644+
PropertyValue = new List<string> { dateTime.ToString("o", CultureInfo.InvariantCulture) },
645+
Json = JsonUtilities.CreateUnsignedToken("dateTime", dateTime)
646+
});
647+
648+
theoryData.Add(new GetPayloadValueTheoryData("IList<string>true")
649+
{
650+
PropertyName = "true",
651+
PropertyType = typeof(IList<string>),
652+
PropertyValue = new List<string> { "True" },
653+
Json = JsonUtilities.CreateUnsignedToken("true", true)
654+
});
655+
656+
theoryData.Add(new GetPayloadValueTheoryData("IList<string>double")
657+
{
658+
PropertyName = "double",
659+
PropertyType = typeof(IList<string>),
660+
PropertyValue = new List<string> { "422.101" },
661+
Json = JsonUtilities.CreateUnsignedToken("double", 422.101)
662+
});
663+
664+
theoryData.Add(new GetPayloadValueTheoryData("IList<string>integer")
665+
{
666+
PropertyName = "integer",
667+
PropertyType = typeof(IList<string>),
668+
PropertyValue = new List<string> { "42" },
669+
Json = JsonUtilities.CreateUnsignedToken("integer", 42)
670+
});
671+
672+
theoryData.Add(new GetPayloadValueTheoryData("IList<string>ulong")
673+
{
674+
PropertyName = "ulong",
675+
PropertyType = typeof(IList<string>),
676+
PropertyValue = new List<string> { "42" },
677+
Json = JsonUtilities.CreateUnsignedToken("ulong", 42)
678+
});
679+
680+
theoryData.Add(new GetPayloadValueTheoryData("IList<string>string")
681+
{
682+
PropertyName = "string",
683+
PropertyType = typeof(IList<string>),
684+
PropertyValue = new List<string> { "property" },
685+
Json = JsonUtilities.CreateUnsignedToken("string", "property")
686+
});
687+
#endregion
688+
689+
#region ICollection:string
690+
theoryData.Add(new GetPayloadValueTheoryData("ICollection<string>dateTime")
691+
{
692+
PropertyName = "dateTime",
693+
PropertyType = typeof(ICollection<string>),
694+
PropertyValue = new Collection<string> { dateTime.ToString("o", CultureInfo.InvariantCulture) },
695+
Json = JsonUtilities.CreateUnsignedToken("dateTime", dateTime)
696+
});
697+
698+
theoryData.Add(new GetPayloadValueTheoryData("ICollection<string>true")
699+
{
700+
PropertyName = "true",
701+
PropertyType = typeof(ICollection<string>),
702+
PropertyValue = new Collection<string> { "True" },
703+
Json = JsonUtilities.CreateUnsignedToken("true", true)
704+
});
705+
706+
theoryData.Add(new GetPayloadValueTheoryData("ICollection<string>double")
707+
{
708+
PropertyName = "double",
709+
PropertyType = typeof(ICollection<string>),
710+
PropertyValue = new Collection<string> { "422.101" },
711+
Json = JsonUtilities.CreateUnsignedToken("double", 422.101)
712+
});
713+
714+
theoryData.Add(new GetPayloadValueTheoryData("ICollection<string>integer")
715+
{
716+
PropertyName = "integer",
717+
PropertyType = typeof(ICollection<string>),
718+
PropertyValue = new Collection<string> { "42" },
719+
Json = JsonUtilities.CreateUnsignedToken("integer", 42)
720+
});
721+
722+
theoryData.Add(new GetPayloadValueTheoryData("ICollection<string>ulong")
723+
{
724+
PropertyName = "ulong",
725+
PropertyType = typeof(ICollection<string>),
726+
PropertyValue = new Collection<string> { "42" },
727+
Json = JsonUtilities.CreateUnsignedToken("ulong", 42)
728+
});
729+
730+
theoryData.Add(new GetPayloadValueTheoryData("ICollection<string>string")
731+
{
732+
PropertyName = "string",
733+
PropertyType = typeof(ICollection<string>),
734+
PropertyValue = new Collection<string> { "property" },
735+
Json = JsonUtilities.CreateUnsignedToken("string", "property")
736+
});
737+
#endregion
738+
739+
#endregion
740+
487741
#region complex types, dictionary, list, array, collection
488742
List<string> listStrings = new List<string> { "listValue1", "listValue2" };
489743
List<object> listObjects = new List<object> { "listValue1", "listValue2" };
@@ -559,6 +813,14 @@ public static TheoryData<GetPayloadValueTheoryData> GetPayloadValueTheoryData
559813
Json = JsonUtilities.CreateUnsignedToken("c", listStrings)
560814
});
561815

816+
theoryData.Add(new GetPayloadValueTheoryData("IListOfStrings")
817+
{
818+
PropertyName = "c",
819+
PropertyType = typeof(IList<string>),
820+
PropertyValue = listStrings,
821+
Json = JsonUtilities.CreateUnsignedToken("c", listStrings)
822+
});
823+
562824
theoryData.Add(new GetPayloadValueTheoryData("ListOfObjects")
563825
{
564826
PropertyName = "c",
@@ -575,6 +837,14 @@ public static TheoryData<GetPayloadValueTheoryData> GetPayloadValueTheoryData
575837
Json = JsonUtilities.CreateUnsignedToken("c", collectionStrings)
576838
});
577839

840+
theoryData.Add(new GetPayloadValueTheoryData("ICollectionOfStrings")
841+
{
842+
PropertyName = "c",
843+
PropertyType = typeof(ICollection<string>),
844+
PropertyValue = collectionStrings,
845+
Json = JsonUtilities.CreateUnsignedToken("c", collectionStrings)
846+
});
847+
578848
theoryData.Add(new GetPayloadValueTheoryData("CollectionOfObjects")
579849
{
580850
PropertyName = "c",

0 commit comments

Comments
 (0)