//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // harsudan // yuronhe //------------------------------------------------------------------------------ using System; using System.Diagnostics; using System.Runtime.ConstrainedExecution; using System.Threading; namespace System.Data.ProviderBase { /// /// Represents the context of an authentication attempt when using the new active directory based authentication mechanisms. /// All data members, except_isUpdateInProgressCounter, should be immutable. /// sealed internal class DbConnectionPoolAuthenticationContext { /// /// The value expected in _isUpdateInProgress if a thread has taken a lock on this context, /// to perform the update on the context. /// private const int STATUS_LOCKED = 1; /// /// The value expected in _isUpdateInProgress if no thread has taken a lock on this context. /// private const int STATUS_UNLOCKED = 0; /// /// Access Token, which is obtained from Active Directory Authentication Library for SQL Server, and needs to be sent to SQL Server /// as part of TDS Token type Federated Authentication Token. /// private readonly byte[] _accessToken; /// /// Expiration time of the above access token. /// private readonly DateTime _expirationTime; /// /// A member which is used to achieve a lock to control refresh attempt on this context. /// private int _isUpdateInProgress; /// /// Constructor. /// /// Access Token that will be used to connect to SQL Server. Carries identity information about a user. /// The expiration time in UTC for the above accessToken. internal DbConnectionPoolAuthenticationContext(byte[] accessToken, DateTime expirationTime) { Debug.Assert(accessToken != null && accessToken.Length > 0); Debug.Assert(expirationTime > DateTime.MinValue && expirationTime < DateTime.MaxValue); _accessToken = accessToken; _expirationTime = expirationTime; _isUpdateInProgress = STATUS_UNLOCKED; } /// /// Static Method. /// Given two contexts, choose one to update in the cache. Chooses based on expiration time. /// /// Context1 /// Context2 internal static DbConnectionPoolAuthenticationContext ChooseAuthenticationContextToUpdate(DbConnectionPoolAuthenticationContext context1, DbConnectionPoolAuthenticationContext context2) { Debug.Assert(context1 != null, "context1 should not be null."); Debug.Assert(context2 != null, "context2 should not be null."); return context1.ExpirationTime > context2.ExpirationTime ? context1 : context2; } internal byte[] AccessToken { get { return _accessToken; } } internal DateTime ExpirationTime { get { return _expirationTime; } } /// /// Try locking the variable _isUpdateInProgressCounter and return if this thread got the lock to update. /// Whichever thread got the chance to update this variable to 1 wins the lock. /// internal bool LockToUpdate() { int oldValue = Interlocked.CompareExchange(ref _isUpdateInProgress, STATUS_LOCKED, STATUS_UNLOCKED); return (oldValue == STATUS_UNLOCKED); } /// /// Release the lock which was obtained through LockToUpdate. /// [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal void ReleaseLockToUpdate() { int oldValue = Interlocked.CompareExchange(ref _isUpdateInProgress, STATUS_UNLOCKED, STATUS_LOCKED); Debug.Assert(oldValue == STATUS_LOCKED); } } }