/// <summary>
        /// Tries integrated windows auth first before trying interactive authentication.
        /// </summary>
        /// <remarks>https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/wam</remarks>
        private async Task <AuthenticationResult> CreateVssCredentialsWithAadForWindowsAsync(IPublicClientApplication app, string[] scopes)
        {
            AuthenticationResult result = null;

            try
            {
                result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                         .ExecuteAsync();

                m_logger("[VssCredentialsFactory] Integrated Windows Authentication was successful.");
            }
            catch (MsalUiRequiredException)
            {
                result = await CreateVssCredentialsWithAadInteractiveAsync(app, scopes);
            }
            catch (MsalServiceException serviceException)
            {
                m_logger($"[VssCredentialsFactory] Unable to acquire credentials with interactive Windows AAD auth with the following exception: '{serviceException}'");
            }
            catch (MsalClientException clientException)
            {
                m_logger($"[VssCredentialsFactory] Unable to acquire credentials with interactive Windows AAD auth with the following exception: '{clientException}'");
            }

            return(result);
        }
Beispiel #2
0
        public async Task <bool> AcquireTokenSilentAsync()
        {
            try
            {
                if (_integratedAuthAvailable)
                {
                    _authenticationResult = await _client.AcquireTokenByIntegratedWindowsAuth(_scopes)
                                            .ExecuteAsync();
                }
                else
                {
                    var accounts = await _client.GetAccountsAsync();

                    _authenticationResult = await _client.AcquireTokenSilent(_scopes)
                                            .WithAccount(accounts.FirstOrDefault())
                                            .ExecuteAsync();
                }

                return(true);
            }
            catch (MsalUiRequiredException)
            {
                // Interactive authentication is required
                return(false);
            }
            catch (MsalException)
            {
                // TODO WTS: Silentauth failed, please handle this exception as appropriate to your scenario
                // For more info on MsalExceptions see
                // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/exceptions
                return(false);
            }
        }
Beispiel #3
0
 private static Task <AuthenticationResult> StartAcquireTokenAsync(IPublicClientApplication pca)
 {
     if (s_useIWA)
     {
         return(pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).ExecuteAsync());
     }
     return(pca.AcquireTokenInteractive(s_scopes).WithUseEmbeddedWebView(false).ExecuteAsync());
 }
Beispiel #4
0
        private static async Task OAuthSSO()
        {
            string[] scopes = new string[] { "user.read" };

            app = PublicClientApplicationBuilder.Create(configuration["Azure:ClientID"])
                  //.WithRedirectUri(configuration["Azure:Redirect"])
                  .WithAuthority(AzureCloudInstance.AzurePublic, configuration["Azure:TenantID"])
                  .Build();


            var accounts = await app.GetAccountsAsync();

            AuthenticationResult result = null;

            if (accounts.Any())
            {
                result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                         .ExecuteAsync();
            }
            else
            {
                try
                {
                    result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .ExecuteAsync(CancellationToken.None);
                }
                catch (MsalUiRequiredException ex)
                {
                    Console.WriteLine(string.Concat("AAD error: ", ex.Message, " Code: ", ex.ErrorCode));
                }
                catch (MsalServiceException ex)
                {
                    Console.WriteLine(ex.Message);
                }
                catch (MsalClientException ex)
                {
                    Console.WriteLine(ex.ErrorCode);

                    // ErrorCode kann hier nachgeschlagen werden : https://docs.microsoft.com/en-us/dotnet/api/microsoft.identity.client.msalerror?view=azure-dotnet

                    Console.WriteLine(ex.Message);

                    if (ex.InnerException != null && ex.InnerException is MsalServiceException)
                    {
                        Console.WriteLine(((MsalServiceException)ex.InnerException).Message);
                        Console.WriteLine(((MsalServiceException)ex.InnerException).ResponseBody);
                    }
                }
            }
        }
Beispiel #5
0
        private async Task <bool> AcquireTokenSilentAsync(string[] scopes)
        {
            if (!NetworkInterface.GetIsNetworkAvailable())
            {
                return(false);
            }

            try
            {
                var accounts = await _client.GetAccountsAsync();

                _authenticationResult = await _client.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                                        .ExecuteAsync();

                return(true);
            }
            catch (MsalUiRequiredException ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                if (_integratedAuthAvailable)
                {
                    try
                    {
                        _authenticationResult = await _client.AcquireTokenByIntegratedWindowsAuth(_graphScopes)
                                                .ExecuteAsync();

                        return(true);
                    }
                    catch (MsalUiRequiredException)
                    {
                        // Interactive authentication is required
                        return(false);
                    }
                }
                else
                {
                    // Interactive authentication is required
                    return(false);
                }
            }
            catch (MsalException)
            {
                // TODO WTS: Silentauth failed, please handle this exception as appropriate to your scenario
                // For more info on MsalExceptions see
                // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/exceptions
                return(false);
            }
        }
Beispiel #6
0
        private async void AcquireTokenIWA_ClickAsync(object sender, RoutedEventArgs e)
        {
            AuthenticationResult result = null;

            try
            {
                result = await _pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                await DisplayErrorAsync(ex).ConfigureAwait(false);

                return;
            }

            await DisplayResultAsync(result).ConfigureAwait(false);
        }
Beispiel #7
0
        public async Task <string> GetAccessTokenAsync(IEnumerable <string> scopes)
        {
            try
            {
                var result = await publicClientApplication.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithUsername(tokenCreatorConfiguration.UserPrincipalName)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                return(result.AccessToken);
            }
            catch (MsalServiceException msalServiceException)
            {
                logger.LogError(msalServiceException, msalServiceException.Message);
                throw new InvalidOperationException(AuthenticationResources.MsalException, msalServiceException);
            }
        }
Beispiel #8
0
        private async Task <bool> AcquireTokenSilentAsync(string[] scopes)
        {
            if (!NetworkInterface.GetIsNetworkAvailable())
            {
                return(false);
            }

            try
            {
                var accounts = await _client.GetAccountsAsync();

                _authenticationResult = await _client.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                                        .ExecuteAsync();

                return(true);
            }
            catch (MsalUiRequiredException)
            {
                if (_integratedAuthAvailable)
                {
                    try
                    {
                        _authenticationResult = await _client.AcquireTokenByIntegratedWindowsAuth(scopes)
                                                .ExecuteAsync();

                        return(true);
                    }
                    catch (MsalUiRequiredException)
                    {
                        // Interactive authentication is required
                        return(false);
                    }
                }
                else
                {
                    // Interactive authentication is required
                    return(false);
                }
            }
            catch (MsalException)
            {
                return(false);
            }
        }
Beispiel #9
0
        /// <summary>
        /// Get token.
        /// </summary>
        public override Task <SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) => Task.Run(async() =>
        {
            IPublicClientApplication app = PublicClientApplicationBuilder.Create(ActiveDirectoryAuthentication.AdoClientId)
                                           .WithAuthority(parameters.Authority)
                                           .WithClientName(Common.DbConnectionStringDefaults.ApplicationName)
                                           .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString())
                                           .Build();
            AuthenticationResult result;
            string scope    = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;
            string[] scopes = new string[] { scope };

            // Note: CorrelationId, which existed in ADAL, can not be set in MSAL (yet?).
            // parameter.ConnectionId was passed as the CorrelationId in ADAL to aid support in troubleshooting.
            // If/When MSAL adds CorrelationId support, it should be passed from parameters here, too.

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
            {
                result = app.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync().Result;
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword)
            {
                SecureString password = new SecureString();
                foreach (char c in parameters.Password)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();
                result = app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password).ExecuteAsync().Result;
            }
            else
            {
                result = await app.AcquireTokenInteractive(scopes)
                         .WithUseEmbeddedWebView(true)
                         .WithLoginHint(parameters.UserId)
                         .ExecuteAsync();
            }

            return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
        });
        /// <summary>
        ///  Token refresh flow for MSAL User Flows.
        /// </summary>
        /// <param name="publicAppClient">MSAL Client to use.</param>
        /// <param name="scopes">Scopes to send in.</param>
        /// <param name="account"></param>
        /// <param name="promptBehavior">prompting behavior</param>
        /// <param name="clientCredentials">user credential package</param>
        /// <param name="useDefaultCreds">should system default creds be used</param>
        /// <param name="logSink">logger to write logs too.</param>
        /// <returns></returns>
        internal async static Task <AuthenticationResult> ObtainAccessTokenAsync(
            IPublicClientApplication publicAppClient,
            List <string> scopes,
            IAccount account,
            PromptBehavior promptBehavior,
            ClientCredentials clientCredentials,
            bool useDefaultCreds   = false,
            CdsTraceLogger logSink = null)
        {
            // This works for user Auth flows.
            AuthenticationResult _authenticationResult = null;
            bool clientCredentialsCheck = clientCredentials != null && clientCredentials.UserName != null && !string.IsNullOrEmpty(clientCredentials.UserName.UserName) && !string.IsNullOrEmpty(clientCredentials.UserName.Password);
            // Login user hint
            string loginUserHint = (clientCredentials != null && clientCredentials.UserName != null) ? clientCredentials.UserName.UserName : string.Empty;

            if (publicAppClient != null)
            {
                if (clientCredentialsCheck && !useDefaultCreds && !(promptBehavior == PromptBehavior.Always || promptBehavior == PromptBehavior.SelectAccount))
                {
                    _authenticationResult = publicAppClient.AcquireTokenByUsernamePassword(scopes, clientCredentials.UserName.UserName, CdsServiceClient.MakeSecureString(clientCredentials.UserName.Password)).ExecuteAsync().Result;
                }
                else
                {
                    if (useDefaultCreds)
                    {
                        if (!string.IsNullOrEmpty(loginUserHint))
                        {
                            _authenticationResult = await publicAppClient.AcquireTokenByIntegratedWindowsAuth(scopes).WithUsername(loginUserHint).ExecuteAsync();
                        }
                        else
                        {
                            _authenticationResult = await publicAppClient.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync();
                        }
                    }
                    else
                    {
                        logSink.Log(string.Format("ObtainAccessToken - PROMPT - Behavior: {0}", promptBehavior), TraceEventType.Verbose);
                        Microsoft.Identity.Client.Prompt?userPrompt = null;
                        switch (promptBehavior)
                        {
                        case PromptBehavior.Auto:
                            break;

                        case PromptBehavior.Always:
                            userPrompt = Microsoft.Identity.Client.Prompt.ForceLogin;
                            break;

                        case PromptBehavior.Never:
                        case PromptBehavior.RefreshSession:
                            userPrompt = Microsoft.Identity.Client.Prompt.NoPrompt;
                            break;

                        case PromptBehavior.SelectAccount:
                            userPrompt = Microsoft.Identity.Client.Prompt.SelectAccount;
                            break;

                        default:
                            break;
                        }

                        if (userPrompt != null)
                        {
                            _authenticationResult = await publicAppClient.AcquireTokenInteractive(scopes).WithLoginHint(loginUserHint).WithPrompt(userPrompt.Value).ExecuteAsync();
                        }
                        else
                        {
                            if (account != null)
                            {
                                _authenticationResult = await publicAppClient.AcquireTokenSilent(scopes, account).ExecuteAsync();
                            }
                            else
                            {
                                _authenticationResult = await publicAppClient.AcquireTokenInteractive(scopes).WithLoginHint(loginUserHint).ExecuteAsync();
                            }
                        }
                    }
                }
            }
            else
            {
                // throw here.
            }
            return(_authenticationResult);
        }
Beispiel #11
0
        private static async Task RunConsoleAppLogicAsync(IPublicClientApplication pca)
        {
            while (true)
            {
                Console.Clear();

                Console.WriteLine("Authority: " + GetAuthority());
                await DisplayAccountsAsync(pca).ConfigureAwait(false);

                // display menu
                Console.WriteLine(@"
                        1. IWA
                        2. Acquire Token with Username and Password
                        3. Acquire Token with Device Code
                        5. Acquire Token Interactive 
                        6. Acquire Token Silently
                        7. Acquire Interactive (logic in netstandard, default authority)
                        8. Clear cache
                        9. Rotate Tenant ID
                        0. Exit App
                    Enter your Selection: ");
                int.TryParse(Console.ReadLine(), out var selection);

                Task <AuthenticationResult> authTask = null;

                try
                {
                    switch (selection)
                    {
                    case 1: // acquire token
                        authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 2: // acquire token u/p
                        SecureString password = GetPasswordFromConsole();
                        authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 3:
                        authTask = pca.AcquireTokenWithDeviceCode(
                            s_scopes,
                            deviceCodeResult =>
                        {
                            Console.WriteLine(deviceCodeResult.Message);
                            return(Task.FromResult(0));
                        }).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 5: // acquire token interactive

                        CancellationTokenSource cts = new CancellationTokenSource();
                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithUseEmbeddedWebView(false)
                                   .WithSystemWebViewOptions(new SystemWebViewOptions()
                        {
                            //BrowserRedirectSuccess = new Uri("https://www.google.com"),
                            HtmlMessageSuccess = "All good, close the browser!",

                            OpenBrowserAsync = (Uri u) =>
                            {
                                string url = u.AbsoluteUri;
                                url        = url.Replace("&", "^&");
                                Process.Start(new ProcessStartInfo("cmd", $"/c start msedge {url}")
                                {
                                    CreateNoWindow = true
                                });
                                return(Task.FromResult(0));
                            }
                        })
                                   .ExecuteAsync(cts.Token);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 6: // acquire token silent
                        IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault();
                        if (account == null)
                        {
                            Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false);
                        }

                        authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 7:
                        CancellationTokenSource cts2 = new CancellationTokenSource();
                        var authenticator            = new NetStandardAuthenticator(Log, CacheFilePath);
                        await FetchTokenAndCallGraphAsync(pca, authenticator.GetTokenInteractiveAsync(cts2.Token)).ConfigureAwait(false);

                        break;

                    case 8:
                        var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                        foreach (var acc in accounts)
                        {
                            await pca.RemoveAsync(acc).ConfigureAwait(false);
                        }

                        break;

                    case 9:

                        s_currentTid = (s_currentTid + 1) % s_tids.Length;
                        pca          = CreatePca();
                        RunConsoleAppLogicAsync(pca).Wait();
                        break;


                    case 0:
                        return;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log(LogLevel.Error, ex.Message, false);
                    Log(LogLevel.Error, ex.StackTrace, false);
                }

                Console.WriteLine("\n\nHit 'ENTER' to continue...");
                Console.ReadLine();
            }
        }
Beispiel #12
0
        /// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
        public override async Task <SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters)
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // Use Connection timeout value to cancel token acquire request after certain period of time.
            cts.CancelAfter(parameters.ConnectionTimeout * 1000); // Convert to milliseconds

            string scope = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;

            string[] scopes = new string[] { scope };

            int    seperatorIndex = parameters.Authority.LastIndexOf('/');
            string tenantId       = parameters.Authority.Substring(seperatorIndex + 1);
            string authority      = parameters.Authority.Remove(seperatorIndex + 1);

            TokenRequestContext tokenRequestContext = new TokenRequestContext(scopes);
            string clientId = string.IsNullOrWhiteSpace(parameters.UserId) ? null : parameters.UserId;

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDefault)
            {
                DefaultAzureCredentialOptions defaultAzureCredentialOptions = new DefaultAzureCredentialOptions()
                {
                    AuthorityHost                       = new Uri(authority),
                    ManagedIdentityClientId             = clientId,
                    InteractiveBrowserTenantId          = tenantId,
                    SharedTokenCacheTenantId            = tenantId,
                    SharedTokenCacheUsername            = clientId,
                    VisualStudioCodeTenantId            = tenantId,
                    VisualStudioTenantId                = tenantId,
                    ExcludeInteractiveBrowserCredential = true // Force disabled, even though it's disabled by default to respect driver specifications.
                };
                AccessToken accessToken = await new DefaultAzureCredential(defaultAzureCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token);
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Default auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
                return(new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn));
            }

            TokenCredentialOptions tokenCredentialOptions = new TokenCredentialOptions()
            {
                AuthorityHost = new Uri(authority)
            };

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity || parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryMSI)
            {
                AccessToken accessToken = await new ManagedIdentityCredential(clientId, tokenCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token);
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Managed Identity auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
                return(new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn));
            }

            AuthenticationResult result;

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal)
            {
                AccessToken accessToken = await new ClientSecretCredential(tenantId, parameters.UserId, parameters.Password, tokenCredentialOptions).GetTokenAsync(tokenRequestContext, cts.Token);
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Service Principal auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
                return(new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn));
            }

            /*
             * Today, MSAL.NET uses another redirect URI by default in desktop applications that run on Windows
             * (urn:ietf:wg:oauth:2.0:oob). In the future, we'll want to change this default, so we recommend
             * that you use https://login.microsoftonline.com/common/oauth2/nativeclient.
             *
             * https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris
             */
            string redirectUri = s_nativeClientRedirectUri;

#if NETCOREAPP
            if (parameters.AuthenticationMethod != SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
            {
                redirectUri = "http://localhost";
            }
#endif
            PublicClientAppKey pcaKey = new PublicClientAppKey(parameters.Authority, redirectUri, _applicationClientId
#if NETFRAMEWORK
                                                               , _iWin32WindowFunc
#endif
#if NETSTANDARD
                                                               , _parentActivityOrWindowFunc
#endif
                                                               );

            IPublicClientApplication app = GetPublicClientAppInstance(pcaKey);

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
            {
                if (!string.IsNullOrEmpty(parameters.UserId))
                {
                    result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .WithUsername(parameters.UserId)
                             .ExecuteAsync(cancellationToken: cts.Token);
                }
                else
                {
                    result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .ExecuteAsync(cancellationToken: cts.Token);
                }
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Integrated auth mode. Expiry Time: {0}", result?.ExpiresOn);
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword)
            {
                SecureString password = new SecureString();
                foreach (char c in parameters.Password)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();

                result = await app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password)
                         .WithCorrelationId(parameters.ConnectionId)
                         .ExecuteAsync(cancellationToken: cts.Token);

                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Password auth mode. Expiry Time: {0}", result?.ExpiresOn);
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive ||
                     parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
            {
                // Fetch available accounts from 'app' instance
                System.Collections.Generic.IEnumerator <IAccount> accounts = (await app.GetAccountsAsync()).GetEnumerator();

                IAccount account = default;
                if (accounts.MoveNext())
                {
                    if (!string.IsNullOrEmpty(parameters.UserId))
                    {
                        do
                        {
                            IAccount currentVal = accounts.Current;
                            if (string.Compare(parameters.UserId, currentVal.Username, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                account = currentVal;
                                break;
                            }
                        }while (accounts.MoveNext());
                    }
                    else
                    {
                        account = accounts.Current;
                    }
                }

                if (null != account)
                {
                    try
                    {
                        // If 'account' is available in 'app', we use the same to acquire token silently.
                        // Read More on API docs: https://docs.microsoft.com/dotnet/api/microsoft.identity.client.clientapplicationbase.acquiretokensilent
                        result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken: cts.Token);

                        SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (silent) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
                    }
                    catch (MsalUiRequiredException)
                    {
                        // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application,
                        // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired),
                        // or the user needs to perform two factor authentication.
                        result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod, cts);

                        SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
                    }
                }
                else
                {
                    // If no existing 'account' is found, we request user to sign in interactively.
                    result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod, cts);

                    SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
                }
            }
            else
            {
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | {0} authentication mode not supported by ActiveDirectoryAuthenticationProvider class.", parameters.AuthenticationMethod);
                throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod);
            }

            return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
        }
        private static async Task RunConsoleAppLogicAsync(IPublicClientApplication pca)
        {
            while (true)
            {
                Console.Clear();

                Console.WriteLine("Authority: " + GetAuthority());
                await DisplayAccountsAsync(pca).ConfigureAwait(false);

                // display menu
                Console.WriteLine(@"
                        1. IWA
                        2. Acquire Token with Username and Password
                        3. Acquire Token with Device Code
                        4. Acquire Token Interactive (via CustomWebUI)
                        5. Acquire Token Interactive
                        6. Acquire Token Silently
                        7. Confidential Client
                        8. Clear cache
                        9. Rotate Tenant ID
                        0. Exit App
                    Enter your Selection: ");
                int.TryParse(Console.ReadLine(), out var selection);

                Task <AuthenticationResult> authTask = null;

                try
                {
                    switch (selection)
                    {
                    case 1:     // acquire token
                        authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 2:     // acquire token u/p
                        SecureString password = GetPasswordFromConsole();
                        authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 3:
                        authTask = pca.AcquireTokenWithDeviceCode(
                            s_scopes,
                            deviceCodeResult =>
                        {
                            Console.WriteLine(deviceCodeResult.Message);
                            return(Task.FromResult(0));
                        }).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 4:     // acquire token interactive with custom web ui

                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithCustomWebUi(new DefaultOsBrowserWebUi()) // make sure you've configured a redirect uri of "http://localhost" or "http://localhost:1234" in the _pca builder
                                   .ExecuteAsync(CancellationToken.None);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 5:     // acquire token interactive

                        var options = new SystemWebViewOptions()
                        {
                            //BrowserRedirectSuccess = new Uri("https://www.bing.com?q=why+is+42+the+meaning+of+life")
                            OpenBrowserAsync = SystemWebViewOptions.OpenWithEdgeBrowserAsync
                        };

                        var cts = new CancellationTokenSource();
                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithSystemWebViewOptions(options)
                                   .ExecuteAsync(cts.Token);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 6:     // acquire token silent
                        IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault();
                        if (account == null)
                        {
                            Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false);
                        }

                        authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 7:
                        for (int i = 0; i < 100; i++)
                        {
                            var cca = CreateCca();

                            var resultX = await cca.AcquireTokenForClient(
                                new[] { "https://graph.microsoft.com/.default" })
                                          //.WithForceRefresh(true)
                                          .ExecuteAsync()
                                          .ConfigureAwait(false);

                            await Task.Delay(500).ConfigureAwait(false);

                            Console.WriteLine("Got a token");
                        }

                        Console.WriteLine("Finished");
                        break;

                    case 8:
                        var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                        foreach (var acc in accounts)
                        {
                            await pca.RemoveAsync(acc).ConfigureAwait(false);
                        }

                        break;

                    case 9:

                        s_currentTid = (s_currentTid + 1) % s_tids.Length;
                        pca          = CreatePca();
                        RunConsoleAppLogicAsync(pca).Wait();
                        break;

                    case 0:
                        return;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log(LogLevel.Error, ex.Message, false);
                    Log(LogLevel.Error, ex.StackTrace, false);
                }

                Console.WriteLine("\n\nHit 'ENTER' to continue...");
                Console.ReadLine();
            }
        }
Beispiel #14
0
        internal async Task <string> IntegratedAsync()
        {
            IPublicClientApplication app = PublicClientApplicationBuilder
                                           .Create(clientId)
                                           .WithTenantId(tenantId)
                                           .Build();

            var accounts = await app.GetAccountsAsync();

            AuthenticationResult auth = null;

            if (accounts.Any())
            {
                auth = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                       .ExecuteAsync();
            }
            else
            {
                try
                {
                    auth = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
                           .WithUsername(username)
                           .ExecuteAsync();
                }
                catch (MsalUiRequiredException ex)
                {
                    // MsalUiRequiredException: AADSTS65001: The user or administrator has not consented to use the application
                    // with ID '{appId}' named '{appName}'.Send an interactive authorization request for this user and resource.

                    // you need to get user consent first. This can be done, if you are not using .NET Core (which does not have any Web UI)
                    // by doing (once only) an AcquireToken interactive.

                    // If you are using .NET core or don't want to do an AcquireTokenInteractive, you might want to suggest the user to navigate
                    // to a URL to consent: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read

                    // AADSTS50079: The user is required to use multi-factor authentication.
                    // There is no mitigation - if MFA is configured for your tenant and AAD decides to enforce it,
                    // you need to fallback to an interactive flows such as AcquireTokenInteractive or AcquireTokenByDeviceCode
                }
                catch (MsalServiceException ex)
                {
                    // Kind of errors you could have (in ex.Message)

                    // MsalServiceException: AADSTS90010: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.
                    // you used common.
                    // Mitigation: as explained in the message from Azure AD, the authoriy needs to be tenanted or otherwise organizations

                    // MsalServiceException: AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
                    // Explanation: this can happen if your application was not registered as a public client application in Azure AD
                    // Mitigation: in the Azure portal, edit the manifest for your application and set the `allowPublicClient` to `true`
                }
                catch (MsalClientException ex)
                {
                    // Error Code: unknown_user Message: Could not identify logged in user
                    // Explanation: the library was unable to query the current Windows logged-in user or this user is not AD or AAD
                    // joined (work-place joined users are not supported).

                    // Mitigation 1: on UWP, check that the application has the following capabilities: Enterprise Authentication,
                    // Private Networks (Client and Server), User Account Information

                    // Mitigation 2: Implement your own logic to fetch the username (e.g. [email protected]) and use the
                    // AcquireTokenByIntegratedWindowsAuth form that takes in the username

                    // Error Code: integrated_windows_auth_not_supported_managed_user
                    // Explanation: This method relies on an a protocol exposed by Active Directory (AD). If a user was created in Azure
                    // Active Directory without AD backing ("managed" user), this method will fail. Users created in AD and backed by
                    // AAD ("federated" users) can benefit from this non-interactive method of authentication.
                    // Mitigation: Use interactive authentication
                }
            }

            return(auth.AccessToken);
        }
        /// <summary>
        /// Get token.
        /// </summary>
        public override Task <SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) => Task.Run(async() =>
        {
            AuthenticationResult result;
            string scope    = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;
            string[] scopes = new string[] { scope };

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal)
            {
                IConfidentialClientApplication ccApp = ConfidentialClientApplicationBuilder.Create(parameters.UserId)
                                                       .WithAuthority(parameters.Authority)
                                                       .WithClientSecret(parameters.Password)
                                                       .WithClientName(Common.DbConnectionStringDefaults.ApplicationName)
                                                       .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString())
                                                       .Build();

                result = ccApp.AcquireTokenForClient(scopes).ExecuteAsync().Result;
                return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
            }

            IPublicClientApplication app = PublicClientApplicationBuilder.Create(ActiveDirectoryAuthentication.AdoClientId)
                                           .WithAuthority(parameters.Authority)
                                           .WithClientName(Common.DbConnectionStringDefaults.ApplicationName)
                                           .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString())
#if netcoreapp
                                           .WithRedirectUri("http://localhost")
#else
                                           /*
                                            * Today, MSAL.NET uses another redirect URI by default in desktop applications that run on Windows
                                            * (urn:ietf:wg:oauth:2.0:oob). In the future, we'll want to change this default, so we recommend
                                            * that you use https://login.microsoftonline.com/common/oauth2/nativeclient.
                                            *
                                            * https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris
                                            */
                                           .WithRedirectUri("https://login.microsoftonline.com/oauth2/nativeclient")
#endif
                                           .Build();

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
            {
                if (!string.IsNullOrEmpty(parameters.UserId))
                {
                    result = app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .WithUsername(parameters.UserId)
                             .ExecuteAsync().Result;
                }
                else
                {
                    result = app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .ExecuteAsync().Result;
                }
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword)
            {
                SecureString password = new SecureString();
                foreach (char c in parameters.Password)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();
                result = app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password)
                         .WithCorrelationId(parameters.ConnectionId)
                         .ExecuteAsync().Result;
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive)
            {
                var accounts = await app.GetAccountsAsync();
                IAccount account;
                if (!string.IsNullOrEmpty(parameters.UserId))
                {
                    account = accounts.FirstOrDefault(a => parameters.UserId.Equals(a.Username, System.StringComparison.InvariantCultureIgnoreCase));
                }
                else
                {
                    account = accounts.FirstOrDefault();
                }

                if (null != account)
                {
                    try
                    {
                        result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();
                    }
                    catch (MsalUiRequiredException)
                    {
                        result = await AcquireTokenInteractive(app, scopes, parameters.ConnectionId, parameters.UserId);
                    }
                }
                else
                {
                    result = await AcquireTokenInteractive(app, scopes, parameters.ConnectionId, parameters.UserId);
                }
            }
            else
            {
                throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod);
            }

            return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
        });
        private static async Task RunConsoleAppLogicAsync(IPublicClientApplication pca)
        {
            while (true)
            {
                Console.Clear();
                Console.ForegroundColor = ConsoleColor.DarkYellow;
                Console.WriteLine($"" +
                                  $"IsDesktopSession: {pca.IsUserInteractive()}, " +
                                  $"IsEmbeddedWebViewAvailable: {pca.IsEmbeddedWebViewAvailable()} " +
                                  $"IsEmbeddedWebViewAvailable: {pca.IsSystemWebViewAvailable()}");

                Console.WriteLine("Authority: " + GetAuthority());
                await DisplayAccountsAsync(pca).ConfigureAwait(false);

                // display menu
                Console.WriteLine(@"
                        1. IWA
                        2. Acquire Token with Username and Password
                        3. Acquire Token with Device Code
                        4. Acquire Token Interactive (via CustomWebUI)
                        5. Acquire Token Interactive
                        6. Acquire Token Silently
                        7. Confidential Client
                        8. Clear cache
                        9. Rotate Tenant ID
                       10. Acquire Token Interactive with Chrome
                       11. AcquireTokenForClient with multiple threads
                        0. Exit App
                    Enter your Selection: ");
                int.TryParse(Console.ReadLine(), out var selection);

                Task <AuthenticationResult> authTask = null;

                try
                {
                    switch (selection)
                    {
                    case 1:     // acquire token
                        authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 2:     // acquire token u/p
                        SecureString password = GetPasswordFromConsole();
                        authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 3:
                        authTask = pca.AcquireTokenWithDeviceCode(
                            s_scopes,
                            deviceCodeResult =>
                        {
                            Console.WriteLine(deviceCodeResult.Message);
                            return(Task.FromResult(0));
                        }).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 4:     // acquire token interactive with custom web ui

                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithCustomWebUi(new DefaultOsBrowserWebUi()) // make sure you've configured a redirect uri of "http://localhost" or "http://localhost:1234" in the _pca builder
                                   .ExecuteAsync(CancellationToken.None);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 5:     // acquire token interactive

                        var options = new SystemWebViewOptions()
                        {
                            //BrowserRedirectSuccess = new Uri("https://www.bing.com?q=why+is+42+the+meaning+of+life")
                            OpenBrowserAsync = SystemWebViewOptions.OpenWithEdgeBrowserAsync
                        };

                        var cts = new CancellationTokenSource();
                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithSystemWebViewOptions(options)
                                   .ExecuteAsync(cts.Token);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 6:     // acquire token silent
                        IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault();
                        if (account == null)
                        {
                            Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false);
                        }

                        authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 7:
                        for (int i = 0; i < 100; i++)
                        {
                            var cca = CreateCca();

                            var resultX = await cca.AcquireTokenForClient(GraphAppScope)
                                          //.WithForceRefresh(true)
                                          .ExecuteAsync()
                                          .ConfigureAwait(false);

                            await Task.Delay(500).ConfigureAwait(false);

                            Console.WriteLine("Got a token");
                        }

                        Console.WriteLine("Finished");
                        break;

                    case 8:
                        var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                        foreach (var acc in accounts)
                        {
                            await pca.RemoveAsync(acc).ConfigureAwait(false);
                        }

                        break;

                    case 9:
                        s_currentTid = (s_currentTid + 1) % s_tids.Length;
                        pca          = CreatePca();
                        RunConsoleAppLogicAsync(pca).Wait();
                        break;

                    case 10:     // acquire token interactive with Chrome

                        var optionsChrome = new SystemWebViewOptions()
                        {
                            //BrowserRedirectSuccess = new Uri("https://www.bing.com?q=why+is+42+the+meaning+of+life")
                            OpenBrowserAsync = SystemWebViewOptions.OpenWithChromeEdgeBrowserAsync
                        };

                        var ctsChrome = new CancellationTokenSource();
                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithSystemWebViewOptions(optionsChrome)
                                   .ExecuteAsync(ctsChrome.Token);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 11:     // AcquireTokenForClient with multiple threads
                        Console.Write("Enter number of threads to start (default 10): ");
                        int totalThreads = int.TryParse(Console.ReadLine(), out totalThreads) ? totalThreads : 10;
                        Console.Write("Enter run duration in seconds (default 10): ");
                        int durationInSeconds = int.TryParse(Console.ReadLine(), out durationInSeconds) ? durationInSeconds : 10;

                        var acquireTokenBuilder = CreateCca().AcquireTokenForClient(GraphAppScope);

                        var threads = new List <Thread>();
                        for (int i = 0; i < totalThreads; i++)
                        {
                            var thread = new Thread(new ThreadStart(new ThreadWork(i, acquireTokenBuilder, durationInSeconds).Run));
                            thread.Name = $"Thread #{i}";
                            threads.Add(thread);
                        }

                        foreach (var thread in threads)
                        {
                            thread.Start();
                        }

                        foreach (var thread in threads)
                        {
                            thread.Join();
                        }

                        break;

                    case 0:
                        return;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log(LogLevel.Error, ex.Message, false);
                    Log(LogLevel.Error, ex.StackTrace, false);
                }

                Console.WriteLine("\n\nHit 'ENTER' to continue...");
                Console.ReadLine();
            }
        }
        private static async Task RunConsoleAppLogicAsync(IPublicClientApplication pca)
        {
            while (true)
            {
                Console.Clear();

                Console.WriteLine("Authority: " + GetAuthority());
                await DisplayAccountsAsync(pca).ConfigureAwait(false);

                // display menu
                Console.WriteLine(@"
                        1. IWA
                        2. Acquire Token with Username and Password
                        3. Acquire Token with Device Code
                        4. Acquire Token Interactive 
                        5. Acquire Token Interactive via NetStandard lib
                        6. Acquire Token Silently
                        7. Acquire Token Silently - multiple requests in parallel
                        8. Clear cache
                        9. Rotate Tenant ID
                        0. Expire all ATs
                        x. Exit app
                    Enter your Selection: ");
                char.TryParse(Console.ReadLine(), out var selection);

                Task <AuthenticationResult> authTask = null;

                try
                {
                    switch (selection)
                    {
                    case '1':     // acquire token
                        authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '2':     // acquire token u/p
                        SecureString password = GetPasswordFromConsole();
                        authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '3':
                        authTask = pca.AcquireTokenWithDeviceCode(
                            s_scopes,
                            deviceCodeResult =>
                        {
                            Console.WriteLine(deviceCodeResult.Message);
                            return(Task.FromResult(0));
                        }).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '4':     // acquire token interactive

                        CancellationTokenSource cts = new CancellationTokenSource();
                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithUseEmbeddedWebView(false)
                                   .WithSystemWebViewOptions(new SystemWebViewOptions()
                        {
                            //BrowserRedirectSuccess = new Uri("https://www.google.com"),
                            HtmlMessageSuccess = "All good, close the browser!",

                            //OpenBrowserAsync = (Uri u) =>
                            //{
                            //    string url = u.AbsoluteUri;
                            //    url = url.Replace("&", "^&");
                            //    Process.Start(new ProcessStartInfo("cmd", $"/c start msedge {url}") { CreateNoWindow = true });
                            //    return Task.FromResult(0);
                            //}
                            OpenBrowserAsync = SystemWebViewOptions.OpenWithEdgeBrowserAsync
                        })
                                   .ExecuteAsync(cts.Token);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '6':     // acquire token silent
                        IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault();
                        if (account == null)
                        {
                            Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false);
                        }

                        authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '7':     // acquire token silent - one request per IAccount
                        var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                        Task <AuthenticationResult>[] tasks = accounts
                                                              .Select(acc => pca.AcquireTokenSilent(s_scopes, acc).ExecuteAsync())
                                                              .ToArray();

                        AuthenticationResult[] result = await Task.WhenAll(tasks).ConfigureAwait(false);

                        foreach (var ar in result)
                        {
                            Console.BackgroundColor = ConsoleColor.DarkGreen;
                            Console.WriteLine($"Got a token for {ar.Account.Username} ");
                            Console.ResetColor();
                        }

                        break;

                    case '5':     // Acquire Token Interactive via NetStandard lib
                        CancellationTokenSource cts2 = new CancellationTokenSource();
                        var authenticator            = new NetStandardAuthenticator(Log, CacheFilePath);
                        await FetchTokenAndCallGraphAsync(pca, authenticator.GetTokenInteractiveAsync(cts2.Token)).ConfigureAwait(false);

                        break;

                    case '8':
                        var accounts2 = await pca.GetAccountsAsync().ConfigureAwait(false);

                        foreach (var acc in accounts2)
                        {
                            await pca.RemoveAsync(acc).ConfigureAwait(false);
                        }

                        break;

                    case '9':

                        s_currentTid = (s_currentTid + 1) % s_tids.Length;
                        pca          = CreatePca();
                        RunConsoleAppLogicAsync(pca).Wait();
                        break;

                    case '0':

                        var tokenCacheInternal = pca.UserTokenCache as ITokenCacheInternal;
                        var ats = tokenCacheInternal.Accessor.GetAllAccessTokens();
                        // set access tokens as expired
                        foreach (var accessItem in ats)
                        {
                            accessItem.ExpiresOnUnixTimestamp =
                                ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds)
                                .ToString(CultureInfo.InvariantCulture);

                            tokenCacheInternal.Accessor.SaveAccessToken(accessItem);
                        }

                        TokenCacheNotificationArgs args = new TokenCacheNotificationArgs(
                            pca.UserTokenCache as ITokenCacheInternal, s_clientIdForPublicApp, null, true);

                        await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false);

                        break;

                    case 'x':
                        return;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log(LogLevel.Error, ex.Message, false);
                    Log(LogLevel.Error, ex.StackTrace, false);
                }

                Console.WriteLine("\n\nHit 'ENTER' to continue...");
                Console.ReadLine();
            }
        }
Beispiel #18
0
        /// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/ActiveDirectoryAuthenticationProvider.xml' path='docs/members[@name="ActiveDirectoryAuthenticationProvider"]/AcquireTokenAsync/*'/>
        public override Task <SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) => Task.Run(async() =>
        {
            AuthenticationResult result;
            string scope    = parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;
            string[] scopes = new string[] { scope };

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal)
            {
                IConfidentialClientApplication ccApp = ConfidentialClientApplicationBuilder.Create(parameters.UserId)
                                                       .WithAuthority(parameters.Authority)
                                                       .WithClientSecret(parameters.Password)
                                                       .WithClientName(Common.DbConnectionStringDefaults.ApplicationName)
                                                       .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString())
                                                       .Build();

                result = ccApp.AcquireTokenForClient(scopes).ExecuteAsync().Result;
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Service Principal auth mode. Expiry Time: {0}", result.ExpiresOn);
                return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
            }

            /*
             * Today, MSAL.NET uses another redirect URI by default in desktop applications that run on Windows
             * (urn:ietf:wg:oauth:2.0:oob). In the future, we'll want to change this default, so we recommend
             * that you use https://login.microsoftonline.com/common/oauth2/nativeclient.
             *
             * https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris
             */
            string redirectUri = s_nativeClientRedirectUri;

#if NETCOREAPP
            if (parameters.AuthenticationMethod != SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
            {
                redirectUri = "http://localhost";
            }
#endif
            PublicClientAppKey pcaKey = new PublicClientAppKey(parameters.Authority, redirectUri, _applicationClientId
#if NETFRAMEWORK
                                                               , _iWin32WindowFunc
#endif
#if NETSTANDARD
                                                               , _parentActivityOrWindowFunc
#endif
                                                               );

            IPublicClientApplication app = GetPublicClientAppInstance(pcaKey);

            if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
            {
                if (!string.IsNullOrEmpty(parameters.UserId))
                {
                    result = app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .WithUsername(parameters.UserId)
                             .ExecuteAsync().Result;
                }
                else
                {
                    result = app.AcquireTokenByIntegratedWindowsAuth(scopes)
                             .WithCorrelationId(parameters.ConnectionId)
                             .ExecuteAsync().Result;
                }
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Integrated auth mode. Expiry Time: {0}", result.ExpiresOn);
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword)
            {
                SecureString password = new SecureString();
                foreach (char c in parameters.Password)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();
                result = app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password)
                         .WithCorrelationId(parameters.ConnectionId)
                         .ExecuteAsync().Result;
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Password auth mode. Expiry Time: {0}", result.ExpiresOn);
            }
            else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive ||
                     parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
            {
                // Fetch available accounts from 'app' instance
                System.Collections.Generic.IEnumerable <IAccount> accounts = await app.GetAccountsAsync();
                IAccount account;
                if (!string.IsNullOrEmpty(parameters.UserId))
                {
                    account = accounts.FirstOrDefault(a => parameters.UserId.Equals(a.Username, System.StringComparison.InvariantCultureIgnoreCase));
                }
                else
                {
                    account = accounts.FirstOrDefault();
                }

                if (null != account)
                {
                    try
                    {
                        // If 'account' is available in 'app', we use the same to acquire token silently.
                        // Read More on API docs: https://docs.microsoft.com/dotnet/api/microsoft.identity.client.clientapplicationbase.acquiretokensilent
                        result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();
                        SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (silent) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn);
                    }
                    catch (MsalUiRequiredException)
                    {
                        // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application,
                        // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired),
                        // or the user needs to perform two factor authentication.
                        result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod);
                        SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn);
                    }
                }
                else
                {
                    // If no existing 'account' is found, we request user to sign in interactively.
                    result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod);
                    SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result.ExpiresOn);
                }
            }
            else
            {
                SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | {0} authentication mode not supported by ActiveDirectoryAuthenticationProvider class.", parameters.AuthenticationMethod);
                throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod);
            }

            return(new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn));
        });
        private static async Task RunConsoleAppLogicAsync(IPublicClientApplication pca)
        {
            while (true)
            {
                Console.Clear();

                Console.WriteLine("Authority: " + GetAuthority());
                await DisplayAccountsAsync(pca).ConfigureAwait(false);

                // display menu
                Console.WriteLine(@"
                        1. IWA
                        2. Acquire Token with Username and Password
                        3. Acquire Token with Device Code
                        4. Acquire Token Interactive 
                        5. Acquire Token Interactive via NetStandard lib
                        6. Acquire Token Silently
                        7. Acquire Token Silently - multiple requests in parallel
                        8. Acquire SSH Cert Interactive
                        c. Clear cache
                        r. Rotate Tenant ID
                        e. Expire all ATs
                        x. Exit app
                    Enter your Selection: ");
                char.TryParse(Console.ReadLine(), out var selection);

                Task <AuthenticationResult> authTask = null;

                try
                {
                    switch (selection)
                    {
                    case '1':     // acquire token
                        authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '2':     // acquire token u/p
                        SecureString password = GetPasswordFromConsole();
                        authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '3':
                        authTask = pca.AcquireTokenWithDeviceCode(
                            s_scopes,
                            deviceCodeResult =>
                        {
                            Console.WriteLine(deviceCodeResult.Message);
                            return(Task.FromResult(0));
                        }).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;


                    case '6':     // acquire token silent
                        IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault();
                        if (account == null)
                        {
                            Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false);
                        }

                        authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case '7':     // acquire token silent - one request per IAccount
                        var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                        Task <AuthenticationResult>[] tasks = accounts
                                                              .Select(acc => pca.AcquireTokenSilent(s_scopes, acc).ExecuteAsync())
                                                              .ToArray();

                        AuthenticationResult[] result = await Task.WhenAll(tasks).ConfigureAwait(false);

                        foreach (var ar in result)
                        {
                            Console.BackgroundColor = ConsoleColor.DarkGreen;
                            Console.WriteLine($"Got a token for {ar.Account.Username} ");
                            Console.ResetColor();
                        }

                        break;

                    case '5':     // Acquire Token Interactive via NetStandard lib
                        CancellationTokenSource cts2 = new CancellationTokenSource();
                        var authenticator            = new NetStandardAuthenticator(Log, CacheFilePath);
                        await FetchTokenAndCallGraphAsync(pca, authenticator.GetTokenInteractiveAsync(cts2.Token)).ConfigureAwait(false);

                        break;

                    case '8':     // acquire SSH cert
                        RSACryptoServiceProvider rsa        = new RSACryptoServiceProvider();
                        RSAParameters            rsaKeyInfo = rsa.ExportParameters(false);

                        string modulus = Base64UrlHelpers.Encode(rsaKeyInfo.Modulus);
                        string exp     = Base64UrlHelpers.Encode(rsaKeyInfo.Exponent);
                        string jwk     = $"{{\"kty\":\"RSA\", \"n\":\"{modulus}\", \"e\":\"{exp}\"}}";

                        CancellationTokenSource cts = new CancellationTokenSource();
                        authTask = pca.AcquireTokenInteractive(s_scopes)
                                   .WithUseEmbeddedWebView(false)
                                   .WithExtraQueryParameters(new Dictionary <string, string>()
                        {
                            { "dc", "prod-wst-test1" },
                            { "slice", "test" },
                            { "sshcrt", "true" }
                        })
                                   .WithSSHCertificateAuthenticationScheme(jwk, "1")
                                   .WithSystemWebViewOptions(new SystemWebViewOptions()
                        {
                            HtmlMessageSuccess = "All good, close the browser!",
                            OpenBrowserAsync   = SystemWebViewOptions.OpenWithEdgeBrowserAsync
                        })
                                   .ExecuteAsync(cts.Token);

                        await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false);

                        break;

                    case 'c':
                        var accounts2 = await pca.GetAccountsAsync().ConfigureAwait(false);

                        foreach (var acc in accounts2)
                        {
                            await pca.RemoveAsync(acc).ConfigureAwait(false);
                        }

                        break;

                    case 'r':     // rotate tid

                        s_currentTid = (s_currentTid + 1) % s_tids.Length;
                        pca          = CreatePca();
                        RunConsoleAppLogicAsync(pca).Wait();
                        break;

                    case 'e':     // expire all ATs

                        var tokenCacheInternal = pca.UserTokenCache as ITokenCacheInternal;
                        var ats = tokenCacheInternal.Accessor.GetAllAccessTokens();
                        // set access tokens as expired
                        foreach (var accessItem in ats)
                        {
                            accessItem.ExpiresOnUnixTimestamp =
                                ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds)
                                .ToString(CultureInfo.InvariantCulture);

                            tokenCacheInternal.Accessor.SaveAccessToken(accessItem);
                        }

                        TokenCacheNotificationArgs args = new TokenCacheNotificationArgs(
                            pca.UserTokenCache as ITokenCacheInternal, s_clientIdForPublicApp, null, true);

                        await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false);

                        break;

                    case 'x':
                        return;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log(LogLevel.Error, ex.Message, false);
                    Log(LogLevel.Error, ex.StackTrace, false);
                }

                Console.WriteLine("\n\nHit 'ENTER' to continue...");
                Console.ReadLine();
            }
        }
Beispiel #20
0
        private static async Task RunConsoleAppLogicAsync()
        {
            while (true)
            {
                Console.Clear();

                Console.WriteLine("Authority: " + GetAuthority());
                await DisplayAccountsAsync(s_pca).ConfigureAwait(false);

                // display menu
                Console.WriteLine(@"
                        1. IWA
                        2. Acquire Token with Username and Password
                        3. Acquire Token with Device Code
                        4. Acquire Token Interactive (via Default System Browser)
                        5. Acquire Token Silently
                        6. Confidential Client with Certificate (needs extra config)
                        7. Clear cache
                        8. Rotate Tenant ID
                        0. Exit App
                    Enter your Selection: ");
                int.TryParse(Console.ReadLine(), out var selection);

                Task <AuthenticationResult> authTask = null;

                try
                {
                    switch (selection)
                    {
                    case 1: // acquire token
                        authTask = s_pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(s_pca, authTask).ConfigureAwait(false);

                        break;

                    case 2: // acquire token u/p
                        SecureString password = GetPasswordFromConsole();
                        authTask = s_pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(s_pca, authTask).ConfigureAwait(false);

                        break;

                    case 3:
                        authTask = s_pca.AcquireTokenWithDeviceCode(
                            s_scopes,
                            deviceCodeResult =>
                        {
                            Console.WriteLine(deviceCodeResult.Message);
                            return(Task.FromResult(0));
                        }).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(s_pca, authTask).ConfigureAwait(false);

                        break;

                    case 4: // acquire token interactive

                        authTask = s_pca.AcquireTokenInteractive(s_scopes)
                                   .WithCustomWebUi(new DefaultOsBrowserWebUi()) // make sure you've configured a redirect uri of "http://localhost" or "http://localhost:1234" in the _pca builder
                                   .ExecuteAsync(CancellationToken.None);

                        await FetchTokenAndCallGraphAsync(s_pca, authTask).ConfigureAwait(false);

                        break;

                    case 5: // acquire token silent
                        IAccount account = s_pca.GetAccountsAsync().Result.FirstOrDefault();
                        if (account == null)
                        {
                            Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false);
                        }

                        authTask = s_pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None);
                        await FetchTokenAndCallGraphAsync(s_pca, authTask).ConfigureAwait(false);

                        break;

                    case 6:
                        RunClientCredentialWithCertificate();
                        break;

                    case 7:
                        var accounts = await s_pca.GetAccountsAsync().ConfigureAwait(false);

                        foreach (var acc in accounts)
                        {
                            await s_pca.RemoveAsync(acc).ConfigureAwait(false);
                        }

                        break;

                    case 8:

                        s_currentTid = (s_currentTid + 1) % s_tids.Length;
                        s_pca        = CreatePca();

                        RunConsoleAppLogicAsync().Wait();
                        break;


                    case 0:
                        return;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log(LogLevel.Error, ex.Message, false);
                    Log(LogLevel.Error, ex.StackTrace, false);
                }

                Console.WriteLine("\n\nHit 'ENTER' to continue...");
                Console.ReadLine();
            }
        }