private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args)
        {
            _logger.Verbose($"OnBeforeAccessAsync - before getting the lock " + _semaphoreSlim.CurrentCount);

            // prevent other threads / background tasks from reading the file
            await _semaphoreSlim.WaitAsync().ConfigureAwait(true);

            _logger.Verbose($"OnBeforeAccessAsync - acquired the lock");

            IStorageFile cacheFile = await ApplicationData.Current.LocalFolder.TryGetItemAsync(CacheFileName) as IStorageFile;

            if (cacheFile != null)
            {
                byte[] decryptedBlob;
                try
                {
                    decryptedBlob = await ReadAndDecryptAsync(cacheFile).ConfigureAwait(true);
                }
                catch (Exception ex)
                {
                    _logger.Error("UWP cache file could not be loaded. Using in-memory cache only.");
                    _logger.ErrorPii(ex);

                    return;
                }

                if (decryptedBlob != null)
                {
                    args.TokenCache.DeserializeMsalV3(decryptedBlob);
                }
            }
        }
        public static void ValidateIosBrokerRedirectUri(Uri redirectUri, string bundleId, ICoreLogger logger)
        {
            string expectedRedirectUri = $"msauth.{bundleId}://auth";

            // It's important to use the original string here because the bundleId is case sensitive
            string actualRedirectUriString = redirectUri.OriginalString;

            // MSAL style redirect uri - case sensitive
            if (string.Equals(expectedRedirectUri, actualRedirectUriString.TrimEnd('/'), StringComparison.Ordinal))
            {
                logger.Verbose("Valid MSAL style redirect Uri detected.");
                return;
            }

            // ADAL style redirect uri - my_scheme://{bundleID}
            if (redirectUri.Authority.Equals(bundleId, StringComparison.OrdinalIgnoreCase))
            {
                logger.Verbose("Valid ADAL style redirect Uri detected.");
                return;
            }

            throw new MsalClientException(
                      MsalError.CannotInvokeBroker,
                      $"The broker redirect URI is incorrect, it should be {expectedRedirectUri} or app_scheme ://{bundleId} - " +
                      $"please visit https://aka.ms/msal-net-xamarin for details about redirect URIs.");
        }
示例#3
0
        internal static List <T> FilterWithLogging <T>(
            this List <T> list,
            Func <T, bool> predicate,
            ICoreLogger logger,
            string logPrefix,
            bool updateOriginalCollection = true)
        {
            if (logger.IsLoggingEnabled(LogLevel.Verbose))
            {
                logger.Verbose($"{logPrefix} - item count before: {list.Count} ");
            }
            if (updateOriginalCollection)
            {
                list.RemoveAll(e => !predicate(e));
            }
            else
            {
                list = list.Where(predicate).ToList();
            }

            if (logger.IsLoggingEnabled(LogLevel.Verbose))
            {
                logger.Verbose($"{logPrefix} - item count after: {list.Count} ");
            }

            return(list);
        }
示例#4
0
        public bool IsBrokerInstalledAndInvokable()
        {
            bool canInvoke = _brokerHelper.CanSwitchToBroker();

            _logger.Verbose("Can invoke broker? " + canInvoke);

            return(canInvoke);
        }
        public bool CanInvokeBroker()
        {
            bool canInvoke = _brokerHelper.CanSwitchToBroker();

            _logger.Verbose("Can invoke broker? " + canInvoke);

            return(canInvoke);
        }
        public bool IsBrokerInstalledAndInvokable(AuthorityType authorityType)
        {
            using (_logger.LogMethodDuration())
            {
                bool canInvoke = CanSwitchToBroker();
                _logger.Verbose("[Android broker] Can invoke broker? " + canInvoke);

                return(canInvoke);
            }
        }
        public bool IsBrokerInstalledAndInvokable()
        {
            using (_logger.LogMethodDuration())
            {
                bool canInvoke = _brokerHelper.CanSwitchToBroker();
                _logger.Verbose("Can invoke broker? " + canInvoke);

                return(canInvoke);
            }
        }
示例#8
0
#pragma warning disable VSTHRD100 // Avoid async void methods
        private async void Authenticator_AccountCommandsRequested(
#pragma warning restore VSTHRD100 // Avoid async void methods
            AccountsSettingsPane sender,
            AccountsSettingsPaneCommandsRequestedEventArgs args)
        {
            AccountsSettingsPaneEventDeferral deferral = null;

            try
            {
                deferral = args.GetDeferral();

                if (!string.IsNullOrEmpty(_optionalHeaderText))
                {
                    args.HeaderText = _optionalHeaderText;
                }

                if (string.Equals("common", _authority.TenantId))
                {
                    _logger.Verbose("Displaying selector for common");
                    await AddSelectorsAsync(
                        args,
                        addOrgAccounts : true,
                        addMsaAccounts : true).ConfigureAwait(true);
                }
                else if (string.Equals("organizations", _authority.TenantId))
                {
                    _logger.Verbose("Displaying selector for organizations");
                    await AddSelectorsAsync(
                        args,
                        addOrgAccounts : true,
                        addMsaAccounts : _isMsaPassthrough).ConfigureAwait(true);
                }
                else if (string.Equals("consumers", _authority.TenantId))
                {
                    _logger.Verbose("Displaying selector for consumers");
                    await AddSelectorsAsync(
                        args,
                        addOrgAccounts : false,
                        addMsaAccounts : true).ConfigureAwait(true);
                }
                else
                {
                    _logger.Verbose("Displaying selector for tenanted authority");
                    await AddSelectorsAsync(
                        args,
                        addOrgAccounts : true,
                        addMsaAccounts : _isMsaPassthrough,
                        tenantId : _authority.AuthorityInfo.CanonicalAuthority).ConfigureAwait(true);
                }
            }
            finally
            {
                deferral?.Complete();
            }
        }
示例#9
0
 private void WebView2Control_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
 {
     if (CheckForEndUrl(new Uri(e.Uri)))
     {
         _logger.Verbose("[WebView2Control] Redirect uri reached. Stopping the interactive view");
         e.Cancel = true;
     }
     else
     {
         _logger.Verbose("[WebView2Control] Navigating to " + e.Uri);
     }
 }
示例#10
0
        private async Task AcquireTokenInteractiveViaContentProviderAsync(BrokerRequest brokerRequest)
        {
            using (_logger.LogMethodDuration())
            {
                _logger.Verbose("[Android broker] Starting interactive authentication. ");

                Bundle bundleResult = await PerformContentResolverOperationAsync(ContentResolverOperation.acquireTokenInteractive, null).ConfigureAwait(false);

                var interactiveIntent = CreateInteractiveBrokerIntent(brokerRequest, bundleResult);

                _brokerHelper.LaunchInteractiveActivity(_parentActivity, interactiveIntent);
            }
        }
示例#11
0
        public InstanceDiscoveryMetadataEntry GetMetadata(string environment, ICoreLogger logger)
        {
            s_cache.TryGetValue(environment, out InstanceDiscoveryMetadataEntry entry);
            logger.Verbose($"[Instance Discovery] Tried to use network cache provider for {environment}. Success? {entry != null}");

            return(entry);
        }
        private async Task AcquireTokenInteractiveViaBrokerAsync(BrokerRequest brokerRequest)
        {
            using (_logger.LogMethodDuration())
            {
                // onActivityResult will receive the response for this activity.
                // Launching this activity will switch to the broker app.

                _logger.Verbose("[Android broker] Starting Android Broker interactive authentication. ");
                Intent brokerIntent = await GetIntentForInteractiveBrokerRequestAsync(brokerRequest).ConfigureAwait(false);

                if (brokerIntent != null)
                {
                    _brokerHelper.LaunchInteractiveActivity(_parentActivity, brokerIntent);
                }
            }
        }
示例#13
0
        private MsalTokenResponse ProcessBrokerResponse()
        {
            using (_logger.LogMethodDuration())
            {
                string[] keyValuePairs = s_brokerResponse.Query.Split('&');
                Dictionary <string, string> responseDictionary = new Dictionary <string, string>(StringComparer.InvariantCulture);

                foreach (string pair in keyValuePairs)
                {
                    string[] keyValue = pair.Split('=');
                    responseDictionary[keyValue[0]] = CoreHelpers.UrlDecode(keyValue[1]);

                    if (responseDictionary[keyValue[0]].Equals("(null)", StringComparison.OrdinalIgnoreCase) &&
                        keyValue[0].Equals(iOSBrokerConstants.Code, StringComparison.OrdinalIgnoreCase))
                    {
                        responseDictionary[iOSBrokerConstants.Error] = iOSBrokerConstants.BrokerError;

                        _logger.VerbosePii(iOSBrokerConstants.BrokerResponseValuesPii + keyValue.ToString(),
                                           iOSBrokerConstants.BrokerResponseContainsError);
                    }
                }

                _logger.Verbose(iOSBrokerConstants.ProcessBrokerResponse + responseDictionary.Count);

                return(ResultFromBrokerResponse(responseDictionary));
            }
        }
示例#14
0
        public InstanceDiscoveryMetadataEntry GetMetadata(
            string environment,
            IEnumerable <string> existingEnvironmentsInCache,
            ICoreLogger logger)
        {
            if (existingEnvironmentsInCache == null)
            {
                existingEnvironmentsInCache = Enumerable.Empty <string>();
            }

            bool canUseProvider = existingEnvironmentsInCache.All(e => s_knownEnvironments.ContainsOrdinalIgnoreCase(e));

            if (canUseProvider)
            {
                s_knownEntries.TryGetValue(environment, out InstanceDiscoveryMetadataEntry entry);
                logger.Verbose($"[Instance Discovery] Tried to use known metadata provider for {environment}. Success? {entry != null}");

                return(entry);
            }

            logger.VerbosePii(
                $"[Instance Discovery] Could not use known metadata provider because at least one environment in the cache is not known. Environments in cache: {string.Join(" ", existingEnvironmentsInCache)} ",
                $"[Instance Discovery] Could not use known metadata provider because at least one environment in the cache is not known");
            return(null);
        }
        public AndroidBrokerHelper(Context androidContext, ICoreLogger logger)
        {
            _androidContext = androidContext ?? throw new ArgumentNullException(nameof(androidContext));
            _logger         = logger ?? throw new ArgumentNullException(nameof(logger));

            _logger.Verbose("Getting the Android context for broker request");
            _androidAccountManager = AccountManager.Get(_androidContext);
        }
示例#16
0
        public async Task <Uri> ListenToSingleRequestAndRespondAsync(
            int port,
            Func <Uri, MessageAndHttpCode> responseProducer,
            CancellationToken cancellationToken)
        {
            TestBeforeTopLevelCall?.Invoke();
            cancellationToken.ThrowIfCancellationRequested();

            HttpListener httpListener = null;

            try
            {
                string urlToListenTo = "http://localhost:" + port + "/";

                httpListener = new HttpListener();
                httpListener.Prefixes.Add(urlToListenTo);

                TestBeforeStart?.Invoke();

                httpListener.Start();
                _logger.Info("Listening for authorization code on " + urlToListenTo);

                using (cancellationToken.Register(() =>
                {
                    _logger.Warning("HttpListener stopped because cancellation was requested.");
                    TryStopListening(httpListener);
                }))
                {
                    TestBeforeGetContext?.Invoke();
                    HttpListenerContext context = await httpListener.GetContextAsync()
                                                  .ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    Respond(responseProducer, context);
                    _logger.Verbose("HttpListner received a message on " + urlToListenTo);

                    // the request URL should now contain the auth code and pkce
                    return(context.Request.Url);
                }
            }
            // If cancellation is requested before GetContextAsync is called, then either
            // an ObjectDisposedException or an HttpListenerException is thrown.
            // But this is just cancellation...
            catch (Exception ex) when(ex is HttpListenerException || ex is ObjectDisposedException)
            {
                _logger.Info("HttpListenerException - cancellation requested? " + cancellationToken.IsCancellationRequested);
                cancellationToken.ThrowIfCancellationRequested();

                // if cancellation was not requested, propagate original ex
                throw;
            }
            finally
            {
                TryStopListening(httpListener);
            }
        }
        public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenInteractiveParameters acquireTokenInteractiveParameters)
        {
            MsalTokenResponse msalTokenResponse = null;

            //need to provide a handle
            if (_parentHandle == IntPtr.Zero)
            {
                throw new MsalClientException(
                          "window_handle_required",
                          "Public Client applications wanting to use WAM need to provide their window handle. Console applications can use GetConsoleWindow Windows API for this.");
            }

            //if OperatingSystemAccount is passed then we use the user signed-in on the machine
            if (PublicClientApplication.IsOperatingSystemAccount(authenticationRequestParameters.Account))
            {
                return(await AcquireTokenInteractiveDefaultUserAsync(authenticationRequestParameters, acquireTokenInteractiveParameters).ConfigureAwait(false));
            }

            var cancellationToken = authenticationRequestParameters.RequestContext.UserCancellationToken;

            _logger.Verbose("[WamBroker] Using Windows account picker.");

            using (var core = new NativeInterop.Core())
                using (var authParams = WamAdapters.GetCommonAuthParameters(authenticationRequestParameters, _wamOptions.MsaPassthrough))
                {
                    //Login Hint
                    string loginHint = authenticationRequestParameters.LoginHint ?? authenticationRequestParameters?.Account?.Username;

                    _logger.Verbose("[WamBroker] AcquireTokenInteractive - login hint provided? " + string.IsNullOrEmpty(loginHint));

                    using (var result = await core.SignInInteractivelyAsync(
                               _parentHandle,
                               authParams,
                               authenticationRequestParameters.CorrelationId.ToString("D"),
                               loginHint,
                               cancellationToken).ConfigureAwait(false))
                    {
                        if (result.IsSuccess)
                        {
                            msalTokenResponse = WamAdapters.ParseRuntimeResponse(result, authenticationRequestParameters, _logger);
                            _logger.Verbose("[WamBroker] Successfully retrieved token.");
                        }
                        else
                        {
                            _logger.Error($"[WamBroker] Could not login interactively. {result.Error}");
                            WamAdapters.ThrowExceptionFromWamError(result, authenticationRequestParameters, _logger);
                        }
                    }
                }

            return(msalTokenResponse);
        }
示例#18
0
        protected override async Task <AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken)
        {
            await UpdateRequestWithAccountAsync().ConfigureAwait(false);

            bool isBrokerConfigured =
                AuthenticationRequestParameters.IsBrokerConfigured &&
                ServiceBundle.PlatformProxy.CanBrokerSupportSilentAuth();

            try
            {
                if (AuthenticationRequestParameters.Account != null)
                {
                    _logger.Verbose("Attempting to acquire token using using local cache...");
                    return(await _clientStrategy.ExecuteAsync(cancellationToken).ConfigureAwait(false));
                }

                if (!isBrokerConfigured)
                {
                    _logger.Verbose("No account passed to AcquireTokenSilent");
                    throw new MsalUiRequiredException(
                              MsalError.UserNullError,
                              MsalErrorMessage.MsalUiRequiredMessage,
                              null,
                              UiRequiredExceptionClassification.AcquireTokenSilentFailed);
                }

                _logger.Verbose("No account passed to AcquireTokenSilent. Only the Windows broker (WAM) may be able to log in user with a default account...");
                return(await _brokerStrategyLazy.Value.ExecuteAsync(cancellationToken).ConfigureAwait(false));
            }
            catch (MsalException ex)
            {
                _logger.Verbose("Token cache could not satisfy silent request");

                if (isBrokerConfigured && ShouldTryWithBrokerError(ex.ErrorCode))
                {
                    _logger.Info("Attempting to use broker instead");
                    return(await _brokerStrategyLazy.Value.ExecuteAsync(cancellationToken).ConfigureAwait(false));
                }

                throw;
            }
        }
        internal static IEnumerable <T> FilterWithLogging <T>(
            this IEnumerable <T> list,
            Func <T, bool> predicate,
            ICoreLogger logger,
            string logPrefix)
        {
            if (logger.IsLoggingEnabled(LogLevel.Verbose))
            {
                logger.Verbose($"{logPrefix} - item count before: {list.Count()} ");
            }

            list = list.Where(predicate);

            if (logger.IsLoggingEnabled(LogLevel.Verbose))
            {
                logger.Verbose($"{logPrefix} - item count after: {list.Count()} ");
            }

            return(list);
        }
示例#20
0
        public async Task <string> TryFetchTransferTokenAsync(AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider accountProvider)
        {
            // Apps can have MSA-PT enabled and can configured to allow MSA users
            // However, some older apps have 2 incarnations, one in AAD tenant and one in MSA tenant
            // For this second case, we can't fetch the transfer token from the client_ID in AAD and this will fail
            _logger.Verbose("WAM MSA-PT - fetching transfer token");
            string transferToken = await FetchMsaPassthroughTransferTokenAsync(
                authenticationRequestParameters, accountProvider)
                                   .ConfigureAwait(false);

            return(transferToken);
        }
        private void CleanCache(ICoreLogger logger)
        {
            if (_lastCleanupTime + s_cleanupCacheInterval < DateTimeOffset.UtcNow &&
                !_cleanupInProgress)
            {
                lock (_padlock)
                {
                    if (!_cleanupInProgress)
                    {
                        logger.Verbose($"[Throttling] Cache size before cleaning up {_cache.Count}");

                        _cleanupInProgress = true;
                        CleanupCacheNoLocks();
                        _lastCleanupTime   = DateTimeOffset.UtcNow;
                        _cleanupInProgress = false;

                        logger.Verbose($"[Throttling] Cache size after cleaning up {_cache.Count}");
                    }
                }
            }
        }
        public async Task <InstanceDiscoveryMetadataEntry> GetMetadataAsync(Uri authority, RequestContext requestContext)
        {
            ICoreLogger logger      = requestContext.Logger;
            string      environment = authority.Host;
            InstanceDiscoveryMetadataEntry cachedEntry = _networkCacheMetadataProvider.GetMetadata(environment, logger);

            if (cachedEntry == null)
            {
                Uri regionalizedAuthority = await BuildAuthorityWithRegionAsync(authority, requestContext).ConfigureAwait(false);

                CacheInstanceDiscoveryMetadata(CreateEntry(authority, regionalizedAuthority));

                cachedEntry = _networkCacheMetadataProvider.GetMetadata(environment, logger);
                logger.Verbose($"[Region Discovery] Created metadata for the regional environment {environment} ? {cachedEntry != null}");
            }
            else
            {
                logger.Verbose($"[Region Discovery] The network provider found an entry for {environment}");
                LogTelemetryData(cachedEntry.PreferredNetwork.Split('.')[0], RegionSource.Cache, requestContext);
            }

            return(cachedEntry);
        }
示例#23
0
        public async Task <string> FetchTransferTokenAsync(AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider accountProvider)
        {
            if (!authenticationRequestParameters.AppConfig.IsMsaPassthrough)
            {
                throw new InvalidOperationException("Not configured for msa-pt");
            }

            _logger.Verbose("WAM MSA-PT - fetching transfer token");
            string transferToken = await FetchMsaPassthroughTransferTokenAsync(
                authenticationRequestParameters, accountProvider)
                                   .ConfigureAwait(false);

            return(transferToken);
        }
示例#24
0
        public AccountPicker(
            IntPtr parentHandle,
            ICoreLogger logger,
            SynchronizationContext synchronizationContext,
            Authority authority,
            bool isMsaPassthrough)
        {
            _parentHandle           = parentHandle;
            _logger                 = logger;
            _synchronizationContext = synchronizationContext;
            _authority              = authority;
            _isMsaPassthrough       = isMsaPassthrough;

            _logger.Verbose("Is MSA passthrough? " + _isMsaPassthrough);
        }
        private void ValidateRedirectUri(Uri redirectUri)
        {
            string bundleId            = NSBundle.MainBundle.BundleIdentifier;
            string expectedRedirectUri = $"msauth.{bundleId}://auth";

            // MSAL style redirect uri - case sensitive
            if (string.Equals(expectedRedirectUri, redirectUri.AbsoluteUri, StringComparison.Ordinal))
            {
                _logger.Verbose("Valid MSAL style redirect Uri detected.");
                return;
            }

            // ADAL style redirect uri - my_scheme://{bundleID}
            if (redirectUri.Authority.Equals(bundleId, StringComparison.Ordinal))
            {
                _logger.Verbose("Valid ADAL style redirect Uri detected.");
                return;
            }

            throw new MsalClientException(
                      MsalError.CannotInvokeBroker,
                      $"The broker redirect URI is incorrect, it should be {expectedRedirectUri} or app_scheme ://{bundleId} - " +
                      $"please visit https://aka.ms/msal-net-xamarin for details about redirect URIs.");
        }
示例#26
0
        public InstanceDiscoveryMetadataEntry GetMetadataOrThrow(string environment, ICoreLogger logger)
        {
            _entries.TryGetValue(environment ?? "", out InstanceDiscoveryMetadataEntry entry);

            logger.Verbose($"[Instance Discovery] Tried to use user metadata provider for {environment}. Success? {entry != null}");

            if (entry == null)
            {
                throw new MsalClientException(
                          MsalError.InvalidUserInstanceMetadata,
                          MsalErrorMessage.NoUserInstanceMetadataEntry(environment));
            }

            return(entry);
        }
示例#27
0
        public async Task <string> TryFetchTransferTokenInteractiveAsync(AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider accountProvider)
        {
            // First party apps can have MSA-PT enabled and can configured to allow MSA users
            _logger.Verbose("WAM MSA-PT - fetching transfer token for interactive flow");

            var webTokenRequestMsa = await _msaPlugin.CreateWebTokenRequestAsync(
                accountProvider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : true,
                isAccountInWam : false,
                TransferTokenScopes)
                                     .ConfigureAwait(false);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequestMsa, _logger);

            var transferResponse = await _wamProxy.RequestTokenForWindowAsync(_parentHandle, webTokenRequestMsa)
                                   .ConfigureAwait(true);

            return(ExtractTransferToken(
                       authenticationRequestParameters.AppConfig.ClientId,
                       transferResponse,
                       isInteractive: true));
        }
        private bool VerifyAuthenticator()
        {
            using (_logger.LogMethodDuration())
            {
                foreach (AuthenticatorDescription authenticator in Authenticators)
                {
                    if (authenticator.Type.Equals(BrokerConstants.BrokerAccountType, StringComparison.OrdinalIgnoreCase) &&
                        VerifySignature(authenticator.PackageName))
                    {
                        _logger.Verbose("Found the Authenticator on the device. ");
                        return(true);
                    }
                }

                _logger.Warning("No Authenticator found on the device. ");
                return(false);
            }
        }
        private bool VerifyAuthenticator()
        {
            // there may be multiple authenticators from same package
            // , but there is only one entry for an authenticator type in
            // AccountManager.
            // If another app tries to install same authenticator type, it will
            // queue up and will be active after first one is uninstalled.
            AuthenticatorDescription[] authenticators = _androidAccountManager.GetAuthenticatorTypes();
            foreach (AuthenticatorDescription authenticator in authenticators)
            {
                if (authenticator.Type.Equals(BrokerConstants.BrokerAccountType, StringComparison.OrdinalIgnoreCase) &&
                    VerifySignature(authenticator.PackageName))
                {
                    _logger.Verbose("Found the Authenticator on the device");
                    return(true);
                }
            }

            _logger.Warning("No Authenticator found on the device.");
            return(false);
        }
        private async void Authenticator_AccountCommandsRequested(
            AccountsSettingsPane sender,
            AccountsSettingsPaneCommandsRequestedEventArgs e)
        {
            AccountsSettingsPaneEventDeferral deferral = null;

            try
            {
                deferral = e.GetDeferral();

                if (string.Equals("common", _authority.TenantId))
                {
                    _logger.Verbose("Displaying selector for common");
                    e.WebAccountProviderCommands.Add(
                        new WebAccountProviderCommand(
                            await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", "consumers"),
                            WebAccountProviderCommandInvoked));

                    e.WebAccountProviderCommands.Add(
                        new WebAccountProviderCommand(
                            await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", "organizations"),
                            WebAccountProviderCommandInvoked));
                }
                else if (string.Equals("organizations", _authority.TenantId))
                {
                    _logger.Verbose("Displaying selector for organizations");

                    e.WebAccountProviderCommands.Add(
                        new WebAccountProviderCommand(
                            await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", "organizations"),
                            WebAccountProviderCommandInvoked));
                }
                else if (string.Equals("consumers", _authority.TenantId))
                {
                    _logger.Verbose("Displaying selector for consumers");

                    e.WebAccountProviderCommands.Add(
                        new WebAccountProviderCommand(
                            await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", "consumers"),
                            WebAccountProviderCommandInvoked));

                    if (_isMsaPassthrough)
                    {
                        e.WebAccountProviderCommands.Add(
                            new WebAccountProviderCommand(
                                await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", "organizations"),
                                WebAccountProviderCommandInvoked));
                    }
                }
                else
                {
                    _logger.Verbose("Displaying selector for tenanted authority");

                    e.WebAccountProviderCommands.Add(
                        new WebAccountProviderCommand(
                            await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", _authority.AuthorityInfo.CanonicalAuthority),
                            WebAccountProviderCommandInvoked));
                }

                //e.HeaderText = "Please select an account to log in with"; // TODO: this is English only, try removing it
            }
            finally
            {
                deferral?.Complete();
            }
        }