1111using System . IO ;
1212using System . Linq ;
1313using System . Reflection ;
14+ using System . Security ;
1415using System . Text ;
1516using System . Threading ;
1617using System . Threading . Tasks ;
18+ using Microsoft . Identity . Client ;
1719using Newtonsoft . Json ;
1820using Xunit ;
1921
@@ -26,8 +28,9 @@ public static class DataTestUtility
2628 public static readonly string TCPConnectionStringHGSVBS = null ;
2729 public static readonly string TCPConnectionStringAASVBS = null ;
2830 public static readonly string TCPConnectionStringAASSGX = null ;
29- public static readonly string AADAccessToken = null ;
31+ public static readonly string AADAuthorityURL = null ;
3032 public static readonly string AADPasswordConnectionString = null ;
33+ public static readonly string AADAccessToken = null ;
3134 public static readonly string AKVBaseUrl = null ;
3235 public static readonly string AKVUrl = null ;
3336 public static readonly string AKVClientId = null ;
@@ -60,7 +63,7 @@ private class Config
6063 public string TCPConnectionStringHGSVBS = null ;
6164 public string TCPConnectionStringAASVBS = null ;
6265 public string TCPConnectionStringAASSGX = null ;
63- public string AADAccessToken = null ;
66+ public string AADAuthorityURL = null ;
6467 public string AADPasswordConnectionString = null ;
6568 public string AzureKeyVaultURL = null ;
6669 public string AzureKeyVaultClientId = null ;
@@ -83,13 +86,20 @@ static DataTestUtility()
8386 TCPConnectionStringHGSVBS = c . TCPConnectionStringHGSVBS ;
8487 TCPConnectionStringAASVBS = c . TCPConnectionStringAASVBS ;
8588 TCPConnectionStringAASSGX = c . TCPConnectionStringAASSGX ;
86- AADAccessToken = c . AADAccessToken ;
89+ AADAuthorityURL = c . AADAuthorityURL ;
8790 AADPasswordConnectionString = c . AADPasswordConnectionString ;
8891 SupportsLocalDb = c . SupportsLocalDb ;
8992 SupportsIntegratedSecurity = c . SupportsIntegratedSecurity ;
9093 SupportsFileStream = c . SupportsFileStream ;
9194 EnclaveEnabled = c . EnclaveEnabled ;
9295
96+ if ( IsAADPasswordConnStrSetup ( ) && IsAADAuthorityURLSetup ( ) )
97+ {
98+ string username = RetrieveValueFromConnStr ( AADPasswordConnectionString , new string [ ] { "User ID" , "UID" } ) ;
99+ string password = RetrieveValueFromConnStr ( AADPasswordConnectionString , new string [ ] { "Password" , "PWD" } ) ;
100+ AADAccessToken = GenerateAccessToken ( AADAuthorityURL , username , password ) ;
101+ }
102+
93103 string url = c . AzureKeyVaultURL ;
94104 Uri AKVBaseUri = null ;
95105 if ( ! string . IsNullOrEmpty ( url ) && Uri . TryCreate ( url , UriKind . Absolute , out AKVBaseUri ) )
@@ -134,6 +144,41 @@ static DataTestUtility()
134144 }
135145 }
136146
147+ private static string GenerateAccessToken ( string authorityURL , string aADAuthUserID , string aADAuthPassword )
148+ {
149+ return AcquireTokenAsync ( authorityURL , aADAuthUserID , aADAuthPassword ) . Result ;
150+ }
151+
152+ private static Task < string > AcquireTokenAsync ( string authorityURL , string userID , string password ) => Task . Run ( ( ) =>
153+ {
154+ // The below properties are set specific to test configurations.
155+ string scope = "https://database.windows.net//.default" ;
156+ string applicationName = "Microsoft Data SqlClient Manual Tests" ;
157+ string clientVersion = "1.0.0.0" ;
158+ string adoClientId = "4d079b4c-cab7-4b7c-a115-8fd51b6f8239" ;
159+
160+ IPublicClientApplication app = PublicClientApplicationBuilder . Create ( adoClientId )
161+ . WithAuthority ( authorityURL )
162+ . WithClientName ( applicationName )
163+ . WithClientVersion ( clientVersion )
164+ . Build ( ) ;
165+ AuthenticationResult result ;
166+ string [ ] scopes = new string [ ] { scope } ;
167+
168+ // Note: CorrelationId, which existed in ADAL, can not be set in MSAL (yet?).
169+ // parameter.ConnectionId was passed as the CorrelationId in ADAL to aid support in troubleshooting.
170+ // If/When MSAL adds CorrelationId support, it should be passed from parameters here, too.
171+
172+ SecureString securePassword = new SecureString ( ) ;
173+
174+ foreach ( char c in password )
175+ securePassword . AppendChar ( c ) ;
176+ securePassword . MakeReadOnly ( ) ;
177+ result = app . AcquireTokenByUsernamePassword ( scopes , userID , securePassword ) . ExecuteAsync ( ) . Result ;
178+
179+ return result . AccessToken ;
180+ } ) ;
181+
137182 public static bool IsDatabasePresent ( string name )
138183 {
139184 AvailableDatabases = AvailableDatabases ?? new Dictionary < string , bool > ( ) ;
@@ -171,6 +216,11 @@ public static bool IsAADPasswordConnStrSetup()
171216 return ! string . IsNullOrEmpty ( AADPasswordConnectionString ) ;
172217 }
173218
219+ public static bool IsAADAuthorityURLSetup ( )
220+ {
221+ return ! string . IsNullOrEmpty ( AADAuthorityURL ) ;
222+ }
223+
174224 public static bool IsNotAzureServer ( )
175225 {
176226 return AreConnStringsSetup ( ) ? ! DataTestUtility . IsAzureSqlServer ( new SqlConnectionStringBuilder ( ( DataTestUtility . TCPConnectionString ) ) . DataSource ) : true ;
@@ -248,10 +298,11 @@ public static string GetUniqueNameForSqlServer(string prefix)
248298
249299 public static string GetAccessToken ( )
250300 {
251- return AADAccessToken ;
301+ // Creates a new Object Reference of Access Token - See GitHub Issue 438
302+ return ( null != AADAccessToken ) ? new string ( AADAccessToken . ToCharArray ( ) ) : null ;
252303 }
253304
254- public static bool IsAccessTokenSetup ( ) => string . IsNullOrEmpty ( GetAccessToken ( ) ) ? false : true ;
305+ public static bool IsAccessTokenSetup ( ) => ! string . IsNullOrEmpty ( GetAccessToken ( ) ) ;
255306
256307 public static bool IsFileStreamSetup ( ) => SupportsFileStream ;
257308
@@ -519,5 +570,54 @@ public static string GetValueString(object paramValue)
519570
520571 return paramValue . ToString ( ) ;
521572 }
573+
574+ public static string RemoveKeysInConnStr ( string connStr , string [ ] keysToRemove )
575+ {
576+ // tokenize connection string and remove input keys.
577+ string res = "" ;
578+ string [ ] keys = connStr . Split ( ';' ) ;
579+ foreach ( var key in keys )
580+ {
581+ if ( ! string . IsNullOrEmpty ( key . Trim ( ) ) )
582+ {
583+ bool removeKey = false ;
584+ foreach ( var keyToRemove in keysToRemove )
585+ {
586+ if ( key . Trim ( ) . ToLower ( ) . StartsWith ( keyToRemove . Trim ( ) . ToLower ( ) ) )
587+ {
588+ removeKey = true ;
589+ break ;
590+ }
591+ }
592+ if ( ! removeKey )
593+ {
594+ res += key + ";" ;
595+ }
596+ }
597+ }
598+ return res ;
599+ }
600+
601+ public static string RetrieveValueFromConnStr ( string connStr , string [ ] keywords )
602+ {
603+ // tokenize connection string and retrieve value for a specific key.
604+ string res = "" ;
605+ string [ ] keys = connStr . Split ( ';' ) ;
606+ foreach ( var key in keys )
607+ {
608+ foreach ( var keyword in keywords )
609+ {
610+ if ( ! string . IsNullOrEmpty ( key . Trim ( ) ) )
611+ {
612+ if ( key . Trim ( ) . ToLower ( ) . StartsWith ( keyword . Trim ( ) . ToLower ( ) ) )
613+ {
614+ res = key . Substring ( key . IndexOf ( '=' ) + 1 ) . Trim ( ) ;
615+ break ;
616+ }
617+ }
618+ }
619+ }
620+ return res ;
621+ }
522622 }
523623}
0 commit comments