@@ -119,7 +119,7 @@ sealed internal class SqlInternalConnectionTds : SqlInternalConnection, IDisposa
119119 // Connection Resiliency
120120 private bool _sessionRecoveryRequested ;
121121 internal bool _sessionRecoveryAcknowledged ;
122- internal SessionData _currentSessionData ; // internal for use from TdsParser only, otehr should use CurrentSessionData property that will fix database and language
122+ internal SessionData _currentSessionData ; // internal for use from TdsParser only, other should use CurrentSessionData property that will fix database and language
123123 private SessionData _recoverySessionData ;
124124
125125 // Federated Authentication
@@ -131,13 +131,14 @@ sealed internal class SqlInternalConnectionTds : SqlInternalConnection, IDisposa
131131 internal bool _federatedAuthenticationInfoRequested ; // Keep this distinct from _federatedAuthenticationRequested, since some fedauth library types may not need more info
132132 internal bool _federatedAuthenticationInfoReceived ;
133133
134+ // The Federated Authentication returned by TryGetFedAuthTokenLocked or GetFedAuthToken.
135+ SqlFedAuthToken _fedAuthToken = null ;
134136 internal byte [ ] _accessTokenInBytes ;
135137
136138 private readonly ActiveDirectoryAuthenticationTimeoutRetryHelper _activeDirectoryAuthTimeoutRetryHelper ;
137139 private readonly SqlAuthenticationProviderManager _sqlAuthenticationProviderManager ;
138140
139141 // Certificate auth calbacks.
140- //
141142 ServerCertificateValidationCallback _serverCallback ;
142143 ClientCertificateRetrievalCallback _clientCallback ;
143144 SqlClientOriginalNetworkAddressInfo _originalNetworkAddressInfo ;
@@ -146,6 +147,18 @@ sealed internal class SqlInternalConnectionTds : SqlInternalConnection, IDisposa
146147
147148 private bool _serverSupportsDNSCaching = false ;
148149
150+ /// <summary>
151+ /// Returns buffer time allowed before access token expiry to continue using the access token.
152+ /// </summary>
153+ private int accessTokenExpirationBufferTime
154+ {
155+ get
156+ {
157+ return ( ConnectionOptions . ConnectTimeout == ADP . InfiniteConnectionTimeout || ConnectionOptions . ConnectTimeout >= ADP . MaxBufferAccessTokenExpiry )
158+ ? ADP . MaxBufferAccessTokenExpiry : ConnectionOptions . ConnectTimeout ;
159+ }
160+ }
161+
149162 /// <summary>
150163 /// Get or set if SQLDNSCaching FeatureExtAck is supported by the server.
151164 /// </summary>
@@ -808,6 +821,10 @@ protected override bool UnbindOnTransactionCompletion
808821 }
809822 }
810823
824+ /// <summary>
825+ /// Validates if federated authentication is used, Access Token used by this connection is active for the value of 'accessTokenExpirationBufferTime'.
826+ /// </summary>
827+ internal override bool IsAccessTokenExpired => _federatedAuthenticationInfoRequested && DateTime. FromFileTimeUtc( _fedAuthToken . expirationFileTime ) < DateTime . UtcNow. AddSeconds( accessTokenExpirationBufferTime ) ;
811828
812829 ////////////////////////////////////////////////////////////////////////////////////////
813830 // GENERAL METHODS
@@ -1321,10 +1338,10 @@ internal void ExecuteTransactionYukon(
13211338 ThreadHasParserLockForClose = false ;
13221339 _parserLock . Release ( ) ;
13231340 releaseConnectionLock = false ;
1324- } , 0 ) ;
1341+ } , ADP . InfiniteConnectionTimeout ) ;
13251342 if ( reconnectTask != null )
13261343 {
1327- AsyncHelper . WaitForCompletion ( reconnectTask , 0 ) ; // there is no specific timeout for BeginTransaction, uses ConnectTimeout
1344+ AsyncHelper . WaitForCompletion ( reconnectTask , ADP . InfiniteConnectionTimeout ) ; // there is no specific timeout for BeginTransaction, uses ConnectTimeout
13281345 internalTransaction . ConnectionHasBeenRestored = true ;
13291346 return ;
13301347 }
@@ -2538,9 +2555,6 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
25382555 // We want to refresh the token, if taking the lock on the authentication context is successful.
25392556 bool attemptRefreshTokenLocked = false ;
25402557
2541- // The Federated Authentication returned by TryGetFedAuthTokenLocked or GetFedAuthToken.
2542- SqlFedAuthToken fedAuthToken = null ;
2543-
25442558 if ( _dbConnectionPool != null )
25452559 {
25462560 Debug . Assert ( _dbConnectionPool . AuthenticationContexts != null ) ;
@@ -2575,7 +2589,7 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
25752589 }
25762590 else if ( _forceExpiryLocked )
25772591 {
2578- attemptRefreshTokenLocked = TryGetFedAuthTokenLocked ( fedAuthInfo , dbConnectionPoolAuthenticationContext , out fedAuthToken ) ;
2592+ attemptRefreshTokenLocked = TryGetFedAuthTokenLocked ( fedAuthInfo , dbConnectionPoolAuthenticationContext , out _fedAuthToken ) ;
25792593 }
25802594#endif
25812595
@@ -2589,11 +2603,11 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
25892603
25902604 // Call the function which tries to acquire a lock over the authentication context before trying to update.
25912605 // If the lock could not be obtained, it will return false, without attempting to fetch a new token.
2592- attemptRefreshTokenLocked = TryGetFedAuthTokenLocked ( fedAuthInfo , dbConnectionPoolAuthenticationContext , out fedAuthToken ) ;
2606+ attemptRefreshTokenLocked = TryGetFedAuthTokenLocked ( fedAuthInfo , dbConnectionPoolAuthenticationContext , out _fedAuthToken ) ;
25932607
2594- // If TryGetFedAuthTokenLocked returns true, it means lock was obtained and fedAuthToken should not be null.
2608+ // If TryGetFedAuthTokenLocked returns true, it means lock was obtained and _fedAuthToken should not be null.
25952609 // If there was an exception in retrieving the new token, TryGetFedAuthTokenLocked should have thrown, so we won't be here.
2596- Debug . Assert ( ! attemptRefreshTokenLocked || fedAuthToken != null , "Either Lock should not have been obtained or fedAuthToken should not be null." ) ;
2610+ Debug . Assert ( ! attemptRefreshTokenLocked || _fedAuthToken != null , "Either Lock should not have been obtained or _fedAuthToken should not be null." ) ;
25972611 Debug . Assert ( ! attemptRefreshTokenLocked || _newDbConnectionPoolAuthenticationContext != null , "Either Lock should not have been obtained or _newDbConnectionPoolAuthenticationContext should not be null." ) ;
25982612
25992613 // Indicate in Bid Trace that we are successful with the update.
@@ -2610,8 +2624,8 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
26102624 if ( dbConnectionPoolAuthenticationContext == null || attemptRefreshTokenUnLocked )
26112625 {
26122626 // Get the Federated Authentication Token.
2613- fedAuthToken = GetFedAuthToken ( fedAuthInfo ) ;
2614- Debug . Assert ( fedAuthToken != null , "fedAuthToken should not be null." ) ;
2627+ _fedAuthToken = GetFedAuthToken ( fedAuthInfo ) ;
2628+ Debug . Assert ( _fedAuthToken != null , "_fedAuthToken should not be null." ) ;
26152629
26162630 if ( _dbConnectionPool != null )
26172631 {
@@ -2622,18 +2636,19 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
26222636 else if ( ! attemptRefreshTokenLocked )
26232637 {
26242638 Debug . Assert ( dbConnectionPoolAuthenticationContext != null , "dbConnectionPoolAuthenticationContext should not be null." ) ;
2625- Debug . Assert ( fedAuthToken == null , "fedAuthToken should be null in this case." ) ;
2639+ Debug . Assert ( _fedAuthToken == null , "_fedAuthToken should be null in this case." ) ;
26262640 Debug . Assert ( _newDbConnectionPoolAuthenticationContext == null , "_newDbConnectionPoolAuthenticationContext should be null." ) ;
26272641
2628- fedAuthToken = new SqlFedAuthToken ( ) ;
2642+ _fedAuthToken = new SqlFedAuthToken ( ) ;
26292643
26302644 // If the code flow is here, then we are re-using the context from the cache for this connection attempt and not
26312645 // generating a new access token on this thread.
2632- fedAuthToken . accessToken = dbConnectionPoolAuthenticationContext . AccessToken ;
2646+ _fedAuthToken . accessToken = dbConnectionPoolAuthenticationContext . AccessToken ;
2647+ _fedAuthToken . expirationFileTime = dbConnectionPoolAuthenticationContext . ExpirationTime . ToFileTime ( ) ;
26332648 }
26342649
2635- Debug . Assert ( fedAuthToken != null && fedAuthToken . accessToken != null , "fedAuthToken and fedAuthToken .accessToken cannot be null." ) ;
2636- _parser . SendFedAuthToken ( fedAuthToken ) ;
2650+ Debug . Assert ( _fedAuthToken != null && _fedAuthToken . accessToken != null , "_fedAuthToken and _fedAuthToken .accessToken cannot be null." ) ;
2651+ _parser . SendFedAuthToken ( _fedAuthToken ) ;
26372652 }
26382653
26392654 /// <summary>
@@ -2873,7 +2888,8 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
28732888 {
28742889 if ( _routingInfo != null )
28752890 {
2876- if ( TdsEnums . FEATUREEXT_SQLDNSCACHING != featureId ) {
2891+ if ( TdsEnums . FEATUREEXT_SQLDNSCACHING != featureId )
2892+ {
28772893 return ;
28782894 }
28792895 }
@@ -3101,16 +3117,18 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
31013117 throw SQL . ParsingError ( ParsingErrorState . CorruptedTdsStream ) ;
31023118 }
31033119
3104- if ( 1 == data [ 0 ] ) {
3120+ if ( 1 == data [ 0 ] )
3121+ {
31053122 IsSQLDNSCachingSupported = true ;
31063123 _cleanSQLDNSCaching = false ;
3107-
3124+
31083125 if ( _routingInfo != null )
31093126 {
31103127 IsDNSCachingBeforeRedirectSupported = true ;
31113128 }
31123129 }
3113- else {
3130+ else
3131+ {
31143132 // we receive the IsSupported whose value is 0
31153133 IsSQLDNSCachingSupported = false ;
31163134 _cleanSQLDNSCaching = true ;
0 commit comments