From 3685a10ec1ef410f1a8d8b1b4e397d2b95324832 Mon Sep 17 00:00:00 2001 From: Gautam Sheth Date: Wed, 27 Nov 2024 22:29:45 +0200 Subject: [PATCH 1/6] Refactor authentication handling to integrate MSAL token caching --- src/Commands/Base/PnPConnection.cs | 78 ++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/src/Commands/Base/PnPConnection.cs b/src/Commands/Base/PnPConnection.cs index 932191f58..c94c9682c 100644 --- a/src/Commands/Base/PnPConnection.cs +++ b/src/Commands/Base/PnPConnection.cs @@ -1,24 +1,27 @@ -using Microsoft.SharePoint.Client; +using Microsoft.Identity.Client; +using Microsoft.Identity.Client.Extensions.Msal; +using Microsoft.SharePoint.Client; using PnP.Core.Services; +using PnP.Framework; +using PnP.Framework.Utilities.Context; +using PnP.PowerShell.ALC; using PnP.PowerShell.Commands.Enums; using PnP.PowerShell.Commands.Model; +using PnP.PowerShell.Commands.Utilities; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Management.Automation; +using System.Net; +using System.Net.Http; using System.Reflection; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using PnP.Framework; -using PnP.PowerShell.ALC; -using Resources = PnP.PowerShell.Commands.Properties.Resources; -using System.Net; -using TextCopy; -using PnP.PowerShell.Commands.Utilities; -using System.Threading.Tasks; using System.Threading; -using System.Net.Http; -using PnP.Framework.Utilities.Context; +using System.Threading.Tasks; +using TextCopy; +using Resources = PnP.PowerShell.Commands.Properties.Resources; namespace PnP.PowerShell.Commands.Base { @@ -265,13 +268,15 @@ internal static PnPConnection CreateWithDeviceLogin(string clientId, string url, { authManager = Framework.AuthenticationManager.CreateWithDeviceLogin(clientId, tenantId, (deviceCodeResult) => { - ClipboardService.SetText(deviceCodeResult.UserCode); messageWriter.WriteWarning($"\n\nCode {deviceCodeResult.UserCode} has been copied to your clipboard and a new tab in the browser has been opened. Please paste this code in there and proceed.\n\n"); BrowserHelper.OpenBrowserForInteractiveLogin(deviceCodeResult.VerificationUrl, BrowserHelper.FindFreeLocalhostRedirectUri(), cancellationTokenSource); return Task.FromResult(0); - }, azureEnvironment); + }, azureEnvironment, tokenCacheCallback: async (tokenCache) => + { + await MSALCacheHelper(tokenCache); + }); } using (authManager) { @@ -304,7 +309,6 @@ internal static PnPConnection CreateWithDeviceLogin(string clientId, string url, { throw; } - } } } @@ -458,7 +462,10 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr } else { - authManager = PnP.Framework.AuthenticationManager.CreateWithCredentials(clientId, credentials.UserName, credentials.Password, redirectUrl, azureEnvironment); + authManager = PnP.Framework.AuthenticationManager.CreateWithCredentials(clientId, credentials.UserName, credentials.Password, redirectUrl, azureEnvironment, tokenCacheCallback: async (tokenCache) => + { + await MSALCacheHelper(tokenCache); + }); } using (authManager) { @@ -586,7 +593,10 @@ internal static PnPConnection CreateWithInteractiveLogin(Uri uri, string clientI tenant, htmlMessageSuccess, htmlMessageFailure, - azureEnvironment: azureEnvironment, useWAM: enableLoginWithWAM); + azureEnvironment: azureEnvironment, tokenCacheCallback: async (tokenCache) => + { + await MSALCacheHelper(tokenCache); + }, useWAM: enableLoginWithWAM); } using (authManager) { @@ -956,6 +966,44 @@ internal static void CleanupCryptoMachineKey(X509Certificate2 certificate) } } } + + private static async Task MSALCacheHelper(ITokenCache tokenCache) + { + const string CacheSchemaName = "pnp.powershell.tokencache"; + string cacheDir = Path.Combine(MsalCacheHelper.UserRootDirectory, @".m365pnppowershell"); + try + { + var storage = + new StorageCreationPropertiesBuilder("pnp.msal.cache", cacheDir) + .WithMacKeyChain( + serviceName: $"{CacheSchemaName}.service", + accountName: $"{CacheSchemaName}.account") + .WithLinuxKeyring( + schemaName: CacheSchemaName, + collection: MsalCacheHelper.LinuxKeyRingDefaultCollection, + secretLabel: "MSAL token cache for PnP PowerShell.", + attribute1: new KeyValuePair("Version", "1"), + attribute2: new KeyValuePair("Product", "PnPPowerShell")) + .Build(); + var cacheHelper = await MsalCacheHelper.CreateAsync(storage).ConfigureAwait(false); + cacheHelper.VerifyPersistence(); + + cacheHelper.RegisterCache(tokenCache); + } + catch (MsalCachePersistenceException) + { + var storage = + new StorageCreationPropertiesBuilder("pnp.msal.cache", cacheDir) + .WithMacKeyChain( + serviceName: $"{CacheSchemaName}.service", + accountName: $"{CacheSchemaName}.account") + .WithLinuxUnprotectedFile() + .Build(); + var cacheHelper = await MsalCacheHelper.CreateAsync(storage).ConfigureAwait(false); + + cacheHelper.RegisterCache(tokenCache); + } + } #endregion } } \ No newline at end of file From 538ecbefef6c36a91490704bbb3438f746ae4a23 Mon Sep 17 00:00:00 2001 From: Erwin van Hunen Date: Thu, 28 Nov 2024 11:52:47 +0100 Subject: [PATCH 2/6] Added configuration --- src/Commands/Base/ConnectOnline.cs | 16 +- src/Commands/Base/DisconnectOnline.cs | 9 + src/Commands/Base/PnPConnection.cs | 183 +++++++++++++----- src/Commands/Model/TokenCacheConfiguration.cs | 9 + 4 files changed, 169 insertions(+), 48 deletions(-) create mode 100644 src/Commands/Model/TokenCacheConfiguration.cs diff --git a/src/Commands/Base/ConnectOnline.cs b/src/Commands/Base/ConnectOnline.cs index 557a3fdca..38a3a622a 100644 --- a/src/Commands/Base/ConnectOnline.cs +++ b/src/Commands/Base/ConnectOnline.cs @@ -267,6 +267,12 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = true, ParameterSetName = ParameterSet_OSLOGIN)] public SwitchParameter OSLogin; + + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_INTERACTIVE)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_DEVICELOGIN)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN)] + public SwitchParameter PersistLogin; + private static readonly string[] sourceArray = ["stop", "ignore", "silentlycontinue"]; protected override void ProcessRecord() @@ -765,8 +771,7 @@ private PnPConnection ConnectInteractive() } } WriteVerbose($"Using ClientID {ClientId}"); - - return PnPConnection.CreateWithInteractiveLogin(new Uri(Url.ToLower()), ClientId, TenantAdminUrl, AzureEnvironment, cancellationTokenSource, ForceAuthentication, Tenant, false); + return PnPConnection.CreateWithInteractiveLogin(new Uri(Url.ToLower()), ClientId, TenantAdminUrl, AzureEnvironment, cancellationTokenSource, ForceAuthentication, Tenant, false, PersistLogin, Host); } private PnPConnection ConnectEnvironmentVariable(InitializationType initializationType = InitializationType.EnvironmentVariable) @@ -902,8 +907,11 @@ private PnPConnection ConnectWithOSLogin() } WriteVerbose($"Using ClientID {ClientId}"); - - return PnPConnection.CreateWithInteractiveLogin(new Uri(Url.ToLower()), ClientId, TenantAdminUrl, AzureEnvironment, cancellationTokenSource, ForceAuthentication, Tenant, true); + if (PnPConnection.CacheEnabled(Url, ClientId)) + { + WriteObject("Cache used. Clear the cache entry with Disconnect-PnPOnline"); + } + return PnPConnection.CreateWithInteractiveLogin(new Uri(Url.ToLower()), ClientId, TenantAdminUrl, AzureEnvironment, cancellationTokenSource, ForceAuthentication, Tenant, true, PersistLogin, Host); } #endregion diff --git a/src/Commands/Base/DisconnectOnline.cs b/src/Commands/Base/DisconnectOnline.cs index 483a0ce70..1579b7e36 100644 --- a/src/Commands/Base/DisconnectOnline.cs +++ b/src/Commands/Base/DisconnectOnline.cs @@ -11,6 +11,10 @@ namespace PnP.PowerShell.Commands.Base [OutputType(typeof(void))] public class DisconnectOnline : PSCmdlet { + + [Parameter(Mandatory = false)] + public SwitchParameter ClearCache; + protected override void ProcessRecord() { if (PnPConnection.Current == null) @@ -30,6 +34,11 @@ protected override void ProcessRecord() PnPConnection.Current.Certificate = null; } + if(ClearCache) + { + PnPConnection.ClearCache(PnPConnection.Current); + } + PnPConnection.Current = null; var provider = SessionState.Provider.GetAll().FirstOrDefault(p => p.Name.Equals(SPOProvider.PSProviderName, StringComparison.InvariantCultureIgnoreCase)); diff --git a/src/Commands/Base/PnPConnection.cs b/src/Commands/Base/PnPConnection.cs index c94c9682c..bf96ca639 100644 --- a/src/Commands/Base/PnPConnection.cs +++ b/src/Commands/Base/PnPConnection.cs @@ -9,15 +9,22 @@ using PnP.PowerShell.Commands.Model; using PnP.PowerShell.Commands.Utilities; using System; +using System.CodeDom; using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Host; +using System.Management.Automation.Language; using System.Net; using System.Net.Http; using System.Reflection; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using TextCopy; @@ -159,6 +166,8 @@ internal PnPContext PnPContext /// public AzureEnvironment AzureEnvironment { get; set; } = AzureEnvironment.Production; + internal PnP.Framework.AuthenticationManager AuthenticationManager { get; set; } + private string _graphEndPoint; #endregion @@ -275,7 +284,7 @@ internal static PnPConnection CreateWithDeviceLogin(string clientId, string url, return Task.FromResult(0); }, azureEnvironment, tokenCacheCallback: async (tokenCache) => { - await MSALCacheHelper(tokenCache); + await MSALCacheHelper(tokenCache, url, clientId); }); } using (authManager) @@ -296,6 +305,7 @@ internal static PnPConnection CreateWithDeviceLogin(string clientId, string url, ConnectionMethod = ConnectionMethod.DeviceLogin, AzureEnvironment = azureEnvironment }; + spoConnection.AuthenticationManager = authManager; return spoConnection; } catch (Microsoft.Identity.Client.MsalServiceException msalServiceException) @@ -452,6 +462,13 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr var tenantId = string.Empty; try { + spoConnection = new PnPConnection(context, ConnectionType.O365, credentials, url.ToString(), tenantAdminUrl, PnPPSVersionTag, initializationType); + + spoConnection.ConnectionMethod = ConnectionMethod.Credentials; + spoConnection.AzureEnvironment = azureEnvironment; + spoConnection.Tenant = tenantId; + spoConnection.ClientId = clientId; + if (!string.IsNullOrWhiteSpace(clientId)) { PnP.Framework.AuthenticationManager authManager = null; @@ -464,7 +481,7 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr { authManager = PnP.Framework.AuthenticationManager.CreateWithCredentials(clientId, credentials.UserName, credentials.Password, redirectUrl, azureEnvironment, tokenCacheCallback: async (tokenCache) => { - await MSALCacheHelper(tokenCache); + await MSALCacheHelper(tokenCache, url.ToString(), clientId); }); } using (authManager) @@ -480,6 +497,7 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr cmdlet.WriteVerbose("Token acquired"); var parsedToken = new Microsoft.IdentityModel.JsonWebTokens.JsonWebToken(accesstoken); tenantId = parsedToken.Claims.FirstOrDefault(c => c.Type == "tid").Value; + spoConnection.AuthenticationManager = authManager; } } else @@ -505,6 +523,7 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr var accessToken = authManager.GetAccessTokenAsync(url.ToString()).GetAwaiter().GetResult(); var parsedToken = new Microsoft.IdentityModel.JsonWebTokens.JsonWebToken(accessToken); tenantId = parsedToken.Claims.FirstOrDefault(c => c.Type == "tid").Value; + spoConnection.AuthenticationManager = authManager; } } } @@ -526,14 +545,8 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr { connectionType = ConnectionType.TenantAdmin; } - - spoConnection = new PnPConnection(context, connectionType, credentials, url.ToString(), tenantAdminUrl, PnPPSVersionTag, initializationType) - { - ConnectionMethod = Model.ConnectionMethod.Credentials, - AzureEnvironment = azureEnvironment, - Tenant = tenantId, - ClientId = clientId - }; + spoConnection.ConnectionType = connectionType; + return spoConnection; } else { @@ -573,8 +586,17 @@ internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCr return spoConnection; } - internal static PnPConnection CreateWithInteractiveLogin(Uri uri, string clientId, string tenantAdminUrl, AzureEnvironment azureEnvironment, CancellationTokenSource cancellationTokenSource, bool forceAuthentication, string tenant, bool enableLoginWithWAM) + internal static PnPConnection CreateWithInteractiveLogin(Uri uri, string clientId, string tenantAdminUrl, AzureEnvironment azureEnvironment, CancellationTokenSource cancellationTokenSource, bool forceAuthentication, string tenant, bool enableLoginWithWAM, bool persistLogin, System.Management.Automation.Host.PSHost host) { + if (persistLogin) + { + EnableCaching(uri.ToString(), clientId); + } + if (CacheEnabled(uri.ToString(), clientId)) + { + WriteCacheEnabledMessage(host); + } + var htmlMessageSuccess = $"PnP PowerShell - Sign InPnP PowerShell
You are signed in now and can close this page.
"; var htmlMessageFailure = $"PnP PowerShell - Sign InPnP PowerShell
An error occured while signing in: {{{{0}}}}
"; @@ -595,7 +617,7 @@ internal static PnPConnection CreateWithInteractiveLogin(Uri uri, string clientI htmlMessageFailure, azureEnvironment: azureEnvironment, tokenCacheCallback: async (tokenCache) => { - await MSALCacheHelper(tokenCache); + await MSALCacheHelper(tokenCache, uri.ToString(), clientId); }, useWAM: enableLoginWithWAM); } using (authManager) @@ -618,6 +640,7 @@ internal static PnPConnection CreateWithInteractiveLogin(Uri uri, string clientI ConnectionMethod = ConnectionMethod.Credentials, AzureEnvironment = azureEnvironment }; + spoConnection.AuthenticationManager = authManager; return spoConnection; } } @@ -967,41 +990,113 @@ internal static void CleanupCryptoMachineKey(X509Certificate2 certificate) } } - private static async Task MSALCacheHelper(ITokenCache tokenCache) + private static async Task MSALCacheHelper(ITokenCache tokenCache, string url, string clientid) { const string CacheSchemaName = "pnp.powershell.tokencache"; string cacheDir = Path.Combine(MsalCacheHelper.UserRootDirectory, @".m365pnppowershell"); - try - { - var storage = - new StorageCreationPropertiesBuilder("pnp.msal.cache", cacheDir) - .WithMacKeyChain( - serviceName: $"{CacheSchemaName}.service", - accountName: $"{CacheSchemaName}.account") - .WithLinuxKeyring( - schemaName: CacheSchemaName, - collection: MsalCacheHelper.LinuxKeyRingDefaultCollection, - secretLabel: "MSAL token cache for PnP PowerShell.", - attribute1: new KeyValuePair("Version", "1"), - attribute2: new KeyValuePair("Product", "PnPPowerShell")) - .Build(); - var cacheHelper = await MsalCacheHelper.CreateAsync(storage).ConfigureAwait(false); - cacheHelper.VerifyPersistence(); - - cacheHelper.RegisterCache(tokenCache); - } - catch (MsalCachePersistenceException) - { - var storage = - new StorageCreationPropertiesBuilder("pnp.msal.cache", cacheDir) - .WithMacKeyChain( - serviceName: $"{CacheSchemaName}.service", - accountName: $"{CacheSchemaName}.account") - .WithLinuxUnprotectedFile() - .Build(); - var cacheHelper = await MsalCacheHelper.CreateAsync(storage).ConfigureAwait(false); - - cacheHelper.RegisterCache(tokenCache); + + if (CacheEnabled(url, clientid)) + { + try + { + StorageCreationPropertiesBuilder builder = + new StorageCreationPropertiesBuilder("pnp.msal.cache", cacheDir) + .WithMacKeyChain( + serviceName: $"{CacheSchemaName}.service", + accountName: $"{CacheSchemaName}.account") + .WithLinuxKeyring( + schemaName: CacheSchemaName, + collection: MsalCacheHelper.LinuxKeyRingDefaultCollection, + secretLabel: "MSAL token cache for PnP PowerShell.", + attribute1: new KeyValuePair("Version", "1"), + attribute2: new KeyValuePair("Product", "PnPPowerShell")); + + var storage = builder.Build(); + var cacheHelper = await MsalCacheHelper.CreateAsync(storage).ConfigureAwait(false); + cacheHelper.VerifyPersistence(); + + cacheHelper.RegisterCache(tokenCache); + } + catch (MsalCachePersistenceException) + { + var storage = + new StorageCreationPropertiesBuilder("pnp.msal.cache", cacheDir) + .WithMacKeyChain( + serviceName: $"{CacheSchemaName}.service", + accountName: $"{CacheSchemaName}.account") + .WithLinuxUnprotectedFile() + .Build(); + var cacheHelper = await MsalCacheHelper.CreateAsync(storage).ConfigureAwait(false); + + cacheHelper.RegisterCache(tokenCache); + } + } + } + + internal static bool CacheEnabled(string url, string clientid) + { + var tenantUri = new Uri(url); + var tenantUrl = $"https://{tenantUri.Authority}"; + var configFile = Path.Combine(MsalCacheHelper.UserRootDirectory, ".m365pnppowershell", "cachesettings.json"); + if (System.IO.File.Exists(configFile)) + { + var configs = JsonSerializer.Deserialize>(System.IO.File.ReadAllText(configFile)); + var entry = configs.FirstOrDefault(c => c.Url == tenantUrl && c.ClientId == clientid); + if (entry != null && entry.Enabled) + { + return true; + } + } + return false; + } + + private static void EnableCaching(string url, string clientid) + { + var tenantUri = new Uri(url); + var tenantUrl = $"https://{tenantUri.Authority}"; + var configFile = Path.Combine(MsalCacheHelper.UserRootDirectory, ".m365pnppowershell", "cachesettings.json"); + var configs = new List(); + if (System.IO.File.Exists(configFile)) + { + configs = JsonSerializer.Deserialize>(System.IO.File.ReadAllText(configFile)); + } + var entry = configs.FirstOrDefault(c => c.Url == tenantUrl && c.ClientId == clientid); + if (entry != null) + { + entry.Enabled = true; + } + else + { + configs.Add(new TokenCacheConfiguration() { ClientId = clientid, Url = tenantUrl, Enabled = true }); + } + System.IO.File.WriteAllText(configFile, JsonSerializer.Serialize(configs)); + } + + private static void WriteCacheEnabledMessage(PSHost host) + { + host.UI.WriteLine(ConsoleColor.Yellow, ConsoleColor.Black, "Secure token cache used for authentication. Clear the cache entry with Disconnect-PnPOnline -ClearCache."); + + } + + internal static void ClearCache(PnPConnection connection) + { + var tenantUri = new Uri(connection.Url); + var tenantUrl = $"https://{tenantUri.Authority}"; + var configFile = Path.Combine(MsalCacheHelper.UserRootDirectory, ".m365pnppowershell", "cachesettings.json"); + + if (System.IO.File.Exists(configFile)) + { + var configs = JsonSerializer.Deserialize>(System.IO.File.ReadAllText(configFile)); + var entry = configs.FirstOrDefault(c => c.Url == tenantUrl && c.ClientId == connection.ClientId); + if (entry != null) + { + configs.Remove(entry); + System.IO.File.WriteAllText(configFile, JsonSerializer.Serialize(configs)); + } + } + if (connection.AuthenticationManager != null) + { + connection.AuthenticationManager.ClearTokenCache(); } } #endregion diff --git a/src/Commands/Model/TokenCacheConfiguration.cs b/src/Commands/Model/TokenCacheConfiguration.cs new file mode 100644 index 000000000..495f4de85 --- /dev/null +++ b/src/Commands/Model/TokenCacheConfiguration.cs @@ -0,0 +1,9 @@ +namespace PnP.PowerShell.Commands.Model +{ + public class TokenCacheConfiguration + { + public string Url { get; set; } + public string ClientId { get; set; } + public bool Enabled { get; set; } + } +} \ No newline at end of file From 51af878230eca322115f8bbdc380123b270be394 Mon Sep 17 00:00:00 2001 From: Erwin van Hunen Date: Thu, 28 Nov 2024 12:26:35 +0100 Subject: [PATCH 3/6] Added support for -admin and -my urls --- src/Commands/Base/PnPConnection.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Commands/Base/PnPConnection.cs b/src/Commands/Base/PnPConnection.cs index bf96ca639..c19df6ecc 100644 --- a/src/Commands/Base/PnPConnection.cs +++ b/src/Commands/Base/PnPConnection.cs @@ -1,6 +1,7 @@ using Microsoft.Identity.Client; using Microsoft.Identity.Client.Extensions.Msal; using Microsoft.SharePoint.Client; +using Microsoft.VisualBasic; using PnP.Core.Services; using PnP.Framework; using PnP.Framework.Utilities.Context; @@ -1035,13 +1036,12 @@ private static async Task MSALCacheHelper(ITokenCache tokenCache, string url, st internal static bool CacheEnabled(string url, string clientid) { - var tenantUri = new Uri(url); - var tenantUrl = $"https://{tenantUri.Authority}"; var configFile = Path.Combine(MsalCacheHelper.UserRootDirectory, ".m365pnppowershell", "cachesettings.json"); if (System.IO.File.Exists(configFile)) { var configs = JsonSerializer.Deserialize>(System.IO.File.ReadAllText(configFile)); - var entry = configs.FirstOrDefault(c => c.Url == tenantUrl && c.ClientId == clientid); + var urls = GetCheckUrls(url); + var entry = configs.FirstOrDefault(c => urls.Contains(c.Url) && c.ClientId == clientid); if (entry != null && entry.Enabled) { return true; @@ -1050,6 +1050,19 @@ internal static bool CacheEnabled(string url, string clientid) return false; } + private static List GetCheckUrls(string url) + { + var urls = new List(); + var uri = new Uri(url); + var baseAuthority = uri.Authority; + baseAuthority = baseAuthority.Replace("-admin.sharepoint.com", ".sharepoint.com").Replace("-my.sharepoint.com", ".sharepoint.com"); + var baseUri = new Uri($"https://{baseAuthority}"); + var host = baseUri.Host.Split('.')[0]; + urls = [$"https://{host}.sharepoint.com", $"https://{host}-my.sharepoint.com", $"https://{host}-admin.sharepoint.com"]; + + return urls; + } + private static void EnableCaching(string url, string clientid) { var tenantUri = new Uri(url); From 1fd8c3604fd9d7eac64a35269bded205605c5dcb Mon Sep 17 00:00:00 2001 From: Erwin van Hunen Date: Thu, 28 Nov 2024 13:40:56 +0100 Subject: [PATCH 4/6] Fixed add additional URL cases --- src/Commands/Base/DisconnectOnline.cs | 4 ++-- src/Commands/Base/PnPConnection.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Commands/Base/DisconnectOnline.cs b/src/Commands/Base/DisconnectOnline.cs index 1579b7e36..6d69b62a7 100644 --- a/src/Commands/Base/DisconnectOnline.cs +++ b/src/Commands/Base/DisconnectOnline.cs @@ -13,7 +13,7 @@ public class DisconnectOnline : PSCmdlet { [Parameter(Mandatory = false)] - public SwitchParameter ClearCache; + public SwitchParameter ClearPersistedLogin; protected override void ProcessRecord() { @@ -34,7 +34,7 @@ protected override void ProcessRecord() PnPConnection.Current.Certificate = null; } - if(ClearCache) + if(ClearPersistedLogin) { PnPConnection.ClearCache(PnPConnection.Current); } diff --git a/src/Commands/Base/PnPConnection.cs b/src/Commands/Base/PnPConnection.cs index c19df6ecc..e59384046 100644 --- a/src/Commands/Base/PnPConnection.cs +++ b/src/Commands/Base/PnPConnection.cs @@ -1,6 +1,7 @@ using Microsoft.Identity.Client; using Microsoft.Identity.Client.Extensions.Msal; using Microsoft.SharePoint.Client; +using Microsoft.SharePoint.TenantCdn; using Microsoft.VisualBasic; using PnP.Core.Services; using PnP.Framework; @@ -1065,22 +1066,23 @@ private static List GetCheckUrls(string url) private static void EnableCaching(string url, string clientid) { - var tenantUri = new Uri(url); - var tenantUrl = $"https://{tenantUri.Authority}"; var configFile = Path.Combine(MsalCacheHelper.UserRootDirectory, ".m365pnppowershell", "cachesettings.json"); var configs = new List(); if (System.IO.File.Exists(configFile)) { configs = JsonSerializer.Deserialize>(System.IO.File.ReadAllText(configFile)); } - var entry = configs.FirstOrDefault(c => c.Url == tenantUrl && c.ClientId == clientid); + var urls = GetCheckUrls(url); + var entry = configs.FirstOrDefault(c => urls.Contains(c.Url) && c.ClientId == clientid); if (entry != null) { entry.Enabled = true; } else { - configs.Add(new TokenCacheConfiguration() { ClientId = clientid, Url = tenantUrl, Enabled = true }); + var baseAuthority = new Uri(url).Authority.Replace("-admin.sharepoint.com", ".sharepoint.com").Replace("-my.sharepoint.com", ".sharepoint.com"); + var baseUrl = $"https://{baseAuthority}"; + configs.Add(new TokenCacheConfiguration() { ClientId = clientid, Url = baseUrl, Enabled = true }); } System.IO.File.WriteAllText(configFile, JsonSerializer.Serialize(configs)); } @@ -1093,14 +1095,12 @@ private static void WriteCacheEnabledMessage(PSHost host) internal static void ClearCache(PnPConnection connection) { - var tenantUri = new Uri(connection.Url); - var tenantUrl = $"https://{tenantUri.Authority}"; var configFile = Path.Combine(MsalCacheHelper.UserRootDirectory, ".m365pnppowershell", "cachesettings.json"); - if (System.IO.File.Exists(configFile)) { var configs = JsonSerializer.Deserialize>(System.IO.File.ReadAllText(configFile)); - var entry = configs.FirstOrDefault(c => c.Url == tenantUrl && c.ClientId == connection.ClientId); + var urls = GetCheckUrls(connection.Url); + var entry = configs.FirstOrDefault(c => urls.Contains(c.Url) && c.ClientId == connection.ClientId); if (entry != null) { configs.Remove(entry); From 2698d69af99755db316eb88e91963c7377e7d1e3 Mon Sep 17 00:00:00 2001 From: Erwin van Hunen Date: Thu, 28 Nov 2024 13:48:58 +0100 Subject: [PATCH 5/6] added MSAL.Identity.Client.Extensions.MSAL --- src/Commands/PnP.PowerShell.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Commands/PnP.PowerShell.csproj b/src/Commands/PnP.PowerShell.csproj index 37d1d6572..c42bde2ba 100644 --- a/src/Commands/PnP.PowerShell.csproj +++ b/src/Commands/PnP.PowerShell.csproj @@ -65,6 +65,8 @@ + + From 118812e61838b573452fc783da1780d0885c299b Mon Sep 17 00:00:00 2001 From: Erwin van Hunen Date: Thu, 28 Nov 2024 13:54:51 +0100 Subject: [PATCH 6/6] Fixed for Credentials parameter set --- src/Commands/Base/ConnectOnline.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Commands/Base/ConnectOnline.cs b/src/Commands/Base/ConnectOnline.cs index 38a3a622a..a06b22ccb 100644 --- a/src/Commands/Base/ConnectOnline.cs +++ b/src/Commands/Base/ConnectOnline.cs @@ -271,6 +271,7 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_INTERACTIVE)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_DEVICELOGIN)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS)] public SwitchParameter PersistLogin; private static readonly string[] sourceArray = ["stop", "ignore", "silentlycontinue"];