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); }
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); }
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); } }
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); } }
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); } }
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; }
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)); }
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; }
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 } }
// 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); }
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); }
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); } } }
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); }
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); }
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; }
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()); } }
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); } }
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); } }
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); } }