Functions/CSP/Private/AuthManager.class.ps1
|
class AuthManager { [string]$Type [string]$Email [string]$CSPRegion = 'US' [string]$CSPUrl [string]$APIKey [string]$JWT [System.Timers.Timer]$RenewalTimer [string]$TimerEventId AuthManager([string]$region = 'US') { $this.CSPRegion = $region switch ($region) { 'US' { $this.CSPUrl = 'https://csp.infoblox.com' } 'EU' { $this.CSPUrl = 'https://csp.eu.infoblox.com' } default { throw "Unsupported region: $region" } } } [void]ConnectJWT([string]$email,[securestring]$SecurePassword) { $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) $plainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) $this.Type = 'JWT' $this.Email = $email $body = @{ email = $this.Email password = $plainPassword } | ConvertTo-Json $headers = @{ "Content-Type" = "application/json" } try { $result = Invoke-RestMethod -Method POST -Uri "$($this.CSPUrl)/v2/session/users/sign_in" -Body $body -Headers $headers if ($result.jwt) { $this.JWT = $result.jwt $this.StartRenewalTimer() Write-Host "Connected as $($this.Email)" -ForegroundColor Green } else { throw "No JWT returned." } } catch { Write-Error "Failed to connect: $_" } } [void]ConnectAPIKey([securestring]$SecureAPIKey) { $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureAPIKey) $this.APIKey = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) $this.Type = 'API' } [void]Disconnect() { if (-not $this.JWT -and -not $this.APIKey) { Write-Warning "No active session to disconnect." return } switch ($this.Type) { 'JWT' { $headers = @{ "Authorization" = "Bearer $($this.JWT)" } try { Invoke-RestMethod -Method DELETE -Uri "$($this.CSPUrl)/v2/session/users/sign_out" -Headers $headers $this.JWT = $null $this.StopRenewalTimer() Write-Host "Disconnected successfully." -ForegroundColor Green } catch { Write-Error "Failed to disconnect: $_" } } 'API' { $this.APIKey = $null Write-Host "Disconnected successfully." -ForegroundColor Green } default { Write-Error "Unknown session type: $($this.Type)" } } } [void]StartRenewalTimer() { $this.RenewalTimer = New-Object System.Timers.Timer $this.RenewalTimer.Interval = 60000 $this.RenewalTimer.AutoReset = $true $session = $this $this.TimerEventId = "TimerElapsed_$($this.Email)" # Unregister any existing event with the same ID Unregister-Event -SourceIdentifier $this.TimerEventId -ErrorAction SilentlyContinue Remove-Event -SourceIdentifier $this.TimerEventId -ErrorAction SilentlyContinue Register-ObjectEvent -InputObject $this.RenewalTimer -EventName Elapsed -SourceIdentifier $this.TimerEventId -MessageData $this -Action { param($a, $b) Write-Verbose "Updating session for $($b.MessageData.Email) at $(Get-Date)" $b.MessageData.RefreshIfNeeded() } $this.RenewalTimer.Start() } [void]StopRenewalTimer() { if ($this.RenewalTimer) { if ($this.TimerEventId) { Unregister-Event -SourceIdentifier $this.TimerEventId -ErrorAction SilentlyContinue Remove-Event -SourceIdentifier $this.TimerEventId -ErrorAction SilentlyContinue } $this.RenewalTimer.Stop() $this.RenewalTimer.Dispose() } } [void]RefreshIfNeeded() { if (-not $this.JWT) { Write-Warning "No JWT available to refresh." return } try { $jwtInfo = $this.ParseJWT($this.JWT) if ($jwtInfo.expires -lt [DateTime]::UtcNow) { Write-Error "JWT has already expired. Please reconnect using Connect()." return } if ($jwtInfo.expires -lt [DateTime]::UtcNow.AddMinutes(5)) { Write-Verbose "JWT is expiring soon. Refreshing session..." $this.UpdateSession() } else { Write-Verbose "JWT is still valid. No refresh needed." } } catch { Write-Error "Failed to evaluate JWT expiration: $_" } } [void]UpdateSession() { if (-not $this.JWT) { Write-Warning "No JWT to refresh." return } $headers = @{ "Authorization" = "Bearer $($this.JWT)" "Content-Type" = "application/json" } try { $result = Invoke-RestMethod -Method POST -Uri "$($this.CSPUrl)/v2/session/users/renew" -Headers $headers if ($result.jwt) { $this.JWT = $result.jwt Write-Verbose "Session refreshed at $(Get-Date)" } else { Write-Warning "Failed to refresh session." } } catch { Write-Error "Error refreshing session: $_" } } [string]SwitchSession([string]$id) { if (-not $this.JWT -and $this.Type -eq 'JWT') { Write-Error "You must be connected to the Infoblox Portal before switching accounts. Please use Connect-B1Account first." return $null } if ($this.Type -ne 'JWT') { Write-Error "You must be connected to the Infoblox Portal using an Email/Password. API Keys do not support account switching." return $null } $body = @{ id = $id } | ConvertTo-Json $headers = @{ "Authorization" = "Bearer $($this.JWT)" "Content-Type" = "application/json" } try { $result = Invoke-RestMethod -Method POST -Uri "$($this.CSPUrl)/v2/session/account_switch" -Body $body -Headers $headers if ($result.jwt) { $this.JWT = $result.jwt $jwtInfo = $this.ParseJWT($this.JWT) Write-Host "Successfully switched to account: $($jwtInfo.account_name)" -ForegroundColor Green return $true } else { Write-Error "Failed to switch accounts." return $null } } catch { Write-Error "Error switching accounts: $_" return $null } } [pscustomobject]GetSessionInfo() { try { switch($this.Type) { 'JWT' { if (-not $this.JWT) { Write-Error "You must be connected to the Infoblox Portal before retrieving the session." return $null } return $this.ParseJWT($this.JWT) } 'API' { if (-not $this.APIKey) { Write-Error "No API Key available." return $null } return $this.APIKey } default { Write-Error "Unknown session type: $($this.Type)" return $null } } return $null } catch { Write-Error "An unknown error occurred while retrieving the Infoblox Portal session." return $_ } } [pscustomobject]ParseJWT([string]$token) { if (!$token.Contains(".") -or !$token.StartsWith("eyJ")) { Write-Error "Invalid token" -ErrorAction Stop } $tokenheader = $token.Split(".")[0].Replace('-', '+').Replace('_', '/') while ($tokenheader.Length % 4) { Write-Verbose "Invalid length for a Base-64 char array or string, adding ="; $tokenheader += "=" } $tokenPayload = $token.Split(".")[1].Replace('-', '+').Replace('_', '/') while ($tokenPayload.Length % 4) { Write-Verbose "Invalid length for a Base-64 char array or string, adding ="; $tokenPayload += "=" } $tokenByteArray = [System.Convert]::FromBase64String($tokenPayload) $tokenArray = [System.Text.Encoding]::ASCII.GetString($tokenByteArray) $tokobj = $tokenArray | ConvertFrom-Json $tokobj | Add-Member -MemberType NoteProperty -Name 'issued' -Value (Get-Date -Date "01/01/1970").AddSeconds($tokobj.iat) $tokobj | Add-Member -MemberType NoteProperty -Name 'expires' -Value (Get-Date -Date "01/01/1970").AddSeconds($tokobj.exp) $tokobj | Add-Member -MemberType NoteProperty -Name 'notBefore' -Value (Get-Date -Date "01/01/1970").AddSeconds($tokobj.nbf) return $tokobj } [string]ToString() { return "Infoblox Portal Session for $($this.Email) [Region: $($this.CSPRegion)]" } } |