// Triggered right before ADAL needs to access the cache. // Reload the cache from the persistent store in case it changed since the last access. void BeforeAccessNotification(TokenCacheNotificationArgs args) { lock (FileLock) { this.Deserialize(File.Exists(CacheFilePath) ? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath), null, DataProtectionScope.CurrentUser) : null); } }
// Triggered right after ADAL accessed the cache. void AfterAccessNotification(TokenCacheNotificationArgs args) { // if the access operation resulted in a cache update if (this.HasStateChanged) { lock (FileLock) { // reflect changes in the persistent store File.WriteAllBytes(CacheFilePath, ProtectedData.Protect(this.Serialize(), null, DataProtectionScope.CurrentUser)); // once the write operation took place, restore the HasStateChanged bit to false this.HasStateChanged = false; } } }
private void AfterAdalAccess(TokenCacheNotificationArgs args) { this.OnAfterAccess(new CredentialCacheNotificationArgs { CredentialCache = this }); }
internal TokenCacheRefreshArgs(TokenCacheNotificationArgs args) { SuggestedCacheKey = args.SuggestedCacheKey; }
/// <summary> /// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry /// </summary> /// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param> private void UserTokenCacheBeforeWriteNotification(TokenCacheNotificationArgs args) { // Since we obtain and release lock right before and after we read the Http session, we need not do anything here. }
private void BeforeWriteNotification(TokenCacheNotificationArgs args) { System.Diagnostics.Debug.WriteLine($"BeforeWriteNotification for {User}"); }
private static async Task RunConsoleAppLogicAsync( IPublicClientApplication pca, IConfidentialClientApplication cca) { while (true) { Console.Clear(); Console.WriteLine("Authority: " + GetAuthority()); await DisplayAccountsAsync(pca).ConfigureAwait(false); // display menu Console.WriteLine(@" 1. IWA 2. Acquire Token with Username and Password 3. Acquire Token with Device Code 4. Acquire Token Interactive 5. Acquire Token Interactive via NetStandard lib 6. Acquire Token Silently 7. Acquire Token Silently - multiple requests in parallel 8. Acquire SSH Cert Interactive 9. Client Credentials c. Clear cache r. Rotate Tenant ID e. Expire all ATs x. Exit app Enter your Selection: "); char.TryParse(Console.ReadLine(), out var selection); Task <AuthenticationResult> authTask = null; try { switch (selection) { case '1': // acquire token authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '2': // acquire token u/p SecureString password = GetPasswordFromConsole(); authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '3': authTask = pca.AcquireTokenWithDeviceCode( s_scopes, deviceCodeResult => { Console.WriteLine(deviceCodeResult.Message); return(Task.FromResult(0)); }).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '4': authTask = pca.AcquireTokenInteractive(s_scopes) .WithPrompt(Prompt.Consent) .ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '6': // acquire token silent IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault(); if (account == null) { Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false); } authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '7': // acquire token silent - one request per IAccount var accounts = await pca.GetAccountsAsync().ConfigureAwait(false); Task <AuthenticationResult>[] tasks = accounts .Select(acc => pca.AcquireTokenSilent(s_scopes, acc).ExecuteAsync()) .ToArray(); AuthenticationResult[] result = await Task.WhenAll(tasks).ConfigureAwait(false); foreach (var ar in result) { Console.BackgroundColor = ConsoleColor.DarkGreen; Console.WriteLine($"Got a token for {ar.Account.Username} "); Console.ResetColor(); } break; case '5': // Acquire Token Interactive via NetStandard lib CancellationTokenSource cts2 = new CancellationTokenSource(); var authenticator = new NetStandardAuthenticator(Log, UserCacheFile); await FetchTokenAndCallGraphAsync(pca, authenticator.GetTokenInteractiveAsync(cts2.Token)).ConfigureAwait(false); break; case '8': // acquire SSH cert RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); RSAParameters rsaKeyInfo = rsa.ExportParameters(false); string modulus = Base64UrlHelpers.Encode(rsaKeyInfo.Modulus); string exp = Base64UrlHelpers.Encode(rsaKeyInfo.Exponent); string jwk = $"{{\"kty\":\"RSA\", \"n\":\"{modulus}\", \"e\":\"{exp}\"}}"; CancellationTokenSource cts = new CancellationTokenSource(); authTask = pca.AcquireTokenInteractive(s_scopes) .WithUseEmbeddedWebView(false) .WithExtraQueryParameters(new Dictionary <string, string>() { { "dc", "prod-wst-test1" }, { "slice", "test" }, { "sshcrt", "true" } }) .WithSSHCertificateAuthenticationScheme(jwk, "1") .WithSystemWebViewOptions(new SystemWebViewOptions() { HtmlMessageSuccess = "All good, close the browser!", OpenBrowserAsync = SystemWebViewOptions.OpenWithEdgeBrowserAsync }) .ExecuteAsync(cts.Token); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '9': authTask = cca.AcquireTokenForClient( new[] { "https://graph.microsoft.com/.default" }). ExecuteAsync(); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case 'c': var accounts2 = await pca.GetAccountsAsync().ConfigureAwait(false); foreach (var acc in accounts2) { await pca.RemoveAsync(acc).ConfigureAwait(false); } break; case 'r': // rotate tid s_currentTid = (s_currentTid + 1) % s_tids.Length; pca = CreatePca(); cca = CreateCca(); RunConsoleAppLogicAsync(pca, cca).Wait(); break; case 'e': // expire all ATs var tokenCacheInternal = pca.UserTokenCache as ITokenCacheInternal; var ats = tokenCacheInternal.Accessor.GetAllAccessTokens(); // set access tokens as expired foreach (var accessItem in ats) { accessItem.ExpiresOnUnixTimestamp = ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds) .ToString(CultureInfo.InvariantCulture); tokenCacheInternal.Accessor.SaveAccessToken(accessItem); } TokenCacheNotificationArgs args = new TokenCacheNotificationArgs( pca.UserTokenCache as ITokenCacheInternal, s_clientIdForPublicApp, null, true); await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false); break; case 'x': return; default: break; } } catch (Exception ex) { Log(LogLevel.Error, ex.Message, false); Log(LogLevel.Error, ex.StackTrace, false); } Console.WriteLine("\n\nHit 'ENTER' to continue..."); Console.ReadLine(); } }
// Triggered right before ADAL needs to access the cache. // Reload the cache from the persistent store in case it changed since the last access. void BeforeAccessNotification(TokenCacheNotificationArgs args) { ReadFileIntoCache(); }
public static void AfterAccess(TokenCacheNotificationArgs args) { // Default implementation, do nothing }
public void OnBeforeWrite(TokenCacheNotificationArgs args) { // NO OP }
void BeforeWriteNotification(TokenCacheNotificationArgs args) { // si quieres asegurarte de que no se produce ninguna escritura concurrente, utiliza esta notificación para bloquear la entrada }
private static CacheSerializerHints CreateHintsFromArgs(TokenCacheNotificationArgs args) { return(new CacheSerializerHints { CancellationToken = args.CancellationToken }); }
private void BeforeAccessHandler(TokenCacheNotificationArgs args) { Load(); }
public void MultiAccessSerializationAsync() { var cache1 = new MockTokenCache(); var helper1 = new MsalCacheHelper( cache1, new MsalCacheStorage(s_storageCreationProperties, _logger), _logger); var cache2 = new MockTokenCache(); var helper2 = new MsalCacheHelper( cache2, new MsalCacheStorage(s_storageCreationProperties, _logger), _logger); //Test signalling thread 1 var resetEvent1 = new ManualResetEvent(initialState: false); //Test signalling thread 2 var resetEvent2 = new ManualResetEvent(initialState: false); //Thread 1 signalling test var resetEvent3 = new ManualResetEvent(initialState: false); // Thread 2 signalling test var resetEvent4 = new ManualResetEvent(initialState: false); var thread1 = new Thread(() => { var args = new TokenCacheNotificationArgs { TokenCache = cache1 }; helper1.BeforeAccessNotification(args); resetEvent3.Set(); resetEvent1.WaitOne(); helper1.AfterAccessNotification(args); }); var thread2 = new Thread(() => { var args = new TokenCacheNotificationArgs { TokenCache = cache2 }; helper2.BeforeAccessNotification(args); resetEvent4.Set(); resetEvent2.WaitOne(); helper2.AfterAccessNotification(args); resetEvent4.Set(); }); // Let thread 1 start and get the lock thread1.Start(); resetEvent3.WaitOne(); // Start thread 2 and give it enough time to get blocked on the lock thread2.Start(); Thread.Sleep(5000); // Make sure helper1 has the lock still, and helper2 doesn't Assert.IsNotNull(helper1.CacheLock); Assert.IsNull(helper2.CacheLock); // Allow thread1 to give up the lock, and wait for helper2 to get it resetEvent1.Set(); resetEvent4.WaitOne(); resetEvent4.Reset(); // Make sure helper1 gave it up properly, and helper2 now owns the lock Assert.IsNull(helper1.CacheLock); Assert.IsNotNull(helper2.CacheLock); // Allow thread2 to give up the lock, and wait for it to complete resetEvent2.Set(); resetEvent4.WaitOne(); // Make sure thread2 cleaned up after itself as well Assert.IsNull(helper2.CacheLock); }
public async Task ThreeRegisteredCachesRemainInSyncTestAsync() { if (File.Exists(s_storageCreationProperties.CacheFilePath)) { File.Delete(s_storageCreationProperties.CacheFilePath); } var helper = await MsalCacheHelper.CreateAsync(s_storageCreationProperties).ConfigureAwait(true); helper._cacheWatcher.EnableRaisingEvents = false; // Intentionally write the file after creating the MsalCacheHelper to avoid the initial inner PCA being created only to read garbage string startString = "Something to start with"; var startBytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(startString), optionalEntropy: null, scope: DataProtectionScope.CurrentUser); await File.WriteAllBytesAsync(s_storageCreationProperties.CacheFilePath, startBytes).ConfigureAwait(true); var cache1 = new MockTokenCache(); var cache2 = new MockTokenCache(); var cache3 = new MockTokenCache(); helper.RegisterCache(cache1); helper.RegisterCache(cache2); helper.RegisterCache(cache3); var storeVersion0 = helper._store.LastVersionToken; // One call from register Assert.AreEqual(1, cache1.DeserializeMsalV3_MergeCache); Assert.AreEqual(1, cache2.DeserializeMsalV3_MergeCache); Assert.AreEqual(1, cache3.DeserializeMsalV3_MergeCache); Assert.AreEqual(startString, cache1.LastDeserializedString); Assert.AreEqual(startString, cache2.LastDeserializedString); Assert.AreEqual(startString, cache3.LastDeserializedString); var args1 = new TokenCacheNotificationArgs { TokenCache = cache1 }; var args2 = new TokenCacheNotificationArgs { TokenCache = cache2 }; var args3 = new TokenCacheNotificationArgs { TokenCache = cache3 }; var changedString = "Hey look, the file changed"; helper.BeforeAccessNotification(args1); cache1.LastDeserializedString = changedString; args1.HasStateChanged = true; helper.AfterAccessNotification(args1); // Note: Here, we haven't yet read anything in, so helper._store.LastVersionToken is out of date. // Validate that we at least have updated the version of the cache that was serialized. var cache1Version = helper._registeredCaches[cache1]; Assert.AreNotEqual(storeVersion0, cache1Version); helper.BeforeAccessNotification(args2); helper.AfterAccessNotification(args2); var storeVersion1 = helper._store.LastVersionToken; Assert.AreEqual(cache1Version, storeVersion1); helper.BeforeAccessNotification(args3); helper.AfterAccessNotification(args3); var storeVersion2 = helper._store.LastVersionToken; Assert.AreEqual(storeVersion1, storeVersion2); // Still only one call from register Assert.AreEqual(1, cache1.DeserializeMsalV3_MergeCache); Assert.AreEqual(1, cache2.DeserializeMsalV3_MergeCache); Assert.AreEqual(1, cache3.DeserializeMsalV3_MergeCache); // Cache 1 shouldn't need to deserialize because it wrote the new data. Assert.AreEqual(0, cache1.DeserializeMsalV3_ClearCache); // Caches 2 and three should need to deserialize Assert.AreEqual(1, cache2.DeserializeMsalV3_ClearCache); Assert.AreEqual(1, cache3.DeserializeMsalV3_ClearCache); Assert.AreEqual(changedString, cache1.LastDeserializedString); Assert.AreEqual(changedString, cache2.LastDeserializedString); Assert.AreEqual(changedString, cache3.LastDeserializedString); File.Delete(s_storageCreationProperties.CacheFilePath); File.Delete(s_storageCreationProperties.CacheFilePath + ".version"); }
private static async Task RunConsoleAppLogicAsync(IPublicClientApplication pca) { while (true) { Console.Clear(); Console.WriteLine("Authority: " + GetAuthority()); await DisplayAccountsAsync(pca).ConfigureAwait(false); // display menu Console.WriteLine(@" 1. IWA 2. Acquire Token with Username and Password 3. Acquire Token with Device Code 4. Acquire Token Interactive 5. Acquire Token Interactive via NetStandard lib 6. Acquire Token Silently 7. Acquire Token Silently - multiple requests in parallel 8. Clear cache 9. Rotate Tenant ID 0. Expire all ATs x. Exit app Enter your Selection: "); char.TryParse(Console.ReadLine(), out var selection); Task <AuthenticationResult> authTask = null; try { switch (selection) { case '1': // acquire token authTask = pca.AcquireTokenByIntegratedWindowsAuth(s_scopes).WithUsername(s_username).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '2': // acquire token u/p SecureString password = GetPasswordFromConsole(); authTask = pca.AcquireTokenByUsernamePassword(s_scopes, s_username, password).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '3': authTask = pca.AcquireTokenWithDeviceCode( s_scopes, deviceCodeResult => { Console.WriteLine(deviceCodeResult.Message); return(Task.FromResult(0)); }).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '4': // acquire token interactive CancellationTokenSource cts = new CancellationTokenSource(); authTask = pca.AcquireTokenInteractive(s_scopes) .WithUseEmbeddedWebView(false) .WithSystemWebViewOptions(new SystemWebViewOptions() { //BrowserRedirectSuccess = new Uri("https://www.google.com"), HtmlMessageSuccess = "All good, close the browser!", //OpenBrowserAsync = (Uri u) => //{ // string url = u.AbsoluteUri; // url = url.Replace("&", "^&"); // Process.Start(new ProcessStartInfo("cmd", $"/c start msedge {url}") { CreateNoWindow = true }); // return Task.FromResult(0); //} OpenBrowserAsync = SystemWebViewOptions.OpenWithEdgeBrowserAsync }) .ExecuteAsync(cts.Token); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '6': // acquire token silent IAccount account = pca.GetAccountsAsync().Result.FirstOrDefault(); if (account == null) { Log(LogLevel.Error, "Test App Message - no accounts found, AcquireTokenSilentAsync will fail... ", false); } authTask = pca.AcquireTokenSilent(s_scopes, account).ExecuteAsync(CancellationToken.None); await FetchTokenAndCallGraphAsync(pca, authTask).ConfigureAwait(false); break; case '7': // acquire token silent - one request per IAccount var accounts = await pca.GetAccountsAsync().ConfigureAwait(false); Task <AuthenticationResult>[] tasks = accounts .Select(acc => pca.AcquireTokenSilent(s_scopes, acc).ExecuteAsync()) .ToArray(); AuthenticationResult[] result = await Task.WhenAll(tasks).ConfigureAwait(false); foreach (var ar in result) { Console.BackgroundColor = ConsoleColor.DarkGreen; Console.WriteLine($"Got a token for {ar.Account.Username} "); Console.ResetColor(); } break; case '5': // Acquire Token Interactive via NetStandard lib CancellationTokenSource cts2 = new CancellationTokenSource(); var authenticator = new NetStandardAuthenticator(Log, CacheFilePath); await FetchTokenAndCallGraphAsync(pca, authenticator.GetTokenInteractiveAsync(cts2.Token)).ConfigureAwait(false); break; case '8': var accounts2 = await pca.GetAccountsAsync().ConfigureAwait(false); foreach (var acc in accounts2) { await pca.RemoveAsync(acc).ConfigureAwait(false); } break; case '9': s_currentTid = (s_currentTid + 1) % s_tids.Length; pca = CreatePca(); RunConsoleAppLogicAsync(pca).Wait(); break; case '0': var tokenCacheInternal = pca.UserTokenCache as ITokenCacheInternal; var ats = tokenCacheInternal.Accessor.GetAllAccessTokens(); // set access tokens as expired foreach (var accessItem in ats) { accessItem.ExpiresOnUnixTimestamp = ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds) .ToString(CultureInfo.InvariantCulture); tokenCacheInternal.Accessor.SaveAccessToken(accessItem); } TokenCacheNotificationArgs args = new TokenCacheNotificationArgs( pca.UserTokenCache as ITokenCacheInternal, s_clientIdForPublicApp, null, true); await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false); break; case 'x': return; default: break; } } catch (Exception ex) { Log(LogLevel.Error, ex.Message, false); Log(LogLevel.Error, ex.StackTrace, false); } Console.WriteLine("\n\nHit 'ENTER' to continue..."); Console.ReadLine(); } }
// Triggered right before ADAL needs to access the cache. // Reload the cache from the persistent store in case it changed since the last access. void BeforeAccessNotification(TokenCacheNotificationArgs args) { Load(); }
private Task BeforeAccessTokenHandler(TokenCacheNotificationArgs arg) { byte[] dataFromStream = File.Exists(_fileCacheLocation) ? File.ReadAllBytes(_fileCacheLocation) : null; arg.TokenCache.DeserializeMsalV3(dataFromStream); return(Task.CompletedTask); }
private void BeforeAccessNotification(TokenCacheNotificationArgs args) { Deserialize(_cache.Get(GetCacheKey())); }
private static void DoBefore(TokenCacheNotificationArgs args) { _count++; }
// Triggered right after ADAL accessed the cache. void AfterAccessNotification(TokenCacheNotificationArgs args) { // if the access operation resulted in a cache update EnsureStateSaved(); }
private static void DoAfter(TokenCacheNotificationArgs args) { Assert.AreEqual(1, _count); _count--; }
// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry protected virtual Task OnBeforeWriteAsync(TokenCacheNotificationArgs args) { return(Task.CompletedTask); }
/// <summary> /// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry /// </summary> /// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param> private void AppTokenCacheBeforeWriteNotification(TokenCacheNotificationArgs args) { // Since we are using a MemoryCache ,whose methods are threads safe, we need not to do anything in this handler. }
private void AfterAccessNoChangeNotification(TokenCacheNotificationArgs args) { Assert.IsFalse(args.HasStateChanged); }
/// <summary> /// Triggered right before MSAL needs to access the cache. Reload the cache from the persistence store in case it changed since the last access. /// </summary> /// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param> private void AppTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) { // Load the token cache from memory byte[] tokenCacheBytes = (byte[])this.memoryCache.Get(args.SuggestedCacheKey); args.TokenCache.DeserializeMsalV3(tokenCacheBytes, shouldClearExistingCache: true); }
// Triggered right before MSAL needs to access the cache. // Reload the cache from the persistent store in case it changed since the last access. void BeforeAccessNotification(TokenCacheNotificationArgs args) { Load(); }
private void BeforeCacheAccess(TokenCacheNotificationArgs args) { args.TokenCache.DeserializeMsalV3(_serializedCache); }
void BeforeWriteNotification(TokenCacheNotificationArgs args) { // if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry }
private void AfterCacheAccess(TokenCacheNotificationArgs args) { _serializedCache = args.TokenCache.SerializeMsalV3(); }
private void BeforeAdalWrite(TokenCacheNotificationArgs args) { this.OnBeforeWrite(new CredentialCacheNotificationArgs { CredentialCache = this }); }
private void UserTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) { LoadUserTokenCacheFromMemory(args); }
private void AppTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args) { args.TokenCache.DeserializeMsalV3(appTokenCache); }
private void UserTokenCacheBeforeWriteNotification(TokenCacheNotificationArgs args) { }
// Triggered right after ADAL accessed the cache. void AfterAccessNotification(TokenCacheNotificationArgs args) { // if the access operation resulted in a cache update if (this.HasStateChanged) { Persist(); } }
// Triggered right before ADAL needs to access the cache. private void BeforeAccessNotification(TokenCacheNotificationArgs args) { // Reload the cache from the persistent store in case it changed since the last access. Load(); }