-
Notifications
You must be signed in to change notification settings - Fork 411
Expand file tree
/
Copy pathClaimsHelper.cs
More file actions
108 lines (98 loc) · 4.49 KB
/
Copy pathClaimsHelper.cs
File metadata and controls
108 lines (98 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Identity.Client.Utils;
using JObject = System.Text.Json.Nodes.JsonObject;
namespace Microsoft.Identity.Client.Internal
{
internal static class ClaimsHelper
{
private const string AccessTokenClaim = "access_token";
private const string XmsClientCapability = "xms_cc";
/// <summary>
/// Merges two JSON claims objects. If either is null/empty the other is returned as-is.
/// </summary>
internal static string MergeClaimsObjects(string claims1, string claims2)
{
if (string.IsNullOrEmpty(claims1)) return claims2;
if (string.IsNullOrEmpty(claims2)) return claims1;
try
{
JObject obj1 = JsonHelper.ParseIntoJsonObject(claims1);
JObject obj2 = JsonHelper.ParseIntoJsonObject(claims2);
JObject merged = JsonHelper.Merge(obj1, obj2);
return JsonHelper.JsonObjectToString(merged);
}
catch (Exception ex) when (ex is JsonException || ex is InvalidOperationException)
{
// InvalidOperationException is thrown by JsonNode.AsObject() when the root token is
// valid JSON but not an object (e.g. an array, a scalar, or the literal 'null').
// Do not include the raw claimsJson in the message — it may contain sensitive data.
throw new MsalClientException(
MsalError.InvalidJsonClaimsFormat,
"The claims value is not a valid JSON object. Inspect the inner exception for parsing details. " +
"See https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter.",
ex);
}
}
internal static string GetMergedClaimsAndClientCapabilities(
string claims,
IEnumerable<string> clientCapabilities)
{
if (clientCapabilities != null && clientCapabilities.Any())
{
JObject capabilitiesJson = CreateClientCapabilitiesRequestJson(clientCapabilities);
JObject mergedClaimsAndCapabilities = MergeClaimsIntoCapabilityJson(claims, capabilitiesJson);
return JsonHelper.JsonObjectToString(mergedClaimsAndCapabilities);
}
return claims;
}
internal static JObject MergeClaimsIntoCapabilityJson(string claims, JObject capabilitiesJson)
{
if (!string.IsNullOrEmpty(claims))
{
JObject claimsJson;
try
{
claimsJson = JsonHelper.ParseIntoJsonObject(claims);
}
catch (Exception ex) when (ex is JsonException || ex is InvalidOperationException)
{
// InvalidOperationException is thrown by JsonNode.AsObject() when the root token is
// valid JSON but not an object (e.g. an array, a scalar, or the literal 'null').
// This method also handles server-issued claims from .WithClaims(), so use a neutral
// message rather than naming client_claims specifically.
throw new MsalClientException(
MsalError.InvalidJsonClaimsFormat,
"The claims value is not a valid JSON object. Inspect the inner exception for parsing details. " +
"See https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter.",
ex);
}
capabilitiesJson = JsonHelper.Merge(capabilitiesJson, claimsJson);
}
return capabilitiesJson;
}
private static JObject CreateClientCapabilitiesRequestJson(IEnumerable<string> clientCapabilities)
{
// "access_token": {
// "xms_cc": {
// values: ["cp1", "cp2"]
// }
// }
return new JObject
{
[AccessTokenClaim] = new JObject
{
[XmsClientCapability] = new JObject
{
["values"] = new JsonArray(clientCapabilities.Select(c => JsonValue.Create(c)).ToArray())
}
}
};
}
}
}