From 23896aa0a0ae5304ab97f3d2c213e65cc4ae46ff Mon Sep 17 00:00:00 2001 From: darrell-thobe-sp Date: Tue, 5 Aug 2025 09:52:46 -0400 Subject: [PATCH] starting point for client id and secret override --- PSSailpoint/Configuration.ps1 | 158 ++++++++++++++++++++++++++++++++-- PSSailpoint/PSSailpoint.psd1 | 3 +- example/clientOverride.ps1 | 107 +++++++++++++++++++++++ 3 files changed, 262 insertions(+), 6 deletions(-) create mode 100644 example/clientOverride.ps1 diff --git a/PSSailpoint/Configuration.ps1 b/PSSailpoint/Configuration.ps1 index fd38a6dd1..38092db54 100644 --- a/PSSailpoint/Configuration.ps1 +++ b/PSSailpoint/Configuration.ps1 @@ -66,6 +66,14 @@ function Get-DefaultConfiguration { $Configuration["Experimental"] = $false } + if (!$Configuration.containsKey("ClientIdOverride")) { + $Configuration["ClientIdOverride"] = $null + } + + if (!$Configuration.containsKey("ClientSecretOverride")) { + $Configuration["ClientSecretOverride"] = $null + } + Return $Configuration } @@ -130,6 +138,8 @@ function Set-DefaultConfiguration { [string]$TokenUrl, [string]$ClientId, [string]$ClientSecret, + [string]$ClientIdOverride, + [string]$ClientSecretOverride, [System.Nullable[Int32]]$MaximumRetryCount, [System.Nullable[Int32]]$RetryIntervalSeconds, [System.Nullable[Boolean]]$Experimental, @@ -172,6 +182,14 @@ function Set-DefaultConfiguration { $Script:Configuration['ClientSecret'] = $ClientSecret } + If ($ClientIdOverride) { + $Script:Configuration['ClientIdOverride'] = $ClientIdOverride + } + + If ($ClientSecretOverride) { + $Script:Configuration['ClientSecretOverride'] = $ClientSecretOverride + } + If ($RetryIntervalSeconds) { $Script:Configuration['RetryIntervalSeconds'] = $RetryIntervalSeconds } @@ -200,14 +218,37 @@ function Set-DefaultConfiguration { } function Get-IDNAccessToken { + [CmdletBinding()] + Param( + [string]$ClientId, + [string]$ClientSecret + ) + Write-Debug "Getting Access Token" - if ($null -eq $Script:Configuration["ClientId"] -or $null -eq $Script:Configuration["ClientSecret"] -or $null -eq $Script:Configuration["TokenUrl"]) { + # Priority: 1. Function parameters, 2. Override configuration, 3. Default configuration + $effectiveClientId = if ($ClientId) { + $ClientId + } elseif ($Script:Configuration["ClientIdOverride"]) { + $Script:Configuration["ClientIdOverride"] + } else { + $Script:Configuration["ClientId"] + } + + $effectiveClientSecret = if ($ClientSecret) { + $ClientSecret + } elseif ($Script:Configuration["ClientSecretOverride"]) { + $Script:Configuration["ClientSecretOverride"] + } else { + $Script:Configuration["ClientSecret"] + } + + if ($null -eq $effectiveClientId -or $null -eq $effectiveClientSecret -or $null -eq $Script:Configuration["TokenUrl"]) { throw "ClientId, ClientSecret or TokenUrl Missing. Please provide values in the environment or in ~/.sailpoint/config.yaml" } else { Write-Debug $Script:Configuration["TokenUrl"] - Write-Debug $Script:Configuration["ClientId"] - Write-Debug $Script:Configuration["ClientSecret"] + Write-Debug $effectiveClientId + Write-Debug $effectiveClientSecret $multipartContent = [System.Net.Http.MultipartFormDataContent]::new() @@ -221,13 +262,13 @@ function Get-IDNAccessToken { #set client id formdata value $stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") $stringHeader.Name = "client_id" - $stringContent = [System.Net.Http.StringContent]::new([string]$Script:Configuration["ClientId"]) + $stringContent = [System.Net.Http.StringContent]::new([string]$effectiveClientId) $stringContent.Headers.ContentDisposition = $stringHeader $multipartContent.Add($stringContent) #set client secret formdata value $stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") $stringHeader.Name = "client_secret" - $stringContent = [System.Net.Http.StringContent]::new([string]$Script:Configuration["ClientSecret"]) + $stringContent = [System.Net.Http.StringContent]::new([string]$effectiveClientSecret) $stringContent.Headers.ContentDisposition = $stringHeader $multipartContent.Add($stringContent) @@ -323,3 +364,110 @@ function Get-Config { return $Configuration } + +<# +.SYNOPSIS + +Set Client ID and Client Secret overrides for all API endpoints + +.DESCRIPTION + +This function sets client ID and secret overrides that will be used for all API calls instead of the default configured values. +These overrides take precedence over environment variables and config file settings. +To clear the overrides, call this function with empty strings or use Clear-ClientCredentialOverride. + +.PARAMETER ClientId +The Client ID to use for authentication + +.PARAMETER ClientSecret +The Client Secret to use for authentication + +.EXAMPLE +Set-ClientCredentialOverride -ClientId "myClientId" -ClientSecret "myClientSecret" + +.EXAMPLE +# Clear overrides +Set-ClientCredentialOverride -ClientId "" -ClientSecret "" + +#> +function Set-ClientCredentialOverride { + [CmdletBinding()] + Param( + [Parameter(Mandatory = $true)] + [string]$ClientId, + [Parameter(Mandatory = $true)] + [string]$ClientSecret + ) + + Process { + if([string]::IsNullOrEmpty($ClientId) -or [string]::IsNullOrEmpty($ClientSecret)) { + $Script:Configuration["ClientIdOverride"] = $null + $Script:Configuration["ClientSecretOverride"] = $null + Write-Verbose "Client credential overrides cleared" + } else { + $Script:Configuration["ClientIdOverride"] = $ClientId + $Script:Configuration["ClientSecretOverride"] = $ClientSecret + Write-Verbose "Client credential overrides set" + } + } +} + +<# +.SYNOPSIS + +Clear Client ID and Client Secret overrides + +.DESCRIPTION + +This function clears any client ID and secret overrides that were set using Set-ClientCredentialOverride. +After calling this function, the SDK will revert to using the default configured credentials. + +.EXAMPLE +Clear-ClientCredentialOverride + +#> +function Clear-ClientCredentialOverride { + [CmdletBinding()] + Param() + + Process { + $Script:Configuration["ClientIdOverride"] = $null + $Script:Configuration["ClientSecretOverride"] = $null + Write-Verbose "Client credential overrides cleared" + } +} + +<# +.SYNOPSIS + +Get the current Client ID and Client Secret override status + +.DESCRIPTION + +This function returns whether client credential overrides are currently set and which client ID is being used. + +.EXAMPLE +Get-ClientCredentialOverride + +.OUTPUTS +PSCustomObject with IsOverrideSet and ClientId properties + +#> +function Get-ClientCredentialOverride { + [CmdletBinding()] + Param() + + Process { + $isOverrideSet = -not [string]::IsNullOrEmpty($Script:Configuration["ClientIdOverride"]) + $clientId = if ($isOverrideSet) { + $Script:Configuration["ClientIdOverride"] + } else { + $null + } + + return [PSCustomObject]@{ + IsOverrideSet = $isOverrideSet + ClientId = $clientId + } + } +} diff --git a/PSSailpoint/PSSailpoint.psd1 b/PSSailpoint/PSSailpoint.psd1 index 0b31ebd57..b8bbfac19 100644 --- a/PSSailpoint/PSSailpoint.psd1 +++ b/PSSailpoint/PSSailpoint.psd1 @@ -75,7 +75,8 @@ RequiredModules = @(@{ModuleName = 'PSSailpoint.Beta'; RequiredVersion = '1.6.6' FunctionsToExport = 'Get-FunctionsToExport', 'Get-DefaultConfiguration', 'Set-DefaultConfiguration', 'Get-IDNAccessToken', 'Get-EnvConfig', 'Get-LocalConfig', 'Get-Config', 'Invoke-Paginate', - 'Invoke-PaginateSearch' + 'Invoke-PaginateSearch', 'Set-ClientCredentialOverride', + 'Get-ClientCredentialOverride', 'Clear-ClientCredentialOverride' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() diff --git a/example/clientOverride.ps1 b/example/clientOverride.ps1 new file mode 100644 index 000000000..7d1c1af90 --- /dev/null +++ b/example/clientOverride.ps1 @@ -0,0 +1,107 @@ +# Example: Client Credential Override Demonstration +# This example shows various ways to use client credential overrides in the PowerShell SDK + +# Import the module (if not already imported) +# Import-Module PSSailpoint -Force + +Write-Host "=== SailPoint PowerShell SDK - Client Credential Override Demo ===" -ForegroundColor Cyan + +# Scenario 1: Temporary credential override for specific operations +Write-Host "`nScenario 1: Using override credentials for a specific task" -ForegroundColor Yellow + +# Save current configuration state +$originalStatus = Get-ClientCredentialOverride +Write-Host "Original override status: $($originalStatus.IsOverrideSet)" + +# Set override credentials (replace with actual credentials) +Set-ClientCredentialOverride -ClientId "temp-client-id" -ClientSecret "temp-client-secret" +Write-Host "Override credentials set" + +try { + # Perform operations with override credentials + Write-Host "Fetching sources with override credentials..." + $sources = Get-Sources -Limit 5 + Write-Host "Successfully retrieved $($sources.Count) sources" +} catch { + Write-Host "Error with override credentials: $_" -ForegroundColor Red +} + +# Clear overrides +Clear-ClientCredentialOverride +Write-Host "Override credentials cleared" + +# Scenario 2: Switching between multiple environments +Write-Host "`nScenario 2: Switching between environments" -ForegroundColor Yellow + +# Production environment +Write-Host "Switching to production environment..." +Set-ClientCredentialOverride -ClientId "prod-client-id" -ClientSecret "prod-client-secret" +$status = Get-ClientCredentialOverride +Write-Host "Active Client ID: $($status.ClientId)" + +# Perform production operations +# ... API calls here ... + +# Development environment +Write-Host "`nSwitching to development environment..." +Set-ClientCredentialOverride -ClientId "dev-client-id" -ClientSecret "dev-client-secret" +$status = Get-ClientCredentialOverride +Write-Host "Active Client ID: $($status.ClientId)" + +# Perform development operations +# ... API calls here ... + +# Scenario 3: Using with pagination +Write-Host "`nScenario 3: Paginated search with override credentials" -ForegroundColor Yellow + +$searchJson = @" +{ + "indices": ["identities"], + "query": { + "query": "attributes.department:Engineering", + "fields": ["name", "email"] + }, + "sort": ["name"] +} +"@ + +$search = ConvertFrom-JsonToSearch -Json $searchJson + +try { + Write-Host "Performing paginated search with override credentials..." + $results = Invoke-PaginateSearch -Increment 50 -Limit 200 -Search $search + Write-Host "Retrieved $($results.Count) identities from Engineering department" +} catch { + Write-Host "Search error: $_" -ForegroundColor Red +} + +# Scenario 4: Error handling and fallback +Write-Host "`nScenario 4: Error handling with credential override" -ForegroundColor Yellow + +# Try with potentially invalid override credentials +Set-ClientCredentialOverride -ClientId "invalid-client" -ClientSecret "invalid-secret" + +try { + $accounts = Get-Accounts -Limit 1 +} catch { + Write-Host "Failed with override credentials: $_" -ForegroundColor Red + + # Clear overrides and fall back to default + Write-Host "Falling back to default credentials..." + Clear-ClientCredentialOverride + + try { + $accounts = Get-Accounts -Limit 1 + Write-Host "Successfully retrieved accounts with default credentials" -ForegroundColor Green + } catch { + Write-Host "Also failed with default credentials: $_" -ForegroundColor Red + } +} + +# Final cleanup +Clear-ClientCredentialOverride +Write-Host "`nDemo completed. All credential overrides have been cleared." -ForegroundColor Cyan + +# Display final status +$finalStatus = Get-ClientCredentialOverride +Write-Host "Final override status: $($finalStatus.IsOverrideSet)" \ No newline at end of file