private IConfidentialClientApplication BuildCCA(
            IConfidentialAppSettings settings,
            HttpSnifferClientFactory factory,
            bool useClaims = false,
            string region  = ConfidentialClientApplication.AttemptRegionDiscovery)
        {
            var builder = ConfidentialClientApplicationBuilder.Create(settings.ClientId);

            if (useClaims)
            {
                builder.WithClientAssertion(GetSignedClientAssertionUsingMsalInternal(settings.ClientId, GetClaims(settings)));
            }
            else
            {
                builder.WithCertificate(settings.GetCertificate());
            }

            builder.WithAuthority($@"https://{settings.Environment}/{settings.TenantId}")
            .WithTestLogging()
            .WithExperimentalFeatures(true)
            .WithHttpClientFactory(factory);

            if (region != null)
            {
                builder.WithAzureRegion(region);
            }

            return(builder.Build());
        }
        public async Task AcquireTokenToGlobalEndpointThenRegionalEndpoint_UseTokenFromCacheAsync()
        {
            // Arrange
            var factory = new HttpSnifferClientFactory();

            _confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(PublicCloudConfidentialClientID)
                                             .WithClientAssertion(GetSignedClientAssertionUsingMsalInternal(PublicCloudConfidentialClientID, GetClaims()))
                                             //.WithClientSecret(_keyVault.GetSecret(TestConstants.MsalCCAKeyVaultUri).Value)
                                             .WithAuthority(PublicCloudTestAuthority)
                                             .WithTestLogging()
                                             .WithExperimentalFeatures(true)
                                             .WithHttpClientFactory(factory)
                                             .Build();

            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
            AuthenticationResult result = await GetAuthenticationResultAsync(autoDetectRegion : false).ConfigureAwait(false); // global endpoint

            AssertValidHost(false, factory);
            AssertTokenSource_IsIdP(result);
            result = await GetAuthenticationResultAsync().ConfigureAwait(false); // regional endpoint, use cached token

            AssertTokenSource_IsCache(result);
            result = await GetAuthenticationResultAsync(autoDetectRegion : false).ConfigureAwait(false); // global endpoint, use cached token

            AssertTokenSource_IsCache(result);
            result = await GetAuthenticationResultAsync(withForceRefresh : true).ConfigureAwait(false); // regional endpoint, new token

            AssertValidHost(true, factory, 1);
            AssertTokenSource_IsIdP(result);
        }
コード例 #3
0
        public async Task PKeyAuthNonInteractiveTestAsync()
        {
            //Arrange
            var labResponse = await LabUserHelper.GetSpecificUserAsync(_deviceAuthuser).ConfigureAwait(false);

            var factory          = new HttpSnifferClientFactory();
            var msalPublicClient = PublicClientApplicationBuilder
                                   .Create(labResponse.App.AppId)
                                   .WithAuthority("https://login.microsoftonline.com/organizations/")
                                   .WithHttpClientFactory(factory)
                                   .Build();

            //Act
            var authResult = msalPublicClient.AcquireTokenByUsernamePassword(
                new[] { "user.read" },
                labResponse.User.Upn,
                new NetworkCredential("", labResponse.User.GetOrFetchPassword()).SecurePassword)
                             .WithClaims(JObject.Parse(_claims).ToString())
                             .ExecuteAsync(CancellationToken.None).Result;

            //Assert
            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(string.Equals(_deviceAuthuser, authResult.Account.Username, StringComparison.InvariantCultureIgnoreCase));

            //Assert that the PKeyAuth header is used and the token response is successful
            var(req, res) = factory.RequestsAndResponses
                            .Where(x => x.Item1.Headers.Authorization != null &&
                                   x.Item1.Headers.Authorization.Scheme.Contains(PKeyAuthConstants.PKeyAuthName) &&
                                   x.Item2.StatusCode == HttpStatusCode.OK).FirstOrDefault();

            Assert.IsNotNull(req);
            Assert.IsNotNull(res);
        }
コード例 #4
0
        public async Task PKeyAuthNonInteractiveTestAsync()
        {
            //Arrange
            var labResponse = await LabUserHelper.GetSpecificUserAsync(_deviceAuthuser).ConfigureAwait(false);

            var factory          = new HttpSnifferClientFactory();
            var msalPublicClient = PublicClientApplicationBuilder
                                   .Create(labResponse.App.AppId)
                                   .WithAuthority("https://login.microsoftonline.com/organizations/")
                                   .WithHttpClientFactory(factory)
                                   .Build();

            //Act
            var authResult = msalPublicClient.AcquireTokenByUsernamePassword(
                new[] { "user.read" },
                labResponse.User.Upn,
                new NetworkCredential("", labResponse.User.GetOrFetchPassword()).SecurePassword)
                             .WithClaims(JObject.Parse(_claims).ToString())
                             .ExecuteAsync(CancellationToken.None).Result;

            //Assert
            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(string.Equals(_deviceAuthuser, authResult.Account.Username, StringComparison.InvariantCultureIgnoreCase));

            var(req, res) = factory.RequestsAndResponses
                            .Where(x => x.Item1.RequestUri.AbsoluteUri == labResponse.Lab.Authority + "organizations/oauth2/v2.0/token" &&
                                   x.Item2.StatusCode == HttpStatusCode.OK).ElementAt(1);

            var AuthHeader = req.Headers.Single(h => h.Key == "Authorization").Value.FirstOrDefault();

            Assert.IsTrue(!string.IsNullOrEmpty(AuthHeader));
            Assert.IsTrue(AuthHeader.Contains("PKeyAuth"));
        }
コード例 #5
0
        [Ignore] //See https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/2781
        public async Task InvalidRegion_GoesToInvalidAuthority_Async()
        {
            // Arrange
            var factory  = new HttpSnifferClientFactory();
            var settings = ConfidentialAppSettings.GetSettings(Cloud.Public);

            _confidentialClientApplication = BuildCCA(settings, factory, true, "invalid");

            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
            AuthenticationResult result = await GetAuthenticationResultAsync(settings.AppScopes).ConfigureAwait(false); // regional endpoint

            AssertTokenSourceIsIdp(result);
            Assert.AreEqual(
                "https://invalid.login.microsoft.com/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/v2.0/token?allowestsrnonmsi=true",
                factory.RequestsAndResponses.Single().Item1.RequestUri.ToString());

            AssertTelemetry(factory, $"{TelemetryConstants.HttpTelemetrySchemaVersion}|1004,{CacheInfoTelemetry.NoCachedAT:D},invalid,3,3|0,1");

            _confidentialClientApplication = BuildCCA(settings, factory, true, TestConstants.Region);
            result = await GetAuthenticationResultAsync(settings.AppScopes, withForceRefresh : true).ConfigureAwait(false); // regional endpoint

            AssertTokenSourceIsIdp(result);
            AssertValidHost(true, factory, 1);
            AssertTelemetry(factory, $"{TelemetryConstants.HttpTelemetrySchemaVersion}|1004,{CacheInfoTelemetry.ForceRefresh:D},centralus,2,1|0,1", 1);
        }
        private async Task CheckTelemetryHeadersAsync(
            LabResponse labResponse)
        {
            var factory = new HttpSnifferClientFactory();

            var msalPublicClient = PublicClientApplicationBuilder
                                   .Create(labResponse.App.AppId)
                                   .WithAuthority(Authority)
                                   .WithHttpClientFactory(factory)
                                   .Build();

            await RunAcquireTokenWithUsernameIncorrectPasswordAsync(msalPublicClient, labResponse.User.Upn).ConfigureAwait(false);

            AuthenticationResult authResult = await msalPublicClient
                                              .AcquireTokenByUsernamePassword(s_scopes, labResponse.User.Upn, new NetworkCredential("", labResponse.User.GetOrFetchPassword()).SecurePassword)
                                              .WithCorrelationId(CorrelationId)
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(string.Equals(labResponse.User.Upn, authResult.Account.Username, StringComparison.InvariantCultureIgnoreCase));
            AssertTelemetryHeaders(factory, true, labResponse);
        }
        public async Task AcquireTokenToRegionalEndpointAsync()
        {
            // Arrange
            var factory = new HttpSnifferClientFactory();

            _confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(PublicCloudConfidentialClientID)
                                             .WithClientAssertion(GetSignedClientAssertionUsingMsalInternal(PublicCloudConfidentialClientID, GetClaims()))
                                             //.WithClientSecret(_keyVault.GetSecret(TestConstants.MsalCCAKeyVaultUri).Value) //use the client secret in case of cert errors
                                             .WithAuthority(PublicCloudTestAuthority)
                                             .WithTestLogging()
                                             .WithExperimentalFeatures(true)
                                             .WithHttpClientFactory(factory)
                                             .Build();

            try
            {
                Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
                AuthenticationResult result = await CreateAuthenticationResultAsync().ConfigureAwait(false); // regional endpoint

                AssertTokenSource_IsIdP(result);
                AssertValidHost(true, factory);
            }
            finally
            {
                Environment.SetEnvironmentVariable(TestConstants.RegionName, null);
            }
        }
        public async Task AcquireTokenUserProvidedRegionDifferentFromRegionDetectedAsync()
        {
            // Arrange
            var factory = new HttpSnifferClientFactory();

            _confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(PublicCloudConfidentialClientID)
                                             .WithClientAssertion(GetSignedClientAssertionUsingMsalInternal(PublicCloudConfidentialClientID, GetClaims()))
                                             //.WithClientSecret(_keyVault.GetSecret(TestConstants.MsalCCAKeyVaultUri).Value) //use the client secret in case of cert errors
                                             .WithAuthority(PublicCloudTestAuthority)
                                             .WithTestLogging()
                                             .WithExperimentalFeatures(true)
                                             .WithHttpClientFactory(factory)
                                             .Build();

            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
            AuthenticationResult result = await GetAuthenticationResultAsync(userProvidedRegion : "invalid").ConfigureAwait(false); // regional endpoint

            AssertTokenSource_IsIdP(result);
            AssertValidHost(true, factory);
            AssertTelemetry(factory, "2|1004,0|centralus,1,0,invalid,0");

            result = await GetAuthenticationResultAsync(userProvidedRegion : TestConstants.Region, withForceRefresh : true).ConfigureAwait(false); // regional endpoint

            AssertTokenSource_IsIdP(result);
            AssertValidHost(true, factory, 1);
            AssertTelemetry(factory, "2|1004,1|centralus,3,0,centralus,", 1);
        }
コード例 #9
0
        private void AssertCcsRoutingInformationIsNotSent(HttpSnifferClientFactory factory)
        {
            var(req, res) = factory.RequestsAndResponses.Single(x => x.Item1.RequestUri.AbsoluteUri.Contains("oauth2/v2.0/token") &&
                                                                x.Item2.StatusCode == HttpStatusCode.OK);

            Assert.IsTrue(!req.Headers.Any(h => h.Key == Constants.CcsRoutingHintHeader));
        }
        private async Task RunHappyPathTestAsync(LabResponse labResponse)
        {
            var factory          = new HttpSnifferClientFactory();
            var msalPublicClient = PublicClientApplicationBuilder
                                   .Create(labResponse.App.AppId)
                                   .WithTestLogging()
                                   .WithHttpClientFactory(factory)
                                   .WithAuthority(labResponse.Lab.Authority, "organizations")
                                   .Build();

            AuthenticationResult authResult = await msalPublicClient
                                              .AcquireTokenByUsernamePassword(s_scopes, labResponse.User.Upn, new NetworkCredential("", labResponse.User.GetOrFetchPassword()).SecurePassword)
                                              .WithCorrelationId(CorrelationId)
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(string.Equals(labResponse.User.Upn, authResult.Account.Username, StringComparison.InvariantCultureIgnoreCase));
            AssertTelemetryHeaders(factory, false, labResponse);
            // If test fails with "user needs to consent to the application, do an interactive request" error,
            // Do the following:
            // 1) Add in code to pull the user's password before creating the SecureString, and put a breakpoint there.
            // string password = ((LabUser)user).GetPassword();
            // 2) Using the MSAL Desktop app, make sure the ClientId matches the one used in integration testing.
            // 3) Do the interactive sign-in with the MSAL Desktop app with the username and password from step 1.
            // 4) After successful log-in, remove the password line you added in with step 1, and run the integration test again.
        }
コード例 #11
0
        private async Task RunB2CHappyPathTestAsync(LabResponse labResponse, string federationMetadata = "")
        {
            var factory = new HttpSnifferClientFactory();
            var user    = labResponse.User;

            SecureString securePassword = new NetworkCredential("", user.GetOrFetchPassword()).SecurePassword;

            var msalPublicClient = PublicClientApplicationBuilder
                                   .Create(labResponse.App.AppId)
                                   .WithB2CAuthority(B2CROPCAuthority)
                                   .WithTestLogging()
                                   .WithHttpClientFactory(factory)
                                   .Build();

            AuthenticationResult authResult = await msalPublicClient
                                              .AcquireTokenByUsernamePassword(s_b2cScopes, labResponse.User.Upn, new NetworkCredential("", labResponse.User.GetOrFetchPassword()).SecurePassword)
                                              .WithCorrelationId(CorrelationId)
                                              .WithFederationMetadata(federationMetadata)
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            AssertCcsRoutingInformationIsNotSent(factory);

            // If test fails with "user needs to consent to the application, do an interactive request" error,
            // Do the following:
            // 1) Add in code to pull the user's password before creating the SecureString, and put a breakpoint there.
            // string password = ((LabUser)user).GetPassword();
            // 2) Using the MSAL Desktop app, make sure the ClientId matches the one used in integration testing.
            // 3) Do the interactive sign-in with the MSAL Desktop app with the username and password from step 1.
            // 4) After successful log-in, remove the password line you added in with step 1, and run the integration test again.
        }
コード例 #12
0
        public async Task ValidateCcsHeadersForInteractiveAuthCodeFlowAsync()
        {
            HttpSnifferClientFactory factory = null;
            LabResponse labResponse          = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false);

            var pca = PublicClientApplicationBuilder
                      .Create(labResponse.App.AppId)
                      .WithDefaultRedirectUri()
                      .WithRedirectUri(SeleniumWebUI.FindFreeLocalhostRedirectUri())
                      .WithTestLogging(out factory)
                      .Build();

            AuthenticationResult authResult = await pca
                                              .AcquireTokenInteractive(s_scopes)
                                              .WithPrompt(Prompt.SelectAccount)
                                              .WithCustomWebUi(CreateSeleniumCustomWebUI(labResponse.User, Prompt.SelectAccount))
                                              .ExecuteAsync(new CancellationTokenSource(_interactiveAuthTimeout).Token)
                                              .ConfigureAwait(false);


            var CcsHeader    = TestCommon.GetCcsHeaderFromSnifferFactory(factory);
            var userObjectId = labResponse.User.ObjectId;
            var userTenantID = labResponse.User.TenantId;

            Assert.AreEqual($"X-AnchorMailbox:Oid:{userObjectId}@{userTenantID}", $"{CcsHeader.Key}:{CcsHeader.Value.FirstOrDefault()}");

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
        }
        private void AssertExtraHTTPHeadersAreSent(HttpSnifferClientFactory factory)
        {
            var(req, res) = factory.RequestsAndResponses.Single(x => x.Item1.RequestUri.AbsoluteUri.Contains("oauth2/v2.0/token") &&
                                                                x.Item2.StatusCode == HttpStatusCode.OK);

            var ExtraHttpHeader = req.Headers.Single(h => h.Key == TestConstants.ExtraHttpHeader.Keys.FirstOrDefault());

            Assert.AreEqual(TestConstants.ExtraHttpHeader.Keys.FirstOrDefault(), ExtraHttpHeader.Key);
            Assert.AreEqual(TestConstants.ExtraHttpHeader.Values.FirstOrDefault(), ExtraHttpHeader.Value.FirstOrDefault());
        }
コード例 #14
0
        private async Task KerberosRunHappyPathTestAsync(LabResponse labResponse)
        {
            // Test with Id token
            var factory             = new HttpSnifferClientFactory();
            var idTokenPublicClient = PublicClientApplicationBuilder
                                      .Create(labResponse.App.AppId)
                                      .WithTestLogging()
                                      .WithHttpClientFactory(factory)
                                      .WithAuthority(labResponse.Lab.Authority, "organizations")
                                      .WithClientId(TestConstants.KerberosTestApplicationId)
                                      .WithKerberosTicketClaim(TestConstants.KerberosServicePrincipalName, KerberosTicketContainer.IdToken)
                                      .Build();

            AuthenticationResult authResult = await GetAuthenticationResultWithAssertAsync(
                labResponse,
                factory,
                idTokenPublicClient,
                "",
                Guid.NewGuid()).ConfigureAwait(false);

            KerberosSupplementalTicket ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult(
                authResult,
                KerberosTicketContainer.IdToken,
                labResponse.User.Upn);

            Assert.IsNotNull(ticket);
            TestCommon.ValidateKerberosWindowsTicketCacheOperation(ticket);

            // Test with Access Token
            factory = new HttpSnifferClientFactory();
            var accessTokenPublicClient = PublicClientApplicationBuilder
                                          .Create(labResponse.App.AppId)
                                          .WithTestLogging()
                                          .WithHttpClientFactory(factory)
                                          .WithAuthority(labResponse.Lab.Authority, "organizations")
                                          .WithClientId(TestConstants.KerberosTestApplicationId)
                                          .WithKerberosTicketClaim(TestConstants.KerberosServicePrincipalName, KerberosTicketContainer.AccessToken)
                                          .Build();

            authResult = await GetAuthenticationResultWithAssertAsync(
                labResponse,
                factory,
                accessTokenPublicClient,
                "",
                Guid.NewGuid()).ConfigureAwait(false);

            ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult(
                authResult,
                KerberosTicketContainer.AccessToken,
                labResponse.User.Upn);
            Assert.IsNotNull(ticket);
            TestCommon.ValidateKerberosWindowsTicketCacheOperation(ticket);
        }
        public async Task AcquireTokenToRegionalEndpointAsync()
        {
            // Arrange
            var factory = new HttpSnifferClientFactory();

            _confidentialClientApplication = BuildCCA(factory);

            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
            AuthenticationResult result = await GetAuthenticationResultAsync().ConfigureAwait(false); // regional endpoint

            AssertTokenSourceIsIdp(result);
            AssertValidHost(true, factory);
            AssertTelemetry(factory, $"{TelemetryConstants.HttpTelemetrySchemaVersion}|1004,{CacheInfoTelemetry.NoCachedAT:D}|centralus,1,0,,,0,1");
        }
コード例 #16
0
        private void AssertExtraHTTPHeadersAreSent(HttpSnifferClientFactory factory)
        {
            //Validate CCS Routing header
            if (!factory.RequestsAndResponses.Any())
            {
                return;
            }

            var(req, res) = factory.RequestsAndResponses.Single(x => x.Item1.RequestUri.AbsoluteUri.Contains("oauth2/v2.0/token") &&
                                                                x.Item2.StatusCode == HttpStatusCode.OK);

            Assert.IsTrue(req.Headers.TryGetValues(Constants.CcsRoutingHintHeader, out var values));
            Assert.AreEqual("oid:597f86cd-13f3-44c0-bece-a1e77ba43228@f645ad92-e38d-4d1a-b510-d1b09a74a8ca", values.First());
        }
コード例 #17
0
        private void AssertCcsRoutingInformationIsSent(HttpSnifferClientFactory factory, LabResponse labResponse)
        {
            if (labResponse.User.FederationProvider != FederationProvider.None)
            {
                return;
            }

            var CcsHeader = TestCommon.GetCcsHeaderFromSnifferFactory(factory);

            if (!String.IsNullOrEmpty(CcsHeader.Value?.FirstOrDefault()))
            {
                ValidateCcsHeader(CcsHeader, labResponse);
            }
        }
        public async Task InvalidRegion_GoesToInvalidAuthority_Async()
        {
            // Arrange
            var factory  = new HttpSnifferClientFactory();
            var settings = ConfidentialAppSettings.GetSettings(Cloud.Public);

            _confidentialClientApplication = BuildCCA(settings, factory, true, "invalid");

            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);

            var ex = await Assert.ThrowsExceptionAsync <HttpRequestException>(
                async() => await GetAuthenticationResultAsync(settings.AppScopes).ConfigureAwait(false)).ConfigureAwait(false);

            Assert.IsTrue(ex is HttpRequestException);
        }
        private IConfidentialClientApplication BuildCCA(HttpSnifferClientFactory factory, string region = ConfidentialClientApplication.AttemptRegionDiscovery)
        {
            var builder = ConfidentialClientApplicationBuilder.Create(PublicCloudConfidentialClientID)
                          .WithClientAssertion(GetSignedClientAssertionUsingMsalInternal(PublicCloudConfidentialClientID, GetClaims()))
                          .WithAuthority(PublicCloudTestAuthority, false)
                          .WithTestLogging()
                          .WithExperimentalFeatures(true)
                          .WithHttpClientFactory(factory);

            if (region != null)
            {
                builder.WithAzureRegion(region);
            }

            return(builder.Build());
        }
 private void AssertValidHost(
     bool isRegionalHost,
     HttpSnifferClientFactory factory,
     int placement = 0)
 {
     if (isRegionalHost)
     {
         var(req, res) = factory.RequestsAndResponses.Skip(placement).Single(x => x.Item1.RequestUri.Host == RegionalHost && x.Item2.StatusCode == HttpStatusCode.OK);
         Assert.AreEqual(RegionalHost, req.RequestUri.Host);
     }
     else
     {
         var(req, res) = factory.RequestsAndResponses.Skip(placement).Single(x => x.Item1.RequestUri.Host == GlobalHost && x.Item2.StatusCode == HttpStatusCode.OK);
         Assert.AreEqual(GlobalHost, req.RequestUri.Host);
     }
 }
        public async Task AcquireTokenToRegionalEndpointAsync()
        {
            // Arrange
            var factory  = new HttpSnifferClientFactory();
            var settings = ConfidentialAppSettings.GetSettings(Cloud.Public);

            _confidentialClientApplication = BuildCCA(settings, factory);

            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
            AuthenticationResult result = await GetAuthenticationResultAsync(settings.AppScopes).ConfigureAwait(false); // regional endpoint

            AssertTokenSourceIsIdp(result);
            AssertValidHost(true, factory);
            AssertTelemetry(factory, $"{TelemetryConstants.HttpTelemetrySchemaVersion}|1004,{CacheRefreshReason.NoCachedAccessToken:D},centralus,3,4|0,1");
            Assert.AreEqual(
                $"https://centralus.r.login.microsoftonline.com/{settings.TenantId}/oauth2/v2.0/token",
                result.AuthenticationResultMetadata.TokenEndpoint);
        }
        private void AssertTelemetryHeaders(HttpSnifferClientFactory factory, bool IsFailure, LabResponse labResponse)
        {
            var(req, res) = factory.RequestsAndResponses.Single(x => x.Item1.RequestUri.AbsoluteUri == labResponse.Lab.Authority + "organizations/oauth2/v2.0/token" &&
                                                                x.Item2.StatusCode == HttpStatusCode.OK);

            var telemetryLastValue    = req.Headers.Single(h => h.Key == TelemetryConstants.XClientLastTelemetry).Value;
            var telemetryCurrentValue = req.Headers.Single(h => h.Key == TelemetryConstants.XClientCurrentTelemetry).Value;
            HttpTelemetryRecorder httpTelemetryRecorder = new HttpTelemetryRecorder();

            string csvCurrent  = telemetryCurrentValue.FirstOrDefault();
            string csvPrevious = telemetryLastValue.FirstOrDefault();

            if (!IsFailure)
            {
                Assert.AreEqual(XClientCurrentTelemetryROPC, csvCurrent);
                Assert.AreEqual(XClientLastTelemetryROPC, csvPrevious);

                httpTelemetryRecorder.SplitCurrentCsv(csvCurrent);
                httpTelemetryRecorder.CheckSchemaVersion(csvCurrent);

                Assert.AreEqual(UPApiId, httpTelemetryRecorder.ApiId.FirstOrDefault(e => e.Contains(UPApiId)));
                Assert.AreEqual(TelemetryConstants.Zero, httpTelemetryRecorder.ForceRefresh);
                Assert.AreEqual(XClientLastTelemetryROPC, csvPrevious);
            }
            else
            {
                Assert.AreEqual(XClientCurrentTelemetryROPCFailure, csvCurrent);
                Assert.AreEqual(XClientLastTelemetryROPCFailure, csvPrevious);
                httpTelemetryRecorder.CheckSchemaVersion(csvCurrent);
                httpTelemetryRecorder.CheckSchemaVersion(csvPrevious);
                httpTelemetryRecorder.SplitCurrentCsv(csvCurrent);
                httpTelemetryRecorder.SplitPreviousCsv(csvPrevious);

                Assert.AreEqual(UPApiId, httpTelemetryRecorder.ApiId.FirstOrDefault(e => e.Contains(UPApiId)));
                Assert.AreEqual(1, httpTelemetryRecorder.ErrorCode.Count());
                Assert.AreEqual(TelemetryConstants.Zero, httpTelemetryRecorder.SilentCallSuccessfulCount);
                Assert.AreEqual(TelemetryConstants.Zero, httpTelemetryRecorder.ForceRefresh);
                Assert.AreEqual(ApiIdAndCorrelationIdSection, httpTelemetryRecorder.ApiIdAndCorrelationIds.FirstOrDefault());
                Assert.AreEqual(InvalidGrantError, httpTelemetryRecorder.ErrorCode.FirstOrDefault());
            }
        }
コード例 #23
0
        private async Task RunHappyPathTestAsync(LabResponse labResponse, string federationMetadata = "")
        {
            var factory          = new HttpSnifferClientFactory();
            var msalPublicClient = PublicClientApplicationBuilder
                                   .Create(labResponse.App.AppId)
                                   .WithTestLogging()
                                   .WithHttpClientFactory(factory)
                                   .WithAuthority(labResponse.Lab.Authority, "organizations")
                                   .Build();

            AuthenticationResult authResult
                = await GetAuthenticationResultWithAssertAsync(
                      labResponse,
                      factory,
                      msalPublicClient,
                      federationMetadata,
                      CorrelationId).ConfigureAwait(false);

            if (AuthorityInfo.FromAuthorityUri(labResponse.Lab.Authority + "/" + labResponse.Lab.TenantId, false).AuthorityType == AuthorityType.Aad)
            {
                AssertTenantProfiles(authResult.Account.GetTenantProfiles(), authResult.TenantId);
            }
            else
            {
                Assert.IsNull(authResult.Account.GetTenantProfiles());
            }

            TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(authResult);
            // If test fails with "user needs to consent to the application, do an interactive request" error,
            // Do the following:
            // 1) Add in code to pull the user's password before creating the SecureString, and put a breakpoint there.
            // string password = ((LabUser)user).GetPassword();
            // 2) Using the MSAL Desktop app, make sure the ClientId matches the one used in integration testing.
            // 3) Do the interactive sign-in with the MSAL Desktop app with the username and password from step 1.
            // 4) After successful log-in, remove the password line you added in with step 1, and run the integration test again.
        }
コード例 #24
0
        private async Task <AuthenticationResult> GetAuthenticationResultWithAssertAsync(
            LabResponse labResponse,
            HttpSnifferClientFactory factory,
            IPublicClientApplication msalPublicClient,
            string federationMetadata,
            Guid testCorrelationId)
        {
            AuthenticationResult authResult = await msalPublicClient
                                              .AcquireTokenByUsernamePassword(s_scopes, labResponse.User.Upn, new NetworkCredential("", labResponse.User.GetOrFetchPassword()).SecurePassword)
                                              .WithCorrelationId(testCorrelationId)
                                              .WithFederationMetadata(federationMetadata)
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(string.Equals(labResponse.User.Upn, authResult.Account.Username, StringComparison.InvariantCultureIgnoreCase));
            AssertTelemetryHeaders(factory, false, labResponse);
            AssertCcsRoutingInformationIsSent(factory, labResponse);

            return(authResult);
        }
        private void AssertCcsRoutingInformationIsSent(HttpSnifferClientFactory factory, LabResponse labResponse)
        {
            var CcsHeader = TestCommon.GetCcsHeaderFromSnifferFactory(factory);

            Assert.AreEqual($"X-AnchorMailbox:UPN:{labResponse.User.Upn}", $"{CcsHeader.Key}:{CcsHeader.Value.FirstOrDefault()}");
        }
コード例 #26
0
        //Since this test performs a large number of operations it should not be rerun on other clouds.
        private async Task RunOnBehalfOfTestWithTokenCacheAsync(LabResponse labResponse)
        {
            LabUser user = labResponse.User;
            string  oboHost;
            string  secret;
            string  authority;
            string  publicClientID;
            string  confidentialClientID;

            string[] oboScope;

            oboHost              = PublicCloudHost;
            secret               = _keyVault.GetSecret(TestConstants.MsalOBOKeyVaultUri).Value;
            authority            = TestConstants.AuthorityOrganizationsTenant;
            publicClientID       = PublicCloudPublicClientIDOBO;
            confidentialClientID = PublicCloudConfidentialClientIDOBO;
            oboScope             = s_publicCloudOBOServiceScope;

            //TODO: acquire scenario specific client ids from the lab response

            SecureString securePassword = new NetworkCredential("", user.GetOrFetchPassword()).SecurePassword;
            var          factory        = new HttpSnifferClientFactory();

            var msalPublicClient = PublicClientApplicationBuilder.Create(publicClientID)
                                   .WithAuthority(authority)
                                   .WithRedirectUri(TestConstants.RedirectUri)
                                   .WithTestLogging()
                                   .WithHttpClientFactory(factory)
                                   .Build();

            var authResult = await msalPublicClient.AcquireTokenByUsernamePassword(oboScope, user.Upn, securePassword)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

            var confidentialApp = ConfidentialClientApplicationBuilder
                                  .Create(confidentialClientID)
                                  .WithAuthority(new Uri(oboHost + authResult.TenantId), true)
                                  .WithClientSecret(secret)
                                  .WithTestLogging()
                                  .BuildConcrete();

            var userCacheRecorder = confidentialApp.UserTokenCache.RecordAccess();

            UserAssertion userAssertion = new UserAssertion(authResult.AccessToken);

            string atHash = userAssertion.AssertionHash;

            authResult = await confidentialApp.AcquireTokenOnBehalfOf(s_scopes, userAssertion)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            MsalAssert.AssertAuthResult(authResult, user);
            Assert.AreEqual(atHash, userCacheRecorder.LastAfterAccessNotificationArgs.SuggestedCacheKey);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);

            //Run OBO again. Should get token from cache
            authResult = await confidentialApp.AcquireTokenOnBehalfOf(s_scopes, userAssertion)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(!userCacheRecorder.LastAfterAccessNotificationArgs.IsApplicationCache);
            Assert.IsTrue(userCacheRecorder.LastAfterAccessNotificationArgs.HasTokens);
            Assert.AreEqual(atHash, userCacheRecorder.LastAfterAccessNotificationArgs.SuggestedCacheKey);
            Assert.AreEqual(TokenSource.Cache, authResult.AuthenticationResultMetadata.TokenSource);

            //Expire access tokens
            TokenCacheHelper.ExpireAllAccessTokens(confidentialApp.UserTokenCacheInternal);

            //Run OBO again. Should do OBO flow since the AT is expired and RTs aren't cached for normal OBO flow
            authResult = await confidentialApp.AcquireTokenOnBehalfOf(s_scopes, userAssertion)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(!userCacheRecorder.LastAfterAccessNotificationArgs.IsApplicationCache);
            Assert.IsTrue(userCacheRecorder.LastAfterAccessNotificationArgs.HasTokens);
            Assert.AreEqual(atHash, userCacheRecorder.LastAfterAccessNotificationArgs.SuggestedCacheKey);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            AssertLastHttpContent("on_behalf_of");

            //creating second app with no refresh tokens
            var atItems          = confidentialApp.UserTokenCacheInternal.Accessor.GetAllAccessTokens();
            var confidentialApp2 = ConfidentialClientApplicationBuilder
                                   .Create(confidentialClientID)
                                   .WithAuthority(new Uri(oboHost + authResult.TenantId), true)
                                   .WithClientSecret(secret)
                                   .WithTestLogging()
                                   .WithHttpClientFactory(factory)
                                   .BuildConcrete();

            TokenCacheHelper.ExpireAccessToken(confidentialApp2.UserTokenCacheInternal, atItems.FirstOrDefault());

            //Should perform OBO flow since the access token is expired and the refresh token does not exist
            authResult = await confidentialApp2.AcquireTokenOnBehalfOf(s_scopes, userAssertion)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(!userCacheRecorder.LastAfterAccessNotificationArgs.IsApplicationCache);
            Assert.IsTrue(userCacheRecorder.LastAfterAccessNotificationArgs.HasTokens);
            Assert.AreEqual(atHash, userCacheRecorder.LastAfterAccessNotificationArgs.SuggestedCacheKey);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            AssertLastHttpContent("on_behalf_of");

            TokenCacheHelper.ExpireAllAccessTokens(confidentialApp2.UserTokenCacheInternal);
            TokenCacheHelper.UpdateUserAssertions(confidentialApp2);

            //Should perform OBO flow since the access token and the refresh token contains the wrong user assertion hash
            authResult = await confidentialApp2.AcquireTokenOnBehalfOf(s_scopes, userAssertion)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNotNull(authResult.IdToken);
            Assert.IsTrue(!userCacheRecorder.LastAfterAccessNotificationArgs.IsApplicationCache);
            Assert.IsTrue(userCacheRecorder.LastAfterAccessNotificationArgs.HasTokens);
            Assert.AreEqual(atHash, userCacheRecorder.LastAfterAccessNotificationArgs.SuggestedCacheKey);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            AssertLastHttpContent("on_behalf_of");
        }
コード例 #27
0
        private async Task <AuthenticationResult> RunTestForUserAsync(LabResponse labResponse, bool directToAdfs = false)
        {
            HttpSnifferClientFactory factory = null;
            IPublicClientApplication pca;

            if (directToAdfs)
            {
                pca = PublicClientApplicationBuilder
                      .Create(Adfs2019LabConstants.PublicClientId)
                      .WithRedirectUri(Adfs2019LabConstants.ClientRedirectUri)
                      .WithAdfsAuthority(Adfs2019LabConstants.Authority)
                      .WithTestLogging()
                      .Build();
            }
            else
            {
                pca = PublicClientApplicationBuilder
                      .Create(labResponse.App.AppId)
                      .WithRedirectUri(SeleniumWebUI.FindFreeLocalhostRedirectUri())
                      .WithAuthority(labResponse.Lab.Authority + "common")
                      .WithTestLogging(out factory)
                      .Build();
            }

            var userCacheAccess = pca.UserTokenCache.RecordAccess();

            Trace.WriteLine("Part 1 - Acquire a token interactively, no login hint");
            AuthenticationResult result = await pca
                                          .AcquireTokenInteractive(s_scopes)
                                          .WithCustomWebUi(CreateSeleniumCustomWebUI(labResponse.User, Prompt.SelectAccount, false, directToAdfs))
                                          .ExecuteAsync(new CancellationTokenSource(_interactiveAuthTimeout).Token)
                                          .ConfigureAwait(false);

            Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0);
            Assert.IsTrue(result.AuthenticationResultMetadata.DurationInHttpInMs > 0);

            userCacheAccess.AssertAccessCounts(0, 1);
            IAccount account = await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false);

            userCacheAccess.AssertAccessCounts(1, 1); // the assert calls GetAccounts
            Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache);

            Trace.WriteLine("Part 2 - Clear the cache");
            await pca.RemoveAsync(account).ConfigureAwait(false);

            userCacheAccess.AssertAccessCounts(1, 2);
            Assert.IsFalse((await pca.GetAccountsAsync().ConfigureAwait(false)).Any());
            userCacheAccess.AssertAccessCounts(2, 2);
            Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache);

            if (factory?.RequestsAndResponses != null)
            {
                factory.RequestsAndResponses.Clear();
            }

            Trace.WriteLine("Part 3 - Acquire a token interactively again, with login hint");
            result = await pca
                     .AcquireTokenInteractive(s_scopes)
                     .WithCustomWebUi(CreateSeleniumCustomWebUI(labResponse.User, Prompt.ForceLogin, true, directToAdfs))
                     .WithPrompt(Prompt.ForceLogin)
                     .WithLoginHint(labResponse.User.Upn)
                     .ExecuteAsync(new CancellationTokenSource(_interactiveAuthTimeout).Token)
                     .ConfigureAwait(false);

            userCacheAccess.AssertAccessCounts(2, 3);
            AssertCcsRoutingInformationIsSent(factory, labResponse);

            account = await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false);

            userCacheAccess.AssertAccessCounts(3, 3);
            Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache);

            if (factory?.RequestsAndResponses != null)
            {
                factory.RequestsAndResponses.Clear();
            }

            Trace.WriteLine("Part 4 - Acquire a token silently");
            result = await pca
                     .AcquireTokenSilent(s_scopes, account)
                     .ExecuteAsync(CancellationToken.None)
                     .ConfigureAwait(false);

            Trace.WriteLine("Part 5 - Acquire a token silently with force refresh");
            result = await pca
                     .AcquireTokenSilent(s_scopes, account)
                     .WithForceRefresh(true)
                     .ExecuteAsync(CancellationToken.None)
                     .ConfigureAwait(false);

            await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false);

            Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache);
            AssertCcsRoutingInformationIsSent(factory, labResponse);

            return(result);
        }
 private void AssertTelemetry(HttpSnifferClientFactory factory, string currentTelemetryHeader, int placement = 0)
 {
     var(req, res) = factory.RequestsAndResponses.Skip(placement).Single();
     Assert.AreEqual(currentTelemetryHeader, req.Headers.GetValues("x-client-current-telemetry").First());
 }