|
2 | 2 | // Licensed under the MIT License.
|
3 | 3 |
|
4 | 4 | using System;
|
| 5 | +using System.Collections.Concurrent; |
5 | 6 | using System.Collections.Generic;
|
6 | 7 | using System.Diagnostics;
|
| 8 | +using System.Runtime.CompilerServices; |
7 | 9 | using Microsoft.IdentityModel.Logging;
|
8 | 10 |
|
9 | 11 | namespace Microsoft.IdentityModel.Tokens
|
@@ -73,7 +75,7 @@ internal Exception GetException(Type exceptionType, Exception innerException)
|
73 | 75 | if (innerException == null && InnerValidationError == null)
|
74 | 76 | {
|
75 | 77 | if (exceptionType == typeof(SecurityTokenArgumentNullException))
|
76 |
| - return new SecurityTokenArgumentNullException(MessageDetail.Message); |
| 78 | + exception = new SecurityTokenArgumentNullException(MessageDetail.Message); |
77 | 79 | else if (exceptionType == typeof(SecurityTokenInvalidAudienceException))
|
78 | 80 | exception = new SecurityTokenInvalidAudienceException(MessageDetail.Message);
|
79 | 81 | else if (exceptionType == typeof(SecurityTokenInvalidIssuerException))
|
@@ -187,6 +189,11 @@ internal Exception GetException(Type exceptionType, Exception innerException)
|
187 | 189 | }
|
188 | 190 | }
|
189 | 191 |
|
| 192 | + if (exception is SecurityTokenException securityTokenException) |
| 193 | + securityTokenException.SetValidationError(this); |
| 194 | + else if (exception is SecurityTokenArgumentNullException securityTokenArgumentNullException) |
| 195 | + securityTokenArgumentNullException.SetValidationError(this); |
| 196 | + |
190 | 197 | return exception;
|
191 | 198 | }
|
192 | 199 |
|
@@ -236,5 +243,41 @@ public ValidationError AddStackFrame(StackFrame stackFrame)
|
236 | 243 | StackFrames.Add(stackFrame);
|
237 | 244 | return this;
|
238 | 245 | }
|
| 246 | + |
| 247 | + /// <summary> |
| 248 | + /// Adds the current stack frame to the list of stack frames and returns the updated object. |
| 249 | + /// If there is no cache entry for the given file path and line number, a new stack frame is created and added to the cache. |
| 250 | + /// </summary> |
| 251 | + /// <param name="filePath">The path to the file from which this method is called. Captured automatically by default.</param> |
| 252 | + /// <param name="lineNumber">The line number from which this method is called. CAptured automatically by default.</param> |
| 253 | + /// <param name="skipFrames">The number of stack frames to skip when capturing. Used to avoid capturing this method and get the caller instead.</param> |
| 254 | + /// <returns>The updated object.</returns> |
| 255 | + internal ValidationError AddCurrentStackFrame([CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, int skipFrames = 1) |
| 256 | + { |
| 257 | + // We add 1 to the skipped frames to skip the current method |
| 258 | + StackFrames.Add(GetCurrentStackFrame(filePath, lineNumber, skipFrames + 1)); |
| 259 | + return this; |
| 260 | + } |
| 261 | + |
| 262 | + /// <summary> |
| 263 | + /// Returns the stack frame corresponding to the file path and line number from which this method is called. |
| 264 | + /// If there is no cache entry for the given file path and line number, a new stack frame is created and added to the cache. |
| 265 | + /// </summary> |
| 266 | + /// <param name="filePath">The path to the file from which this method is called. Captured automatically by default.</param> |
| 267 | + /// <param name="lineNumber">The line number from which this method is called. CAptured automatically by default.</param> |
| 268 | + /// <param name="skipFrames">The number of stack frames to skip when capturing. Used to avoid capturing this method and get the caller instead.</param> |
| 269 | + /// <returns>The captured stack frame.</returns> |
| 270 | + /// <remarks>If this is called from a helper method, consider adding an extra skip frame to avoid capturing the helper instead.</remarks> |
| 271 | + internal static StackFrame GetCurrentStackFrame( |
| 272 | + [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, int skipFrames = 1) |
| 273 | + { |
| 274 | + // String is allocated, but it goes out of scope immediately after the call |
| 275 | + string key = filePath + lineNumber; |
| 276 | + StackFrame frame = CachedStackFrames.GetOrAdd(key, new StackFrame(skipFrames, true)); |
| 277 | + return frame; |
| 278 | + } |
| 279 | + |
| 280 | + // ConcurrentDictionary is thread-safe and only locks when adding a new item. |
| 281 | + private static ConcurrentDictionary<string, StackFrame> CachedStackFrames { get; } = new(); |
239 | 282 | }
|
240 | 283 | }
|
0 commit comments