public async Task ATI_RequiresSyncContext_Async()
        {
            var wamBroker = new WamBroker(
                new CoreUIParent(), // no sync context here
                _logger,
                _aadPlugin,
                _msaPlugin,
                _wamProxy,
                _webAccountProviderFactory,
                _accountPickerFactory);

            using (var harness = CreateTestHarness())
            {
                var requestParams = harness.CreateAuthenticationRequestParameters(TestConstants.AuthorityHomeTenant); // AAD
                var atiParams     = new AcquireTokenInteractiveParameters();

                // Act
                var ex = await AssertException.TaskThrowsAsync <MsalClientException>(
                    () => wamBroker.AcquireTokenInteractiveAsync(requestParams, atiParams)).ConfigureAwait(false);

                // Assert
                Assert.AreEqual(MsalError.WamUiThread, ex.ErrorCode);
            }
        }
        public void RedirectUriContainsFragmentErrorTest()
        {
            try
            {
                using (var harness = CreateTestHarness())
                {
                    AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                        TestConstants.AuthorityHomeTenant,
                        TestConstants.s_scope,
                        new TokenCache(harness.ServiceBundle),
                        extraQueryParameters: new Dictionary <string, string>
                    {
                        { "extra", "qp" }
                    });
                    parameters.RedirectUri = new Uri("some://uri#fragment=not-so-good");
                    parameters.LoginHint   = TestConstants.DisplayableId;
                    var interactiveParameters = new AcquireTokenInteractiveParameters
                    {
                        Prompt = Prompt.ForceLogin,
                        ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(),
                    };

                    new InteractiveRequest(
                        harness.ServiceBundle,
                        parameters,
                        interactiveParameters,
                        new MockWebUI());

                    Assert.Fail("ArgumentException should be thrown here");
                }
            }
            catch (ArgumentException ae)
            {
                Assert.IsTrue(ae.Message.Contains(MsalErrorMessage.RedirectUriContainsFragment));
            }
        }
        private void CreateBrokerHelper()
        {
            using (MockHttpAndServiceBundle harness = CreateTestHarness())
            {
                AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                    MsalTestConstants.AuthorityHomeTenant,
                    MsalTestConstants.Scope,
                    new TokenCache(harness.ServiceBundle),
                    extraQueryParameters: MsalTestConstants.ExtraQueryParams,
                    claims: MsalTestConstants.Claims);

                parameters.IsBrokerEnabled = true;

                AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters();

                InteractiveRequest request = new InteractiveRequest(
                    harness.ServiceBundle,
                    parameters,
                    interactiveParameters,
                    new MockWebUI());

                _brokerInteractiveRequest = new BrokerInteractiveRequest(parameters, interactiveParameters, harness.ServiceBundle, null);
            }
        }
예제 #4
0
        private IWebUI CreateWebAuthenticationDialog(
            AcquireTokenInteractiveParameters interactiveParameters,
            RequestContext requestContext)
        {
            if (interactiveParameters.CustomWebUi != null)
            {
                return(new CustomWebUiHandler(interactiveParameters.CustomWebUi));
            }

            var coreUiParent = interactiveParameters.UiParent;

#if ANDROID || iOS
            coreUiParent.UseEmbeddedWebview = interactiveParameters.UseEmbeddedWebView;
#endif

#if WINDOWS_APP || DESKTOP
            // hidden web view can be used in both WinRT and desktop applications.
            coreUiParent.UseHiddenBrowser = interactiveParameters.Prompt.Equals(Prompt.Never);
#if WINDOWS_APP
            coreUiParent.UseCorporateNetwork = _publicClientApplication.AppConfig.UseCorporateNetwork;
#endif
#endif
            return(ServiceBundle.PlatformProxy.GetWebUiFactory().CreateAuthenticationDialog(coreUiParent, requestContext));
        }
예제 #5
0
        private MockHttpAndServiceBundle CreateBrokerHelper()
        {
            MockHttpAndServiceBundle harness = CreateTestHarness();

            _parameters = harness.CreateAuthenticationRequestParameters(
                TestConstants.AuthorityHomeTenant,
                TestConstants.s_scope,
                new TokenCache(harness.ServiceBundle, false),
                extraQueryParameters: TestConstants.ExtraQueryParameters,
                claims: TestConstants.Claims);

            _parameters.IsBrokerConfigured = true;

            AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters();

            _acquireTokenSilentParameters = new AcquireTokenSilentParameters();

            IBroker broker = harness.ServiceBundle.PlatformProxy.CreateBroker(null);

            _brokerInteractiveRequest =
                new BrokerInteractiveRequestComponent(
                    _parameters,
                    interactiveParameters,
                    broker,
                    "install_url");

            _brokerSilentAuthStrategy =
                new SilentBrokerAuthStrategy(
                    new SilentRequest(harness.ServiceBundle, _parameters, _acquireTokenSilentParameters),
                    harness.ServiceBundle,
                    _parameters,
                    _acquireTokenSilentParameters,
                    broker);

            return(harness);
        }
예제 #6
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));
        }
 public Task <MsalTokenResponse> AcquireTokenInteractiveAsync(AuthenticationRequestParameters authenticationRequestParameters, AcquireTokenInteractiveParameters acquireTokenInteractiveParameters)
 {
     throw new NotImplementedException();
 }
예제 #8
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 (_synchronizationContext == null)
            {
                throw new MsalClientException(
                          MsalError.WamUiThread,
                          "AcquireTokenInteractive with broker must be called from the UI thread when using WAM. " +
                          "Note that console applications are not currently supported in conjuction with WAM." + ErrorMessageSuffix);
            }

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

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

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

                    return(CreateMsalTokenResponse(wamResult, wamPlugin, isInteractive: true));
                }

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

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

                    return(CreateMsalTokenResponse(wamResult, wamPlugin, isInteractive: true));
                }
            }

            return(await AcquireInteractiveWithPickerAsync(
                       authenticationRequestParameters)
                   .ConfigureAwait(false));
        }
예제 #9
0
        public void VerifyAuthorizationResultTest()
        {
            using (MockHttpAndServiceBundle harness = CreateTestHarness())
            {
                MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager);

                MockWebUI webUi = new MockWebUI()
                {
                    MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?error=" + OAuth2Error.LoginRequired),
                };

                AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                    TestConstants.AuthorityHomeTenant,
                    TestConstants.s_scope,
                    new TokenCache(harness.ServiceBundle, false),
                    extraQueryParameters: new Dictionary <string, string> {
                    { "extra", "qp" }
                });
                parameters.RedirectUri = new Uri("some://uri");
                parameters.LoginHint   = TestConstants.DisplayableId;
                AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters
                {
                    Prompt = Prompt.ForceLogin,
                    ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(),
                };

                InteractiveRequest request = new InteractiveRequest(
                    harness.ServiceBundle,
                    parameters,
                    interactiveParameters,
                    webUi);

                try
                {
                    request.ExecuteAsync(CancellationToken.None).Wait();
                    Assert.Fail("MsalException should have been thrown here");
                }
                catch (Exception exc)
                {
                    Assert.IsTrue(exc.InnerException is MsalUiRequiredException);
                    Assert.AreEqual(
                        MsalError.NoPromptFailedError,
                        ((MsalUiRequiredException)exc.InnerException).ErrorCode);

                    Assert.AreEqual(
                        UiRequiredExceptionClassification.PromptNeverFailed,
                        ((MsalUiRequiredException)exc.InnerException).Classification);
                }

                webUi = new MockWebUI
                {
                    MockResult = AuthorizationResult.FromUri(
                        TestConstants.AuthorityHomeTenant + "?error=invalid_request&error_description=some error description")
                };

                request = new InteractiveRequest(
                    harness.ServiceBundle,
                    parameters,
                    interactiveParameters,
                    webUi);

                try
                {
                    request.ExecuteAsync(CancellationToken.None).Wait(CancellationToken.None);
                    Assert.Fail("MsalException should have been thrown here");
                }
                catch (Exception exc)
                {
                    Assert.IsTrue(exc.InnerException is MsalException);
                    Assert.AreEqual("invalid_request", ((MsalException)exc.InnerException).ErrorCode);
                    Assert.AreEqual("some error description", ((MsalException)exc.InnerException).Message);
                }
            }
        }
예제 #10
0
        public void NoCacheLookup()
        {
            MyReceiver myReceiver = new MyReceiver();

            using (MockHttpAndServiceBundle harness = CreateTestHarness(telemetryCallback: myReceiver.HandleTelemetryEvents))
            {
                TokenCache cache = new TokenCache(harness.ServiceBundle, false);

                MsalAccessTokenCacheItem atItem = new MsalAccessTokenCacheItem(
                    TestConstants.ProductionPrefNetworkEnvironment,
                    TestConstants.ClientId,
                    TestConstants.s_scope.AsSingleString(),
                    TestConstants.Utid,
                    null,
                    new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(3599)),
                    new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(7200)),
                    MockHelpers.CreateClientInfo());

                string atKey = atItem.GetKey().ToString();
                atItem.Secret = atKey;
                ((ITokenCacheInternal)cache).Accessor.SaveAccessToken(atItem);

                MockWebUI ui = new MockWebUI()
                {
                    MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?code=some-code")
                };

                MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager);

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(TestConstants.AuthorityHomeTenant);

                AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                    TestConstants.AuthorityHomeTenant,
                    TestConstants.s_scope,
                    cache,
                    extraQueryParameters: new Dictionary <string, string>
                {
                    { "extra", "qp" }
                });
                parameters.RedirectUri = new Uri("some://uri");
                parameters.LoginHint   = TestConstants.DisplayableId;
                AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters
                {
                    Prompt = Prompt.SelectAccount,
                    ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(),
                };

                InteractiveRequest request = new InteractiveRequest(
                    harness.ServiceBundle,
                    parameters,
                    interactiveParameters,
                    ui);

                Task <AuthenticationResult> task = request.RunAsync(CancellationToken.None);
                task.Wait();
                AuthenticationResult result = task.Result;
                Assert.IsNotNull(result);
                Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllRefreshTokens().Count());
                Assert.AreEqual(2, ((ITokenCacheInternal)cache).Accessor.GetAllAccessTokens().Count());
                Assert.AreEqual(result.AccessToken, "some-access-token");

                Assert.IsNotNull(
                    myReceiver.EventsReceived.Find(
                        anEvent => // Expect finding such an event
                        anEvent[EventBase.EventNameKey].EndsWith("ui_event") &&
                        anEvent[UiEvent.UserCancelledKey] == "false"));
                Assert.IsNotNull(
                    myReceiver.EventsReceived.Find(
                        anEvent => // Expect finding such an event
                        anEvent[EventBase.EventNameKey].EndsWith("api_event") &&
                        anEvent[ApiEvent.PromptKey] == "select_account"));
                Assert.IsNotNull(
                    myReceiver.EventsReceived.Find(
                        anEvent => // Expect finding such an event
                        anEvent[EventBase.EventNameKey].EndsWith("ui_event") &&
                        anEvent[UiEvent.AccessDeniedKey] == "false"));
            }
        }
        public async Task VerifyAuthorizationResultTestAsync()
        {
            using (MockHttpAndServiceBundle harness = CreateTestHarness())
            {
                MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager);

                MockWebUI webUi = new MockWebUI()
                {
                    MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?error=" + OAuth2Error.LoginRequired),
                };
                MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle.PlatformProxy, webUi);

                AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                    TestConstants.AuthorityHomeTenant,
                    TestConstants.s_scope,
                    new TokenCache(harness.ServiceBundle, false),
                    extraQueryParameters: new Dictionary <string, string> {
                    { "extra", "qp" }
                });
                parameters.RedirectUri = new Uri("some://uri");
                parameters.LoginHint   = TestConstants.DisplayableId;
                AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters
                {
                    Prompt = Prompt.ForceLogin,
                    ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(),
                };

                InteractiveRequest request = new InteractiveRequest(
                    parameters,
                    interactiveParameters);

                var ex = await AssertException.TaskThrowsAsync <MsalUiRequiredException>(
                    () => request.RunAsync())
                         .ConfigureAwait(false);

                Assert.AreEqual(
                    MsalError.NoPromptFailedError,
                    ex.ErrorCode);

                Assert.AreEqual(
                    UiRequiredExceptionClassification.PromptNeverFailed,
                    ex.Classification);


                webUi = new MockWebUI
                {
                    MockResult = AuthorizationResult.FromUri(
                        TestConstants.AuthorityHomeTenant + "?error=invalid_request&error_description=some error description")
                };
                MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle.PlatformProxy, webUi);

                request = new InteractiveRequest(
                    parameters,
                    interactiveParameters);

                var ex2 = await AssertException.TaskThrowsAsync <MsalServiceException>(
                    () => request.RunAsync())
                          .ConfigureAwait(false);

                Assert.AreEqual("invalid_request", ex2.ErrorCode);
                Assert.AreEqual("some error description", ex2.Message);
            }
        }
        public async Task WithMultiCloudSupportEnabledAsync(bool multiCloudSupportEnabled)
        {
            var expectedQueryParams    = TestConstants.ExtraQueryParameters;
            var authorizationResultUri = TestConstants.AuthorityHomeTenant + "?code=some-code";

            if (multiCloudSupportEnabled)
            {
                expectedQueryParams.Add("instance_aware", "true");
                authorizationResultUri = authorizationResultUri + "&cloud_instance_name=microsoftonline.us&cloud_instance_host_name=login.microsoftonline.us";
            }


            using (MockHttpAndServiceBundle harness = CreateTestHarness(isMultiCloudSupportEnabled: multiCloudSupportEnabled))
            {
                var cache = new TokenCache(harness.ServiceBundle, false);

                var ui = new MockWebUI()
                {
                    MockResult            = AuthorizationResult.FromUri(authorizationResultUri),
                    QueryParamsToValidate = expectedQueryParams
                };
                MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle, ui);

                MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager);

                var tokenResponseHandler = new MockHttpMessageHandler
                {
                    ExpectedMethod      = HttpMethod.Post,
                    ExpectedQueryParams = expectedQueryParams,
                    ExpectedPostData    = new Dictionary <string, string>()
                    {
                        { OAuth2Parameter.Claims, TestConstants.Claims }
                    },
                    ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage()
                };
                harness.HttpManager.AddMockHandler(tokenResponseHandler);

                AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                    TestConstants.AuthorityHomeTenant,
                    TestConstants.s_scope,
                    cache,
                    extraQueryParameters: TestConstants.ExtraQueryParameters,
                    claims: TestConstants.Claims);

                parameters.RedirectUri = new Uri("some://uri");
                parameters.LoginHint   = TestConstants.DisplayableId;

                AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters
                {
                    Prompt = Prompt.SelectAccount,
                    ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(),
                };

                var request = new InteractiveRequest(
                    parameters,
                    interactiveParameters);

                AuthenticationResult result = await request.RunAsync().ConfigureAwait(false);

                Assert.IsNotNull(result);

                if (multiCloudSupportEnabled)
                {
                    Assert.AreEqual("https://login.microsoftonline.us/home/oauth2/v2.0/token", result.AuthenticationResultMetadata.TokenEndpoint);
                }
                else
                {
                    Assert.AreEqual("https://login.microsoftonline.com/home/oauth2/v2.0/token", result.AuthenticationResultMetadata.TokenEndpoint);
                }
                Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllRefreshTokens().Count());
                Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllAccessTokens().Count());
                Assert.AreEqual(result.AccessToken, "some-access-token");
            }
        }
        public async Task NoCacheLookupAsync()
        {
            using (MockHttpAndServiceBundle harness = CreateTestHarness())
            {
                TokenCache cache                = new TokenCache(harness.ServiceBundle, false);
                string     clientInfo           = MockHelpers.CreateClientInfo();
                string     homeAccountId        = ClientInfo.CreateFromJson(clientInfo).ToAccountIdentifier();
                MsalAccessTokenCacheItem atItem = new MsalAccessTokenCacheItem(
                    TestConstants.ProductionPrefNetworkEnvironment,
                    TestConstants.ClientId,
                    TestConstants.s_scope.AsSingleString(),
                    TestConstants.Utid,
                    null,
                    new DateTimeOffset(DateTime.UtcNow),
                    new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(3599)),
                    new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(7200)),
                    clientInfo,
                    homeAccountId);

                string atKey = atItem.GetKey().ToString();
                atItem.Secret = atKey;
                ((ITokenCacheInternal)cache).Accessor.SaveAccessToken(atItem);

                MockWebUI ui = new MockWebUI()
                {
                    MockResult = AuthorizationResult.FromUri(TestConstants.AuthorityHomeTenant + "?code=some-code")
                };

                MsalMockHelpers.ConfigureMockWebUI(harness.ServiceBundle, ui);

                MockInstanceDiscoveryAndOpenIdRequest(harness.HttpManager);

                harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(TestConstants.AuthorityHomeTenant);

                AuthenticationRequestParameters parameters = harness.CreateAuthenticationRequestParameters(
                    TestConstants.AuthorityHomeTenant,
                    TestConstants.s_scope,
                    cache,
                    extraQueryParameters: new Dictionary <string, string>
                {
                    { "extra", "qp" }
                });
                parameters.RedirectUri = new Uri("some://uri");
                parameters.LoginHint   = TestConstants.DisplayableId;
                AcquireTokenInteractiveParameters interactiveParameters = new AcquireTokenInteractiveParameters
                {
                    Prompt = Prompt.SelectAccount,
                    ExtraScopesToConsent = TestConstants.s_scopeForAnotherResource.ToArray(),
                };

                InteractiveRequest request = new InteractiveRequest(
                    parameters,
                    interactiveParameters);

                AuthenticationResult result = await request.RunAsync().ConfigureAwait(false);

                Assert.AreEqual(1, ((ITokenCacheInternal)cache).Accessor.GetAllRefreshTokens().Count());
                Assert.AreEqual(2, ((ITokenCacheInternal)cache).Accessor.GetAllAccessTokens().Count());
                Assert.AreEqual(result.AccessToken, "some-access-token");
            }
        }
예제 #14
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));
        }