From 422943f2b166d5c43022e0ebe6ccfa6efff1e709 Mon Sep 17 00:00:00 2001 From: Fabian Hutzli Date: Mon, 13 Jul 2026 13:47:45 +0200 Subject: [PATCH] Add GitLab CI/CD support to Connect-PnPOnline -FederatedIdentity Detects GitLab CI via GITLAB_CI and GITLAB_OIDC_TOKEN (populated by the id_tokens block in .gitlab-ci.yml) and exchanges that OIDC token for an Entra ID access token via the existing federated token exchange, alongside the current GitHub Actions and Azure DevOps support. --- documentation/Connect-PnPOnline.md | 20 ++++++++++++++++++-- src/Commands/Base/TokenHandler.cs | 19 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/documentation/Connect-PnPOnline.md b/documentation/Connect-PnPOnline.md index 620cd7bee0..6a6c24806e 100644 --- a/documentation/Connect-PnPOnline.md +++ b/documentation/Connect-PnPOnline.md @@ -308,6 +308,22 @@ Connect-PnPOnline -Url "https://contoso.sharepoint.com" -FederatedIdentity Connect to SharePoint/Microsoft Graph using federated identity credentials in Azure DevOps. This option is available from version 3.1.51-nightly onwards. +### EXAMPLE 22 +```powershell +Connect-PnPOnline -Url "https://contoso.sharepoint.com" -ClientId 6c5c98c7-e05a-4a0f-bcfa-0cfc65aa1f28 -Tenant 'contoso.onmicrosoft.com' -FederatedIdentity +``` + +Connect to SharePoint/Microsoft Graph using federated identity credentials in GitLab CI/CD. This requires the job to request an ID token named `GITLAB_OIDC_TOKEN` with audience `api://AzureADTokenExchange`, for example: + +```yaml +job: + id_tokens: + GITLAB_OIDC_TOKEN: + aud: api://AzureADTokenExchange +``` + +The corresponding federated credential on the Entra ID app registration must have issuer `https://gitlab.com` (or your self-managed GitLab instance URL) and a subject matching the GitLab OIDC claim for the job, e.g. `project_path:/:ref_type:branch:ref:`. + ## PARAMETERS ### -AccessToken @@ -822,7 +838,7 @@ Accept wildcard characters: False ``` ### -AzureADWorkloadIdentity -Connects using Azure AD Workload Identity in Azure workload identity environments where `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_AUTHORITY_HOST`, and `AZURE_FEDERATED_TOKEN_FILE` are available. For GitHub Actions and Azure DevOps pipelines, use `-FederatedIdentity` instead. +Connects using Azure AD Workload Identity in Azure workload identity environments where `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_AUTHORITY_HOST`, and `AZURE_FEDERATED_TOKEN_FILE` are available. For GitHub Actions, Azure DevOps and GitLab CI/CD pipelines, use `-FederatedIdentity` instead. ```yaml Type: SwitchParameter @@ -879,7 +895,7 @@ Accept wildcard characters: False ### -FederatedIdentity -Connects using Federated Identity. Use this option for GitHub Actions and Azure DevOps pipelines. For Azure workload identity environments that provide `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_AUTHORITY_HOST`, and `AZURE_FEDERATED_TOKEN_FILE`, use `-AzureADWorkloadIdentity` instead. 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). +Connects using Federated Identity. Use this option for GitHub Actions, Azure DevOps and GitLab CI/CD pipelines. For Azure workload identity environments that provide `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_AUTHORITY_HOST`, and `AZURE_FEDERATED_TOKEN_FILE`, use `-AzureADWorkloadIdentity` instead. 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). This option is available from version 3.1.51-nightly onwards. diff --git a/src/Commands/Base/TokenHandler.cs b/src/Commands/Base/TokenHandler.cs index 5cd291c0b1..fe00279e4a 100644 --- a/src/Commands/Base/TokenHandler.cs +++ b/src/Commands/Base/TokenHandler.cs @@ -346,7 +346,7 @@ internal static async Task GetAzureADWorkloadIdentityTokenAsync(string r } /// - /// Returns an access token based on a Federated Identity. Only works within Azure components supporting federated identities like GitHub/AzureDevOps. + /// Returns an access token based on a Federated Identity. Only works within Azure components supporting federated identities like GitHub Actions, Azure DevOps and GitLab CI/CD. /// /// The client Id of the Federated Identity application /// The tenant Id of the Federated Identity application @@ -363,6 +363,8 @@ internal static async Task GetFederatedIdentityTokenAsync(string clientI var actionsIdTokenRequestUrl = Environment.GetEnvironmentVariable("ACTIONS_ID_TOKEN_REQUEST_URL"); var actionsIdTokenRequestToken = Environment.GetEnvironmentVariable("ACTIONS_ID_TOKEN_REQUEST_TOKEN"); var systemOidcRequestUri = Environment.GetEnvironmentVariable("SYSTEM_OIDCREQUESTURI"); + var gitlabCi = Environment.GetEnvironmentVariable("GITLAB_CI"); + var gitlabOidcToken = Environment.GetEnvironmentVariable("GITLAB_OIDC_TOKEN"); if (!string.IsNullOrWhiteSpace(actionsIdTokenRequestUrl) && !string.IsNullOrWhiteSpace(actionsIdTokenRequestToken)) { @@ -403,9 +405,22 @@ internal static async Task GetFederatedIdentityTokenAsync(string clientI var federationToken = await GetFederationTokenFromAzureDevOpsAsync(systemOidcRequestUri, systemAccessToken, serviceConnectionId); return await GetAccessTokenWithFederatedTokenAsync(serviceConnectionAppId, serviceConnectionTenantId, requiredScope, federationToken); } + else if (!string.IsNullOrWhiteSpace(gitlabCi) && !string.IsNullOrWhiteSpace(gitlabOidcToken)) + { + if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(tenant)) + { + throw new PSInvalidOperationException("ClientId and Tenant must be provided when using Federated Identity in GitLab CI/CD."); + } + + Framework.Diagnostics.Log.Debug("TokenHandler", "GITLAB_CI and GITLAB_OIDC_TOKEN env variables found. The context is GitLab CI/CD..."); + + // GitLab's id_tokens feature mints the OIDC JWT directly into the configured job variable, so no + // separate request to GitLab is needed to obtain the federation token before exchanging it with Entra ID. + return await GetAccessTokenWithFederatedTokenAsync(clientId, tenant, requiredScope, gitlabOidcToken); + } else { - throw new PSInvalidOperationException("Federated identity is currently only supported in GitHub Actions and Azure DevOps."); + throw new PSInvalidOperationException("Federated identity is currently only supported in GitHub Actions, Azure DevOps and GitLab CI/CD."); } }