private async Task <string> FetchTransferTokenAsync(
            WebAccountProvider accountProvider,
            WebAccount wamAcc,
            string clientId)
        {
            var transferTokenRequest = await _msaPlugin.CreateWebTokenRequestAsync(
                accountProvider,
                clientId,
                TransferTokenScopes)
                                       .ConfigureAwait(true);

            var transferResponse = await _wamProxy.RequestTokenForWindowAsync(
                _parentHandle,
                transferTokenRequest,
                wamAcc).ConfigureAwait(false);

            if (!transferResponse.ResponseStatus.IsSuccessStatus())
            {
                var errorResp = WamAdapters.CreateMsalResponseFromWamResponse(transferResponse, _msaPlugin, _logger, true);
                throw new MsalServiceException(
                          errorResp.Error,
                          "Error fetching the MSA-PT transfer token - " + errorResp.ErrorDescription);
            }

            var resp = _msaPlugin.ParseSuccessfullWamResponse(transferResponse.ResponseData[0], out var properties);

            properties.TryGetValue("code", out string code);
            _logger.Info("WAM MSA-PT: Transfer token obtained? " + !string.IsNullOrEmpty(code));

            return(code);
        }
        private async Task <WebAccount> TryFetchWebAccountFromMsaAsync(
            AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider accountProvider)
        {
            // This response has an v1 MSA Access Token, which MSAL should expose to the user
            var webTokenRequestMsa = await _msaPlugin.CreateWebTokenRequestAsync(
                accountProvider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : true,
                isAccountInWam : false)
                                     .ConfigureAwait(false);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequestMsa);

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

            if (!webTokenResponseMsa.ResponseStatus.IsSuccessStatus())
            {
                var errorResp = WamAdapters.CreateMsalResponseFromWamResponse(webTokenResponseMsa, _msaPlugin, _logger, true);
                _logger.Warning(
                    "WAM MSA-PT: could not get a transfer token, ussually this is because the " +
                    "1st party app is configured for MSA-PT but not configured to login MSA users (signinaudience =2). " +
                    "Error was: " + errorResp.Error + " " + errorResp.ErrorDescription);

                return(null);
            }

            // Cannot use this WebAccount with the AAD provider
            WebAccount msaPtWebAccount = webTokenResponseMsa.ResponseData[0].WebAccount;

            return(msaPtWebAccount);
        }
示例#3
0
        public async Task <MsalTokenResponse> AcquireTokenSilentDefaultUserAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenSilentParameters acquireTokenSilentParameters)
        {
            using (_logger.LogMethodDuration())
            {
                bool isMsa = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    null,
                    _wamOptions.MsaPassthrough).ConfigureAwait(false);

                IWamPlugin         wamPlugin = isMsa ? _msaPlugin : _aadPlugin;
                WebAccountProvider provider  = await GetProviderAsync(
                    authenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority,
                    isMsa).ConfigureAwait(false);

                WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                    provider,
                    authenticationRequestParameters,
                    isForceLoginPrompt : false,
                    isAccountInWam : false,
                    isInteractive : false)
                                                  .ConfigureAwait(false);

                WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest);

                var wamResult =
                    await _wamProxy.GetTokenSilentlyForDefaultAccountAsync(webTokenRequest).ConfigureAwait(false);

                return(WamAdapters.CreateMsalResponseFromWamResponse(wamResult, wamPlugin, _logger, isInteractive: false));
            }
        }
示例#4
0
        // only works for AAD plugin. MSA plugin does not allow for privacy reasons
        private async Task <MsalTokenResponse> AcquireInteractiveWithAadBrowserAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt msalPrompt)
        {
            var provider = await _webAccountProviderFactory.GetAccountProviderAsync(
                authenticationRequestParameters.Authority.TenantId).ConfigureAwait(true);

            WebTokenRequest webTokenRequest = await _aadPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : true,
                isInteractive : true,
                isAccountInWam : false)
                                              .ConfigureAwait(false);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger);
            AddPromptToRequest(msalPrompt, true, webTokenRequest);

            var wamResult = await _wamProxy.RequestTokenForWindowAsync(
                _parentHandle,
                webTokenRequest).ConfigureAwait(false);

            return(WamAdapters.CreateMsalResponseFromWamResponse(
                       wamResult,
                       _aadPlugin,
                       authenticationRequestParameters.AppConfig.ClientId,
                       _logger,
                       isInteractive: true));
        }
示例#5
0
        public async Task <string> TryFetchTransferTokenSilentAsync(AuthenticationRequestParameters authenticationRequestParameters, WebAccount account)
        {
            _logger.Verbose("WAM MSA-PT - fetching transfer token for silent flow");

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

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequestMsa, _logger);

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

            return(ExtractTransferToken(
                       authenticationRequestParameters.AppConfig.ClientId,
                       transferResponse,
                       isInteractive: false));
        }
示例#6
0
        private async Task <WebAccount> FetchWebAccountFromMsaAsync(
            AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider accountProvider)
        {
            // This response has an v1 MSA Access Token, which MSAL should expose to the user
            var webTokenRequestMsa = await _msaPlugin.CreateWebTokenRequestAsync(
                accountProvider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : true,
                isAccountInWam : false)
                                     .ConfigureAwait(false);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequestMsa);

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

            if (!webTokenResponseMsa.ResponseStatus.IsSuccessStatus())
            {
                var errorResp = WamAdapters.CreateMsalResponseFromWamResponse(webTokenResponseMsa, _msaPlugin, _logger, true);
                throw new MsalServiceException(
                          errorResp.Error,
                          "Error fetching the MSA-PT initial token - " + errorResp.ErrorDescription);
            }

            // Cannot use this WebAccount with the AAD provider
            WebAccount msaPtWebAccount = webTokenResponseMsa.ResponseData[0].WebAccount;

            return(msaPtWebAccount);
        }
示例#7
0
        public async Task <MsalTokenResponse> AcquireTokenSilentAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenSilentParameters acquireTokenSilentParameters)
        {
            using (_logger.LogMethodDuration())
            {
                // Important: MSAL will have already resolved the authority by now,
                // so we are not expecting "common" or "organizations" but a tenanted authority
                bool isMsa = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    null,
                    _wamOptions.MsaPassthrough)
                             .ConfigureAwait(false);

                IWamPlugin         wamPlugin = isMsa ? _msaPlugin : _aadPlugin;
                WebAccountProvider provider  = await GetProviderAsync(
                    authenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority,
                    isMsa).ConfigureAwait(false);

                WebAccount webAccount = await FindWamAccountForMsalAccountAsync(
                    provider,
                    wamPlugin,
                    authenticationRequestParameters.Account,
                    null, // ATS requires an account object, login_hint is not supported on its own
                    authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false);

                if (webAccount == null)
                {
                    throw new MsalUiRequiredException(
                              MsalError.InteractionRequired,
                              "Could not find a WAM account for the silent request.");
                }

                WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                    provider,
                    authenticationRequestParameters,
                    isForceLoginPrompt : false,
                    isAccountInWam : true,
                    isInteractive : false)
                                                  .ConfigureAwait(false);

                WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger);

                var wamResult =
                    await _wamProxy.GetTokenSilentlyAsync(webAccount, webTokenRequest).ConfigureAwait(false);

                return(WamAdapters.CreateMsalResponseFromWamResponse(
                           wamResult,
                           wamPlugin,
                           authenticationRequestParameters.AppConfig.ClientId,
                           _logger,
                           isInteractive: false));
            }
        }
示例#8
0
        private async Task <IWebTokenRequestResultWrapper> AcquireInteractiveWithoutPickerAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt prompt,
            IWamPlugin wamPlugin,
            WebAccountProvider provider,
            WebAccount wamAccount)
        {
            bool isForceLoginPrompt = IsForceLoginPrompt(prompt);

            WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : isForceLoginPrompt,
                isInteractive : true,
                isAccountInWam : true)
                                              .ConfigureAwait(false);

            if (isForceLoginPrompt &&
                ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 6))
            {
                // this feature works correctly since windows RS4, aka 1803 with the AAD plugin only!
                webTokenRequest.Properties["prompt"] = prompt.PromptValue;
            }

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest);

            try
            {
                IWebTokenRequestResultWrapper wamResult;
                if (wamAccount != null)
                {
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest,
                        wamAccount).ConfigureAwait(false);
                }
                else
                {
                    // default user
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest).ConfigureAwait(false);
                }
                return(wamResult);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamInteractiveError,
                          "AcquireTokenInteractive without picker failed. See inner exception for details. ", ex);
            }
        }
示例#9
0
        private async Task <IWebTokenRequestResultWrapper> AcquireInteractiveWithWamAccountAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt msalPrompt,
            IWamPlugin wamPlugin,
            WebAccountProvider provider,
            WebAccount wamAccount)
        {
            WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : true,
                isAccountInWam : true)
                                              .ConfigureAwait(false);

            // because of https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/2476
            string differentAuthority = null;

            if (string.Equals(wamAccount?.WebAccountProvider?.Authority, Constants.OrganizationsTenant) &&
                string.Equals(authenticationRequestParameters.Authority.TenantId, Constants.OrganizationsTenant))
            {
                differentAuthority = authenticationRequestParameters.Authority.GetTenantedAuthority("common");
            }

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, differentAuthority);

            try
            {
                IWebTokenRequestResultWrapper wamResult;
                if (wamAccount != null)
                {
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest,
                        wamAccount).ConfigureAwait(false);
                }
                else
                {
                    // default user
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest).ConfigureAwait(false);
                }
                return(wamResult);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamInteractiveError,
                          "AcquireTokenInteractive without picker failed. See inner exception for details. ", ex);
            }
        }
示例#10
0
        public async Task <MsalTokenResponse> AcquireTokenSilentDefaultUserAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenSilentParameters acquireTokenSilentParameters)
        {
            using (_logger.LogMethodDuration())
            {
                var defaultAccountProvider = await _webAccountProviderFactory.GetDefaultProviderAsync().ConfigureAwait(false);

                if (defaultAccountProvider == null)
                {
                    throw new MsalUiRequiredException(
                              MsalError.InteractionRequired,
                              "A default account was not found");
                }
                // special case: passthrough + default MSA account. Need to use the transfer token protocol.
                if (_wamOptions.MsaPassthrough &&
                    _webAccountProviderFactory.IsConsumerProvider(defaultAccountProvider))
                {
                    return(await AcquireTokenSilentDefaultUserPassthroughAsync(authenticationRequestParameters, defaultAccountProvider).ConfigureAwait(false));
                }

                bool isMsa = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    null,
                    _wamOptions.MsaPassthrough).ConfigureAwait(false);

                IWamPlugin         wamPlugin = isMsa ? _msaPlugin : _aadPlugin;
                WebAccountProvider provider  = await GetProviderAsync(
                    authenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority,
                    isMsa).ConfigureAwait(false);

                WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                    provider,
                    authenticationRequestParameters,
                    isForceLoginPrompt : false,
                    isAccountInWam : false,
                    isInteractive : false)
                                                  .ConfigureAwait(false);

                WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger);

                var wamResult =
                    await _wamProxy.GetTokenSilentlyForDefaultAccountAsync(webTokenRequest).ConfigureAwait(false);

                return(WamAdapters.CreateMsalResponseFromWamResponse(
                           wamResult,
                           wamPlugin,
                           authenticationRequestParameters.AppConfig.ClientId,
                           _logger,
                           isInteractive: false));
            }
        }
        private async Task <IWebTokenRequestResultWrapper> AcquireInteractiveWithoutPickerAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt msalPrompt,
            IWamPlugin wamPlugin,
            WebAccountProvider provider,
            WebAccount wamAccount)
        {
            bool isForceLoginPrompt = IsForceLoginPrompt(msalPrompt);

            WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : isForceLoginPrompt,
                isInteractive : true,
                isAccountInWam : true)
                                              .ConfigureAwait(false);

            AddPromptToRequest(msalPrompt, isForceLoginPrompt, webTokenRequest);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest);

            try
            {
                IWebTokenRequestResultWrapper wamResult;
                if (wamAccount != null)
                {
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest,
                        wamAccount).ConfigureAwait(false);
                }
                else
                {
                    // default user
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest).ConfigureAwait(false);
                }
                return(wamResult);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamInteractiveError,
                          "AcquireTokenInteractive without picker failed. See inner exception for details. ", ex);
            }
        }
示例#12
0
        private string ExtractTransferToken(
            string clientId,
            IWebTokenRequestResultWrapper transferResponse,
            bool isInteractive)
        {
            if (!transferResponse.ResponseStatus.IsSuccessStatus())
            {
                try
                {
                    _ = WamAdapters.CreateMsalResponseFromWamResponse(
                        transferResponse,
                        _msaPlugin,
                        clientId,
                        _logger,
                        isInteractive: isInteractive);
                }
                catch (MsalServiceException exception)
                {
                    _logger.Warning(
                        "WAM MSA-PT: could not get a transfer token, ussually this is because the " +
                        "1st party app is configured for MSA-PT but not configured to login MSA users (signinaudience =2). " +
                        "Error was: " + exception.ErrorCode + " " + exception.Message);
                }

                return(null);
            }

            _ = _msaPlugin.ParseSuccessfullWamResponse(transferResponse.ResponseData[0], out var properties);
            properties.TryGetValue("code", out string code);

            // Important: cannot use this WebAccount with the AAD provider
            WebAccount msaPtWebAccount = transferResponse.ResponseData[0].WebAccount;

            _logger.InfoPii($"Obtained a transfer token for {msaPtWebAccount.UserName} ?  {code != null}", $"Obtained a transfer token? {code != null}");

            return(code);
        }
示例#13
0
        private async Task <MsalTokenResponse> AcquireTokenSilentDefaultUserPassthroughAsync(AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider defaultAccountProvider)
        {
            var transferToken = await _msaPassthroughHandler.TryFetchTransferTokenSilentDefaultAccountAsync(authenticationRequestParameters, defaultAccountProvider).ConfigureAwait(false);

            if (string.IsNullOrEmpty(transferToken))
            {
                throw new MsalUiRequiredException(
                          MsalError.InteractionRequired,
                          "Cannot get a token silently (internal error: found an MSA account, but could not retrieve a transfer token for it when calling WAM)");
            }

            var aadAccountProvider = await _webAccountProviderFactory.GetAccountProviderAsync("organizations").ConfigureAwait(false);

            var webTokenRequest = await _aadPlugin.CreateWebTokenRequestAsync(
                aadAccountProvider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : false,
                isAccountInWam : true)
                                  .ConfigureAwait(false);

            _msaPassthroughHandler.AddTransferTokenToRequest(webTokenRequest, transferToken);

            string overrideAuthority = authenticationRequestParameters.Authority.GetTenantedAuthority(InfrastructureTenant, true);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger, overrideAuthority);

            var wamResult =
                await _wamProxy.RequestTokenForWindowAsync(_parentHandle, webTokenRequest).ConfigureAwait(false);

            return(WamAdapters.CreateMsalResponseFromWamResponse(
                       wamResult,
                       _aadPlugin,
                       authenticationRequestParameters.AppConfig.ClientId,
                       _logger,
                       isInteractive: false));
        }
示例#14
0
        public async Task <string> TryFetchTransferTokenSilentDefaultAccountAsync(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 silent flow with default OS account");

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

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequestMsa, _logger);

            var transferResponse = await _wamProxy.GetTokenSilentlyForDefaultAccountAsync(webTokenRequestMsa)
                                   .ConfigureAwait(true);

            return(ExtractTransferToken(
                       authenticationRequestParameters.AppConfig.ClientId,
                       transferResponse,
                       isInteractive: false));
        }
示例#15
0
        private async Task <MsalTokenResponse> AcquireInteractiveWithPickerAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt msalPrompt)
        {
            bool isMsaPassthrough = _wamOptions.MsaPassthrough;
            var  accountPicker    = _accountPickerFactory.Create(
                _parentHandle,
                _logger,
                _synchronizationContext,
                authenticationRequestParameters.Authority,
                isMsaPassthrough);

            IWamPlugin      wamPlugin;
            WebTokenRequest webTokenRequest;

            try
            {
                WebAccountProvider accountProvider = await
                                                     accountPicker.DetermineAccountInteractivelyAsync().ConfigureAwait(false);

                if (accountProvider == null)
                {
                    var errorMessage = "WAM Account Picker did not return an account.";
#if !WINDOWS_APP
                    if (WindowsNativeUtils.IsElevatedUser())
                    {
                        errorMessage = MsalErrorMessage.AuthenticationFailedWamElevatedProcess;
                    }
#endif
                    throw new MsalClientException(MsalError.AuthenticationCanceledError, errorMessage);
                }

                bool isConsumerTenant = _webAccountProviderFactory.IsConsumerProvider(accountProvider);
                // WAM returns the tenant here, not the full authority
                wamPlugin = (isConsumerTenant && !isMsaPassthrough) ? _msaPlugin : _aadPlugin;

                string transferToken      = null;
                bool   isForceLoginPrompt = false;
                if (isConsumerTenant && isMsaPassthrough)
                {
                    // Get a transfer token to avoid prompting the user twice
                    transferToken = await _msaPassthroughHandler.TryFetchTransferTokenAsync(
                        authenticationRequestParameters,
                        accountProvider).ConfigureAwait(false);

                    // If a TT cannot be obtained, force the interactive experience again
                    isForceLoginPrompt = string.IsNullOrEmpty(transferToken);

                    // For MSA-PT, the MSA provider will issue v1 token, which cannot be used.
                    // Only the AAD provider can issue a v2 token
                    accountProvider = await _webAccountProviderFactory.GetAccountProviderAsync(
                        authenticationRequestParameters.Authority.TenantId)
                                      .ConfigureAwait(false);
                }

                webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                    accountProvider,
                    authenticationRequestParameters,
                    isForceLoginPrompt : isForceLoginPrompt,
                    isInteractive : true,
                    isAccountInWam : false)
                                  .ConfigureAwait(true);

                _msaPassthroughHandler.AddTransferTokenToRequest(webTokenRequest, transferToken);

                WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger);
                AddPromptToRequest(msalPrompt, isForceLoginPrompt, webTokenRequest);
            }
            catch (Exception ex) when(!(ex is MsalException))
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamPickerError,
                          "Could not get the account provider - account picker. See inner exception for details", ex);
            }

            IWebTokenRequestResultWrapper wamResult;
            try
            {
                wamResult = await _wamProxy.RequestTokenForWindowAsync(_parentHandle, webTokenRequest).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamPickerError,
                          "Could not get the result - account picker. See inner exception for details", ex);
            }

            return(WamAdapters.CreateMsalResponseFromWamResponse(
                       wamResult,
                       wamPlugin,
                       authenticationRequestParameters.AppConfig.ClientId,
                       _logger,
                       isInteractive: true));
        }
示例#16
0
        /// <summary>
        /// In WAM, AcquireTokenInteractive is always associated to an account. WAM also allows for an "account picker" to be displayed,
        /// which is similar to the EVO browser experience, allowing the user to add an account or use an existing one.
        ///
        /// MSAL does not have a concept of account picker so MSAL.AccquireTokenInteractive will:
        ///
        /// 1. Call WAM.AccountPicker if an IAccount (or possibly login_hint) is not configured
        /// 2. Figure out the WAM.AccountID associated to the MSAL.Account
        /// 3. Call WAM.AcquireTokenInteractive with the WAM.AccountID
        ///
        /// To make matters more complicated, WAM has 2 plugins - AAD and MSA. With AAD plugin,
        /// it is possible to list all WAM accounts and find the one associated to the MSAL account.
        /// However, MSA plugin does NOT allow listing of accounts, and the only way to figure out the
        /// WAM account ID is to use the account picker. This makes AcquireTokenSilent impossible for MSA,
        /// because we would not be able to map an Msal.Account to a WAM.Account. To overcome this,
        /// we save the WAM.AccountID in MSAL's cache.
        /// </summary>
        public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenInteractiveParameters acquireTokenInteractiveParameters)
        {
#if WINDOWS_APP
            if (_synchronizationContext == null)
            {
                throw new MsalClientException(
                          MsalError.WamUiThread,
                          "AcquireTokenInteractive with broker must be called from the UI thread when using WAM." +
                          ErrorMessageSuffix);
            }
#endif

            if (authenticationRequestParameters.Account != null ||
                !string.IsNullOrEmpty(authenticationRequestParameters.LoginHint))
            {
                bool isMsaPassthrough = _wamOptions.MsaPassthrough;
                bool isMsa            = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    authenticationRequestParameters?.Account?.HomeAccountId?.TenantId, // TODO: we could further optimize here by searching for an account based on UPN
                    isMsaPassthrough).ConfigureAwait(false);

                IWamPlugin         wamPlugin = isMsa ? _msaPlugin : _aadPlugin;
                WebAccountProvider provider  = await GetProviderAsync(
                    authenticationRequestParameters.Authority.TenantId, isMsa)
                                               .ConfigureAwait(false);

                if (PublicClientApplication.IsOperatingSystemAccount(authenticationRequestParameters.Account))
                {
                    var wamResult = await AcquireInteractiveWithWamAccountAsync(
                        authenticationRequestParameters,
                        acquireTokenInteractiveParameters.Prompt,
                        wamPlugin,
                        provider,
                        null)
                                    .ConfigureAwait(false);

                    return(WamAdapters.CreateMsalResponseFromWamResponse(
                               wamResult,
                               wamPlugin,
                               authenticationRequestParameters.AppConfig.ClientId,
                               _logger,
                               isInteractive: true));
                }

                var wamAccount = await FindWamAccountForMsalAccountAsync(
                    provider,
                    wamPlugin,
                    authenticationRequestParameters.Account,
                    authenticationRequestParameters.LoginHint,
                    authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false);

                if (wamAccount != null)
                {
                    var wamResult = await AcquireInteractiveWithWamAccountAsync(
                        authenticationRequestParameters,
                        acquireTokenInteractiveParameters.Prompt,
                        wamPlugin,
                        provider,
                        wamAccount)
                                    .ConfigureAwait(false);

                    return(WamAdapters.CreateMsalResponseFromWamResponse(
                               wamResult,
                               wamPlugin,
                               authenticationRequestParameters.AppConfig.ClientId,
                               _logger,
                               isInteractive: true));
                }
                else
                {
                    if (IsAadOnlyAuthority(authenticationRequestParameters.Authority))
                    {
                        return(await AcquireInteractiveWithAadBrowserAsync(
                                   authenticationRequestParameters,
                                   acquireTokenInteractiveParameters.Prompt).ConfigureAwait(false));
                    }
                }
            }

            return(await AcquireInteractiveWithPickerAsync(
                       authenticationRequestParameters,
                       acquireTokenInteractiveParameters.Prompt)
                   .ConfigureAwait(false));
        }
示例#17
0
        /// <summary>
        /// In WAM, AcquireTokenInteractive is always associated to an account. WAM also allows for an "account picker" to be displayed,
        /// which is similar to the EVO browser experience, allowing the user to add an account or use an existing one.
        ///
        /// MSAL does not have a concept of account picker so MSAL.AccquireTokenInteractive will:
        ///
        /// 1. Call WAM.AccountPicker if an IAccount (or possibly login_hint) is not configured
        /// 2. Figure out the WAM.AccountID associated to the MSAL.Account
        /// 3. Call WAM.AcquireTokenInteractive with the WAM.AccountID
        ///
        /// To make matters more complicated, WAM has 2 plugins - AAD and MSA. With AAD plugin,
        /// it is possible to list all WAM accounts and find the one associated to the MSAL account.
        /// However, MSA plugin does NOT allow listing of accounts, and the only way to figure out the
        /// WAM account ID is to use the account picker. This makes AcquireTokenSilent impossible for MSA,
        /// because we would not be able to map an Msal.Account to a WAM.Account. To overcome this,
        /// we save the WAM.AccountID in MSAL's cache.
        /// </summary>
        public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenInteractiveParameters acquireTokenInteractiveParameters)
        {
#if WINDOWS_APP
            if (_synchronizationContext == null)
            {
                throw new MsalClientException(
                          MsalError.WamUiThread,
                          "AcquireTokenInteractive with broker must be called from the UI thread when using WAM." +
                          ErrorMessageSuffix);
            }
#endif

            if (authenticationRequestParameters.Account != null ||
                !string.IsNullOrEmpty(authenticationRequestParameters.LoginHint))
            {
                _logger.Verbose("[WamBroker] AcquireTokenIntractive - account information provided. Trying to find a Windows account that matches.");

                bool isMsaPassthrough = _wamOptions.MsaPassthrough;
                bool isMsa            = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    authenticationRequestParameters?.Account?.HomeAccountId?.TenantId,
                    isMsaPassthrough).ConfigureAwait(false);

                IWamPlugin         wamPlugin = isMsa ? _msaPlugin : _aadPlugin;
                WebAccountProvider provider  = await GetProviderAsync(
                    authenticationRequestParameters.Authority.TenantId, isMsa)
                                               .ConfigureAwait(false);

                if (PublicClientApplication.IsOperatingSystemAccount(authenticationRequestParameters.Account))
                {
                    var wamResult = await AcquireInteractiveWithWamAccountAsync(
                        authenticationRequestParameters,
                        acquireTokenInteractiveParameters.Prompt,
                        wamPlugin,
                        provider,
                        null)
                                    .ConfigureAwait(false);

                    return(WamAdapters.CreateMsalResponseFromWamResponse(
                               wamResult,
                               wamPlugin,
                               authenticationRequestParameters.AppConfig.ClientId,
                               _logger,
                               isInteractive: true));
                }

                var wamAccount = await FindWamAccountForMsalAccountAsync(
                    provider,
                    wamPlugin,
                    authenticationRequestParameters.Account,
                    authenticationRequestParameters.LoginHint,
                    authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false);

                if (wamAccount != null)
                {
                    var wamResult = await AcquireInteractiveWithWamAccountAsync(
                        authenticationRequestParameters,
                        acquireTokenInteractiveParameters.Prompt,
                        wamPlugin,
                        provider,
                        wamAccount)
                                    .ConfigureAwait(false);

                    return(WamAdapters.CreateMsalResponseFromWamResponse(
                               wamResult,
                               wamPlugin,
                               authenticationRequestParameters.AppConfig.ClientId,
                               _logger,
                               isInteractive: true));
                }

                _logger.Verbose("[WamBroker] AcquireTokenIntractive - account information provided but no matching account was found ");
            }

            // no account information available, need an account picker
            if (CanSkipAccountPicker(authenticationRequestParameters.Authority))
            {
                _logger.Verbose("[WamBroker] Using AAD plugin account picker");
                return(await AcquireInteractiveWithAadBrowserAsync(
                           authenticationRequestParameters,
                           acquireTokenInteractiveParameters.Prompt).ConfigureAwait(false));
            }

            _logger.Verbose("[WamBroker] Using Windows account picker (AccountsSettingsPane)");
            return(await AcquireInteractiveWithPickerAsync(
                       authenticationRequestParameters,
                       acquireTokenInteractiveParameters.Prompt)
                   .ConfigureAwait(false));
        }
示例#18
0
        public async Task <MsalTokenResponse> AcquireTokenSilentAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenSilentParameters acquireTokenSilentParameters)
        {
            using (_logger.LogMethodDuration())
            {
                // Important: MSAL will have already resolved the authority by now,
                // so we are not expecting "common" or "organizations" but a tenanted authority
                bool isMsa = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    null,
                    _wamOptions.MsaPassthrough)
                             .ConfigureAwait(false);

                IWamPlugin wamPlugin = isMsa ? _msaPlugin : _aadPlugin;

                WebAccountProvider provider;
                if (_wamOptions.MsaPassthrough)
                {
                    provider = await GetProviderAsync(
                        "organizations", false).ConfigureAwait(false);
                }
                else
                {
                    provider = await GetProviderAsync(
                        authenticationRequestParameters.AuthorityInfo.CanonicalAuthority,
                        isMsa).ConfigureAwait(false);
                }

                WebAccount webAccount = await FindWamAccountForMsalAccountAsync(
                    provider,
                    wamPlugin,
                    authenticationRequestParameters.Account,
                    null, // ATS requires an account object, login_hint is not supported on its own
                    authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false);

                if (webAccount == null && _wamOptions.MsaPassthrough)
                {
                    return(await AcquireMsaTokenSilentForPassthroughAsync(
                               authenticationRequestParameters,
                               provider).ConfigureAwait(false));
                }

                if (webAccount == null)
                {
                    throw new MsalUiRequiredException(
                              MsalError.InteractionRequired,
                              "Could not find a WAM account for the silent request.");
                }

                WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                    provider,
                    authenticationRequestParameters,
                    isForceLoginPrompt : false,
                    isAccountInWam : true,
                    isInteractive : false)
                                                  .ConfigureAwait(false);

                // For MSA-PT scenario, MSAL's authority is wrong. MSAL will use Account.HomeTenantId
                // which will essentialyl be /consumers. This is wrong, we are not trying to obtain
                // an MSA token, we are trying to obtain an ADD *guest* token.
                string differentAuthority = null;
                if (_wamOptions.MsaPassthrough &&
                    authenticationRequestParameters.Authority is AadAuthority aadAuthority &&
                    aadAuthority.IsConsumers())
                {
                    differentAuthority = authenticationRequestParameters.Authority.GetTenantedAuthority("organizations", forceTenantless: true);
                }

                WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger, differentAuthority);

                var wamResult =
                    await _wamProxy.GetTokenSilentlyAsync(webAccount, webTokenRequest).ConfigureAwait(false);

                return(WamAdapters.CreateMsalResponseFromWamResponse(
                           wamResult,
                           wamPlugin,
                           authenticationRequestParameters.AppConfig.ClientId,
                           _logger,
                           isInteractive: false));
            }
        }
示例#19
0
        private async Task <MsalTokenResponse> AcquireMsaTokenSilentForPassthroughAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            WebAccountProvider aadAccountProvider)
        {
            // Try to find an MSA account which matches the MSAL account
            var msaProvider = await GetProviderAsync("consumers", true).ConfigureAwait(false);

            var msaWebAccount = await FindWamAccountForMsalAccountAsync(
                msaProvider,
                _msaPlugin,
                authenticationRequestParameters.Account,
                null, // ATS requires an account object, login_hint is not supported on its own
                authenticationRequestParameters.AppConfig.ClientId).ConfigureAwait(false);

            if (msaWebAccount == null)
            {
                throw new MsalUiRequiredException(
                          MsalError.InteractionRequired,
                          "Could not find a WAM MSA account for the silent request.");
            }

            // We can't use the account as is to get a token, because this account is from MSA but the provider is AAD
            // so we have to perform the transfer token flow
            string transferToken = await _msaPassthroughHandler.TryFetchTransferTokenSilentAsync(
                authenticationRequestParameters,
                msaWebAccount).ConfigureAwait(false);

            if (string.IsNullOrEmpty(transferToken))
            {
                throw new MsalUiRequiredException(
                          MsalError.InteractionRequired,
                          "Found an MSA account, but could not retrieve a transfer token for it.");
            }

            // Now make a request to AAD plugin, including the login hint and transfer token
            var webTokenRequest = await _aadPlugin.CreateWebTokenRequestAsync(
                aadAccountProvider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : false,
                isAccountInWam : true)
                                  .ConfigureAwait(true);

            _msaPassthroughHandler.AddTransferTokenToRequest(webTokenRequest, transferToken);

            // We can't make this request on the /consumers authority, this is a known MSA-PT issue with the browser as well
            // but we can make the request over /organizations or over /MicrosoftInfrastructureTenant
            string overrideAuthority = null;

            if (authenticationRequestParameters.Authority is AadAuthority aadAuthority && aadAuthority.IsConsumers())
            {
                overrideAuthority =
                    authenticationRequestParameters.Authority.GetTenantedAuthority("organizations", true);
            }
            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger, overrideAuthority);

            var wamResult =
                await _wamProxy.RequestTokenForWindowAsync(_parentHandle, webTokenRequest).ConfigureAwait(false);

            return(WamAdapters.CreateMsalResponseFromWamResponse(
                       wamResult,
                       _aadPlugin,
                       authenticationRequestParameters.AppConfig.ClientId,
                       _logger,
                       isInteractive: false));
        }