public void ConfidentialClientUsingCertificateTest()
        {
            ClientCredential cc = new ClientCredential(new ClientAssertionCertificate(new X509Certificate2("valid_cert.pfx", "password")));
            ConfidentialClientApplication app = new ConfidentialClientApplication(TestConstants.DefaultClientId,
                                                                                  TestConstants.DefaultRedirectUri, cc, new TokenCache());

            app.AppTokenCache = new TokenCache();
            HttpMessageHandlerFactory.MockHandler = new MockHttpMessageHandler()
            {
                Method          = HttpMethod.Post,
                ResponseMessage = MockHelpers.CreateSuccessfulClientCredentialTokenResponseMessage()
            };

            Task <AuthenticationResult> task = app.AcquireTokenForClient(TestConstants.DefaultScope.ToArray(),
                                                                         TestConstants.DefaultPolicy);
            AuthenticationResult result = task.Result;

            Assert.IsNotNull(result);
            Assert.IsNotNull("header.payload.signature", result.Token);
            Assert.AreEqual(TestConstants.DefaultScope.AsSingleString(), result.ScopeSet.AsSingleString());

            //make sure user token cache is empty
            Assert.AreEqual(0, app.UserTokenCache.Count);

            //check app token cache count to be 1
            Assert.AreEqual(1, app.AppTokenCache.Count);
            //make sure refresh token is null
            foreach (var value in app.AppTokenCache.tokenCacheDictionary.Values)
            {
                Assert.IsNull(value.RefreshToken);
            }

            //assert client credential
            Assert.IsNotNull(cc.ClientAssertion);
            Assert.AreNotEqual(0, cc.ValidTo);

            //save client assertion.
            string cachedAssertion = cc.ClientAssertion.Assertion;
            long   cacheValidTo    = cc.ValidTo;

            HttpMessageHandlerFactory.MockHandler = new MockHttpMessageHandler()
            {
                Method          = HttpMethod.Post,
                ResponseMessage = MockHelpers.CreateSuccessfulClientCredentialTokenResponseMessage()
            };

            task = app.AcquireTokenForClient(TestConstants.ScopeForAnotherResource.ToArray(),
                                             TestConstants.DefaultPolicy);
            result = task.Result;
            Assert.IsNotNull(result);
            Assert.AreEqual(cacheValidTo, cc.ValidTo);
            Assert.AreEqual(cachedAssertion, cc.ClientAssertion.Assertion);
        }
예제 #2
0
        private static async Task RunClientCreds_Async(MockHttpManager httpManager, ConfidentialClientApplication app)
        {
            httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();

            var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

            Assert.AreEqual(TestConstants.s_scope.AsSingleString(), result.Scopes.AsSingleString());
            Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);

            result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

            Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
        }
예제 #3
0
        private async Task <(HttpRequestMessage HttpRequest, Guid Correlationid)> RunAcquireTokenForClientAsync(
            AcquireTokenForClientOutcome outcome, bool forceRefresh = false)
        {
            MockHttpMessageHandler tokenRequestHandler = null;
            Guid correlationId = default;

            switch (outcome)
            {
            case AcquireTokenForClientOutcome.Success:

                tokenRequestHandler = _harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(authority: TestConstants.AuthorityRegional);
                var authResult = await _app
                                 .AcquireTokenForClient(TestConstants.s_scope)
                                 .WithAzureRegion(true)
                                 .WithForceRefresh(forceRefresh)
                                 .ExecuteAsync()
                                 .ConfigureAwait(false);

                correlationId = authResult.CorrelationId;
                break;

            case AcquireTokenForClientOutcome.AADUnavailableError:
                correlationId = Guid.NewGuid();

                tokenRequestHandler = new MockHttpMessageHandler()
                {
                    ExpectedMethod  = HttpMethod.Post,
                    ResponseMessage = MockHelpers.CreateFailureMessage(
                        System.Net.HttpStatusCode.GatewayTimeout, "gateway timeout")
                };
                var tokenRequestHandler2 = new MockHttpMessageHandler()
                {
                    ExpectedMethod  = HttpMethod.Post,
                    ResponseMessage = MockHelpers.CreateFailureMessage(
                        System.Net.HttpStatusCode.GatewayTimeout, "gateway timeout")
                };

                // 2 of these are needed because MSAL has a "retry once" policy for 5xx errors
                _harness.HttpManager.AddMockHandler(tokenRequestHandler2);
                _harness.HttpManager.AddMockHandler(tokenRequestHandler);

                var serviceEx = await AssertException.TaskThrowsAsync <MsalServiceException>(() =>
                                                                                             _app
                                                                                             .AcquireTokenForClient(TestConstants.s_scope)
                                                                                             .WithAzureRegion(true)
                                                                                             .WithForceRefresh(true)
                                                                                             .WithCorrelationId(correlationId)
                                                                                             .ExecuteAsync())
                                .ConfigureAwait(false);

                break;

            default:
                throw new NotImplementedException();
            }

            Assert.AreEqual(0, _harness.HttpManager.QueueSize);

            return(tokenRequestHandler?.ActualRequestMessage, correlationId);
        }
        public void ConfidentialClientUsingSecretTest()
        {
            ConfidentialClientApplication app = new ConfidentialClientApplication(TestConstants.DefaultClientId,
                                                                                  TestConstants.DefaultRedirectUri, new ClientCredential(TestConstants.DefaultClientSecret), new TokenCache());

            app.AppTokenCache = new TokenCache();
            HttpMessageHandlerFactory.MockHandler = new MockHttpMessageHandler()
            {
                Method          = HttpMethod.Post,
                ResponseMessage = MockHelpers.CreateSuccessfulClientCredentialTokenResponseMessage()
            };

            Task <AuthenticationResult> task = app.AcquireTokenForClient(TestConstants.DefaultScope.ToArray(),
                                                                         TestConstants.DefaultPolicy);
            AuthenticationResult result = task.Result;

            Assert.IsNotNull(result);
            Assert.IsNotNull("header.payload.signature", result.Token);
            Assert.AreEqual(TestConstants.DefaultScope.AsSingleString(), result.ScopeSet.AsSingleString());

            //make sure user token cache is empty
            Assert.AreEqual(0, app.UserTokenCache.Count);

            //check app token cache count to be 1
            Assert.AreEqual(1, app.AppTokenCache.Count);
            //make sure refresh token is null
            foreach (var value in app.AppTokenCache.tokenCacheDictionary.Values)
            {
                Assert.IsNull(value.RefreshToken);
            }
        }
예제 #5
0
        public async Task POP_ShrValidation_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithHttpManager(httpManager)
                    .WithExperimentalFeatures(true)
                    .BuildConcrete();

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl));
                var popConfig = new PoPAuthenticationConfiguration(request);
                var provider  = PoPProviderFactory.GetOrCreateProvider();

                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .WithAuthority(TestConstants.AuthorityUtidTenant)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                // access token parsing can be done with MSAL's id token parsing logic
                var claims = IdToken.Parse(result.AccessToken).ClaimsPrincipal;

                Assert.IsTrue(!string.IsNullOrEmpty(claims.FindAll("nonce").Single().Value));
                AssertSingedHttpRequestClaims(provider, claims);
            }
        }
        public async Task ClientCreds_NonExpired_NeedsRefresh_ValidResponse_Async()
        {
            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app with a token cache with one AT");
                ConfidentialClientApplication app = SetupCca(harness);

                Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed");
                UpdateATWithRefreshOn(app.AppTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1));
                TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess();

                Trace.WriteLine("3. Configure AAD to respond with valid token to the refresh RT flow");
                AddHttpMocks(TokenResponseType.Valid, harness.HttpManager, pca: false);

                // Act
                Trace.WriteLine("4. ATS - should perform an RT refresh");
                AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

                // Assert
                Assert.IsNotNull(result);
                Assert.AreEqual(0, harness.HttpManager.QueueSize,
                                "MSAL should have refreshed the token because the original AT was marked for refresh");
                cacheAccess.AssertAccessCounts(1, 1);
            }
        }
예제 #7
0
        public async Task ClientCreds_NonExpired_NeedsRefresh_AADInvalidResponse_Async()
        {
            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app");
                ConfidentialClientApplication app = SetupCca(harness);

                Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed");

                MsalAccessTokenCacheItem atItem = TokenCacheHelper.CreateAccessTokenItem();
                UpdateATWithRefreshOn(atItem, DateTime.UtcNow - TimeSpan.FromMinutes(1));
                TokenCacheHelper.PopulateDefaultAppTokenCache(app, atItem);

                TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess();

                Trace.WriteLine("3. Configure AAD to respond with the typical Invalid Grant error");
                harness.HttpManager.AddAllMocks(TokenResponseType.InvalidGrant);

                // Act
                await AssertException.TaskThrowsAsync <MsalUiRequiredException>(() =>
                                                                                app.AcquireTokenForClient(TestConstants.s_scope)
                                                                                .ExecuteAsync())
                .ConfigureAwait(false);

                cacheAccess.AssertAccessCounts(1, 0);
            }
        }
예제 #8
0
        public async Task ClientCreds_WithClientAssertion_Adfs_Async()
        {
            var cert = await _keyVault.GetCertificateWithPrivateMaterialAsync(AdfsCertName)
                       .ConfigureAwait(false);

            string clientAssertion =
                GetSignedClientAssertionUsingWilson(Adfs2019LabConstants.Authority, cert);

            ConfidentialClientApplication msalConfidentialClient =
                ConfidentialClientApplicationBuilder.Create(Adfs2019LabConstants.ConfidentialClientId)
                .WithAdfsAuthority(Adfs2019LabConstants.Authority, true)
                .WithTestLogging()
                .WithRedirectUri(Adfs2019LabConstants.ClientRedirectUri)
                .WithClientAssertion(clientAssertion)
                .BuildConcrete();

            AuthenticationResult authResult = await msalConfidentialClient
                                              .AcquireTokenForClient(s_adfsScopes)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNull(authResult.IdToken);
        }
        public async Task Get(string tenantId)
        {
            // Get a token for the Microsoft Graph
            ConfidentialClientApplication daemonClient = new ConfidentialClientApplication(String.Format(authorityFormat, tenantId), Startup.clientId, Startup.redirectUri, new ClientCredential(Startup.clientSecret), new TokenCache());
            AuthenticationResult          authResult   = await daemonClient.AcquireTokenForClient(new string[] { msGraphScope }, null);

            // Query for list of users in the tenant
            HttpClient         client  = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, msGraphQuery);

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.Token);
            HttpResponseMessage response = await client.SendAsync(request);

            if (!response.IsSuccessStatusCode)
            {
                throw new HttpResponseException(response.StatusCode);
            }

            // Record users in the data store (note that this only records the first page of users)
            string json = await response.Content.ReadAsStringAsync();

            MsGraphUserListResponse users = JsonConvert.DeserializeObject <MsGraphUserListResponse>(json);

            usersByTenant[tenantId] = users.value;
            return;
        }
예제 #10
0
        public async Task MetricsUpdatedSucessfully_AcquireTokenForClient_Async()
        {
            using (var harness = CreateTestHarness())
            {
                harness.HttpManager.AddInstanceDiscoveryMockHandler();
                harness.HttpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();

                ConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                                                    .WithAuthority(new Uri(ClientApplicationBase.DefaultAuthority), false)
                                                    .WithRedirectUri(TestConstants.RedirectUri)
                                                    .WithClientSecret(TestConstants.ClientSecret)
                                                    .WithHttpManager(harness.HttpManager)
                                                    .BuildConcrete();

                InMemoryTokenCache memoryTokenCache = new InMemoryTokenCache(withOperationDelay: true, shouldClearExistingCache: false);
                memoryTokenCache.Bind(cca.AppTokenCache);

                // Act - AcquireTokenForClient
                AuthenticationResult result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationInCacheInMs > 0);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0);
                Assert.AreEqual(
                    "https://login.microsoftonline.com/common/oauth2/v2.0/token",
                    result.AuthenticationResultMetadata.TokenEndpoint);
                Assert.AreEqual(1, Metrics.TotalAccessTokensFromIdP);
                Assert.AreEqual(0, Metrics.TotalAccessTokensFromCache);
                Assert.AreEqual(0, Metrics.TotalAccessTokensFromBroker);

                // Act - AcquireTokenForClient returns result from cache
                result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationInCacheInMs > 0);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationInHttpInMs == 0);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0);
                Assert.AreEqual(1, Metrics.TotalAccessTokensFromIdP);
                Assert.AreEqual(1, Metrics.TotalAccessTokensFromCache);
                Assert.AreEqual(0, Metrics.TotalAccessTokensFromBroker);
                Assert.IsTrue(Metrics.TotalDurationInMs > 0);
                Assert.IsNull(result.AuthenticationResultMetadata.TokenEndpoint);
            }
        }
        public async Task AcquireTokenForClient_BypassesCacheForAccessTokens_IfClaimsUsed_Async()
        {
            // Arrange
            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app with a token cache with one AT");
                ConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                                                    .WithAuthority(AzureCloudInstance.AzurePublic, TestConstants.Utid)
                                                    .WithClientSecret(TestConstants.ClientSecret)
                                                    .WithHttpManager(harness.HttpManager)
                                                    .BuildConcrete();

                var tokenCacheHelper = new TokenCacheHelper();
                tokenCacheHelper.PopulateCache(app.AppTokenCacheInternal.Accessor, addSecondAt: false);

                Trace.WriteLine("2. AcquireTokenForClient returns from the cache ");
                AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

                Assert.IsNotNull(result, "A result is obtained from the cache, i.e. without HTTP calls");

                harness.HttpManager.AddInstanceDiscoveryMockHandler();
                harness.HttpManager.AddMockHandlerForTenantEndpointDiscovery(
                    TestConstants.AuthorityUtidTenant);
                var refreshHandler = new MockHttpMessageHandler()
                {
                    ExpectedMethod  = HttpMethod.Post,
                    ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage(
                        TestConstants.UniqueId,
                        TestConstants.DisplayableId,
                        TestConstants.s_scope.ToArray())
                };
                harness.HttpManager.AddMockHandler(refreshHandler);

                // Act
                Trace.WriteLine("3. AcquireTokenForClient + Claims does not return AT from cache");
                await app.AcquireTokenForClient(TestConstants.s_scope)
                .WithClaims(TestConstants.Claims)
                .ExecuteAsync()
                .ConfigureAwait(false);

                Assert.IsNotNull(result, "An access token is no longer obtained from the cache. The RT is used to get one from the STS.");
            }
        }
        protected async Task <AuthenticationHeaderValue> GetAuthHeaderValueAsync()
        {
            // TODO: Implement retries for when we get 429 som AAD:
            // https://github.com/azureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after
            // Should use Polly instead for above example.
            var result = await ConfidentialClientApplication.AcquireTokenForClient(Scopes).ExecuteAsync().ConfigureAwait(false);

            return(new AuthenticationHeaderValue("bearer", result.AccessToken));
        }
예제 #13
0
        private void ConnectGraphAAD()
        {
            var appCredentials       = new ClientCredential(AppSecret);
            var authority            = new Uri(GraphAADLogin, AADDomain).AbsoluteUri;
            var clientApplication    = new ConfidentialClientApplication(authority, AppId, RedirectUri, appCredentials, null);
            var authenticationResult = clientApplication.AcquireTokenForClient(GraphDefaultScope, null).GetAwaiter().GetResult();

            SPOnlineConnection.AuthenticationResult = authenticationResult;
        }
예제 #14
0
        public async Task ClientCreds_NonExpired_NeedsRefresh_AADUnavailableResponse_Async()
        {
            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app ");
                ConfidentialClientApplication app = SetupCca(harness);

                Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed");

                MsalAccessTokenCacheItem atItem = TokenCacheHelper.CreateAccessTokenItem();
                UpdateATWithRefreshOn(atItem, DateTime.UtcNow - TimeSpan.FromMinutes(1));
                TokenCacheHelper.PopulateDefaultAppTokenCache(app, atItem);

                TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess();

                //UpdateATWithRefreshOn(app.AppTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1));


                Trace.WriteLine("3. Configure AAD to respond with an error");
                harness.HttpManager.AddAllMocks(TokenResponseType.Invalid_AADUnavailable503);
                harness.HttpManager.AddTokenResponse(TokenResponseType.Invalid_AADUnavailable503);

                // Act
                AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

                // Assert
                Assert.IsNotNull(result, "ClientCreds should still succeeds even though AAD is unavaible");
                Assert.AreEqual(0, harness.HttpManager.QueueSize);
                cacheAccess.AssertAccessCounts(1, 0); // the refresh failed, no new data is written to the cache

                // Now let AAD respond with tokens
                harness.HttpManager.AddTokenResponse(TokenResponseType.Valid);

                result = await app.AcquireTokenForClient(TestConstants.s_scope)
                         .ExecuteAsync()
                         .ConfigureAwait(false);

                Assert.IsNotNull(result);
                cacheAccess.AssertAccessCounts(2, 1); // new tokens written to cache
            }
        }
예제 #15
0
        // GET: Calendar
        public async Task <ActionResult> Index()
        {
            // Make sure the user is signed in
            if (!Request.IsAuthenticated)
            {
                return(new RedirectResult("/Account/Index"));
            }

            string tenantId = ClaimsPrincipal.Current.FindFirst(tenantIdClaimType).Value;

            try
            {
                // Try to get a token for the tenant
                ConfidentialClientApplication daemonClient = new ConfidentialClientApplication(String.Format(authorityFormat, tenantId), Startup.clientId, Startup.redirectUri, new ClientCredential(Startup.clientSecret), null);
                AuthenticationResult          authResult   = await daemonClient.AcquireTokenForClient(new string[] { msGraphScope }, null);

                // Query for list of users in the tenant, to ensure we have been granted the necessary permissions
                HttpClient         client  = new HttpClient();
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, msGraphQuery);
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.Token);
                HttpResponseMessage response = await client.SendAsync(request);

                // If we get back a 403, we need to ask the admin for permissions
                if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
                {
                    daemonClient.AppTokenCache.Clear(Startup.clientId);
                    return(new RedirectResult("/Account/GrantPermissions"));
                }
                else if (!response.IsSuccessStatusCode)
                {
                    throw new HttpResponseException(response.StatusCode);
                }
            }
            catch (MsalException ex)
            {
                // If we can't get a token, we need to ask the admin for permissions as well
                if (ex.ErrorCode == "failed_to_acquire_token_silently")
                {
                    return(new RedirectResult("/Account/GrantPermissions"));
                }

                return(View("Error"));
            }
            catch (Exception ex)
            {
                return(View("Error"));
            }

            // If we can get a token & make the query, permissions have been granted and we can proceed to showing the list of users
            ViewBag.TenantId = tenantId;
            ViewBag.Users    = SyncController.GetUsersForTenant(tenantId);

            return(View());
        }
        public async Task AcquireTokenForClient_DifferentScopes_TestAsync()
        {
            Random random = new Random();
            string scope  = $"scope_{random.Next(0, TokenCacheSize)}";

            await _ccaTokensDifferByScope.AcquireTokenForClient(new[] { scope })
            .WithForceRefresh(false)
            .WithAuthority($"https://login.microsoftonline.com/tid")
            .ExecuteAsync()
            .ConfigureAwait(false);
        }
        public async Task AcquireTokenForClient_DifferentTenants_TestAsync()
        {
            Random random = new Random();
            string tenant = $"tid_{random.Next(0, TokenCacheSize)}";

            await _ccaTokensDifferByTenant.AcquireTokenForClient(new[] { "scope" })
            .WithForceRefresh(false)
            .WithAuthority($"https://login.microsoft.com/{tenant}")
            .ExecuteAsync()
            .ConfigureAwait(false);
        }
예제 #18
0
        public async Task <string> GetAppOnlyAccessToken()
        {
            var clientCredential = new ClientCredential(ConfigurationManager.AppSettings["ida:Password"]);

            // authenticate
            var authority = string.Format("https://login.microsoftonline.com/{0}/v2.0", SettingsHelper.AzureAdTenantId);
            var cca       = new ConfidentialClientApplication(authority, SettingsHelper.ClientId, SettingsHelper.RedirectUri, clientCredential, null);

            string[] scopes     = { "https://graph.microsoft.com/.default" };
            var      authResult = await cca.AcquireTokenForClient(scopes, null);

            return(authResult.Token);
        }
예제 #19
0
        public async Task ClientCreds_NonExpired_NeedsRefresh_ValidResponse_Async()
        {
            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app");
                ConfidentialClientApplication app = SetupCca(harness);

                Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed");
                var refreshOn = UpdateATWithRefreshOn(app.AppTokenCacheInternal.Accessor).RefreshOn;

                TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess();

                Trace.WriteLine("3. Configure AAD to respond with valid token to the refresh RT flow");
                harness.HttpManager.AddAllMocks(TokenResponseType.Valid_ClientCredentials);

                // Act
                Trace.WriteLine("4. ATS - should perform an RT refresh");
                AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

                // Assert
                YieldTillSatisfied(() => harness.HttpManager.QueueSize == 0);
                Assert.IsNotNull(result);
                Assert.AreEqual(0, harness.HttpManager.QueueSize,
                                "MSAL should have refreshed the token because the original AT was marked for refresh");
                cacheAccess.WaitTo_AssertAcessCounts(1, 1);
                Assert.IsTrue(result.AuthenticationResultMetadata.CacheRefreshReason == CacheRefreshReason.ProactivelyRefreshed);
                Assert.IsTrue(result.AuthenticationResultMetadata.RefreshOn == refreshOn);

                result = await app.AcquireTokenForClient(TestConstants.s_scope)
                         .ExecuteAsync()
                         .ConfigureAwait(false);

                Assert.IsTrue(result.AuthenticationResultMetadata.CacheRefreshReason == CacheRefreshReason.NotApplicable);
            }
        }
        private async Task RunSemaphoreTestAsync(bool useCacheSyncronization)
        {
            using (var harness = base.CreateTestHarness())
            {
                MockHttpManager httpManager = harness.HttpManager;
                httpManager.AddInstanceDiscoveryMockHandler();

                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithAuthority(TestConstants.AuthorityUtidTenant)
                    .WithCacheSynchronization(useCacheSyncronization)
                    .WithHttpManager(httpManager)
                    .BuildConcrete();

                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();

                BlockingCache inMemoryTokenCache = new BlockingCache();
                inMemoryTokenCache.Bind(app.AppTokenCache);

                // Seed the cache with a token
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                Assert.IsTrue(result.AuthenticationResultMetadata.TokenSource == TokenSource.IdentityProvider);


                var blockingTask     = RunAsync(inMemoryTokenCache, app, true);
                var nonBlockingTask1 = RunAsync(inMemoryTokenCache, app, false);
                var nonBlockingTask2 = RunAsync(inMemoryTokenCache, app, false);

                int res = Task.WaitAny(new[] { blockingTask, nonBlockingTask1, nonBlockingTask2 }, 100);


                if (useCacheSyncronization)
                {
                    Assert.AreEqual(-1, res, "WaitAny should have timed out, all tasks are blocked when the first call is blocking");
                }
                else
                {
                    Assert.AreNotEqual(-1, res, "WaitAny should have NOT timed out, the 2 non-blocking tasks should be allowed to complete");
                    Assert.IsTrue(nonBlockingTask1.IsCompleted);
                    Assert.IsTrue(nonBlockingTask2.IsCompleted);
                    Assert.IsFalse(blockingTask.IsCompleted, "The blocking task should still be blocked");
                    Assert.IsTrue(nonBlockingTask1.Result.AuthenticationResultMetadata.TokenSource == TokenSource.Cache);
                    Assert.IsTrue(nonBlockingTask2.Result.AuthenticationResultMetadata.TokenSource == TokenSource.Cache);
                }
            }
        }
예제 #21
0
        public async Task AcquireTokenWithClientSecretFromAdfsAsync()
        {
            SecretBundle secret = _keyVault.GetSecret(Adfs2019LabConstants.ADFS2019ClientSecretURL);

            ConfidentialClientApplication msalConfidentialClient = ConfidentialClientApplicationBuilder.Create(Adfs2019LabConstants.ConfidentialClientId)
                                                                   .WithAdfsAuthority(Adfs2019LabConstants.Authority, true)
                                                                   .WithRedirectUri(Adfs2019LabConstants.ClientRedirectUri)
                                                                   .WithClientSecret(secret.Value)
                                                                   .BuildConcrete();

            //AuthenticationResult authResult = await msalConfidentialClient.AcquireTokenForClientAsync(AdfsScopes).ConfigureAwait(false);
            AuthenticationResult authResult = await msalConfidentialClient.AcquireTokenForClient(s_adfsScopes).ExecuteAsync().ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNull(authResult.IdToken);
        }
예제 #22
0
        public async Task ClientCreds_WithCertificate_Adfs_Async()
        {
            var cert = await _keyVault.GetCertificateWithPrivateMaterialAsync(AdfsCertName)
                       .ConfigureAwait(false);

            ConfidentialClientApplication msalConfidentialClient = ConfidentialClientApplicationBuilder.Create(Adfs2019LabConstants.ConfidentialClientId)
                                                                   .WithAdfsAuthority(Adfs2019LabConstants.Authority, true)
                                                                   .WithRedirectUri(Adfs2019LabConstants.ClientRedirectUri)
                                                                   .WithCertificate(cert)
                                                                   .BuildConcrete();

            AuthenticationResult authResult = await msalConfidentialClient
                                              .AcquireTokenForClient(s_adfsScopes)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNull(authResult.IdToken);
        }
예제 #23
0
        public async Task ClientCreds_WithClientSecret_Adfs_Async()
        {
            SecretBundle secret = _keyVault.GetSecret(Adfs2019LabConstants.ADFS2019ClientSecretURL);

            ConfidentialClientApplication msalConfidentialClient = ConfidentialClientApplicationBuilder.Create(Adfs2019LabConstants.ConfidentialClientId)
                                                                   .WithAdfsAuthority(Adfs2019LabConstants.Authority, true)
                                                                   .WithRedirectUri(Adfs2019LabConstants.ClientRedirectUri)
                                                                   .WithClientSecret(secret.Value)
                                                                   .WithTestLogging()
                                                                   .BuildConcrete();

            AuthenticationResult authResult = await msalConfidentialClient
                                              .AcquireTokenForClient(s_adfsScopes)
                                              .ExecuteAsync()
                                              .ConfigureAwait(false);

            Assert.IsNotNull(authResult);
            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.IsNotNull(authResult.AccessToken);
            Assert.IsNull(authResult.IdToken);
        }
        protected override void ProcessRecord()
        {
            AuthenticationResult authenticationResult;

            if (Scopes != null)
            {
                var clientApplication = new PublicClientApplication(MSALPnPPowerShellClientId);
                // Acquire an access token for the given scope
                authenticationResult = clientApplication.AcquireTokenAsync(Scopes).GetAwaiter().GetResult();
            }
            else
            {
                var appCredentials    = new ClientCredential(AppSecret);
                var authority         = new Uri(AADLogin, AADDomain).AbsoluteUri;
                var clientApplication = new ConfidentialClientApplication(authority, AppId, RedirectUri, appCredentials, null);
                authenticationResult = clientApplication.AcquireTokenForClient(DefaultScope, null).GetAwaiter().GetResult();
            }

            // Get back the Access Token and the Refresh Token
            PnPAzureADConnection.AuthenticationResult = authenticationResult;
        }
예제 #25
0
        public async Task POP_NoHttpRequest_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithHttpManager(httpManager)
                    .WithExperimentalFeatures(true)
                    .BuildConcrete();

                // no HTTP method binding, but custom nonce
                var popConfig = new PoPAuthenticationConfiguration()
                {
                    Nonce = CustomNonce
                };
                var provider = PoPProviderFactory.GetOrCreateProvider();

                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .WithAuthority(TestConstants.AuthorityUtidTenant)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                // access token parsing can be done with MSAL's id token parsing logic
                var claims = IdToken.Parse(result.AccessToken).ClaimsPrincipal;

                Assert.AreEqual(CustomNonce, claims.FindAll("nonce").Single().Value);
                AssertTsAndJwkClaims(provider, claims);

                Assert.IsFalse(claims.FindAll("m").Any());
                Assert.IsFalse(claims.FindAll("u").Any());
                Assert.IsFalse(claims.FindAll("p").Any());
            }
        }
예제 #26
0
        public async Task ClientCreds_NonExpired_NeedsRefresh_AADInvalidResponse_Async()
        {
            bool wasErrorLogged = false;

            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app");
                ConfidentialClientApplication app = SetupCca(harness, LocalLogCallback);

                Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed");

                UpdateATWithRefreshOn(app.AppTokenCacheInternal.Accessor);

                TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess();

                Trace.WriteLine("3. Configure AAD to respond with the typical Invalid Grant error");
                harness.HttpManager.AddAllMocks(TokenResponseType.InvalidGrant);

                // Act
                await app.AcquireTokenForClient(TestConstants.s_scope)
                .ExecuteAsync()
                .ConfigureAwait(false);

                Assert.IsTrue(YieldTillSatisfied(() => wasErrorLogged == true));
                cacheAccess.WaitTo_AssertAcessCounts(1, 0);
            }

            void LocalLogCallback(LogLevel level, string message, bool containsPii)
            {
                if (level == LogLevel.Error &&
                    message.Contains(BackgroundFetch_Failed))
                {
                    wasErrorLogged = true;
                }
            }
        }
 /// <summary>
 /// Generate a certificate. Create a Confidential Client Application with that certificate and
 /// an AcquireTokenForClient call to benchmark.
 /// </summary>
 public CryptoManagerTests()
 {
     _httpManager = new MockHttpManager();
     _httpManager.MessageHandlerFunc = () => new MockHttpMessageHandler()
     {
         ExpectedMethod  = HttpMethod.Post,
         ResponseMessage = MockHelpers.CreateSuccessfulClientCredentialTokenResponseMessage()
     };
     _requests = new AcquireTokenForClientParameterBuilder[AppsCount];
     for (int i = 0; i < AppsCount; i++)
     {
         X509Certificate2 certificate = CreateCertificate("CN=rsa2048", RSA.Create(2048), HashAlgorithmName.SHA256, null);
         _cca = ConfidentialClientApplicationBuilder
                .Create(TestConstants.ClientId)
                .WithAuthority(new Uri(TestConstants.AuthorityTestTenant))
                .WithRedirectUri(TestConstants.RedirectUri)
                .WithCertificate(certificate)
                .WithHttpManager(_httpManager)
                .BuildConcrete();
         AddHostToInstanceCache(_cca.ServiceBundle, TestConstants.ProductionPrefNetworkEnvironment);
         _requests[_requestIdx] = _cca.AcquireTokenForClient(TestConstants.s_scope)
                                  .WithForceRefresh(true);
     }
 }
예제 #28
0
        public async Task CacheKey_Includes_POPKid_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                ConfidentialClientApplication app =
                    ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                    .WithClientSecret(TestConstants.ClientSecret)
                    .WithHttpManager(httpManager)
                    .WithExperimentalFeatures(true)
                    .BuildConcrete();
                var testTimeService = new TestTimeService();
                PoPProviderFactory.TimeService = testTimeService;

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl));
                var popConfig   = new PoPAuthenticationConfiguration(request);
                var cacheAccess = app.AppTokenCache.RecordAccess();

                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                Trace.WriteLine("1. AcquireTokenForClient ");
                var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                             .WithAuthority(TestConstants.AuthorityUtidTenant)
                             .WithProofOfPossession(popConfig)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                // Assert
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                string expectedKid    = GetKidFromJwk(PoPProviderFactory.GetOrCreateProvider().CannonicalPublicKeyJwk);
                string actualCacheKey = cacheAccess.LastBeforeAccessNotificationArgs.SuggestedCacheKey;
                Assert.AreEqual(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "{0}{1}_{2}_AppTokenCache",
                        expectedKid,
                        TestConstants.ClientId,
                        TestConstants.Utid),
                    actualCacheKey);

                // Arrange - force a new key by moving to the future
                (PoPProviderFactory.TimeService as TestTimeService).MoveToFuture(
                    PoPProviderFactory.KeyRotationInterval.Add(TimeSpan.FromMinutes(10)));

                httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop");

                // Act
                Trace.WriteLine("1. AcquireTokenForClient again, after time passes - expect POP key rotation");
                result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                         .WithAuthority(TestConstants.AuthorityUtidTenant)
                         .WithProofOfPossession(popConfig)
                         .ExecuteAsync()
                         .ConfigureAwait(false);

                // Assert
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                string expectedKid2    = GetKidFromJwk(PoPProviderFactory.GetOrCreateProvider().CannonicalPublicKeyJwk);
                string actualCacheKey2 = cacheAccess.LastBeforeAccessNotificationArgs.SuggestedCacheKey;
                Assert.AreEqual(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "{0}{1}_{2}_AppTokenCache",
                        expectedKid2,
                        TestConstants.ClientId,
                        TestConstants.Utid),
                    actualCacheKey2);

                Assert.AreNotEqual(actualCacheKey, actualCacheKey2);
            }
        }
예제 #29
0
        public async Task RefreshReasonExpired_ConfidentialClient_Async()
        {
            using (var harness = CreateTestHarness())
            {
                #region ClientCredential
                harness.HttpManager.AddInstanceDiscoveryMockHandler();
                harness.HttpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();
                harness.HttpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();

                ConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                                                    .WithAuthority(new Uri(ClientApplicationBase.DefaultAuthority), false)
                                                    .WithRedirectUri(TestConstants.RedirectUri)
                                                    .WithClientSecret(TestConstants.ClientSecret)
                                                    .WithHttpManager(harness.HttpManager)
                                                    .BuildConcrete();

                // Act - AcquireTokenForClient returns result from IDP. Refresh reason is no access tokens.
                AuthenticationResult result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                Assert.AreEqual(CacheRefreshReason.NoCachedAccessToken, result.AuthenticationResultMetadata.CacheRefreshReason);

                //expire access tokens
                TokenCacheHelper.ExpireAllAccessTokens(cca.AppTokenCacheInternal);

                // Act - AcquireTokenForClient returns result from IDP because token is expired.
                result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                Assert.AreEqual(CacheRefreshReason.Expired, result.AuthenticationResultMetadata.CacheRefreshReason);

                // Act - AcquireTokenForClient returns result from Cache. Refresh reason is not applicable.
                result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray())
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
                Assert.AreEqual(CacheRefreshReason.NotApplicable, result.AuthenticationResultMetadata.CacheRefreshReason);
                #endregion

                #region ObBehalfOf
                harness.HttpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();
                harness.HttpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();

                // Act - AcquireTokenForClient returns result from IDP. Refresh reason is no access tokens.
                result = await cca.AcquireTokenOnBehalfOf(TestConstants.s_scope.ToArray(), new UserAssertion(TestConstants.UserAssertion))
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                Assert.AreEqual(CacheRefreshReason.NoCachedAccessToken, result.AuthenticationResultMetadata.CacheRefreshReason);

                //expire access tokens
                TokenCacheHelper.ExpireAllAccessTokens(cca.UserTokenCacheInternal);

                // Act - AcquireTokenOnBehalfOf returns result from IDP because access token is expired.
                result = await cca.AcquireTokenOnBehalfOf(TestConstants.s_scope.ToArray(), new UserAssertion(TestConstants.UserAssertion))
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                Assert.AreEqual(CacheRefreshReason.Expired, result.AuthenticationResultMetadata.CacheRefreshReason);

                // Act - AcquireTokenOnBehalfOf returns result from cache. Refresh reason is not applicable.
                result = await cca.AcquireTokenOnBehalfOf(TestConstants.s_scope.ToArray(), new UserAssertion(TestConstants.UserAssertion))
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
                Assert.AreEqual(CacheRefreshReason.NotApplicable, result.AuthenticationResultMetadata.CacheRefreshReason);
                #endregion
            }
        }
        public async Task ClientCreds_Expired_NeedsRefresh_AADInvalidResponse_Async()
        {
            // Arrange
            using (MockHttpAndServiceBundle harness = base.CreateTestHarness())
            {
                Trace.WriteLine("1. Setup an app with a token cache with one AT");
                ConfidentialClientApplication app = SetupCca(harness);

                Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed, but is also expired");
                UpdateATWithRefreshOn(app.AppTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1), true);
                TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess();

                Trace.WriteLine("3. Configure AAD to be unavaiable");
                AddHttpMocks(TokenResponseType.Invalid_AADUnavailable, harness.HttpManager, pca: false);

                // Act
                MsalServiceException ex = await AssertException.TaskThrowsAsync <MsalServiceException>(() => app
                                                                                                       .AcquireTokenForClient(TestConstants.s_scope)
                                                                                                       .ExecuteAsync())
                                          .ConfigureAwait(false);

                Assert.IsFalse(ex is MsalUiRequiredException, "5xx exceptions do not translate to MsalUIRequired");
                Assert.AreEqual(504, ex.StatusCode);
                cacheAccess.AssertAccessCounts(1, 0);
            }
        }