コード例 #1
0
        private void RunAcquireTokenSilentCacheOnlyTest(string authority, bool expectNetworkDiscovery)
        {
            var receiver = new MyReceiver();

            using (MockHttpAndServiceBundle testHarness = base.CreateTestHarness())
            {
                PublicClientApplication app = PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                                              .WithAuthority(authority, true)
                                              .WithHttpManager(testHarness.HttpManager)
                                              .WithTelemetry(receiver.HandleTelemetryEvents)
                                              .BuildConcrete();

                var tokenCacheHelper = new TokenCacheHelper();
                tokenCacheHelper.PopulateCache(app.UserTokenCacheInternal.Accessor);

                app.UserTokenCacheInternal.Accessor.DeleteAccessToken(new MsalAccessTokenCacheKey(
                                                                          TestConstants.ProductionPrefNetworkEnvironment,
                                                                          TestConstants.Utid,
                                                                          TestConstants.s_userIdentifier,
                                                                          TestConstants.ClientId,
                                                                          TestConstants.ScopeForAnotherResourceStr,
                                                                          TestConstants.Bearer));

                if (expectNetworkDiscovery)
                {
                    string host          = new Uri(authority).Host;
                    string discoveryHost = KnownMetadataProvider.IsKnownEnvironment(host)
                                               ? host
                                               : AadAuthority.DefaultTrustedHost;

                    string discoveryEndpoint = $"https://{discoveryHost}/common/discovery/instance";

                    var jsonResponse = TestConstants.DiscoveryJsonResponse.Replace("login.microsoft.com", host);
                    testHarness.HttpManager.AddMockHandler(
                        MockHelpers.CreateInstanceDiscoveryMockHandler(discoveryEndpoint, jsonResponse));
                }

                Task <AuthenticationResult> task = app
                                                   .AcquireTokenSilent(
                    TestConstants.s_scope.ToArray(),
                    new Account(TestConstants.s_userIdentifier, TestConstants.DisplayableId, null))
                                                   .WithAuthority(app.Authority, false)
                                                   .WithForceRefresh(false)
                                                   .ExecuteAsync(CancellationToken.None);

                AuthenticationResult result = task.Result;
                Assert.IsNotNull(result);
                Assert.AreEqual(TestConstants.DisplayableId, result.Account.Username);
                Assert.AreEqual(TestConstants.s_scope.AsSingleString(), result.Scopes.AsSingleString());

                Assert.AreEqual(2, app.UserTokenCacheInternal.Accessor.GetAllAccessTokens().Count());
                Assert.AreEqual(1, app.UserTokenCacheInternal.Accessor.GetAllRefreshTokens().Count());
                Assert.IsNotNull(receiver.EventsReceived.Find(anEvent =>  // Expect finding such an event
                                                              anEvent[EventBase.EventNameKey].EndsWith("api_event") && anEvent[ApiEvent.WasSuccessfulKey] == "true" &&
                                                              anEvent[MsalTelemetryBlobEventNames.ApiIdConstStrKey] == "1007"));
            }
        }
        public void KnownMetadataProvider_IsKnown()
        {
            Assert.IsFalse(KnownMetadataProvider.IsKnownEnvironment(null));
            Assert.IsFalse(KnownMetadataProvider.IsKnownEnvironment(""));
            Assert.IsFalse(KnownMetadataProvider.IsKnownEnvironment("bogus"));

            Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("login.microsoftonline.de"));
            Assert.IsTrue(KnownMetadataProvider.IsKnownEnvironment("LOGIN.microsoftonline.de"));
        }
コード例 #3
0
        public void KnownMetadataProvider_publicEnvironment()
        {
            Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment(""));
            Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment(null));
            Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment("unknown"));
            Assert.IsFalse(KnownMetadataProvider.IsPublicEnvironment("login.microsoftonline.de"));

            Assert.IsTrue(KnownMetadataProvider.IsPublicEnvironment("login.microsoft.com"));
            Assert.IsTrue(KnownMetadataProvider.IsPublicEnvironment("login.microsoftonline.com"));
            Assert.IsTrue(KnownMetadataProvider.IsPublicEnvironment("Login.microsoftonline.com"));
        }
        public static void AddInstanceDiscoveryMockHandler(this MockHttpManager httpManager, string authority)
        {
            Uri    authorityURI  = new Uri(authority);
            string discoveryHost = KnownMetadataProvider.IsKnownEnvironment(authorityURI.Host)
                                       ? authorityURI.Host
                                       : AadAuthority.DefaultTrustedHost;

            string discoveryEndpoint = UriBuilderExtensions.GetHttpsUriWithOptionalPort($"https://{discoveryHost}/common/discovery/instance", authorityURI.Port);

            httpManager.AddMockHandler(
                MockHelpers.CreateInstanceDiscoveryMockHandler(discoveryEndpoint));
        }
コード例 #5
0
        public static void AddInstanceDiscoveryMockHandler(this MockHttpManager httpManager, string authority)
        {
            string host          = new Uri(authority).Host;
            string discoveryHost = KnownMetadataProvider.IsKnownEnvironment(host)
                                       ? host
                                       : AadAuthority.DefaultTrustedHost;

            string discoveryEndpoint = $"https://{discoveryHost}/common/discovery/instance";

            httpManager.AddMockHandler(
                MockHelpers.CreateInstanceDiscoveryMockHandler(discoveryEndpoint));
        }
コード例 #6
0
        private string GetRegionalizedEnviroment(Uri authority, string region)
        {
            var builder = new UriBuilder(authority);

            // special rule for Global cloud
            if (KnownMetadataProvider.IsPublicEnvironment(authority.Host))
            {
                return($"{region}.login.microsoft.com");
            }

            return($"{region}.{builder.Host}");
        }
        private async Task <Uri> BuildAuthorityWithRegionAsync(Uri canonicalAuthority, RequestContext requestContext)
        {
            string regionToUse = requestContext.ServiceBundle.Config.AuthorityInfo.RegionToUse;

            if (s_region.IsNullOrEmpty())
            {
                try
                {
                    s_region = await GetRegionAsync(requestContext).ConfigureAwait(false);

                    if (!regionToUse.IsNullOrEmpty())
                    {
                        requestContext.ApiEvent.IsValidUserProvidedRegion = s_region.Equals(regionToUse);
                        requestContext.Logger.Info($"The auto detected region is {s_region}.");
                        if (s_region.Equals(regionToUse))
                        {
                            requestContext.Logger.Info("The region provided by the user is valid and equal to the auto detected region.");
                        }
                        else
                        {
                            requestContext.Logger.Info($"The region provided by the user is invalid. Region detected: {s_region} Region provided: {regionToUse}");
                        }
                    }
                }
                catch (MsalServiceException e)
                {
                    if (regionToUse.IsNullOrEmpty())
                    {
                        throw e;
                    }

                    s_region = regionToUse;
                    requestContext.Logger.Info($"Region auto detection failed. Region provided by the user will be used: ${regionToUse}.");
                    LogTelemetryData(s_region, RegionSource.UserProvided, requestContext);
                }
            }

            var builder = new UriBuilder(canonicalAuthority);

            if (KnownMetadataProvider.IsPublicEnvironment(canonicalAuthority.Host))
            {
                builder.Host = $"{s_region}.login.microsoft.com";
            }
            else
            {
                builder.Host = $"{s_region}.{builder.Host}";
            }

            return(builder.Uri);
        }
        /// <summary>
        /// AAD performs authority validation by calling the instance metadata endpoint. This is a bit unfortunate,
        /// because instance metadata is used for aliasing, and authority validation is orthogonal to that.
        /// MSAL must figure out aliasing even if ValidateAuthority is set to false.
        /// </summary>
        public async Task ValidateAuthorityAsync(
            AuthorityInfo authorityInfo,
            RequestContext requestContext)
        {
            var authorityUri = new Uri(authorityInfo.CanonicalAuthority);

            if (authorityInfo.ValidateAuthority && !KnownMetadataProvider.IsKnownEnvironment(authorityUri.Host))
            {
                // MSAL will throw if the instance discovery URI does not respond with a valid json
                await _serviceBundle.InstanceDiscoveryManager.GetMetadataEntryAsync(
                    authorityInfo.CanonicalAuthority,
                    requestContext).ConfigureAwait(false);
            }
        }
        /// <inheritdoc />
        public async Task <string> ValidateAuthorityAndGetOpenIdDiscoveryEndpointAsync(
            AuthorityInfo authorityInfo,
            string userPrincipalName,
            RequestContext requestContext)
        {
            var authorityUri = new Uri(authorityInfo.CanonicalAuthority);

            if (authorityInfo.ValidateAuthority && !KnownMetadataProvider.IsKnownEnvironment(authorityUri.Host))
            {
                // MSAL will throw if the instance discovery URI does not respond with a valid json
                await _serviceBundle.InstanceDiscoveryManager.GetMetadataEntryAsync(
                    authorityInfo.CanonicalAuthority,
                    requestContext).ConfigureAwait(false);
            }

            return(authorityInfo.CanonicalAuthority + Constants.OpenIdConfigurationEndpoint);
        }
        private async Task <Uri> BuildAuthorityWithRegionAsync(Uri canonicalAuthority, RequestContext requestContext)
        {
            string region = await GetRegionAsync(requestContext).ConfigureAwait(false);

            var builder = new UriBuilder(canonicalAuthority);

            if (KnownMetadataProvider.IsPublicEnvironment(canonicalAuthority.Host))
            {
                builder.Host = $"{region}.login.microsoft.com";
            }
            else
            {
                builder.Host = $"{region}.{builder.Host}";
            }

            return(builder.Uri);
        }
コード例 #11
0
        private string GetRegionalizedEnviroment(Uri authority, string region)
        {
            string host = authority.Host;

            if (KnownMetadataProvider.IsPublicEnvironment(host))
            {
                return($"{region}.{PublicEnvForRegional}");
            }

            // Regional business rule - use the PreferredNetwork value for public and sovereign clouds
            // but do not do instance discovery for it - rely on cached values only
            if (KnownMetadataProvider.TryGetKnownEnviromentPreferredNetwork(host, out var preferredNetworkEnv))
            {
                host = preferredNetworkEnv;
            }

            return($"{region}.{host}");
        }
コード例 #12
0
        /// <summary>
        /// AAD performs authority validation by calling the instance metadata endpoint. This is a bit unfortunate,
        /// because instance metadata is used for aliasing, and authority validation is orthogonal to that.
        /// MSAL must figure out aliasing even if ValidateAuthority is set to false.
        /// </summary>
        public async Task ValidateAuthorityAsync(
            AuthorityInfo authorityInfo)
        {
            var  authorityUri = new Uri(authorityInfo.CanonicalAuthority);
            bool isKnownEnv   = KnownMetadataProvider.IsKnownEnvironment(authorityUri.Host);

            _requestContext.Logger.Info($"Authority validation enabled? {authorityInfo.ValidateAuthority}. ");
            _requestContext.Logger.Info($"Authority validation - is known env? {isKnownEnv}. ");

            if (authorityInfo.ValidateAuthority && !isKnownEnv)
            {
                _requestContext.Logger.Info($"Authority validation is being performed. ");

                // MSAL will throw if the instance discovery URI does not respond with a valid json
                await _requestContext.ServiceBundle.InstanceDiscoveryManager.GetMetadataEntryAsync(
                    authorityInfo,
                    _requestContext).ConfigureAwait(false);
            }
        }
コード例 #13
0
        public void KnownMetadataProvider_RespondsIfEnvironmentsAreKnown()
        {
            // Arrange
            KnownMetadataProvider knownMetadataProvider = new KnownMetadataProvider();

            InstanceDiscoveryMetadataEntry result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, null, _logger);

            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, Enumerable.Empty <string>(), _logger);
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { LoginMicrosoftOnlineCom }, _logger);
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { LoginMicrosoftOnlineCom }, _logger);
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { "login.windows.net", "login.microsoft.com", "login.partner.microsoftonline.cn" }, _logger);
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                "login.partner.microsoftonline.cn", new[] { "login.windows.net", "login.microsoft.com", "login.partner.microsoftonline.cn" }, _logger);
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                "login.windows-ppe.net", new[] { "login.windows-ppe.net", "sts.windows-ppe.net", "login.microsoft-ppe.com" }, _logger);
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { "login.windows.net", "bogus", "login.partner.microsoftonline.cn" }, _logger);
            Assert.IsNull(result);

            result = knownMetadataProvider.GetMetadata(
                "bogus", new[] { "login.windows.net", "login.microsoft.com", "login.partner.microsoftonline.cn" }, _logger);
            Assert.IsNull(result);
        }
        private void RunAcquireTokenSilentCacheOnlyTest(string authority, bool expectNetworkDiscovery)
        {
            using (MockHttpAndServiceBundle testHarness = base.CreateTestHarness())
            {
                PublicClientApplication app = PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                                              .WithAuthority(authority, true)
                                              .WithHttpManager(testHarness.HttpManager)
                                              .BuildConcrete();

                TokenCacheHelper.PopulateCache(app.UserTokenCacheInternal.Accessor);

                if (expectNetworkDiscovery)
                {
                    string host          = new Uri(authority).Host;
                    string discoveryHost = KnownMetadataProvider.IsKnownEnvironment(host)
                                               ? host
                                               : AadAuthority.DefaultTrustedHost;

                    string discoveryEndpoint = $"https://{discoveryHost}/common/discovery/instance";

                    var jsonResponse = TestConstants.DiscoveryJsonResponse.Replace("login.microsoft.com", host);
                    testHarness.HttpManager.AddMockHandler(
                        MockHelpers.CreateInstanceDiscoveryMockHandler(discoveryEndpoint, jsonResponse));
                }

                Task <AuthenticationResult> task = app
                                                   .AcquireTokenSilent(
                    TestConstants.s_scope.ToArray(),
                    new Account(TestConstants.s_userIdentifier, TestConstants.DisplayableId, null))
                                                   .WithForceRefresh(false)
                                                   .ExecuteAsync(CancellationToken.None);

                AuthenticationResult result = task.Result;
                Assert.IsNotNull(result);
                Assert.AreEqual(TestConstants.DisplayableId, result.Account.Username);
                Assert.AreEqual(TestConstants.s_scope.AsSingleString(), result.Scopes.AsSingleString());

                Assert.AreEqual(2, app.UserTokenCacheInternal.Accessor.GetAllAccessTokens().Count());
                Assert.AreEqual(1, app.UserTokenCacheInternal.Accessor.GetAllRefreshTokens().Count());
            }
        }
コード例 #15
0
        private void LogRequestStarted(AuthenticationRequestParameters authenticationRequestParameters)
        {
            if (authenticationRequestParameters.RequestContext.Logger.IsLoggingEnabled(LogLevel.Info))
            {
                int    appHashCode    = authenticationRequestParameters.AppConfig.GetHashCode();
                string scopes         = authenticationRequestParameters.Scope.AsSingleString();
                string messageWithPii = string.Format(
                    CultureInfo.InvariantCulture,
                    "=== Token Acquisition ({3}) started:\n\tAuthority: {0}\n\tScope: {1}\n\tClientId: {2}\n\tAppHashCode: {4}",
                    authenticationRequestParameters.AuthorityInfo?.CanonicalAuthority,
                    scopes,
                    authenticationRequestParameters.AppConfig.ClientId,
                    GetType().Name,
                    appHashCode);

                string messageWithoutPii = string.Format(
                    CultureInfo.InvariantCulture,
                    "=== Token Acquisition ({0}) started:\n\t Scopes: {1} AppHashCode: {2}",
                    GetType().Name,
                    scopes,
                    appHashCode);

                if (authenticationRequestParameters.AuthorityInfo != null &&
                    KnownMetadataProvider.IsKnownEnvironment(authenticationRequestParameters.AuthorityInfo?.Host))
                {
                    messageWithoutPii += string.Format(
                        CultureInfo.CurrentCulture,
                        "\n\tAuthority Host: {0}",
                        authenticationRequestParameters.AuthorityInfo?.Host);
                }

                authenticationRequestParameters.RequestContext.Logger.InfoPii(messageWithPii, messageWithoutPii);
            }

            if (authenticationRequestParameters.IsConfidentialClient &&
                !CacheManager.TokenCacheInternal.IsTokenCacheSerialized())
            {
                authenticationRequestParameters.RequestContext.Logger.Error("The default token cache provided by MSAL is not designed to be performant when used in confidential client applications. Please use token cache serialization. See https://aka.ms/msal-net-cca-token-cache-serialization.");
            }
        }
        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());
        }
コード例 #17
0
        private void LogRequestStarted(AuthenticationRequestParameters authenticationRequestParameters)
        {
            if (authenticationRequestParameters.RequestContext.Logger.IsLoggingEnabled(LogLevel.Info))
            {
                string scopes         = authenticationRequestParameters.Scope.AsSingleString();
                string messageWithPii = string.Format(
                    CultureInfo.InvariantCulture,
                    "=== Token Acquisition ({3}) started:\n\tAuthority: {0}\n\tScope: {1}\n\tClientId: {2}\n\t",
                    authenticationRequestParameters.AuthorityInfo?.CanonicalAuthority,
                    scopes,
                    authenticationRequestParameters.AppConfig.ClientId,
                    GetType().Name);

                string messageWithoutPii = string.Format(
                    CultureInfo.InvariantCulture,
                    "=== Token Acquisition ({0}) started:\n\t Scopes: {1}",
                    GetType().Name,
                    scopes);

                if (authenticationRequestParameters.AuthorityInfo != null &&
                    KnownMetadataProvider.IsKnownEnvironment(authenticationRequestParameters.AuthorityInfo?.Host))
                {
                    messageWithoutPii += string.Format(
                        CultureInfo.CurrentCulture,
                        "\n\tAuthority Host: {0}",
                        authenticationRequestParameters.AuthorityInfo?.Host);
                }

                authenticationRequestParameters.RequestContext.Logger.InfoPii(messageWithPii, messageWithoutPii);
            }

            if (authenticationRequestParameters.IsConfidentialClient &&
                !authenticationRequestParameters.IsClientCredentialRequest &&
                !CacheManager.TokenCacheInternal.IsAppSubscribedToSerializationEvents())
            {
                authenticationRequestParameters.RequestContext.Logger.Warning(
                    "Only in-memory caching is used. The cache is not persisted and will be lost if the machine is restarted. It also does not scale for a web app or web API, where the number of users can grow large. In production, web apps and web APIs should use distributed caching like Redis. See https://aka.ms/msal-net-cca-token-cache-serialization");
            }
        }
コード例 #18
0
        public void KnownMetadataProvider_RespondsIfEnvironmentsAreKnown()
        {
            // Arrange
            KnownMetadataProvider knownMetadataProvider = new KnownMetadataProvider();

            var result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, null);

            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, Enumerable.Empty <string>());
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { LoginMicrosoftOnlineCom });
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { LoginMicrosoftOnlineCom });
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { "login.windows.net", "login.microsoft.com", "login.partner.microsoftonline.cn" });
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                "login.partner.microsoftonline.cn", new[] { "login.windows.net", "login.microsoft.com", "login.partner.microsoftonline.cn" });
            Assert.IsNotNull(result);

            result = knownMetadataProvider.GetMetadata(
                LoginMicrosoftOnlineCom, new[] { "login.windows.net", "bogus", "login.partner.microsoftonline.cn" });
            Assert.IsNull(result);

            result = knownMetadataProvider.GetMetadata(
                "bogus", new[] { "login.windows.net", "login.microsoft.com", "login.partner.microsoftonline.cn" });
            Assert.IsNull(result);
        }