Beispiel #1
0
        private void AssertAccountCacheItemsAreEqual(MsalAccountCacheItem expected, MsalAccountCacheItem actual)
        {
            AssertCacheItemBaseItemsAreEqual(expected, actual);

            Assert.AreEqual(expected.PreferredUsername, actual.PreferredUsername, nameof(actual.PreferredUsername));
            Assert.AreEqual(expected.Name, actual.Name, nameof(actual.Name));
            Assert.AreEqual(expected.GivenName, actual.GivenName, nameof(actual.GivenName));
            Assert.AreEqual(expected.FamilyName, actual.FamilyName, nameof(actual.FamilyName));
            Assert.AreEqual(expected.LocalAccountId, actual.LocalAccountId, nameof(actual.LocalAccountId));
            Assert.AreEqual(expected.AuthorityType, actual.AuthorityType, nameof(actual.AuthorityType));
            Assert.AreEqual(expected.TenantId, actual.TenantId, nameof(actual.TenantId));
            CoreAssert.AssertDictionariesAreEqual(expected.WamAccountIds, actual.WamAccountIds, StringComparer.Ordinal);
        }
Beispiel #2
0
        private static void AssertTsAndJwkClaims(IPoPCryptoProvider popCryptoProvider, System.Security.Claims.ClaimsPrincipal claims)
        {
            long ts = long.Parse(claims.FindAll("ts").Single().Value);

            CoreAssert.IsWithinRange(DateTimeOffset.UtcNow, DateTimeHelpers.UnixTimestampToDateTime(ts), TimeSpan.FromSeconds(5));

            string  jwkClaim    = claims.FindAll("cnf").Single().Value;
            JToken  publicKey   = JToken.Parse(popCryptoProvider.CannonicalPublicKeyJwk);
            JObject jwkInConfig = new JObject(new JProperty(PoPClaimTypes.JWK, publicKey));
            var     jwkInToken  = JObject.Parse(jwkClaim);

            Assert.IsTrue(JObject.DeepEquals(jwkInConfig, jwkInToken));
        }
        public void IdTokenParsing_AADToken()
        {
            /*
             *  "aud": "b6c69a37-df96-4db0-9088-2ab96e1d8215",
             *  "iss": "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0",
             *  "iat": 1538538422,
             *  "nbf": 1538538422,
             *  "exp": 1538542322,
             *  "name": "Cloud IDLAB Basic User",
             *  "oid": "9f4880d8-80ba-4c40-97bc-f7a23c703084",
             *  "preferred_username": "******",
             *  "sub": "Y6YkBdHNNLHNmTKel9KhRz8wrasxdLRFiP14BRPWrn4",
             *  "tid": "f645ad92-e38d-4d1a-b510-d1b09a74a8ca",
             *  "uti": "6nciX02SMki9k73-F1sZAA",
             *  "ver": "2.0"
             */
            var addIdToken  = TestConstants.CreateAadTestTokenResponse().IdToken;
            var parsedToken = IdToken.Parse(addIdToken);

            CoreAssert.AreEqual("Cloud IDLAB Basic User", parsedToken.Name, parsedToken.ClaimsPrincipal.FindFirst("name").Value);
            CoreAssert.AreEqual("9f4880d8-80ba-4c40-97bc-f7a23c703084", parsedToken.ObjectId, parsedToken.ClaimsPrincipal.FindFirst("oid").Value);
            CoreAssert.AreEqual("*****@*****.**", parsedToken.PreferredUsername, parsedToken.ClaimsPrincipal.FindFirst("preferred_username").Value);
            CoreAssert.AreEqual("Y6YkBdHNNLHNmTKel9KhRz8wrasxdLRFiP14BRPWrn4", parsedToken.Subject, parsedToken.ClaimsPrincipal.FindFirst("sub").Value);
            CoreAssert.AreEqual("f645ad92-e38d-4d1a-b510-d1b09a74a8ca", parsedToken.TenantId, parsedToken.ClaimsPrincipal.FindFirst("tid").Value);

            Assert.AreEqual("b6c69a37-df96-4db0-9088-2ab96e1d8215", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "aud").Value);
            Assert.AreEqual("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "iss").Value);
            Assert.AreEqual("1538538422", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "iat").Value);
            Assert.AreEqual("1538538422", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "nbf").Value);
            Assert.AreEqual("1538542322", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "exp").Value);
            Assert.AreEqual("Cloud IDLAB Basic User", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "name").Value);
            Assert.AreEqual("9f4880d8-80ba-4c40-97bc-f7a23c703084", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "oid").Value);
            Assert.AreEqual("*****@*****.**", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "preferred_username").Value);
            Assert.AreEqual("Y6YkBdHNNLHNmTKel9KhRz8wrasxdLRFiP14BRPWrn4", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "sub").Value);
            Assert.AreEqual("f645ad92-e38d-4d1a-b510-d1b09a74a8ca", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "tid").Value);
            Assert.AreEqual("6nciX02SMki9k73-F1sZAA", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "uti").Value);
            Assert.AreEqual("2.0", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "ver").Value);

            Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.Where(c => (new[] { "nbf", "iat", "exp" }).Contains(c.Type) == true).All(c => c.ValueType == ClaimValueTypes.Integer.ToString()));
            Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.Where(c => (new[] { "nbf", "iat", "exp" }).Contains(c.Type) == false).All(c => c.ValueType == ClaimValueTypes.String.ToString()));

            Assert.IsNull(parsedToken.Upn);
            Assert.IsNull(parsedToken.FamilyName);
            Assert.IsNull(parsedToken.GivenName);

            Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.All(c => c.Issuer == "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0"));
            Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.All(c => c.OriginalIssuer == "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0"));
        }
        public void ValidateCommonParameters(
            ApiEvent.ApiIds expectedApiId,
            string expectedAuthorityOverride = null,
            Dictionary <string, string> expectedExtraQueryParameters = null,
            IEnumerable <string> expectedScopes = null)
        {
            Assert.IsNotNull(CommonParametersReceived);

            Assert.AreEqual(expectedApiId, CommonParametersReceived.ApiId);
            Assert.AreEqual(expectedAuthorityOverride, CommonParametersReceived.AuthorityOverride);

            CoreAssert.AreScopesEqual(
                (expectedScopes ?? MsalTestConstants.Scope).AsSingleString(),
                CommonParametersReceived.Scopes.AsSingleString());

            CollectionAssert.AreEqual(
                expectedExtraQueryParameters,
                CommonParametersReceived.ExtraQueryParameters?.ToList());
        }
Beispiel #5
0
        public void AccessToken_WithKidAndType_FromMsalResponseJson()
        {
            // Arrange
            string json = TestConstants.TokenResponseJson;

            json = JsonTestUtils.AddKeyValue(json, StorageJsonKeys.TokenType, "pop");

            var tokenResponse = JsonHelper.DeserializeFromJson <MsalTokenResponse>(json);

            // Act
            MsalAccessTokenCacheItem at = new MsalAccessTokenCacheItem(TestConstants.ProductionPrefNetworkEnvironment,
                                                                       TestConstants.ClientId,
                                                                       tokenResponse,
                                                                       TestConstants.TenantId,
                                                                       keyId: "kid1");

            // Assert
            Assert.AreEqual("kid1", at.KeyId);
            CoreAssert.AreEqual(tokenResponse.TokenType, at.TokenType, "pop");
        }
Beispiel #6
0
        public void ValidateInteractiveParameters(
            IAccount expectedAccount = null,
            IEnumerable <string> expectedExtraScopesToConsent = null,
            string expectedLoginHint         = null,
            string expectedPromptValue       = null,
            bool expectedEmbeddedWebView     = false,
            ICustomWebUi expectedCustomWebUi = null)
        {
            Assert.IsNotNull(InteractiveParametersReceived);

            Assert.AreEqual(expectedAccount, InteractiveParametersReceived.Account);
            CoreAssert.AreScopesEqual(
                (expectedExtraScopesToConsent ?? new List <string>()).AsSingleString(),
                InteractiveParametersReceived.ExtraScopesToConsent.AsSingleString());
            Assert.AreEqual(expectedLoginHint, InteractiveParametersReceived.LoginHint);
            Assert.AreEqual(expectedPromptValue ?? Prompt.SelectAccount.PromptValue, InteractiveParametersReceived.Prompt.PromptValue);
            Assert.IsNotNull(InteractiveParametersReceived.UiParent);
            Assert.AreEqual(expectedEmbeddedWebView, InteractiveParametersReceived.UseEmbeddedWebView);
            Assert.AreEqual(expectedCustomWebUi, InteractiveParametersReceived.CustomWebUi);
        }
        private static void AssertPreviousTelemetry(
            HttpRequestMessage requestMessage,
            int expectedSilentCount,
            ApiIds[] expectedFailedApiIds  = null,
            Guid[] expectedCorrelationIds  = null,
            string[] expectedErrors        = null,
            string[] expectedRegions       = null,
            string[] expectedRegionSources = null)
        {
            expectedFailedApiIds   = expectedFailedApiIds ?? new ApiIds[0];
            expectedCorrelationIds = expectedCorrelationIds ?? new Guid[0];
            expectedErrors         = expectedErrors ?? new string[0];
            expectedRegions        = expectedRegions ?? new string[0];
            expectedRegionSources  = expectedRegionSources ?? new string[0];

            var actualHeader = ParseLastRequestHeader(requestMessage);

            Assert.AreEqual(expectedSilentCount, actualHeader.SilentCount);
            CoreAssert.AreEqual(actualHeader.FailedApis.Length, actualHeader.CorrelationIds.Length, actualHeader.Errors.Length);

            CollectionAssert.AreEqual(
                expectedFailedApiIds.Select(apiId => ((int)apiId).ToString(CultureInfo.InvariantCulture)).ToArray(),
                actualHeader.FailedApis);

            CollectionAssert.AreEqual(
                expectedCorrelationIds.Select(g => g.ToString()).ToArray(),
                actualHeader.CorrelationIds);

            CollectionAssert.AreEqual(
                expectedErrors,
                actualHeader.Errors);

            CollectionAssert.AreEqual(
                expectedRegions,
                actualHeader.Regions);

            CollectionAssert.AreEqual(
                expectedRegionSources,
                actualHeader.RegionSources);
        }
        public async Task KnownInstanceMetadataIsUpToDateAsync()
        {
            const string        validDiscoveryUri    = @"https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fv2.0%2Fauthorize";
            const string        validPpeDiscoveryUri = @"https://login.windows-ppe.net/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fv2.0%2Fauthorize";
            HttpClient          httpClient           = new HttpClient();
            HttpResponseMessage discoveryResponse    = await httpClient.SendAsync(
                new HttpRequestMessage(
                    HttpMethod.Get,
                    validDiscoveryUri)).ConfigureAwait(false);

            string discoveryJson = await discoveryResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

            HttpResponseMessage ppeDiscoveryResponse = await httpClient.SendAsync(
                new HttpRequestMessage(
                    HttpMethod.Get,
                    validPpeDiscoveryUri)).ConfigureAwait(false);

            string ppeDiscoveryJson = await ppeDiscoveryResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

            InstanceDiscoveryMetadataEntry[] actualMetadata    = JsonHelper.DeserializeFromJson <InstanceDiscoveryResponse>(discoveryJson).Metadata;
            InstanceDiscoveryMetadataEntry[] actualPpeMetadata = JsonHelper.DeserializeFromJson <InstanceDiscoveryResponse>(ppeDiscoveryJson).Metadata;

            var processedMetadata = new Dictionary <string, InstanceDiscoveryMetadataEntry>();

            foreach (InstanceDiscoveryMetadataEntry entry in actualMetadata.Concat(actualPpeMetadata))
            {
                foreach (var alias in entry.Aliases)
                {
                    processedMetadata[alias] = entry;
                }
            }

            IDictionary <string, InstanceDiscoveryMetadataEntry> expectedMetadata =
                KnownMetadataProvider.GetAllEntriesForTest();

            CoreAssert.AssertDictionariesAreEqual(
                expectedMetadata,
                processedMetadata,
                new InstanceDiscoveryMetadataEntryComparer());
        }
Beispiel #9
0
        public void ValidateInteractiveParameters(
            WebViewPreference expectedEmbeddedWebView,
            IAccount expectedAccount = null,
            IEnumerable <string> expectedExtraScopesToConsent = null,
            string expectedLoginHint            = null,
            string expectedPromptValue          = null,
            ICustomWebUi expectedCustomWebUi    = null,
            SystemWebViewOptions browserOptions = null)
        {
            Assert.IsNotNull(InteractiveParametersReceived);

            Assert.AreEqual(expectedAccount, InteractiveParametersReceived.Account);
            CoreAssert.AreScopesEqual(
                (expectedExtraScopesToConsent ?? new List <string>()).AsSingleString(),
                InteractiveParametersReceived.ExtraScopesToConsent.AsSingleString());
            Assert.AreEqual(expectedLoginHint, InteractiveParametersReceived.LoginHint);
            Assert.AreEqual(expectedPromptValue ?? Prompt.NotSpecified.PromptValue, InteractiveParametersReceived.Prompt.PromptValue);
            Assert.IsNotNull(InteractiveParametersReceived.UiParent);
            Assert.AreEqual(expectedEmbeddedWebView, InteractiveParametersReceived.UseEmbeddedWebView);
            Assert.AreEqual(expectedCustomWebUi, InteractiveParametersReceived.CustomWebUi);
            Assert.AreEqual(browserOptions, InteractiveParametersReceived.UiParent.SystemWebViewOptions);
        }
        public void AccessToken_WithRefresh_FromMsalResponseJson()
        {
            // Arrange
            string json = TestConstants.TokenResponseJson;

            json = JsonTestUtils.AddKeyValue(json, "refresh_in", "1800");

            var tokenResponse = JsonHelper.DeserializeFromJson <MsalTokenResponse>(json);

            // Act
            MsalAccessTokenCacheItem at = new MsalAccessTokenCacheItem(TestConstants.ProductionPrefNetworkEnvironment,
                                                                       TestConstants.ClientId,
                                                                       tokenResponse,
                                                                       TestConstants.TenantId);

            // Assert
            Assert.AreEqual(tokenResponse.RefreshIn, 1800);
            Assert.IsTrue(at.RefreshOn.HasValue);
            CoreAssert.AreEqual(
                at.RefreshOn.Value,
                (at.CachedAtOffset + TimeSpan.FromSeconds(1800)),
                TimeSpan.FromSeconds(1));
        }
Beispiel #11
0
 public void ImmutableTest()
 {
     CoreAssert.IsImmutable <AadAuthority>();
     CoreAssert.IsImmutable <AdfsAuthority>();
     CoreAssert.IsImmutable <B2CAuthority>();
 }
        public async Task WAM_AccountIds_GetMerged_Async()
        {
            // Arrange
            using (var httpManager = new MockHttpManager())
            {
                var cache = new InMemoryTokenCache();
                httpManager.AddInstanceDiscoveryMockHandler();

                var mockBroker = Substitute.For <IBroker>();
                mockBroker.IsBrokerInstalledAndInvokable(AuthorityType.Aad).Returns(true);

                var msalTokenResponse1 = CreateMsalTokenResponseFromWam("wam1");
                var msalTokenResponse2 = CreateMsalTokenResponseFromWam("wam2");
                var msalTokenResponse3 = CreateMsalTokenResponseFromWam("wam3");

                // 2 apps must share the token cache, like FOCI apps, for this test to be interesting
                var pca1 = PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                           .WithExperimentalFeatures(true)
                           .WithTestBroker(mockBroker)
                           .WithHttpManager(httpManager)
                           .BuildConcrete();

                var pca2 = PublicClientApplicationBuilder.Create(TestConstants.ClientId2)
                           .WithExperimentalFeatures(true)
                           .WithTestBroker(mockBroker)
                           .WithHttpManager(httpManager)
                           .BuildConcrete();

                cache.Bind(pca1.UserTokenCache);
                cache.Bind(pca2.UserTokenCache);

                pca1.ServiceBundle.Config.BrokerCreatorFunc = (app, config, logger) => mockBroker;
                pca2.ServiceBundle.Config.BrokerCreatorFunc = (app, config, logger) => mockBroker;

                // Act
                mockBroker.AcquireTokenInteractiveAsync(null, null).ReturnsForAnyArgs(Task.FromResult(msalTokenResponse1));
                await pca1.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                // this should override wam1 id
                mockBroker.AcquireTokenInteractiveAsync(null, null).ReturnsForAnyArgs(Task.FromResult(msalTokenResponse2));
                await pca1.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                mockBroker.AcquireTokenInteractiveAsync(null, null).ReturnsForAnyArgs(Task.FromResult(msalTokenResponse3));
                await pca2.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                var accounts1 = await pca1.GetAccountsAsync().ConfigureAwait(false);

                var accounts2 = await pca2.GetAccountsAsync().ConfigureAwait(false);

                // Assert
#if SUPPORTS_BROKER
                var wamAccountIds = (accounts1.Single() as Account).WamAccountIds;
                Assert.AreEqual(2, wamAccountIds.Count);
                Assert.AreEqual("wam2", wamAccountIds[TestConstants.ClientId]);
                Assert.AreEqual("wam3", wamAccountIds[TestConstants.ClientId2]);
                CoreAssert.AssertDictionariesAreEqual(wamAccountIds, (accounts2.Single() as Account).WamAccountIds, StringComparer.Ordinal);
#else
                Assert.IsTrue(accounts1.All(a => (a as IAccountInternal).WamAccountIds == null));
                Assert.IsTrue(accounts2.All(a => (a as IAccountInternal).WamAccountIds == null));
#endif
            }
        }
Beispiel #13
0
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            ActualRequestMessage = request;

            if (ExceptionToThrow != null)
            {
                throw ExceptionToThrow;
            }

            var uri = request.RequestUri;

            if (!string.IsNullOrEmpty(ExpectedUrl))
            {
                Assert.AreEqual(
                    ExpectedUrl,
                    uri.AbsoluteUri.Split(
                        new[]
                {
                    '?'
                })[0]);
            }

            Assert.AreEqual(ExpectedMethod, request.Method);

            // Match QP passed in for validation.
            if (ExpectedQueryParams != null)
            {
                Assert.IsFalse(
                    string.IsNullOrEmpty(uri.Query),
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "provided url ({0}) does not contain query parameters, as expected",
                        uri.AbsolutePath));
                IDictionary <string, string> inputQp = CoreHelpers.ParseKeyValueList(uri.Query.Substring(1), '&', false, null);
                Assert.AreEqual(ExpectedQueryParams.Count, inputQp.Count, "Different number of query params`");
                foreach (string key in ExpectedQueryParams.Keys)
                {
                    Assert.IsTrue(
                        inputQp.ContainsKey(key),
                        string.Format(
                            CultureInfo.InvariantCulture,
                            "expected QP ({0}) not found in the url ({1})",
                            key,
                            uri.AbsolutePath));
                    Assert.AreEqual(ExpectedQueryParams[key], inputQp[key]);
                }
            }

            if (ExpectedPostData != null)
            {
                string postData = request.Content.ReadAsStringAsync().Result;
                Dictionary <string, string> requestPostDataPairs = CoreHelpers.ParseKeyValueList(postData, '&', true, null);

                foreach (string key in ExpectedPostData.Keys)
                {
                    Assert.IsTrue(requestPostDataPairs.ContainsKey(key));
                    if (key.Equals(OAuth2Parameter.Scope, StringComparison.OrdinalIgnoreCase))
                    {
                        CoreAssert.AreScopesEqual(ExpectedPostData[key], requestPostDataPairs[key]);
                    }
                    else
                    {
                        Assert.AreEqual(ExpectedPostData[key], requestPostDataPairs[key]);
                    }
                }
            }

            if (HttpTelemetryHeaders != null)
            {
                if (ActualRequestMessage.Headers.Contains(TelemetryConstants.XClientLastTelemetry))
                {
                    Assert.AreEqual(HttpTelemetryHeaders[TelemetryConstants.XClientLastTelemetry], ReturnValueFromRequestHeader(TelemetryConstants.XClientLastTelemetry));
                    Assert.AreEqual(HttpTelemetryHeaders[TelemetryConstants.XClientCurrentTelemetry], ReturnValueFromRequestHeader(TelemetryConstants.XClientCurrentTelemetry));
                }
            }

            AdditionalRequestValidation?.Invoke(request);

            return(new TaskFactory().StartNew(() => ResponseMessage, cancellationToken));
        }
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            ActualRequestMessage = request;

            if (ExceptionToThrow != null)
            {
                throw ExceptionToThrow;
            }

            var uri = request.RequestUri;

            if (!string.IsNullOrEmpty(ExpectedUrl))
            {
                Assert.AreEqual(
                    ExpectedUrl,
                    uri.AbsoluteUri.Split(
                        new[]
                {
                    '?'
                })[0]);
            }

            Assert.AreEqual(ExpectedMethod, request.Method);

            // Match QP passed in for validation.
            if (ExpectedQueryParams != null)
            {
                Assert.IsFalse(
                    string.IsNullOrEmpty(uri.Query),
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "provided url ({0}) does not contain query parameters, as expected",
                        uri.AbsolutePath));
                IDictionary <string, string> inputQp = CoreHelpers.ParseKeyValueList(uri.Query.Substring(1), '&', false, null);
                Assert.AreEqual(ExpectedQueryParams.Count, inputQp.Count, "Different number of query params`");
                foreach (string key in ExpectedQueryParams.Keys)
                {
                    Assert.IsTrue(
                        inputQp.ContainsKey(key),
                        string.Format(
                            CultureInfo.InvariantCulture,
                            "expected QP ({0}) not found in the url ({1})",
                            key,
                            uri.AbsolutePath));
                    Assert.AreEqual(ExpectedQueryParams[key], inputQp[key]);
                }
            }

            if (request.Method != HttpMethod.Get && request.Content != null)
            {
                string postData = request.Content.ReadAsStringAsync().Result;
                ActualRequestPostData = CoreHelpers.ParseKeyValueList(postData, '&', true, null);
            }

            if (ExpectedPostData != null)
            {
                foreach (string key in ExpectedPostData.Keys)
                {
                    Assert.IsTrue(ActualRequestPostData.ContainsKey(key));
                    if (key.Equals(OAuth2Parameter.Scope, StringComparison.OrdinalIgnoreCase))
                    {
                        CoreAssert.AreScopesEqual(ExpectedPostData[key], ActualRequestPostData[key]);
                    }
                    else
                    {
                        Assert.AreEqual(ExpectedPostData[key], ActualRequestPostData[key]);
                    }
                }
            }

            if (ExpectedRequestHeaders != null)
            {
                foreach (var kvp in ExpectedRequestHeaders)
                {
                    Assert.IsTrue(
                        request.Headers.Any(h =>
                                            string.Equals(h.Key, kvp.Key, StringComparison.OrdinalIgnoreCase) &&
                                            string.Equals(h.Value.AsSingleString(), kvp.Value, StringComparison.OrdinalIgnoreCase))
                        , $"Expecting a request header {kvp.Key}: {kvp.Value} but did not find in the actual request: {request}");
                }
            }

            if (UnexpectedRequestHeaders != null)
            {
                foreach (var item in UnexpectedRequestHeaders)
                {
                    Assert.IsTrue(
                        !request.Headers.Any(h => string.Equals(h.Key, item, StringComparison.OrdinalIgnoreCase))
                        , $"Not expecting a request header with key={item} but it was found in the actual request: {request}");
                }
            }

            AdditionalRequestValidation?.Invoke(request);

            return(new TaskFactory().StartNew(() => ResponseMessage, cancellationToken));
        }