-
Notifications
You must be signed in to change notification settings - Fork 420
/
Copy pathJsonWebTokenHandler.cs
537 lines (464 loc) · 26.4 KB
/
JsonWebTokenHandler.cs
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text.RegularExpressions;
using Microsoft.IdentityModel.Abstractions;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages;
namespace Microsoft.IdentityModel.JsonWebTokens
{
/// <summary>
/// A <see cref="SecurityTokenHandler"/> designed for creating and validating JSON Web Tokens.
/// See: <see href="https://datatracker.ietf.org/doc/html/rfc7519"/> and <see href="https://www.rfc-editor.org/info/rfc7515"/>.
/// </summary>
public partial class JsonWebTokenHandler : TokenHandler
{
private IDictionary<string, string> _inboundClaimTypeMap;
private const string _namespace = "http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties";
private static string _shortClaimType = _namespace + "/ShortTypeName";
private bool _mapInboundClaims = DefaultMapInboundClaims;
/// <summary>
/// Default claim type mapping for inbound claims.
/// </summary>
public static IDictionary<string, string> DefaultInboundClaimTypeMap = new Dictionary<string, string>(ClaimTypeMapping.InboundClaimTypeMap);
/// <summary>
/// Default value for the flag that determines whether or not the InboundClaimTypeMap is used.
/// </summary>
public static bool DefaultMapInboundClaims;
/// <summary>
/// Gets the Base64Url encoded string representation of the following JWT header:
/// { <see cref="JwtHeaderParameterNames.Alg"/>, <see cref="SecurityAlgorithms.None"/> }.
/// </summary>
/// <return>The Base64Url encoded string representation of the unsigned JWT header.</return>
public const string Base64UrlEncodedUnsignedJWSHeader = "eyJhbGciOiJub25lIn0";
/// <summary>
/// Initializes a new instance of the <see cref="JsonWebTokenHandler"/> class.
/// </summary>
public JsonWebTokenHandler()
{
if (_mapInboundClaims)
_inboundClaimTypeMap = new Dictionary<string, string>(DefaultInboundClaimTypeMap);
else
_inboundClaimTypeMap = new Dictionary<string, string>();
}
/// <summary>
/// Gets the type of the <see cref="JsonWebToken"/>.
/// </summary>
/// <return>The type of <see cref="JsonWebToken"/>.</return>
public Type TokenType
{
get { return typeof(JsonWebToken); }
}
/// <summary>
/// Gets or sets the property name of <see cref="Claim.Properties"/> the will contain the original JSON claim 'name' if a mapping occurred when the <see cref="Claim"/>(s) were created.
/// </summary>
/// <exception cref="ArgumentException">Thrown if 'value' is null or whitespace.</exception>
public static string ShortClaimTypeProperty
{
get
{
return _shortClaimType;
}
set
{
if (string.IsNullOrWhiteSpace(value))
throw LogHelper.LogArgumentNullException(nameof(value));
_shortClaimType = value;
}
}
/// <summary>
/// Gets or sets the <see cref="MapInboundClaims"/> property which is used when determining whether or not to map claim types that are extracted when validating a <see cref="JsonWebToken"/>.
/// <para>If this is set to true, the <see cref="Claim.Type"/> is set to the JSON claim 'name' after translating using this mapping. Otherwise, no mapping occurs.</para>
/// <para>The default value is false.</para>
/// </summary>
public bool MapInboundClaims
{
get
{
return _mapInboundClaims;
}
set
{
if (!_mapInboundClaims && value && _inboundClaimTypeMap.Count == 0)
_inboundClaimTypeMap = new Dictionary<string, string>(DefaultInboundClaimTypeMap);
_mapInboundClaims = value;
}
}
/// <summary>
/// Gets or sets the <see cref="InboundClaimTypeMap"/> which is used when setting the <see cref="Claim.Type"/> for claims in the <see cref="ClaimsPrincipal"/> extracted when validating a <see cref="JsonWebToken"/>.
/// <para>The <see cref="Claim.Type"/> is set to the JSON claim 'name' after translating using this mapping.</para>
/// <para>The default value is ClaimTypeMapping.InboundClaimTypeMap.</para>
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if 'value' is null.</exception>
public IDictionary<string, string> InboundClaimTypeMap
{
get
{
return _inboundClaimTypeMap;
}
set
{
_inboundClaimTypeMap = value ?? throw LogHelper.LogArgumentNullException(nameof(value));
}
}
/// <summary>
/// Determines if the string is a well formed JSON Web Token (JWT). See: <see href="https://datatracker.ietf.org/doc/html/rfc7519"/>.
/// </summary>
/// <param name="token">String that should represent a valid JWT.</param>
/// <remarks>Uses <see cref="Regex.IsMatch(string, string)"/> matching:
/// <para>JWS: @"^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$"</para>
/// <para>JWE: (dir): @"^[A-Za-z0-9-_]+\.\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$"</para>
/// <para>JWE: (wrappedkey): @"^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]$"</para>
/// </remarks>
/// <returns>
/// <para><see langword="false"/> if the token is null or whitespace.</para>
/// <para><see langword="false"/> if token.Length is greater than <see cref="TokenHandler.MaximumTokenSizeInBytes"/>.</para>
/// <para><see langword="true"/> if the token is in JSON Compact Serialization format.</para>
/// </returns>
public virtual bool CanReadToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
return false;
if (token.Length > MaximumTokenSizeInBytes)
{
if (LogHelper.IsEnabled(EventLogLevel.Informational))
LogHelper.LogInformation(TokenLogMessages.IDX10209, LogHelper.MarkAsNonPII(token.Length), LogHelper.MarkAsNonPII(MaximumTokenSizeInBytes));
return false;
}
// Count the number of segments, which is the number of periods + 1. We can stop when we've encountered
// more segments than the maximum we know how to handle.
int pos = 0;
int segmentCount = 1;
while (segmentCount <= JwtConstants.MaxJwtSegmentCount && ((pos = token.IndexOf('.', pos)) >= 0))
{
pos++;
segmentCount++;
}
switch (segmentCount)
{
case JwtConstants.JwsSegmentCount:
return JwtTokenUtilities.RegexJws.IsMatch(token);
case JwtConstants.JweSegmentCount:
return JwtTokenUtilities.RegexJwe.IsMatch(token);
default:
LogHelper.LogInformation(LogMessages.IDX14107);
return false;
}
}
private static StringComparison GetStringComparisonRuleIf509(SecurityKey securityKey) =>
securityKey is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
private static StringComparison GetStringComparisonRuleIf509OrECDsa(SecurityKey securityKey) =>
(securityKey is X509SecurityKey || securityKey is ECDsaSecurityKey) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
/// <summary>
/// Creates a <see cref="ClaimsIdentity"/> from a <see cref="JsonWebToken"/>.
/// </summary>
/// <param name="jwtToken">The <see cref="JsonWebToken"/> to use as a <see cref="Claim"/> source.</param>
/// <param name="validationParameters">The <see cref="TokenValidationParameters"/> to be used for validating the token.</param>
/// <returns>A <see cref="ClaimsIdentity"/> containing the <see cref="JsonWebToken.Claims"/>.</returns>
protected virtual ClaimsIdentity CreateClaimsIdentity(JsonWebToken jwtToken, TokenValidationParameters validationParameters)
{
_ = jwtToken ?? throw LogHelper.LogArgumentNullException(nameof(jwtToken));
return CreateClaimsIdentityPrivate(jwtToken, validationParameters, GetActualIssuer(jwtToken));
}
/// <summary>
/// Creates a <see cref="ClaimsIdentity"/> from a <see cref="JsonWebToken"/> with the specified issuer.
/// </summary>
/// <param name="jwtToken">The <see cref="JsonWebToken"/> to use as a <see cref="Claim"/> source.</param>
/// <param name="validationParameters">The <see cref="TokenValidationParameters"/> to be used for validating the token.</param>
/// <param name="issuer">Specifies the issuer for the <see cref="ClaimsIdentity"/>.</param>
/// <returns>A <see cref="ClaimsIdentity"/> containing the <see cref="JsonWebToken.Claims"/>.</returns>
protected virtual ClaimsIdentity CreateClaimsIdentity(JsonWebToken jwtToken, TokenValidationParameters validationParameters, string issuer)
{
_ = jwtToken ?? throw LogHelper.LogArgumentNullException(nameof(jwtToken));
if (string.IsNullOrWhiteSpace(issuer))
issuer = GetActualIssuer(jwtToken);
if (MapInboundClaims)
return CreateClaimsIdentityWithMapping(jwtToken, validationParameters, issuer);
return CreateClaimsIdentityPrivate(jwtToken, validationParameters, issuer);
}
private ClaimsIdentity CreateClaimsIdentityWithMapping(JsonWebToken jwtToken, TokenValidationParameters validationParameters, string issuer)
{
_ = validationParameters ?? throw LogHelper.LogArgumentNullException(nameof(validationParameters));
ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, issuer);
foreach (Claim jwtClaim in jwtToken.Claims)
{
bool wasMapped = _inboundClaimTypeMap.TryGetValue(jwtClaim.Type, out string claimType);
if (!wasMapped)
claimType = jwtClaim.Type;
if (claimType == ClaimTypes.Actor)
{
if (identity.Actor != null)
throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(
LogMessages.IDX14112,
LogHelper.MarkAsNonPII(JwtRegisteredClaimNames.Actort),
jwtClaim.Value)));
if (CanReadToken(jwtClaim.Value))
{
JsonWebToken actor = ReadToken(jwtClaim.Value) as JsonWebToken;
identity.Actor = CreateClaimsIdentity(actor, validationParameters);
}
}
if (wasMapped)
{
Claim claim = new Claim(claimType, jwtClaim.Value, jwtClaim.ValueType, issuer, issuer, identity);
if (jwtClaim.Properties.Count > 0)
{
foreach (var kv in jwtClaim.Properties)
{
claim.Properties[kv.Key] = kv.Value;
}
}
claim.Properties[ShortClaimTypeProperty] = jwtClaim.Type;
identity.AddClaim(claim);
}
else
{
identity.AddClaim(jwtClaim);
}
}
return identity;
}
internal override ClaimsIdentity CreateClaimsIdentityInternal(SecurityToken securityToken, TokenValidationParameters tokenValidationParameters, string issuer)
{
return CreateClaimsIdentity(securityToken as JsonWebToken, tokenValidationParameters, issuer);
}
private static string GetActualIssuer(JsonWebToken jwtToken)
{
string actualIssuer = jwtToken.Issuer;
if (string.IsNullOrWhiteSpace(actualIssuer))
{
if (LogHelper.IsEnabled(EventLogLevel.Verbose))
LogHelper.LogVerbose(TokenLogMessages.IDX10244, ClaimsIdentity.DefaultIssuer);
actualIssuer = ClaimsIdentity.DefaultIssuer;
}
return actualIssuer;
}
private ClaimsIdentity CreateClaimsIdentityPrivate(JsonWebToken jwtToken, TokenValidationParameters validationParameters, string issuer)
{
_ = validationParameters ?? throw LogHelper.LogArgumentNullException(nameof(validationParameters));
ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, issuer);
foreach (Claim jwtClaim in jwtToken.Claims)
{
string claimType = jwtClaim.Type;
if (claimType == ClaimTypes.Actor)
{
if (identity.Actor != null)
throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(LogMessages.IDX14112, LogHelper.MarkAsNonPII(JwtRegisteredClaimNames.Actort), jwtClaim.Value)));
if (CanReadToken(jwtClaim.Value))
{
JsonWebToken actor = ReadToken(jwtClaim.Value) as JsonWebToken;
identity.Actor = CreateClaimsIdentity(actor, validationParameters, issuer);
}
}
if (jwtClaim.Properties.Count == 0)
{
identity.AddClaim(new Claim(claimType, jwtClaim.Value, jwtClaim.ValueType, issuer, issuer, identity));
}
else
{
Claim claim = new Claim(claimType, jwtClaim.Value, jwtClaim.ValueType, issuer, issuer, identity);
foreach (var kv in jwtClaim.Properties)
claim.Properties[kv.Key] = kv.Value;
identity.AddClaim(claim);
}
}
return identity;
}
/// <summary>
/// Decrypts a JWE and returns the clear text.
/// </summary>
/// <param name="jwtToken">The JWE that contains the cypher text.</param>
/// <param name="validationParameters">The <see cref="TokenValidationParameters"/> to be used for validating the token.</param>
/// <returns>The decoded / cleartext contents of the JWE.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="jwtToken"/> is null.</exception>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="validationParameters"/> is null.</exception>
/// <exception cref="SecurityTokenException">Thrown if <see cref="JsonWebToken.Enc"/> is null or empty.</exception>
/// <exception cref="SecurityTokenDecompressionFailedException">Thrown if the decompression failed.</exception>
/// <exception cref="SecurityTokenEncryptionKeyNotFoundException">Thrown if <see cref="JsonWebToken.Kid"/> is not null AND the decryption fails.</exception>
/// <exception cref="SecurityTokenDecryptionFailedException">Thrown if the JWE was not able to be decrypted.</exception>
public string DecryptToken(JsonWebToken jwtToken, TokenValidationParameters validationParameters)
{
return DecryptToken(jwtToken, validationParameters, null);
}
private string DecryptToken(JsonWebToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
{
if (jwtToken == null)
throw LogHelper.LogArgumentNullException(nameof(jwtToken));
if (validationParameters == null)
throw LogHelper.LogArgumentNullException(nameof(validationParameters));
if (string.IsNullOrEmpty(jwtToken.Enc))
throw LogHelper.LogExceptionMessage(new SecurityTokenException(LogHelper.FormatInvariant(TokenLogMessages.IDX10612)));
var keys = GetContentEncryptionKeys(jwtToken, validationParameters, configuration);
return JwtTokenUtilities.DecryptJwtToken(
jwtToken,
validationParameters,
new JwtTokenDecryptionParameters
{
DecompressionFunction = JwtTokenUtilities.DecompressToken,
Keys = keys,
MaximumDeflateSize = MaximumTokenSizeInBytes
});
}
private static SecurityKey ResolveTokenDecryptionKeyFromConfig(JsonWebToken jwtToken, BaseConfiguration configuration)
{
if (jwtToken == null)
throw LogHelper.LogArgumentNullException(nameof(jwtToken));
if (!string.IsNullOrEmpty(jwtToken.Kid) && configuration.TokenDecryptionKeys != null)
{
foreach (var key in configuration.TokenDecryptionKeys)
{
if (key != null && string.Equals(key.KeyId, jwtToken.Kid, GetStringComparisonRuleIf509OrECDsa(key)))
return key;
}
}
if (!string.IsNullOrEmpty(jwtToken.X5t) && configuration.TokenDecryptionKeys != null)
{
foreach (var key in configuration.TokenDecryptionKeys)
{
if (key != null && string.Equals(key.KeyId, jwtToken.X5t, GetStringComparisonRuleIf509(key)))
return key;
var x509Key = key as X509SecurityKey;
if (x509Key != null && string.Equals(x509Key.X5t, jwtToken.X5t, StringComparison.OrdinalIgnoreCase))
return key;
}
}
return null;
}
/// <summary>
/// Returns a <see cref="SecurityKey"/> to use when decrypting a JWE.
/// </summary>
/// <param name="token">The <see cref="string"/> the token that is being decrypted.</param>
/// <param name="jwtToken">The <see cref="JsonWebToken"/> that is being decrypted.</param>
/// <param name="validationParameters">The <see cref="TokenValidationParameters"/> to be used for validating the token.</param>
/// <returns>A <see cref="SecurityKey"/> to use for signature validation.</returns>
/// <remarks>If key fails to resolve, then null is returned.</remarks>
protected virtual SecurityKey ResolveTokenDecryptionKey(string token, JsonWebToken jwtToken, TokenValidationParameters validationParameters)
{
if (jwtToken == null)
throw LogHelper.LogArgumentNullException(nameof(jwtToken));
if (validationParameters == null)
throw LogHelper.LogArgumentNullException(nameof(validationParameters));
StringComparison stringComparison = GetStringComparisonRuleIf509OrECDsa(validationParameters.TokenDecryptionKey);
if (!string.IsNullOrEmpty(jwtToken.Kid))
{
if (validationParameters.TokenDecryptionKey != null
&& string.Equals(validationParameters.TokenDecryptionKey.KeyId, jwtToken.Kid, stringComparison))
return validationParameters.TokenDecryptionKey;
if (validationParameters.TokenDecryptionKeys != null)
{
foreach (var key in validationParameters.TokenDecryptionKeys)
{
if (key != null && string.Equals(key.KeyId, jwtToken.Kid, GetStringComparisonRuleIf509OrECDsa(key)))
return key;
}
}
}
if (!string.IsNullOrEmpty(jwtToken.X5t))
{
if (validationParameters.TokenDecryptionKey != null)
{
if (string.Equals(validationParameters.TokenDecryptionKey.KeyId, jwtToken.X5t, stringComparison))
return validationParameters.TokenDecryptionKey;
var x509Key = validationParameters.TokenDecryptionKey as X509SecurityKey;
if (x509Key != null && string.Equals(x509Key.X5t, jwtToken.X5t, StringComparison.OrdinalIgnoreCase))
return validationParameters.TokenDecryptionKey;
}
if (validationParameters.TokenDecryptionKeys != null)
{
foreach (var key in validationParameters.TokenDecryptionKeys)
{
if (key != null && string.Equals(key.KeyId, jwtToken.X5t, GetStringComparisonRuleIf509(key)))
return key;
var x509Key = key as X509SecurityKey;
if (x509Key != null && string.Equals(x509Key.X5t, jwtToken.X5t, StringComparison.OrdinalIgnoreCase))
return key;
}
}
}
return null;
}
/// <summary>
/// Converts a string into an instance of <see cref="JsonWebToken"/>.
/// </summary>
/// <param name="token">A JSON Web Token (JWT) in JWS or JWE Compact Serialization format.</param>
/// <returns>A <see cref="JsonWebToken"/>.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="token"/> is null or empty.</exception>
/// <exception cref="ArgumentException">Thrown if the length of <paramref name="token"/> is greater than <see cref="TokenHandler.MaximumTokenSizeInBytes"/>.</exception>
/// <remarks>
/// <para>If the <paramref name="token"/> is in JWE Compact Serialization format, only the protected header will be deserialized.</para>
/// This method is unable to decrypt the payload. Use <see cref="ValidateToken(string, TokenValidationParameters)"/>to obtain the payload.
/// <para>
/// The token is NOT validated and no security decisions should be made about the contents.
/// Use <see cref="ValidateToken(string, TokenValidationParameters)"/> or <see cref="ValidateTokenAsync(string, TokenValidationParameters)"/> to ensure the token is acceptable.
/// </para>
/// </remarks>
public virtual JsonWebToken ReadJsonWebToken(string token)
{
if (string.IsNullOrEmpty(token))
throw LogHelper.LogArgumentNullException(nameof(token));
if (token.Length > MaximumTokenSizeInBytes)
throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(TokenLogMessages.IDX10209, LogHelper.MarkAsNonPII(token.Length), LogHelper.MarkAsNonPII(MaximumTokenSizeInBytes))));
return new JsonWebToken(token);
}
/// <summary>
/// Converts a string into an instance of <see cref="JsonWebToken"/>.
/// </summary>
/// <param name="token">A JSON Web Token (JWT) in JWS or JWE Compact Serialization format.</param>
/// <returns>A <see cref="JsonWebToken"/>.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="token"/> is null or empty.</exception>
/// <exception cref="ArgumentException">Thrown if the length of <paramref name="token"/> is greater than <see cref="TokenHandler.MaximumTokenSizeInBytes"/>.</exception>
/// <remarks>The token is NOT validated and no security decisions should be made about the contents.
/// <para>Use <see cref="ValidateToken(string, TokenValidationParameters)"/> or <see cref="ValidateTokenAsync(string, TokenValidationParameters)"/> to ensure the token is acceptable.</para>
/// </remarks>
public override SecurityToken ReadToken(string token)
{
return ReadJsonWebToken(token);
}
/// <summary>
/// Converts a string into an instance of <see cref="JsonWebToken"/>.
/// </summary>
/// <param name="token">A JSON Web Token (JWT) in JWS or JWE Compact Serialization format.</param>
/// <param name="validationParameters">A <see cref="TokenValidationParameters"/> whose TokenReader, if set, will be used to read a JWT.</param>
/// <returns>A <see cref="TokenValidationResult"/>.</returns>
/// <exception cref="SecurityTokenMalformedException">Thrown if the validationParameters.TokenReader delegate is not able to parse/read the token as a valid <see cref="JsonWebToken"/>.</exception>
/// <exception cref="SecurityTokenMalformedException">Thrown if <paramref name="token"/> is not a valid JWT, <see cref="JsonWebToken"/>.</exception>
private static TokenValidationResult ReadToken(string token, TokenValidationParameters validationParameters)
{
JsonWebToken jsonWebToken = null;
if (validationParameters.TokenReader != null)
{
var securityToken = validationParameters.TokenReader(token, validationParameters);
if (securityToken == null)
throw LogHelper.LogExceptionMessage(new SecurityTokenMalformedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10510, LogHelper.MarkAsSecurityArtifact(token, JwtTokenUtilities.SafeLogJwtToken))));
jsonWebToken = securityToken as JsonWebToken;
if (jsonWebToken == null)
throw LogHelper.LogExceptionMessage(new SecurityTokenMalformedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10509, typeof(JsonWebToken), securityToken.GetType(), LogHelper.MarkAsSecurityArtifact(token, JwtTokenUtilities.SafeLogJwtToken))));
}
else
{
#pragma warning disable CA1031 // Do not catch general exception types
try
{
jsonWebToken = new JsonWebToken(token);
}
catch (Exception ex)
{
return new TokenValidationResult
{
Exception = ex,
IsValid = false
};
}
#pragma warning restore CA1031 // Do not catch general exception types
}
return new TokenValidationResult
{
SecurityToken = jsonWebToken,
IsValid = true
};
}
}
}