@@ -34,6 +34,7 @@ public sealed partial class SqlConnection : DbConnection, ICloneable
3434 private SqlCredential _credential ;
3535 private string _connectionString ;
3636 private int _connectRetryCount ;
37+ private string _accessToken ; // Access Token to be used for token based authentication
3738
3839 // connection resiliency
3940 private object _reconnectLock = new object ( ) ;
@@ -97,6 +98,7 @@ private SqlConnection(SqlConnection connection)
9798 _credential = new SqlCredential ( connection . _credential . UserId , password ) ;
9899 }
99100
101+ _accessToken = connection . _accessToken ;
100102 CacheConnectionStringProperties ( ) ;
101103 }
102104
@@ -222,12 +224,19 @@ public override string ConnectionString
222224 }
223225 set
224226 {
225- if ( _credential != null )
227+ if ( _credential != null || _accessToken != null )
226228 {
227229 SqlConnectionString connectionOptions = new SqlConnectionString ( value ) ;
228- CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential ( connectionOptions ) ;
230+ if ( _credential != null )
231+ {
232+ CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential ( connectionOptions ) ;
233+ }
234+ else
235+ {
236+ CheckAndThrowOnInvalidCombinationOfConnectionOptionAndAccessToken ( connectionOptions ) ;
237+ }
229238 }
230- ConnectionString_Set ( new SqlConnectionPoolKey ( value , _credential ) ) ;
239+ ConnectionString_Set ( new SqlConnectionPoolKey ( value , _credential , _accessToken ) ) ;
231240 _connectionString = value ; // Change _connectionString value only after value is validated
232241 CacheConnectionStringProperties ( ) ;
233242 }
@@ -242,6 +251,37 @@ public override int ConnectionTimeout
242251 }
243252 }
244253
254+ // AccessToken: To be used for token based authentication
255+ public string AccessToken
256+ {
257+ get
258+ {
259+ string result = _accessToken ;
260+ // When a connection is connecting or is ever opened, make AccessToken available only if "Persist Security Info" is set to true
261+ // otherwise, return null
262+ SqlConnectionString connectionOptions = ( SqlConnectionString ) UserConnectionOptions ;
263+ return InnerConnection . ShouldHidePassword && connectionOptions != null && ! connectionOptions . PersistSecurityInfo ? null : _accessToken ;
264+ }
265+ set
266+ {
267+ // If a connection is connecting or is ever opened, AccessToken cannot be set
268+ if ( ! InnerConnection . AllowSetConnectionString )
269+ {
270+ throw ADP . OpenConnectionPropertySet ( nameof ( AccessToken ) , InnerConnection . State ) ;
271+ }
272+
273+ if ( value != null )
274+ {
275+ // Check if the usage of AccessToken has any conflict with the keys used in connection string and credential
276+ CheckAndThrowOnInvalidCombinationOfConnectionOptionAndAccessToken ( ( SqlConnectionString ) ConnectionOptions ) ;
277+ }
278+
279+ // Need to call ConnectionString_Set to do proper pool group check
280+ ConnectionString_Set ( new SqlConnectionPoolKey ( _connectionString , credential : _credential , accessToken : value ) ) ;
281+ _accessToken = value ;
282+ }
283+ }
284+
245285 public override string Database
246286 {
247287 // if the connection is open, we need to ask the inner connection what it's
@@ -396,12 +436,16 @@ public SqlCredential Credential
396436 if ( value != null )
397437 {
398438 CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential ( ( SqlConnectionString ) ConnectionOptions ) ;
439+ if ( _accessToken != null )
440+ {
441+ throw ADP . InvalidMixedUsageOfCredentialAndAccessToken ( ) ;
442+ }
399443 }
400444
401445 _credential = value ;
402446
403447 // Need to call ConnectionString_Set to do proper pool group check
404- ConnectionString_Set ( new SqlConnectionPoolKey ( _connectionString , _credential ) ) ;
448+ ConnectionString_Set ( new SqlConnectionPoolKey ( _connectionString , _credential , accessToken : _accessToken ) ) ;
405449 }
406450 }
407451
@@ -422,6 +466,29 @@ private void CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential
422466 }
423467 }
424468
469+ // CheckAndThrowOnInvalidCombinationOfConnectionOptionAndAccessToken: check if the usage of AccessToken has any conflict
470+ // with the keys used in connection string and credential
471+ // If there is any conflict, it throws InvalidOperationException
472+ // This is to be used setter of ConnectionString and AccessToken properties
473+ private void CheckAndThrowOnInvalidCombinationOfConnectionOptionAndAccessToken ( SqlConnectionString connectionOptions )
474+ {
475+ if ( UsesClearUserIdOrPassword ( connectionOptions ) )
476+ {
477+ throw ADP . InvalidMixedUsageOfAccessTokenAndUserIDPassword ( ) ;
478+ }
479+
480+ if ( UsesIntegratedSecurity ( connectionOptions ) )
481+ {
482+ throw ADP . InvalidMixedUsageOfAccessTokenAndIntegratedSecurity ( ) ;
483+ }
484+
485+ // Check if the usage of AccessToken has the conflict with credential
486+ if ( _credential != null )
487+ {
488+ throw ADP . InvalidMixedUsageOfCredentialAndAccessToken ( ) ;
489+ }
490+ }
491+
425492 protected override DbProviderFactory DbProviderFactory
426493 {
427494 get => SqlClientFactory . Instance ;
@@ -654,6 +721,7 @@ public override void Close()
654721 private void DisposeMe ( bool disposing )
655722 {
656723 _credential = null ;
724+ _accessToken = null ;
657725
658726 if ( ! disposing )
659727 {
@@ -1360,7 +1428,7 @@ public static void ChangePassword(string connectionString, string newPassword)
13601428 throw ADP . InvalidArgumentLength ( nameof ( newPassword ) , TdsEnums . MAXLEN_NEWPASSWORD ) ;
13611429 }
13621430
1363- SqlConnectionPoolKey key = new SqlConnectionPoolKey ( connectionString , credential : null ) ;
1431+ SqlConnectionPoolKey key = new SqlConnectionPoolKey ( connectionString , credential : null , accessToken : null ) ;
13641432
13651433 SqlConnectionString connectionOptions = SqlConnectionFactory . FindSqlConnectionOptions ( key ) ;
13661434 if ( connectionOptions . IntegratedSecurity )
@@ -1403,7 +1471,7 @@ public static void ChangePassword(string connectionString, SqlCredential credent
14031471 throw ADP . InvalidArgumentLength ( nameof ( newSecurePassword ) , TdsEnums . MAXLEN_NEWPASSWORD ) ;
14041472 }
14051473
1406- SqlConnectionPoolKey key = new SqlConnectionPoolKey ( connectionString , credential ) ;
1474+ SqlConnectionPoolKey key = new SqlConnectionPoolKey ( connectionString , credential : null , accessToken : null ) ;
14071475
14081476 SqlConnectionString connectionOptions = SqlConnectionFactory . FindSqlConnectionOptions ( key ) ;
14091477
@@ -1441,7 +1509,7 @@ private static void ChangePassword(string connectionString, SqlConnectionString
14411509 if ( con != null )
14421510 con . Dispose ( ) ;
14431511 }
1444- SqlConnectionPoolKey key = new SqlConnectionPoolKey ( connectionString , credential ) ;
1512+ SqlConnectionPoolKey key = new SqlConnectionPoolKey ( connectionString , credential : null , accessToken : null ) ;
14451513
14461514 SqlConnectionFactory . SingletonInstance . ClearPool ( key ) ;
14471515 }
0 commit comments