Public/Connection/Connect-JIM.ps1
|
function Connect-JIM { <# .SYNOPSIS Connects to a JIM instance for administration. .DESCRIPTION Establishes a connection to a JIM (Junctional Identity Manager) instance. This connection is required before using any other JIM cmdlets. Supports two authentication methods: 1. Interactive browser-based SSO authentication (default for interactive sessions) 2. API key authentication (for automation, CI/CD, and scripting) .PARAMETER Url The base URL of the JIM instance, e.g., 'https://jim.company.com' or 'http://localhost:5200'. .PARAMETER ApiKey The API key for authentication. API keys can be created in the JIM web interface under Admin > API Keys. When specified, skips interactive authentication. .PARAMETER Force Forces re-authentication even if a valid session exists. .PARAMETER TimeoutSeconds How long to wait for interactive authentication to complete. Defaults to 300 (5 minutes). .OUTPUTS Returns the connection information on success. .EXAMPLE Connect-JIM -Url "https://jim.company.com" Connects using interactive browser-based SSO authentication. Opens the default browser for authentication. .EXAMPLE Connect-JIM -Url "https://jim.company.com" -ApiKey "jim_ak_abc123..." Connects using an API key (for automation scenarios). .EXAMPLE Connect-JIM -Url "http://localhost:5200" -ApiKey $env:JIM_API_KEY Connects to a local JIM instance using an API key from an environment variable. .EXAMPLE Connect-JIM -Url "https://jim.company.com" -Force Forces re-authentication, ignoring any cached session. .NOTES Interactive authentication requires: - SSO to be configured on the JIM server - A browser to be available - The IDP to have localhost redirect URIs configured For automation scenarios (CI/CD, scripts), use API key authentication. API keys can be created in the JIM web interface under Admin > API Keys. .LINK Disconnect-JIM Test-JIMConnection https://github.com/TetronIO/JIM #> [CmdletBinding(DefaultParameterSetName = 'Interactive')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string]$Url, [Parameter(Mandatory, ParameterSetName = 'ApiKey', Position = 1)] [ValidateNotNullOrEmpty()] [string]$ApiKey, [Parameter(ParameterSetName = 'Interactive')] [switch]$Force, [Parameter(ParameterSetName = 'Interactive')] [ValidateRange(30, 600)] [int]$TimeoutSeconds = 300 ) Write-Verbose "Connecting to JIM at $Url" # Validate URL format if (-not ($Url -match '^https?://')) { throw "Invalid URL format. URL must start with http:// or https://" } $baseUrl = $Url.TrimEnd('/') # Check if we should use API key authentication if ($PSCmdlet.ParameterSetName -eq 'ApiKey') { return Connect-JIMWithApiKey -BaseUrl $baseUrl -ApiKey $ApiKey } # Interactive authentication return Connect-JIMInteractive -BaseUrl $baseUrl -Force:$Force -TimeoutSeconds $TimeoutSeconds } function Connect-JIMWithApiKey { <# .SYNOPSIS Internal function to connect using API key authentication. #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [string]$BaseUrl, [Parameter(Mandatory)] [string]$ApiKey ) # Store connection info $script:JIMConnection = [PSCustomObject]@{ Url = $BaseUrl ApiKey = $ApiKey AccessToken = $null RefreshToken = $null TokenExpiresAt = $null AuthMethod = 'ApiKey' Connected = $false } # Test the connection try { Write-Verbose "Testing connection to JIM..." $health = Invoke-JIMApi -Endpoint '/api/v1/health' $script:JIMConnection.Connected = $true # Fetch server version $serverVersion = Get-JIMServerVersion Write-Verbose "Successfully connected to JIM using API key" if ($serverVersion) { Write-Host "" Write-Host "Connected to JIM server v$serverVersion at $BaseUrl" -ForegroundColor Green Write-Host "" } # Return connection info (without exposing full API key) $keyPreview = if ($ApiKey.Length -gt 12) { $ApiKey.Substring(0, 8) + "..." + $ApiKey.Substring($ApiKey.Length - 4) } else { "***" } [PSCustomObject]@{ Url = $script:JIMConnection.Url AuthMethod = 'ApiKey' ApiKey = $keyPreview Connected = $true ServerVersion = $serverVersion Status = $health.status ?? 'Connected' } } catch { $script:JIMConnection = $null throw "Failed to connect to JIM at $BaseUrl`: $_" } } function Connect-JIMInteractive { <# .SYNOPSIS Internal function to connect using interactive browser authentication. #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [string]$BaseUrl, [switch]$Force, [int]$TimeoutSeconds = 300 ) # Check for existing valid session if (-not $Force -and $script:JIMConnection -and $script:JIMConnection.AuthMethod -eq 'OAuth') { if ($script:JIMConnection.Url -eq $BaseUrl -and $script:JIMConnection.Connected) { # Check if token is still valid (with 5 minute buffer) if ($script:JIMConnection.TokenExpiresAt -and $script:JIMConnection.TokenExpiresAt -gt (Get-Date).AddMinutes(5)) { Write-Verbose "Using existing valid OAuth session" return [PSCustomObject]@{ Url = $script:JIMConnection.Url AuthMethod = 'OAuth' Connected = $true ExpiresAt = $script:JIMConnection.TokenExpiresAt Status = 'Connected (cached)' } } # Try to refresh the token if ($script:JIMConnection.RefreshToken -and $script:JIMConnection.OAuthConfig) { try { Write-Verbose "Access token expired, attempting refresh..." $tokens = Invoke-OAuthTokenRefresh ` -TokenEndpoint $script:JIMConnection.OAuthConfig.TokenEndpoint ` -ClientId $script:JIMConnection.OAuthConfig.ClientId ` -RefreshToken $script:JIMConnection.RefreshToken ` -Scopes $script:JIMConnection.OAuthConfig.Scopes $script:JIMConnection.AccessToken = $tokens.AccessToken $script:JIMConnection.RefreshToken = $tokens.RefreshToken $script:JIMConnection.TokenExpiresAt = $tokens.ExpiresAt Write-Verbose "Successfully refreshed access token" return [PSCustomObject]@{ Url = $script:JIMConnection.Url AuthMethod = 'OAuth' Connected = $true ExpiresAt = $tokens.ExpiresAt Status = 'Connected (refreshed)' } } catch { Write-Verbose "Token refresh failed, proceeding with full authentication: $_" } } } } # Get OAuth configuration from JIM Write-Verbose "Fetching OAuth configuration from JIM..." try { $authConfig = Invoke-RestMethod -Uri "$BaseUrl/api/v1/auth/config" -Method Get } catch { $statusCode = $_.Exception.Response.StatusCode.value__ if ($statusCode -eq 503) { throw "SSO is not configured on this JIM instance. Use Connect-JIM with -ApiKey parameter for API key authentication." } throw "Failed to get OAuth configuration from JIM: $_" } # Get OIDC discovery document Write-Verbose "Fetching OIDC discovery document from $($authConfig.authority)..." $discovery = Get-OidcDiscoveryDocument -Authority $authConfig.authority # Perform browser-based authentication Write-Host "" Write-Host "Starting interactive authentication with JIM..." -ForegroundColor Cyan Write-Host "You will be redirected to your organisation's identity provider." -ForegroundColor Gray Write-Host "" $tokens = Invoke-OAuthBrowserFlow ` -AuthorizeEndpoint $discovery.AuthorizeEndpoint ` -TokenEndpoint $discovery.TokenEndpoint ` -ClientId $authConfig.clientId ` -Scopes $authConfig.scopes ` -TimeoutSeconds $TimeoutSeconds # Store connection info $script:JIMConnection = [PSCustomObject]@{ Url = $BaseUrl ApiKey = $null AccessToken = $tokens.AccessToken RefreshToken = $tokens.RefreshToken TokenExpiresAt = $tokens.ExpiresAt AuthMethod = 'OAuth' Connected = $false OAuthConfig = @{ Authority = $authConfig.authority ClientId = $authConfig.clientId Scopes = $authConfig.scopes TokenEndpoint = $discovery.TokenEndpoint } } # Test the connection with the new token try { Write-Verbose "Testing connection to JIM with OAuth token..." $health = Invoke-JIMApi -Endpoint '/api/v1/health' $script:JIMConnection.Connected = $true # Fetch server version $serverVersion = Get-JIMServerVersion Write-Host "" if ($serverVersion) { Write-Host "Connected to JIM server v$serverVersion at $BaseUrl" -ForegroundColor Green } else { Write-Host "Successfully connected to JIM!" -ForegroundColor Green } Write-Host "" [PSCustomObject]@{ Url = $script:JIMConnection.Url AuthMethod = 'OAuth' Connected = $true ServerVersion = $serverVersion ExpiresAt = $tokens.ExpiresAt Status = $health.status ?? 'Connected' } } catch { $script:JIMConnection = $null throw "Authentication succeeded but failed to connect to JIM API: $_" } } |