public override async ValueTask <AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) { bool uiRequired = false; if (_account != null) { try { var result = await _app.AcquireTokenSilent(requestContext.Scopes, _account) .ExecuteAsync(cancellationToken); return(new AccessToken(result.AccessToken, result.ExpiresOn)); } catch (MsalUiRequiredException) { // will be handled lower uiRequired = true; } } // we give the lock a total wait time of 1 hour because the breakpoint to do device code authentication is inside the lock using (await SentinelFileLock.AcquireAsync(DeviceCodeLockPath, 3600, TimeSpan.FromMilliseconds(1000))) { _account = (await _app.GetAccountsAsync()).FirstOrDefault(); if (_account == null || uiRequired) { var deviceCodeResult = await _app.AcquireTokenWithDeviceCode(requestContext.Scopes, DeviceCodeResultCallback) .ExecuteAsync(cancellationToken); _account = deviceCodeResult.Account; return(new AccessToken(deviceCodeResult.AccessToken, deviceCodeResult.ExpiresOn)); } } // a recursive call here is fine because there wasn't any better way to do this, and this is local dev only // This return statement will only get executed when `_account` was null at the top of the method, // and it becomes non-null at line 91 // When that happens the function will either return the access token from AcquireTokenSilentAsync, // or will hit the `uiRequired` branch and call AcquireTokenWithDeviceCode and return return(await GetTokenAsync(requestContext, cancellationToken)); }
private static async Task OnAfterAccessAsync(TokenCacheNotificationArgs arg) { using (await SentinelFileLock.AcquireAsync(CacheLockPath, 100, TimeSpan.FromMilliseconds(600))) { _lastReadTime = default; var bytes = arg.TokenCache.SerializeMsalV3(); var protectedBytes = ProtectedData.Protect(bytes, null, DataProtectionScope.LocalMachine); var info = new FileInfo(CacheFilePath); if (!info.Exists) { if (!IsBoostrapping) { throw new InvalidOperationException("Token Cache File Not Found, Please re-run boostrap."); } try { using (info.Create()) { } } catch { } var sec = new FileSecurity(); sec.SetAccessRuleProtection(true, false); sec.AddAccessRule(new FileSystemAccessRule(ConfigurationConstants.ConfigurationAccessGroupName, FileSystemRights.FullControl, AccessControlType.Allow)); sec.AddAccessRule(new FileSystemAccessRule("Administrators", FileSystemRights.FullControl, AccessControlType.Allow)); info.SetAccessControl(sec); using (FileStream stream = info.OpenWrite()) { stream.Write(protectedBytes); } } else { using (var stream = info.OpenWrite()) { stream.Write(protectedBytes); } } } }
private static async Task OnBeforeAccessAsync(TokenCacheNotificationArgs arg) { var ts = File.GetLastWriteTimeUtc(CacheFilePath); if (File.Exists(CacheFilePath) && _lastReadTime < ts) { try { using (await SentinelFileLock.AcquireAsync(CacheLockPath, 100, TimeSpan.FromMilliseconds(600))) { var protectedBytes = await File.ReadAllBytesAsync(CacheFilePath); var bytes = ProtectedData.Unprotect(protectedBytes, null, DataProtectionScope.LocalMachine); _lastReadTime = ts; arg.TokenCache.DeserializeMsalV3(bytes, false); } } catch (CryptographicException) { // Unable to deserialize, just treat it as if the file is gone } } }