private static MsalCacheHelper CreateCacheHelperAsync(string clientId) { StorageCreationProperties storageProperties; try { storageProperties = new StorageCreationPropertiesBuilder( "cache.plaintext", System.AppContext.BaseDirectory, clientId) .WithLinuxUnprotectedFile() .Build(); var cacheHelper = MsalCacheHelper.CreateAsync(storageProperties).Result; return(cacheHelper); } catch (MsalCachePersistenceException e) { storageProperties = new StorageCreationPropertiesBuilder( "cache.plaintext", System.AppContext.BaseDirectory, clientId) .WithLinuxUnprotectedFile() .Build(); var cacheHelper = MsalCacheHelper.CreateAsync(storageProperties).Result; cacheHelper.VerifyPersistence(); return(cacheHelper); } }
private async Task RegisterTokenCacheAsync(IPublicClientApplication app) { Context.Trace.WriteLine( "Configuring Microsoft Authentication token cache to instance shared with Microsoft developer tools..."); if (!PlatformUtils.IsWindows() && !PlatformUtils.IsPosix()) { string osType = PlatformUtils.GetPlatformInformation().OperatingSystemType; Context.Trace.WriteLine($"Token cache integration is not supported on {osType}."); return; } // We use the MSAL extension library to provide us consistent cache file access semantics (synchronisation, etc) // as other Microsoft developer tools such as the Azure PowerShell CLI. MsalCacheHelper helper = null; try { var storageProps = CreateTokenCacheProps(useLinuxFallback: false); helper = await MsalCacheHelper.CreateAsync(storageProps); // Test that cache access is working correctly helper.VerifyPersistence(); } catch (MsalCachePersistenceException ex) { Context.Streams.Error.WriteLine("warning: cannot persist Microsoft authentication token cache securely!"); Context.Trace.WriteLine("Cannot persist Microsoft Authentication data securely!"); Context.Trace.WriteException(ex); if (PlatformUtils.IsMacOS()) { // On macOS sometimes the Keychain returns the "errSecAuthFailed" error - we don't know why // but it appears to be something to do with not being able to access the keychain. // Locking and unlocking (or restarting) often fixes this. Context.Streams.Error.WriteLine( "warning: there is a problem accessing the login Keychain - either manually lock and unlock the " + "login Keychain, or restart the computer to remedy this"); } else if (PlatformUtils.IsLinux()) { // On Linux the SecretService/keyring might not be available so we must fall-back to a plaintext file. Context.Streams.Error.WriteLine("warning: using plain-text fallback token cache"); Context.Trace.WriteLine("Using fall-back plaintext token cache on Linux."); var storageProps = CreateTokenCacheProps(useLinuxFallback: true); helper = await MsalCacheHelper.CreateAsync(storageProps); } } if (helper is null) { Context.Streams.Error.WriteLine("error: failed to set up Microsoft Authentication token cache!"); Context.Trace.WriteLine("Failed to integrate with shared token cache!"); } else { helper.RegisterCache(app.UserTokenCache); Context.Trace.WriteLine("Microsoft developer tools token cache configured."); } }
public async Task <AcquireTokenResult> AcquireTokenAsync() { var app = PublicClientApplicationBuilder.Create(_clientId).WithTenantId(_tenantId).WithDefaultRedirectUri().Build(); var storageCreationProperties = new StorageCreationPropertiesBuilder("tokenCache.dat", ".", _clientId).Build(); (await MsalCacheHelper.CreateAsync(storageCreationProperties)).RegisterCache(app.UserTokenCache); var account = await GetAccountAsync(app); AuthenticationResult authenticationResult; try { authenticationResult = await app.AcquireTokenSilent(_scopes, account).ExecuteAsync(); } catch (MsalUiRequiredException) { authenticationResult = await app.AcquireTokenWithDeviceCode(_scopes, deviceCodeResult => { Console.WriteLine(deviceCodeResult.Message); return(deviceCodeResult.VerificationUrl == null ? Task.CompletedTask : OpenBrowserAsync(deviceCodeResult.VerificationUrl)); }).ExecuteAsync(); } return(new AcquireTokenResult(authenticationResult.AccessToken, ExtractObjectId(authenticationResult.IdToken))); }
public async Task StartAsync(CancellationToken cancellationToken) { // Initialize services that you need before app activation await InitializeAsync(); // https://aka.ms/msal-net-token-cache-serialization // this generates a file-system safe directory name to stick the cache in - or use something like Resources.AppDisplayName // should also consider this root dir for other configuration data var safeAppDirectoryName = System.IO.Path.GetInvalidFileNameChars().Aggregate(typeof(App).Assembly.GetName().Name, (current, c) => current.Replace(c, '-')); var rootCacheDirectory = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), safeAppDirectoryName, _config.IdentityCacheDirectoryName); var storageCreationProperties = new StorageCreationPropertiesBuilder(_config.IdentityCacheFileName, rootCacheDirectory, _config.IdentityClientId).Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageCreationProperties).ConfigureAwait(false); _identityService.InitializeWithAadAndPersonalMsAccounts(_config.IdentityClientId, "http://localhost", cacheHelper); var silentLoginSuccess = await _identityService.AcquireTokenSilentAsync(); if (!silentLoginSuccess || !_identityService.IsAuthorized()) { _logInWindow = _serviceProvider.GetService(typeof(ILogInWindow)) as ILogInWindow; _logInWindow.ShowWindow(); await StartupAsync(); return; } _shellWindow = _serviceProvider.GetService(typeof(IShellWindow)) as IShellWindow; _navigationService.Initialize(_shellWindow.GetNavigationFrame()); _shellWindow.ShowWindow(); _navigationService.NavigateTo(typeof(MainViewModel).FullName); // Tasks after activation await StartupAsync(); }
public void TestInitialize() { var storageBuilder = new StorageCreationPropertiesBuilder( Path.GetFileName(CacheFilePath), Path.GetDirectoryName(CacheFilePath)); storageBuilder = storageBuilder.WithMacKeyChain( serviceName: "Microsoft.Developer.IdentityService.Test", accountName: "MSALCacheTest"); // unit tests run on Linux boxes without LibSecret storageBuilder.WithLinuxUnprotectedFile(); // 1. Use MSAL to create an instance of the Public Client Application var app = PublicClientApplicationBuilder.Create(ClientId) .Build(); // 3. Create the high level MsalCacheHelper based on properties and a logger _cacheHelper = MsalCacheHelper.CreateAsync( storageBuilder.Build(), new TraceSource("MSAL.CacheExtension.Test")) .GetAwaiter().GetResult(); // 4. Let the cache helper handle MSAL's cache _cacheHelper.RegisterCache(app.UserTokenCache); }
private async Task RegisterVisualStudioTokenCacheAsync(IPublicClientApplication app) { Context.Trace.WriteLine("Configuring Visual Studio token cache..."); // We currently only support Visual Studio on Windows if (PlatformUtils.IsWindows()) { // The Visual Studio MSAL cache is located at "%LocalAppData%\.IdentityService\msal.cache" on Windows. // We use the MSAL extension library to provide us consistent cache file access semantics (synchronisation, etc) // as Visual Studio itself follows, as well as other Microsoft developer tools such as the Azure PowerShell CLI. const string cacheFileName = "msal.cache"; string appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); string cacheDirectory = Path.Combine(appData, ".IdentityService"); var storageProps = new StorageCreationPropertiesBuilder(cacheFileName, cacheDirectory, app.AppConfig.ClientId).Build(); var helper = await MsalCacheHelper.CreateAsync(storageProps); helper.RegisterCache(app.UserTokenCache); Context.Trace.WriteLine("Visual Studio token cache configured."); } else { string osType = PlatformUtils.GetPlatformInformation().OperatingSystemType; Context.Trace.WriteLine($"Visual Studio token cache integration is not supported on {osType}."); } }
private async Task InitializeAsync() { ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(_options.ClientId).WithAuthority(_options.AuthorityHost.AbsoluteUri, _options.TenantId).WithHttpClientFactory(new HttpPipelineClientFactory(_options.Pipeline.HttpPipeline)); if (_options.Secret != null) { confClientBuilder.WithClientSecret(_options.Secret); } if (_options.CertificateProvider != null) { X509Certificate2 clientCertificate = await _options.CertificateProvider.GetCertificateAsync(true, default).ConfigureAwait(false); confClientBuilder.WithCertificate(clientCertificate); } _client = confClientBuilder.Build(); if (_options.AttachSharedCache) { StorageCreationProperties storageProperties = new StorageCreationPropertiesBuilder(Constants.DefaultMsalTokenCacheName, Constants.DefaultMsalTokenCacheDirectory, _options.ClientId) .WithMacKeyChain(Constants.DefaultMsalTokenCacheKeychainService, Constants.DefaultMsalTokenCacheKeychainAccount) .WithLinuxKeyring(Constants.DefaultMsalTokenCacheKeyringSchema, Constants.DefaultMsalTokenCacheKeyringCollection, Constants.DefaultMsalTokenCacheKeyringLabel, Constants.DefaultMsaltokenCacheKeyringAttribute1, Constants.DefaultMsaltokenCacheKeyringAttribute2) .Build(); MsalCacheHelper cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.RegisterCache(_client.UserTokenCache); } }
private static async ValueTask <MsalCacheHelper> CreateCacheHelper(StorageCreationProperties storageProperties, bool async) { return(async ? await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false) #pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. : MsalCacheHelper.CreateAsync(storageProperties).GetAwaiter().GetResult()); #pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. }
public MicrosoftAuthentication(TeamsPresencePublisherOptions options) { var storageProperties = new StorageCreationPropertiesBuilder("TeamsPresencePublisher.msalcache.bin", options.CacheFolder, ClientId) .Build(); _msalCacheHelper = MsalCacheHelper.CreateAsync(storageProperties).GetAwaiter().GetResult(); _publicClientApplication = BuildPublicClientApplication(); AuthProvider = new InteractiveAuthenticationProvider(_publicClientApplication, s_scopes); }
/// <summary> /// Calls MSAL to get authentication token with AAD. /// </summary> /// <returns></returns> /// <remarks>https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively</remarks> public async Task <VssCredentials> CreateVssCredentialsWithAadAsync() { // 1. Configuration var app = PublicClientApplicationBuilder .Create(VsoAadConstants.Client) .WithTenantId(VsoAadConstants.MicrosoftTenantId) .WithRedirectUri(VsoAadConstants.RedirectUri) .Build(); // 2. Token cache // https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=desktop // https://github.com/AzureAD/microsoft-authentication-extensions-for-dotnet/wiki/Cross-platform-Token-Cache var storageProperties = new StorageCreationPropertiesBuilder(m_tokenCacheFileName, m_tokenCacheDirectory).Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties); cacheHelper.RegisterCache(app.UserTokenCache); // 3. Try silent authentication var accounts = await app.GetAccountsAsync(); var scopes = new string[] { VsoAadConstants.Scope }; AuthenticationResult result = null; try { result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) .ExecuteAsync(); m_logger("[VssCredentialsFactory] Successfully acquired authentication token through silent AAD authentication."); } catch (MsalUiRequiredException) { // 4. Interactive Authentication m_logger("[VssCredentialsFactory] Unable to acquire authentication token through silent AAD authentication."); // On Windows, we can try Integrated Windows Authentication which will fallback to interactive auth if that fails result = OperatingSystemHelper.IsWindowsOS ? await CreateVssCredentialsWithAadForWindowsAsync(app, scopes) : await CreateVssCredentialsWithAadInteractiveAsync(app, scopes); } catch (Exception ex) { m_logger($"[VssCredentialsFactory] Unable to acquire credentials with AAD with the following exception: '{ex}'"); } if (result == null) { // Something went wrong during AAD auth, return null m_logger($"[VssCredentialsFactory] Unable to acquire AAD token."); return(new VssAadCredential()); } return(new VssAadCredential(new VssAadToken(VsoAadConstants.TokenType, result.AccessToken))); }
/// <summary> /// Helper function to initialize the token cache for non-UWP apps. MSAL handles this automatically on UWP. /// </summary> /// <param name="provider">The instance of <see cref="MsalProvider"/> to init the cache for.</param> /// <param name="storageProperties">Properties for configuring the storage cache.</param> /// <param name="logger">Passing null uses the default TraceSource logger.</param> /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns> public static async Task InitTokenCacheAsync( this MsalProvider provider, StorageCreationProperties storageProperties, TraceSource logger = null) { #if !WINDOWS_UWP // Token cache persistence (not required on UWP as MSAL does it for you) var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties, logger); cacheHelper.RegisterCache(provider.Client.UserTokenCache); #endif }
private async Task RegisterTokenCacheAsync(IPublicClientApplication app) { Context.Trace.WriteLine( "Configuring Microsoft Authentication token cache to instance shared with Microsoft developer tools..."); if (!PlatformUtils.IsWindows() && !PlatformUtils.IsPosix()) { string osType = PlatformUtils.GetPlatformInformation().OperatingSystemType; Context.Trace.WriteLine($"Token cache integration is not supported on {osType}."); return; } string clientId = app.AppConfig.ClientId; // We use the MSAL extension library to provide us consistent cache file access semantics (synchronisation, etc) // as other Microsoft developer tools such as the Azure PowerShell CLI. MsalCacheHelper helper = null; try { var storageProps = CreateTokenCacheProps(clientId, useLinuxFallback: false); helper = await MsalCacheHelper.CreateAsync(storageProps); // Test that cache access is working correctly helper.VerifyPersistence(); } catch (MsalCachePersistenceException ex) { Context.Streams.Error.WriteLine("warning: cannot persist Microsoft Authentication data securely!"); Context.Trace.WriteLine("Cannot persist Microsoft Authentication data securely!"); Context.Trace.WriteException(ex); // On Linux the SecretService/keyring might not be available so we must fall-back to a plaintext file. if (PlatformUtils.IsLinux()) { Context.Trace.WriteLine("Using fall-back plaintext token cache on Linux."); var storageProps = CreateTokenCacheProps(clientId, useLinuxFallback: true); helper = await MsalCacheHelper.CreateAsync(storageProps); } } if (helper is null) { Context.Streams.Error.WriteLine("error: failed to set up Microsoft Authentication token cache!"); Context.Trace.WriteLine("Failed to integrate with shared token cache!"); } else { helper.RegisterCache(app.UserTokenCache); Context.Trace.WriteLine("Microsoft developer tools token cache configured."); } }
private static async Task <MsalCacheHelper> CreateCacheHelperAsync() { StorageCreationProperties storageProperties; try { storageProperties = new StorageCreationPropertiesBuilder( Config.CacheFileName, Config.CacheDir, Config.ClientId) .WithLinuxKeyring( Config.LinuxKeyRingSchema, Config.LinuxKeyRingCollection, Config.LinuxKeyRingLabel, Config.LinuxKeyRingAttr1, Config.LinuxKeyRingAttr2) .WithMacKeyChain( Config.KeyChainServiceName, Config.KeyChainAccountName) .Build(); var cacheHelper = await MsalCacheHelper.CreateAsync( storageProperties).ConfigureAwait(false); cacheHelper.VerifyPersistence(); return(cacheHelper); } catch (Exception e) { Console.WriteLine($"WARNING! Libsecret is not usable. " + $"Secrets will be stored in plaintext at {Path.Combine(Config.CacheDir, Config.CacheFileName)} !"); Console.WriteLine($"Libsecret exception: " + e); storageProperties = new StorageCreationPropertiesBuilder( Config.CacheFileName, Config.CacheDir, Config.ClientId) .WithLinuxUnprotectedFile() .WithMacKeyChain( Config.KeyChainServiceName, Config.KeyChainAccountName) .Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.VerifyPersistence(); return(cacheHelper); } }
private async Task InitializeAsync() { if (_attachSharedCache) { StorageCreationProperties storageProperties = new StorageCreationPropertiesBuilder(Constants.DefaultMsalTokenCacheName, Constants.DefaultMsalTokenCacheDirectory, _clientId) .WithMacKeyChain(Constants.DefaultMsalTokenCacheKeychainService, Constants.DefaultMsalTokenCacheKeychainAccount) .WithLinuxKeyring(Constants.DefaultMsalTokenCacheKeyringSchema, Constants.DefaultMsalTokenCacheKeyringCollection, Constants.DefaultMsalTokenCacheKeyringLabel, Constants.DefaultMsaltokenCacheKeyringAttribute1, Constants.DefaultMsaltokenCacheKeyringAttribute2) .Build(); MsalCacheHelper cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.RegisterCache(_client.UserTokenCache); } }
/// <summary> /// Gets an aptly configured instance of the <see cref="MsalCacheStorage" /> class. /// </summary> /// <returns>An aptly configured instance of the <see cref="MsalCacheStorage" /> class.</returns> private MsalCacheHelper GetMsalCacheStorage() { StorageCreationPropertiesBuilder builder = new StorageCreationPropertiesBuilder(Path.GetFileName(CacheFilePath), Path.GetDirectoryName(CacheFilePath), ClientId); builder = builder.WithMacKeyChain(serviceName: "Microsoft.Developer.IdentityService", accountName: "MSALCache"); builder = builder.WithLinuxKeyring( schemaName: "msal.cache", collection: "default", secretLabel: "MSALCache", attribute1: new KeyValuePair <string, string>("MsalClientID", "Microsoft.Developer.IdentityService"), attribute2: new KeyValuePair <string, string>("MsalClientVersion", "1.0.0.0")); return(MsalCacheHelper.CreateAsync(builder.Build(), new TraceSource("Partner Center PowerShell")).ConfigureAwait(false).GetAwaiter().GetResult()); }
private static async Task <MsalCacheHelper> CreateCacheHelperAsync() { StorageCreationProperties storageProperties; try { storageProperties = new StorageCreationPropertiesBuilder( Config.CacheFileName, Config.CacheDir) .WithLinuxKeyring( Config.LinuxKeyRingSchema, Config.LinuxKeyRingCollection, Config.LinuxKeyRingLabel, Config.LinuxKeyRingAttr1, Config.LinuxKeyRingAttr2) .WithMacKeyChain( Config.KeyChainServiceName, Config.KeyChainAccountName) .WithCacheChangedEvent( // do NOT use unless really necessary, high perf penalty! Config.ClientId, Config.Authority) .Build(); var cacheHelper = await MsalCacheHelper.CreateAsync( storageProperties).ConfigureAwait(false); cacheHelper.VerifyPersistence(); return(cacheHelper); } catch (MsalCachePersistenceException e) { Console.WriteLine($"WARNING! Unable to encrypt tokens at rest." + $" Saving tokens in plaintext at {Path.Combine(Config.CacheDir, Config.CacheFileName)} ! Please protect this directory or delete the file after use"); Console.WriteLine($"Encryption exception: " + e); storageProperties = new StorageCreationPropertiesBuilder( Config.CacheFileName + ".plaintext", // do not use the same file name so as not to overwrite the encypted version Config.CacheDir) .WithUnprotectedFile() .Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.VerifyPersistence(); return(cacheHelper); } }
private async Task InitializeCacheAsync() { // Building StorageCreationProperties var storageProperties = new StorageCreationPropertiesBuilder( CacheFileName, CacheDir, ClientId) .Build(); // This hooks up the cross-platform cache into MSAL var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties); cacheHelper.RegisterCache(app.UserTokenCache); }
private async Task <MsalCacheHelper> GetMsalCacheHelperAsync() { // There are options to set up the cache correctly using StorageCreationProperties on other OS's but that will need to be tested // for now only support windows if (helper == null && this.cacheEnabled && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var fileName = Path.GetFileName(cacheLocation); var directory = Path.GetDirectoryName(cacheLocation); var builder = new StorageCreationPropertiesBuilder(fileName, directory, this.clientId); StorageCreationProperties creationProps = builder.Build(); helper = await MsalCacheHelper.CreateAsync(creationProps); } return(helper); }
private static MsalCacheHelper InitializeCacheHelper(string clientId) { StorageCreationPropertiesBuilder builder = new StorageCreationPropertiesBuilder(Path.GetFileName(CacheFilePath), Path.GetDirectoryName(CacheFilePath), clientId); builder = builder.WithMacKeyChain(serviceName: "Microsoft.Developer.IdentityService", accountName: "MSALCache"); builder = builder.WithLinuxKeyring( schemaName: "msal.cache", collection: "default", secretLabel: "MSALCache", attribute1: new KeyValuePair <string, string>("MsalClientID", "Microsoft.Developer.IdentityService"), attribute2: new KeyValuePair <string, string>("MsalClientVersion", "1.0.0.0")); StorageCreationProperties storageCreationProperties = builder.Build(); return(MsalCacheHelper.CreateAsync(storageCreationProperties).ConfigureAwait(false).GetAwaiter().GetResult()); }
public async Task RunAsync() { Console.WriteLine("START"); var ClientId = "<Client Id>"; var TenantId = "<Tenant Id>"; string[] Scopes = new[] { "https://api.businesscentral.dynamics.com/Financials.ReadWrite.All" }; var app = PublicClientApplicationBuilder.Create(ClientId) .WithDefaultRedirectUri() .WithTenantId(TenantId) .Build(); // OPTIONAL: Create cache helper to persist token cache var CacheFileName = "msal_cache.dat"; var CacheDir = @"MSAL_CACHE"; var storageProperties = new StorageCreationPropertiesBuilder(CacheFileName, CacheDir).Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties); cacheHelper.RegisterCache(app.UserTokenCache); // Acquire token interactively var result = await app.AcquireTokenInteractive(Scopes).ExecuteAsync(); Console.WriteLine($"ACCESS TOKEN (INTERACTIVE): [{result.ExpiresOn}] {result.AccessToken}"); Console.WriteLine(); await Task.Delay(TimeSpan.FromSeconds(5)); // Acquire token silently var accounts = await app.GetAccountsAsync(); var silentResult = await app.AcquireTokenSilent(Scopes, accounts.FirstOrDefault()).WithForceRefresh(true).ExecuteAsync(); Console.WriteLine($"ACCESS TOKEN (SILENT): [{silentResult.ExpiresOn}] {silentResult.AccessToken}"); Console.WriteLine(); Console.WriteLine("FINISH"); }
internal static async Task <(string[], IPublicClientApplication, MsalCacheHelper)> GetPublicClientAsync( string resource, string tenant, Uri baseAuthority, bool validateAuthority, string clientId, string cacheFilename, string cacheDirectory, string serviceName, string accountName) { // tenant can be null resource = resource ?? throw new ArgumentNullException(nameof(resource)); Console.WriteLine($"Using resource: '{resource}', tenant:'{tenant}'"); var scopes = new string[] { resource + "/.default" }; Console.WriteLine($"Using scopes: '{string.Join(",", scopes)}'"); var authority = $"{baseAuthority.AbsoluteUri}{tenant}"; Console.WriteLine($"GetPublicClient for authority: '{authority}' ValidateAuthority: '{validateAuthority}'"); Uri authorityUri = new Uri(authority); var appBuilder = PublicClientApplicationBuilder.Create(clientId).WithAuthority(authorityUri, validateAuthority); var app = appBuilder.Build(); Console.WriteLine($"Built public client"); var storageCreationPropsBuilder = new StorageCreationPropertiesBuilder(cacheFilename, cacheDirectory, clientId); storageCreationPropsBuilder = storageCreationPropsBuilder.WithMacKeyChain(serviceName, accountName); var storageCreationProps = storageCreationPropsBuilder.Build(); // This hooks up our custom cache onto the one used by MSAL var cacheHelper = await MsalCacheHelper.CreateAsync(storageCreationProps).ConfigureAwait(false); cacheHelper.RegisterCache(app.UserTokenCache); Console.WriteLine($"Cache registered"); return(scopes, app, cacheHelper); }
private static async Task <MsalCacheHelper> CreateCacheHelperAsync() { StorageCreationProperties storageProperties; MsalCacheHelper cacheHelper; try { storageProperties = ConfigureSecureStorage(usePlaintextFileOnLinux: false); cacheHelper = await MsalCacheHelper.CreateAsync( storageProperties, new TraceSource(TraceSourceName)) .ConfigureAwait(false); // the underlying persistence mechanism might not be usable // this typically happens on Linux over SSH cacheHelper.VerifyPersistence(); return(cacheHelper); } catch (MsalCachePersistenceException ex) { Console.WriteLine("Cannot persist data securely. "); Console.WriteLine("Details: " + ex); if (SharedUtilities.IsLinuxPlatform()) { storageProperties = ConfigureSecureStorage(usePlaintextFileOnLinux: true); Console.WriteLine($"Falling back on using a plaintext " + $"file located at {storageProperties.CacheFilePath} Users are responsible for securing this file!"); cacheHelper = await MsalCacheHelper.CreateAsync( storageProperties, new TraceSource(TraceSourceName)) .ConfigureAwait(false); return(cacheHelper); } throw; } }
/// <summary> /// ctor for AuthenticationTokenFactory /// </summary> /// <param name="applicationClientId">ClientId for AAD application that accesses BingAdsApi</param> /// <param name="usernameLoginHint">Username LoginHint to retrieve matching AccessToken from TokenCache</param> /// <param name="tokenCacheCorrelationId"> /// Used to identify persisted TokenCache location. /// Provide a consistent non-null value across sessions for access to the same persisted cache. /// If app must not need TokenCache persistence, just pass in null. /// </param> /// <param name="acesssTokenExpirationOffsetInSec"> /// Specifies when a new Token will be refreshed silently, based on AccessToken's expiresOn property. /// If AccessToken.ExpiresOn = "09:30" and offset = "-600", /// then call to fetch accessToken after "09:20" will try to get a refreshed accessToken. /// </param> /// <param name="apiEnvironment"></param> public AuthenticationTokenFactory( string applicationClientId, string usernameLoginHint = null, string tokenCacheCorrelationId = null, int acesssTokenExpirationOffsetInSec = Config.DefaultAccessTokenExpirationOffsetInSec, ApiEnvironment apiEnvironment = ApiEnvironment.Production) { if (string.IsNullOrWhiteSpace(applicationClientId)) { throw new ArgumentNullException(nameof(applicationClientId)); } if (acesssTokenExpirationOffsetInSec > 0) { throw new ArgumentException($"value of {nameof(acesssTokenExpirationOffsetInSec)} must be negative"); } this.apiEnvironment = apiEnvironment; this.usernameLoginHint = usernameLoginHint; this.acesssTokenExpirationOffsetInSec = acesssTokenExpirationOffsetInSec; // create IPublicClientApplication for accessing BingAdsApi application = PublicClientApplicationBuilder.Create(applicationClientId) .WithRedirectUri(Config.RedirectUri[apiEnvironment]) .Build(); // try load TokenCache from persisted file storage if (tokenCacheCorrelationId != null) { var cacheFileName = $".msalcache.{tokenCacheCorrelationId}"; Logger.Verbose($"TokenCache persistence at {Config.DefaultTokenCacheFileLocation}\\{cacheFileName}"); var cacheStorageInfo = new StorageCreationPropertiesBuilder( cacheFileName, Config.DefaultTokenCacheFileLocation, applicationClientId) .Build(); var cacheHelper = MsalCacheHelper.CreateAsync(cacheStorageInfo).Result; cacheHelper.RegisterCache(application.UserTokenCache); } }
public async Task StartAsync(CancellationToken cancellationToken) { // Initialize services that you need before app activation await InitializeAsync(); // https://aka.ms/msal-net-token-cache-serialization var storageCreationProperties = new StorageCreationPropertiesBuilder(_config.IdentityCacheFileName, _config.IdentityCacheDirectoryName, _config.IdentityClientId).Build(); var cacheHelper = await MsalCacheHelper.CreateAsync(storageCreationProperties).ConfigureAwait(false); _identityService.InitializeWithAadAndPersonalMsAccounts(_config.IdentityClientId, "http://localhost", cacheHelper); await _identityService.AcquireTokenSilentAsync(); _shellWindow = _serviceProvider.GetService(typeof(IShellWindow)) as IShellWindow; _navigationService.Initialize(_shellWindow.GetNavigationFrame()); _shellWindow.ShowWindow(); _navigationService.NavigateTo(typeof(MainViewModel).FullName); // Tasks after activation await StartupAsync(); }
private async Task InitializeAsync() { Client = await CreateClientAsync().ConfigureAwait(false); if (EnablePersistentCache) { MsalCacheHelper cacheHelper; StorageCreationProperties storageProperties = new StorageCreationPropertiesBuilder(Constants.DefaultMsalTokenCacheName, Constants.DefaultMsalTokenCacheDirectory, ClientId) .WithMacKeyChain(Constants.DefaultMsalTokenCacheKeychainService, Constants.DefaultMsalTokenCacheKeychainAccount) .WithLinuxKeyring(Constants.DefaultMsalTokenCacheKeyringSchema, Constants.DefaultMsalTokenCacheKeyringCollection, Constants.DefaultMsalTokenCacheKeyringLabel, Constants.DefaultMsaltokenCacheKeyringAttribute1, Constants.DefaultMsaltokenCacheKeyringAttribute2) .Build(); try { cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.VerifyPersistence(); } catch (MsalCachePersistenceException) { if (AllowUnencryptedCache) { storageProperties = new StorageCreationPropertiesBuilder(Constants.DefaultMsalTokenCacheName, Constants.DefaultMsalTokenCacheDirectory, ClientId) .WithMacKeyChain(Constants.DefaultMsalTokenCacheKeychainService, Constants.DefaultMsalTokenCacheKeychainAccount) .WithLinuxUnprotectedFile() .Build(); cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.VerifyPersistence(); } else { throw; } } cacheHelper.RegisterCache(Client.UserTokenCache); } }
public void ImportExport() { var storageBuilder = new StorageCreationPropertiesBuilder( Path.GetFileName(CacheFilePath), Path.GetDirectoryName(CacheFilePath), ClientId); storageBuilder = storageBuilder.WithMacKeyChain( serviceName: "Microsoft.Developer.IdentityService.Test", accountName: "MSALCacheTest"); // unit tests run on Linux boxes without LibSecret storageBuilder.WithLinuxUnprotectedFile(); // 1. Use MSAL to create an instance of the Public Client Application var app = PublicClientApplicationBuilder.Create(ClientId) .Build(); // 3. Create the high level MsalCacheHelper based on properties and a logger _cacheHelper = MsalCacheHelper.CreateAsync( storageBuilder.Build(), new TraceSource("MSAL.CacheExtension.Test")) .GetAwaiter().GetResult(); // 4. Let the cache helper handle MSAL's cache _cacheHelper.RegisterCache(app.UserTokenCache); // Act string dataString = "Hello World"; byte[] dataBytes = Encoding.UTF8.GetBytes(dataString); var result = _cacheHelper.LoadUnencryptedTokenCache(); Assert.AreEqual(0, result.Length); _cacheHelper.SaveUnencryptedTokenCache(dataBytes); byte[] actualData = _cacheHelper.LoadUnencryptedTokenCache(); Assert.AreEqual(dataString, Encoding.UTF8.GetString(actualData)); }
private async Task <IPublicClientApplication> GetOrCreateApp() { if (App == null) { // On Windows, USERPROFILE is guaranteed to be set string userProfile = Environment.GetEnvironmentVariable("USERPROFILE") !; string cacheDir = Path.Combine(userProfile, @"AppData\Local\.IdentityService"); // TODO: what about the other platforms? string clientId = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"; var storageProperties = new StorageCreationPropertiesBuilder( "msal.cache", cacheDir) /* * .WithLinuxKeyring( * Config.LinuxKeyRingSchema, * Config.LinuxKeyRingCollection, * Config.LinuxKeyRingLabel, * Config.LinuxKeyRingAttr1, * Config.LinuxKeyRingAttr2) * .WithMacKeyChain( * Config.KeyChainServiceName, * Config.KeyChainAccountName) */ .Build(); App = PublicClientApplicationBuilder.Create(clientId) .WithRedirectUri(RedirectUri) .Build(); // This hooks up the cross-platform cache into MSAL var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false); cacheHelper.RegisterCache(App.UserTokenCache); } return(App); }
private async Task <MsalCacheHelper> CreateCacheHelperAsync() { StorageCreationProperties storageProperties; MsalCacheHelper cacheHelper; try { storageProperties = ConfigureSecureStorage(); cacheHelper = await MsalCacheHelper.CreateAsync( storageProperties, null).ConfigureAwait(false); cacheHelper.VerifyPersistence(); return(cacheHelper); } catch (MsalCachePersistenceException ex) { Console.WriteLine("Cannot persist data securely. "); Console.WriteLine("Details: " + ex); throw; } }
public static MsalCacheHelper GetCacheHelper() { if (MsalCacheHelper == null) { lock (ObjectLock) { if (MsalCacheHelper == null) { var cacheDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ".IdentityService"); try { StorageCreationProperties storageProperties = new StorageCreationPropertiesBuilder("msal.cache", cacheDirectory) .WithMacKeyChain("Microsoft.Developer.IdentityService", "MSALCache") .WithLinuxKeyring("msal.cache", "default", "MSALCache", new KeyValuePair <string, string>("MsalClientID", "Microsoft.Developer.IdentityService"), new KeyValuePair <string, string>("Microsoft.Developer.IdentityService", "1.0.0.0")) .Build(); var cacheHelper = MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false).GetAwaiter().GetResult(); cacheHelper.VerifyPersistence(); MsalCacheHelper = cacheHelper; } catch (MsalCachePersistenceException) { StorageCreationProperties storageProperties = new StorageCreationPropertiesBuilder("msal.cache", cacheDirectory) .WithMacKeyChain("Microsoft.Developer.IdentityService", "MSALCache") .WithLinuxUnprotectedFile() .Build(); MsalCacheHelper = MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false).GetAwaiter().GetResult(); } } } } return(MsalCacheHelper); }
public async Task <IAzureWorkspace?> GetAuthenticatedWorkspaceAsync( IChannel channel, ILogger?logger, string resourceGroupName, string workspaceName, string location, bool refreshCredentials) { location = GetNormalizedLocation(location, channel); switch (Type) { case AzureEnvironmentType.Mock: channel.Stdout("AZURE_QUANTUM_ENV set to Mock. Using mock Azure workspace rather than connecting to a real service."); return(new MockAzureWorkspace(workspaceName, location)); case AzureEnvironmentType.Canary: channel.Stdout($"AZURE_QUANTUM_ENV set to Canary. Connecting to location eastus2euap rather than specified location {location}."); break; case AzureEnvironmentType.Dogfood: channel.Stdout($"AZURE_QUANTUM_ENV set to Dogfood. Connecting to test endpoint rather than production service."); break; case AzureEnvironmentType.Production: logger?.LogInformation($"AZURE_QUANTUM_ENV not set, or set to Production. Connecting to production service."); break; } // Find the token cache folder var cacheDirectoryEnvVarName = "AZURE_QUANTUM_TOKEN_CACHE"; var cacheDirectory = System.Environment.GetEnvironmentVariable(cacheDirectoryEnvVarName); if (string.IsNullOrEmpty(cacheDirectory)) { cacheDirectory = Path.Join(System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile), ".azure-quantum"); } // Register the token cache for serialization var cacheFileName = "iqsharp.bin"; var storageCreationProperties = new StorageCreationPropertiesBuilder(cacheFileName, cacheDirectory, ClientId) .WithMacKeyChain( serviceName: "Microsoft.Quantum.IQSharp", accountName: "MSALCache") .WithLinuxKeyring( schemaName: "com.microsoft.quantum.iqsharp", collection: "default", secretLabel: "Credentials used by Microsoft IQ# kernel", attribute1: new KeyValuePair <string, string>("Version", typeof(AzureClient).Assembly.GetName().Version.ToString()), attribute2: new KeyValuePair <string, string>("ProductGroup", "QDK")) .Build(); MsalCacheHelper?cacheHelper; try { cacheHelper = await MsalCacheHelper.CreateAsync(storageCreationProperties); cacheHelper.VerifyPersistence(); } catch (MsalCachePersistenceException e) { // Will occur on Linux if encryption is unavailable. Fallback to unencrypted cache on Linux, as documented here: // https://github.com/AzureAD/microsoft-authentication-extensions-for-dotnet/blob/master/docs/keyring_fallback_proposal.md var unencryptedCacheFileName = "iqsharp-unencrypted.bin"; logger?.LogWarning(e, "Encrypted credential cache is unavailable. Cache will be stored in plaintext at {Path}. Error: {Message}", Path.Combine(cacheDirectory, unencryptedCacheFileName), e.Message); storageCreationProperties = new StorageCreationPropertiesBuilder(unencryptedCacheFileName, cacheDirectory, ClientId) .WithMacKeyChain( serviceName: "Microsoft.Quantum.IQSharp", accountName: "MSALCache") .WithLinuxUnprotectedFile() .Build(); cacheHelper = await MsalCacheHelper.CreateAsync(storageCreationProperties); cacheHelper.VerifyPersistence(); } var msalApp = PublicClientApplicationBuilder.Create(ClientId).WithAuthority(Authority).Build(); cacheHelper.RegisterCache(msalApp.UserTokenCache); // Perform the authentication bool shouldShowLoginPrompt = refreshCredentials; AuthenticationResult?authenticationResult = null; if (!shouldShowLoginPrompt) { try { var accounts = await msalApp.GetAccountsAsync(); authenticationResult = await msalApp.AcquireTokenSilent( Scopes, accounts.FirstOrDefault()).WithAuthority(msalApp.Authority).ExecuteAsync(); } catch (MsalUiRequiredException) { shouldShowLoginPrompt = true; } } if (shouldShowLoginPrompt) { authenticationResult = await msalApp.AcquireTokenWithDeviceCode( Scopes, deviceCodeResult => { channel.Stdout(deviceCodeResult.Message); return(Task.FromResult(0)); }).WithAuthority(msalApp.Authority).ExecuteAsync(); } if (authenticationResult == null) { return(null); } // Construct and return the AzureWorkspace object var credentials = new Rest.TokenCredentials(authenticationResult.AccessToken); var azureQuantumClient = new QuantumClient(credentials) { SubscriptionId = SubscriptionId, ResourceGroupName = resourceGroupName, WorkspaceName = workspaceName, BaseUri = BaseUriForLocation(location), }; var azureQuantumWorkspace = new Azure.Quantum.Workspace( azureQuantumClient.SubscriptionId, azureQuantumClient.ResourceGroupName, azureQuantumClient.WorkspaceName, authenticationResult?.AccessToken, BaseUriForLocation(location)); return(new AzureWorkspace(azureQuantumClient, azureQuantumWorkspace, location)); }