From 94c157973c302919f6769d48f4c8f5bd53b3c804 Mon Sep 17 00:00:00 2001 From: Gautam Sheth Date: Mon, 21 Apr 2025 21:50:12 +0300 Subject: [PATCH] Add support for Federated Identity Credentials in connection methods and parameters --- documentation/Connect-PnPOnline.md | 44 +++++++- src/Commands/Base/ConnectOnline.cs | 66 ++++++++++++ src/Commands/Base/PnPConnection.cs | 132 +++++++++++++++-------- src/Commands/Enums/InitializationType.cs | 3 +- src/Commands/Model/ConnectionMethod.cs | 5 +- 5 files changed, 197 insertions(+), 53 deletions(-) diff --git a/documentation/Connect-PnPOnline.md b/documentation/Connect-PnPOnline.md index cbde984cf..c7825c0ca 100644 --- a/documentation/Connect-PnPOnline.md +++ b/documentation/Connect-PnPOnline.md @@ -112,6 +112,21 @@ Connect-PnPOnline -OSLogin [-ReturnConnection] [-Url] [-PersistLogin] [ [-ClientId ] [-AzureEnvironment ] [-TenantAdminUrl ] [-ForceAuthentication] [-ValidateConnection] [-MicrosoftGraphEndPoint ] [-AzureADLoginEndPoint ] [-Connection ] ``` +### Federated Identity Credentials with User Assigned Managed Identity by Client Id +```powershell +Connect-PnPOnline [-Url ] [-Tenant ] -FederatedIdentityCredentials -UserAssignedManagedIdentityClientId [-AzureEnvironment ] [-TenantAdminUrl ] [-ValidateConnection] [-MicrosoftGraphEndPoint ] [-AzureADLoginEndPoint ] [-Connection ] +``` + +### Federated Identity Credentials with User Assigned Managed Identity by Principal Id +```powershell +Connect-PnPOnline [-Url ] -FederatedIdentityCredentials -UserAssignedManagedIdentityObjectId [-AzureEnvironment ] [-TenantAdminUrl ] [-ValidateConnection] [-MicrosoftGraphEndPoint ] [-AzureADLoginEndPoint ] [-Connection ] +``` + +### Federated Identity Credentials with User Assigned Managed Identity by Azure Resource Id +```powershell +Connect-PnPOnline [-Url ] -FederatedIdentityCredentials -UserAssignedManagedIdentityAzureResourceId [-AzureEnvironment ] [-TenantAdminUrl ] [-ValidateConnection] [-MicrosoftGraphEndPoint ] [-AzureADLoginEndPoint ] [-Connection ] +``` + ## DESCRIPTION Connects to a SharePoint site or another API and creates a context that is required for the other PnP Cmdlets. See https://pnp.github.io/powershell/articles/connecting.html for more information on the options to connect. @@ -289,6 +304,13 @@ Connect to SharePoint using Credentials (username and password) from Credential On Windows, this entry needs to be under "Generic Credentials". +### EXAMPLE 20 +```powershell +Connect-PnPOnline -Url "https://contoso.sharepoint.com" -ClientId 6c5c98c7-e05a-4a0f-bcfa-0cfc65aa1f28 -Tenant 'contoso.onmicrosoft.com' -FederatedIdentityCredentials -UserAssignedManagedIdentityObjectId 363c1b31-6872-47fd-a616-574d3aec2a51 +``` + +Connect to SharePoint/Microsoft Graph using federated identity credentials. + ## PARAMETERS ### -AccessToken @@ -715,7 +737,7 @@ Can be used in combination with `-ManagedIdentity` to specify the object/princip ```yaml Type: String -Parameter Sets: User Assigned Managed Identity by Principal Id +Parameter Sets: User Assigned Managed Identity by Principal Id, Federated Identity Credentials, Federated Identity Credentials by Principal Id Aliases: UserAssignedManagedIdentityPrincipalId Required: False @@ -730,7 +752,7 @@ Can be used in combination with `-ManagedIdentity` to specify the client id of t ```yaml Type: String -Parameter Sets: User Assigned Managed Identity by Client Id +Parameter Sets: User Assigned Managed Identity by Client Id, Federated Identity Credentials, Federated Identity Credentials by Client Id Aliases: Required: False @@ -745,7 +767,7 @@ Can be used in combination with `-ManagedIdentity` to specify the Azure Resource ```yaml Type: String -Parameter Sets: User Assigned Managed Identity by Azure Resource Id +Parameter Sets: User Assigned Managed Identity by Azure Resource Id, Federated Identity Credentials, Federated Identity Credentials by Azure Resource Id Aliases: Required: False @@ -876,6 +898,22 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -FederatedIdentityCredentials + +Connects using Federated Identity credentials. For more information on this, you can visit [this link](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-create-trust?pivots=identity-wif-apps-methods-rest). + +```yaml +Type: SwitchParameter +Parameter Sets: Federated Identity Credentials, Federated Identity Credentials by Client Id, Federated Identity Credentials by Principal Id, Federated Identity Credentials by Azure Resource Id +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ## RELATED LINKS [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) diff --git a/src/Commands/Base/ConnectOnline.cs b/src/Commands/Base/ConnectOnline.cs index e6cd06d99..50da1712a 100644 --- a/src/Commands/Base/ConnectOnline.cs +++ b/src/Commands/Base/ConnectOnline.cs @@ -37,6 +37,10 @@ public class ConnectOnline : BasePSCmdlet private const string ParameterSet_ENVIRONMENTVARIABLE = "Environment Variable"; private const string ParameterSet_AZUREAD_WORKLOAD_IDENTITY = "Azure AD Workload Identity"; private const string ParameterSet_OSLOGIN = "OS login"; + private const string ParameterSet_FEDERATEDIDENTITYCREDENTIALS = "Federated Identity Credentials"; + private const string ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID = "Federated Identity Credentials by Client Id"; + private const string ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID = "Federated Identity Credentials by Principal Id"; + private const string ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID = "Federated Identity Credentials by Azure Resource Id"; [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS, ValueFromPipeline = true)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACSAPPONLY, ValueFromPipeline = true)] @@ -52,6 +56,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_AZUREAD_WORKLOAD_IDENTITY)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN, ValueFromPipeline = true)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] public SwitchParameter ReturnConnection; [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS, ValueFromPipeline = true)] @@ -68,6 +76,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID, ValueFromPipeline = true)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_AZUREAD_WORKLOAD_IDENTITY, ValueFromPipeline = true)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN, ValueFromPipeline = true)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS, ValueFromPipeline = true)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID, ValueFromPipeline = true)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID, ValueFromPipeline = true)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID, ValueFromPipeline = true)] public SwitchParameter ValidateConnection; [Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_CREDENTIALS, ValueFromPipeline = true)] @@ -84,6 +96,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_ENVIRONMENTVARIABLE, ValueFromPipeline = true)] [Parameter(Mandatory = false, Position = 0, ParameterSetName = ParameterSet_AZUREAD_WORKLOAD_IDENTITY, ValueFromPipeline = true)] [Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_OSLOGIN, ValueFromPipeline = true)] + [Parameter(Mandatory = false, Position = 0, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS, ValueFromPipeline = true)] + [Parameter(Mandatory = false, Position = 0, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID, ValueFromPipeline = true)] + [Parameter(Mandatory = false, Position = 0, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID, ValueFromPipeline = true)] + [Parameter(Mandatory = false, Position = 0, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID, ValueFromPipeline = true)] public string Url; [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS)] @@ -140,6 +156,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_INTERACTIVE)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_DEVICELOGIN)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] [Alias("ApplicationId")] public string ClientId; @@ -153,6 +173,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_DEVICELOGIN)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ENVIRONMENTVARIABLE)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] public string Tenant; [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCERTIFICATE)] @@ -184,6 +208,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYCLIENTID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYPRINCIPALID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] public Framework.AzureEnvironment AzureEnvironment = Framework.AzureEnvironment.Production; // [Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYCLIENTIDCLIENTSECRETAADDOMAIN)] @@ -204,14 +232,23 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = true, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID)] public SwitchParameter ManagedIdentity; + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] + public SwitchParameter FederatedIdentityCredentials; + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYPRINCIPALID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] [Alias("UserAssignedManagedIdentityPrincipalId")] public string UserAssignedManagedIdentityObjectId; [Parameter(Mandatory = true, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYCLIENTID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] public string UserAssignedManagedIdentityClientId; [Parameter(Mandatory = true, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID)] + [Parameter(Mandatory = true, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] public string UserAssignedManagedIdentityAzureResourceId; [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS)] @@ -244,6 +281,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYPRINCIPALID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] public string MicrosoftGraphEndPoint; [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS)] @@ -259,6 +300,10 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYPRINCIPALID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_USERASSIGNEDMANAGEDIDENTITYBYAZURERESOURCEID)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_OSLOGIN)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALS)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID)] public string AzureADLoginEndPoint; [Parameter(Mandatory = true, ParameterSetName = ParameterSet_AZUREAD_WORKLOAD_IDENTITY)] @@ -376,6 +421,12 @@ protected void Connect(ref CancellationToken cancellationToken) case ParameterSet_OSLOGIN: newConnection = ConnectWithOSLogin(); break; + case ParameterSet_FEDERATEDIDENTITYCREDENTIALS: + case ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYAZURERESOURCEID: + case ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYCLIENTID: + case ParameterSet_FEDERATEDIDENTITYCREDENTIALSBYPRINCIPALID: + newConnection = ConnectFederatedIdentityCredentials(); + break; } // Ensure a connection instance has been created by now @@ -916,6 +967,21 @@ private PnPConnection ConnectWithOSLogin() return PnPConnection.CreateWithInteractiveLogin(new Uri(Url.ToLower()), ClientId, TenantAdminUrl, AzureEnvironment, cancellationTokenSource, ForceAuthentication, Tenant, true, PersistLogin, Host); } + private PnPConnection ConnectFederatedIdentityCredentials() + { + // Add validation for FederatedIdentityCredentials to ensure at least one identity parameter is specified + if (!ParameterSpecified(nameof(UserAssignedManagedIdentityClientId)) && + !ParameterSpecified(nameof(UserAssignedManagedIdentityObjectId)) && + !ParameterSpecified(nameof(UserAssignedManagedIdentityAzureResourceId))) + { + throw new PSArgumentException("When using FederatedIdentityCredentials, you must specify at least one of the following parameters: UserAssignedManagedIdentityClientId, UserAssignedManagedIdentityObjectId, or UserAssignedManagedIdentityAzureResourceId."); + } + LogDebug("Connecting using Federated Identity Credentials"); + + var tenantId = TenantExtensions.GetTenantIdByUrl(Url, AzureEnvironment); + + return PnPConnection.CreateWithFederatedIdentityCredentials(Url, TenantAdminUrl, ClientId, tenantId, UserAssignedManagedIdentityObjectId, UserAssignedManagedIdentityClientId, UserAssignedManagedIdentityAzureResourceId); + } #endregion #region Helper methods diff --git a/src/Commands/Base/PnPConnection.cs b/src/Commands/Base/PnPConnection.cs index d1b2b2f9f..4e573d55c 100644 --- a/src/Commands/Base/PnPConnection.cs +++ b/src/Commands/Base/PnPConnection.cs @@ -378,27 +378,6 @@ internal static PnPConnection CreateWithCert(Uri url, string clientId, string te /// Instantiated PnPConnection internal static PnPConnection CreateWithManagedIdentity(string url, string tenantAdminUrl, string userAssignedManagedIdentityObjectId = null, string userAssignedManagedIdentityClientId = null, string userAssignedManagedIdentityAzureResourceId = null) { - var endPoint = Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT"); - PnP.Framework.Diagnostics.Log.Debug("PnPConnection", $"Using identity endpoint: {endPoint}"); - //cmdlet.LogDebug($"Using identity endpoint: {endPoint}"); - - var identityHeader = Environment.GetEnvironmentVariable("IDENTITY_HEADER"); - PnP.Framework.Diagnostics.Log.Debug("PnPConnection", $"Using identity header: {identityHeader}"); - //cmdlet.LogDebug($"Using identity header: {identityHeader}"); - - if (string.IsNullOrEmpty(endPoint)) - { - endPoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT"); - identityHeader = Environment.GetEnvironmentVariable("MSI_SECRET"); - } - if (string.IsNullOrEmpty(endPoint)) - { - // additional fallback - // using well-known endpoint for Instance Metadata Service, useful in Azure VM scenario. - // https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http - endPoint = "http://169.254.169.254/metadata/identity/oauth2/token"; - } - // Define the type of Managed Identity that will be used ManagedIdentityType managedIdentityType = ManagedIdentityType.SystemAssigned; string managedIdentityUserAssignedIdentifier = null; @@ -426,32 +405,35 @@ internal static PnPConnection CreateWithManagedIdentity(string url, string tenan } // Set up the AuthenticationManager in PnP Framework to use a Managed Identity context - using var authManager = new Framework.AuthenticationManager(endPoint, identityHeader, managedIdentityType, managedIdentityUserAssignedIdentifier); - PnPClientContext context = null; - ConnectionType connectionType = ConnectionType.O365; - if (url != null) + using (var authManager = Framework.AuthenticationManager.CreateWithManagedIdentity(null, null, managedIdentityType, managedIdentityUserAssignedIdentifier)) { - context = PnPClientContext.ConvertFrom(authManager.GetContext(url.ToString())); - context.ApplicationName = Resources.ApplicationName; - context.DisableReturnValueCache = true; - context.ExecutingWebRequest += (sender, e) => - { - e.WebRequestExecutor.WebRequest.UserAgent = $"NONISV|SharePointPnP|PnPPS/{((AssemblyFileVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttribute(typeof(AssemblyFileVersionAttribute))).Version} ({System.Environment.OSVersion.VersionString})"; - }; - if (IsTenantAdminSite(context)) + PnPClientContext context = null; + ConnectionType connectionType = ConnectionType.O365; + if (url != null) { - connectionType = ConnectionType.TenantAdmin; + context = PnPClientContext.ConvertFrom(authManager.GetContext(url.ToString())); + context.ApplicationName = Resources.ApplicationName; + context.DisableReturnValueCache = true; + context.ExecutingWebRequest += (sender, e) => + { + e.WebRequestExecutor.WebRequest.UserAgent = $"NONISV|SharePointPnP|PnPPS/{((AssemblyFileVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttribute(typeof(AssemblyFileVersionAttribute))).Version} ({System.Environment.OSVersion.VersionString})"; + }; + if (IsTenantAdminSite(context)) + { + connectionType = ConnectionType.TenantAdmin; + } } - } - // Set up PnP PowerShell to use a Managed Identity - var connection = new PnPConnection(context, connectionType, null, url?.ToString(), tenantAdminUrl, PnPPSVersionTag, InitializationType.ManagedIdentity) - { - UserAssignedManagedIdentityObjectId = userAssignedManagedIdentityObjectId, - UserAssignedManagedIdentityClientId = userAssignedManagedIdentityClientId, - UserAssignedManagedIdentityAzureResourceId = userAssignedManagedIdentityAzureResourceId - }; - return connection; + // Set up PnP PowerShell to use a Managed Identity + var connection = new PnPConnection(context, connectionType, null, url?.ToString(), tenantAdminUrl, PnPPSVersionTag, InitializationType.ManagedIdentity) + { + UserAssignedManagedIdentityObjectId = userAssignedManagedIdentityObjectId, + UserAssignedManagedIdentityClientId = userAssignedManagedIdentityClientId, + UserAssignedManagedIdentityAzureResourceId = userAssignedManagedIdentityAzureResourceId, + ConnectionMethod = ConnectionMethod.ManagedIdentity, + }; + return connection; + } } internal static PnPConnection CreateWithCredentials(Cmdlet cmdlet, Uri url, PSCredential credentials, bool currentCredentials, string tenantAdminUrl, bool persistLogin, System.Management.Automation.Host.PSHost host, AzureEnvironment azureEnvironment = AzureEnvironment.Production, string clientId = null, string redirectUrl = null, bool onPrem = false, InitializationType initializationType = InitializationType.Credentials) @@ -675,6 +657,66 @@ internal static PnPConnection CreateWithAzureADWorkloadIdentity(string url, stri return connection; } } + + internal static PnPConnection CreateWithFederatedIdentityCredentials(string url, string tenantAdminUrl, string appClientId, string tenantId, string userAssignedManagedIdentityObjectId = null, string userAssignedManagedIdentityClientId = null, string userAssignedManagedIdentityAzureResourceId = null) + { + // Define the type of Managed Identity that will be used + ManagedIdentityType managedIdentityType = ManagedIdentityType.SystemAssigned; + string managedIdentityUserAssignedIdentifier = null; + + if (!string.IsNullOrEmpty(userAssignedManagedIdentityObjectId)) + { + managedIdentityType = ManagedIdentityType.UserAssignedByObjectId; + managedIdentityUserAssignedIdentifier = userAssignedManagedIdentityObjectId; + } + if (!string.IsNullOrEmpty(userAssignedManagedIdentityClientId)) + { + managedIdentityType = ManagedIdentityType.UserAssignedByClientId; + managedIdentityUserAssignedIdentifier = userAssignedManagedIdentityClientId; + } + if (!string.IsNullOrEmpty(userAssignedManagedIdentityAzureResourceId)) + { + managedIdentityType = ManagedIdentityType.UserAssignedByResourceId; + managedIdentityUserAssignedIdentifier = userAssignedManagedIdentityAzureResourceId; + } + + // Ensure if its not a System Assigned Managed Identity, that we an identifier pointing to the user assigned Managed Identity + if (managedIdentityType != ManagedIdentityType.SystemAssigned && string.IsNullOrEmpty(managedIdentityUserAssignedIdentifier)) + { + throw new InvalidOperationException("Unable to use a User Assigned Managed Identity without passing in an identifier for the User Assigned Managed Identity."); + } + + // Set up the AuthenticationManager in PnP Framework to use a Managed Identity context + using (var authManager = Framework.AuthenticationManager.CreateWithManagedIdentityFederatedIdentityCredential(null, null, appClientId, tenantId, managedIdentityType, managedIdentityUserAssignedIdentifier)) + { + PnPClientContext context = null; + ConnectionType connectionType = ConnectionType.O365; + if (url != null) + { + context = PnPClientContext.ConvertFrom(authManager.GetContext(url.ToString())); + context.ApplicationName = Resources.ApplicationName; + context.DisableReturnValueCache = true; + context.ExecutingWebRequest += (sender, e) => + { + e.WebRequestExecutor.WebRequest.UserAgent = $"NONISV|SharePointPnP|PnPPS/{((AssemblyFileVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttribute(typeof(AssemblyFileVersionAttribute))).Version} ({System.Environment.OSVersion.VersionString})"; + }; + if (IsTenantAdminSite(context)) + { + connectionType = ConnectionType.TenantAdmin; + } + } + + // Set up PnP PowerShell to use a Managed Identity + var connection = new PnPConnection(context, connectionType, null, url?.ToString(), tenantAdminUrl, PnPPSVersionTag, InitializationType.FederatedIdentityCredentials) + { + UserAssignedManagedIdentityObjectId = userAssignedManagedIdentityObjectId, + UserAssignedManagedIdentityClientId = userAssignedManagedIdentityClientId, + UserAssignedManagedIdentityAzureResourceId = userAssignedManagedIdentityAzureResourceId, + ConnectionMethod = ConnectionMethod.FederatedIdentityCredentials, + }; + return connection; + } + } #endregion #region Constructors @@ -701,10 +743,6 @@ private PnPConnection(ClientContext context, { connectionMethod = ConnectionMethod.AzureADWorkloadIdentity; } - else if (initializationType == InitializationType.ManagedIdentity) - { - connectionMethod = ConnectionMethod.ManagedIdentity; - } if (context != null) { diff --git a/src/Commands/Enums/InitializationType.cs b/src/Commands/Enums/InitializationType.cs index b724f212d..7d2c56afc 100644 --- a/src/Commands/Enums/InitializationType.cs +++ b/src/Commands/Enums/InitializationType.cs @@ -15,6 +15,7 @@ public enum InitializationType GraphDeviceLogin, ManagedIdentity, EnvironmentVariable, - AzureADWorkloadIdentity + AzureADWorkloadIdentity, + FederatedIdentityCredentials } } diff --git a/src/Commands/Model/ConnectionMethod.cs b/src/Commands/Model/ConnectionMethod.cs index b80cfbb28..b6bfaf952 100644 --- a/src/Commands/Model/ConnectionMethod.cs +++ b/src/Commands/Model/ConnectionMethod.cs @@ -32,7 +32,8 @@ public enum ConnectionMethod /// Using a System Assigned or User Assigned Managed Identity /// ManagedIdentity, - - AzureADWorkloadIdentity + + AzureADWorkloadIdentity, + FederatedIdentityCredentials } }