diff --git a/src/Microsoft.Identity.Web.OWIN/OpenIdConnectCachingSecurityTokenProvider.cs b/src/Microsoft.Identity.Web.OWIN/OpenIdConnectCachingSecurityTokenProvider.cs index 10950971b..f563985ee 100644 --- a/src/Microsoft.Identity.Web.OWIN/OpenIdConnectCachingSecurityTokenProvider.cs +++ b/src/Microsoft.Identity.Web.OWIN/OpenIdConnectCachingSecurityTokenProvider.cs @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; using Microsoft.Owin.Security.Jwt; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace Microsoft.Identity.Web { @@ -15,16 +15,14 @@ namespace Microsoft.Identity.Web // the OpenID Connect metadata endpoint exposed by the STS by default. internal class OpenIdConnectCachingSecurityTokenProvider : IIssuerSecurityKeyProvider { + private int _lock = 0; + public ConfigurationManager _configManager; private string? _issuer; private IEnumerable? _keys; - private readonly string _metadataEndpoint; - - private readonly ReaderWriterLockSlim _synclock = new ReaderWriterLockSlim(); public OpenIdConnectCachingSecurityTokenProvider(string metadataEndpoint) { - _metadataEndpoint = metadataEndpoint; _configManager = new ConfigurationManager(metadataEndpoint, new OpenIdConnectConfigurationRetriever()); RetrieveMetadata(); @@ -41,15 +39,7 @@ public string? Issuer get { RetrieveMetadata(); - _synclock.EnterReadLock(); - try - { - return _issuer; - } - finally - { - _synclock.ExitReadLock(); - } + return _issuer; } } @@ -64,32 +54,29 @@ public IEnumerable? SecurityKeys get { RetrieveMetadata(); - _synclock.EnterReadLock(); - try - { - return _keys; - } - finally - { - _synclock.ExitReadLock(); - } + return _keys; } } private void RetrieveMetadata() { - _synclock.EnterWriteLock(); - try + // Try to acquire the lock + // + // Interlocked.Exchange returns the original value of _lock before it was swapped. + // If it's 0, it means it went from 0 to 1, so we did acquire the lock. + // If it's 1, then the lock was already acquired by another thread. + // + // See the example in the Exchange(Int32, Int32) overload: https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked.exchange?view=netframework-4.7.2 + if (Interlocked.Exchange(ref _lock, 1) == 0) { #pragma warning disable VSTHRD002 // Avoid problematic synchronous waits OpenIdConnectConfiguration config = Task.Run(_configManager.GetConfigurationAsync).Result; #pragma warning restore VSTHRD002 // Avoid problematic synchronous waits _issuer = config.Issuer; _keys = config.SigningKeys; - } - finally - { - _synclock.ExitWriteLock(); + + // Release the lock + Interlocked.Exchange(ref _lock, 0); } } }