Skip to content

Commit

Permalink
0.1 - Update 2 (#4)
Browse files Browse the repository at this point in the history
* Update deploy-github.ps1

Lowered minimum version to publish GitHub release.

* ✨🚩UPDATE New-IDSession

Adds saml authentication support, when providing SAML assertion from an external IDP

* Update CHANGELOG.md
  • Loading branch information
pspete committed Sep 19, 2023
1 parent 6fb05d0 commit 536794f
Show file tree
Hide file tree
Showing 11 changed files with 539 additions and 45 deletions.
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Change Log
All notable changes to this project will be documented in this file.

## [unreleased] - 2023-08-30
## [unreleased] - 2023-09-19

### Added
- N/A
Expand All @@ -12,6 +12,17 @@ All notable changes to this project will be documented in this file.
### Fixed
- N/A

## [0.1 - Update 2] - 2023-09-19

### Added
- N/A

### Changed
- `New-IDSession` - Adds federated authentication support, with ability to provide a SamlResponse from an external IDP

### Fixed
- N/A

## [0.1 - Update 1] - 2023-08-30

Additional Functions
Expand Down
60 changes: 60 additions & 0 deletions IdentityCommand/Private/Complete-SamlAuthentication.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Function Complete-SamlAuthentication {
<#
.SYNOPSIS
Completes a saml authentication request
.DESCRIPTION
Complete the SAML authentication session against CyberArk Identity.
This request utilizes the cookies returned after Start-SamlAuthentication.
The CyberArk ISPSS tenant should respond and set additional cookies that are used for subsequent authentication.
.PARAMETER LogonRequest
The LogonRequest created via New-IDSession
.EXAMPLE
$LogonRequest | Complete-SamlAuthentication
Complete the SAML authentication process, started by Start-SamlAuthentication.
.NOTES
Pete Maan 2023
#>

[CmdletBinding(SupportsShouldProcess)]
param(
[parameter(
Mandatory = $true,
ValueFromPipeline = $true
)]
[ValidateNotNullOrEmpty()]
[hashtable]$LogonRequest
)

process {

#Setup request. This command will return html, so supress output/html error detection
$Script:ExpectHtml = $true
$LogonRequest['Method'] = 'GET'
$LogonRequest['Uri'] = "$Script:tenant_url/login"

if ($PSCmdlet.ShouldProcess($Script:tenant_url, 'Send Assertion')) {

try {

#Perform Start Authentication
$IDSession = Invoke-IDRestMethod @LogonRequest

#Output IDSession
$IDSession

} catch { throw $PSItem }

}

$Script:ExpectHtml = $false
#TODO: Check if sucesful auth or error

}

}
26 changes: 18 additions & 8 deletions IdentityCommand/Private/Get-IDResponse.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,30 @@ function Get-IDResponse {

If ($IDResponse -match '<HTML>') {

#Fail if HTML received from request to API
If ($Script:ExpectHtml) {
#HTML output expected, null the html result
$IDResponse = $null

$PSCmdlet.ThrowTerminatingError(
}

Else {

#Fail if HTML received from request to API

$PSCmdlet.ThrowTerminatingError(

[System.Management.Automation.ErrorRecord]::new(
[System.Management.Automation.ErrorRecord]::new(

'Unexpected HTML Response Received. Check the URL provided for your Identity Portal.',
$StatusCode,
[System.Management.Automation.ErrorCategory]::NotSpecified,
$APIResponse
'Unexpected HTML Response Received. Check the URL provided for your Identity Portal.',
$StatusCode,
[System.Management.Automation.ErrorCategory]::NotSpecified,
$APIResponse

)

)

)
}

}

Expand Down
78 changes: 78 additions & 0 deletions IdentityCommand/Private/Start-SamlAuthentication.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
Function Start-SamlAuthentication {
<#
.SYNOPSIS
Starts SAML user authentication
.DESCRIPTION
Start SAML user authentication against CyberArk Identity.
When the user wants to authenticate to CyberArk Identity providing a SAML Response.
Successful response should contain the following cookies: .ASPXAUTH, antixss, CCSID, podloc, sessdata, userdata
Returned cookies will be saved in the WebSession object used by the module for future operations.
.PARAMETER LogonRequest
The LogonRequest created via New-IDSession
.PARAMETER SAMLResponse
Credential object containing username and password required to authenticate to CyberArk Identity.
.EXAMPLE
$LogonRequest | Start-SamlAuthentication SAMLResponse $SAMLResponse
Start the SAML authentication process using the specified SAMLResponse.
.NOTES
Pete Maan 2023
#>

[CmdletBinding(SupportsShouldProcess)]
param(
[parameter(
Mandatory = $true,
ValueFromPipeline = $true
)]
[ValidateNotNullOrEmpty()]
[hashtable]$LogonRequest,

#SAML Assertion
[Parameter(
Mandatory = $true,
ValueFromPipelinebyPropertyName = $true
)]
[ValidateNotNullOrEmpty()]
[string]$SAMLResponse
)

process {

#Setup request. This command will return html, so supress output/html error detection
$Script:ExpectHtml = $true
$LogonRequest['ContentType'] = 'application/x-www-form-urlencoded'
$LogonRequest['Uri'] = "$Script:tenant_url/my"

$LogonRequest['Body'] = @{

SAMLResponse = $SAMLResponse

}

if ($PSCmdlet.ShouldProcess($Script:tenant_url, 'Send SAML Assertion')) {

try {

#Perform Start Authentication
$IDSession = Invoke-IDRestMethod @LogonRequest

#Output IDSession
$IDSession

} catch { throw $PSItem }

}

$Script:ExpectHtml = $false
#TODO: Check for expected cookies

}

}
94 changes: 65 additions & 29 deletions IdentityCommand/Public/New-IDSession.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,20 @@ Function New-IDSession {
#User Creds
[Parameter(
Mandatory = $true,
ValueFromPipelinebyPropertyName = $true
ValueFromPipelinebyPropertyName = $true,
ParameterSetName = 'Credential'
)]
[ValidateNotNullOrEmpty()]
[PSCredential]$Credential
[PSCredential]$Credential,

#SAML Assertion
[Parameter(
Mandatory = $true,
ValueFromPipeline = $false,
ValueFromPipelinebyPropertyName = $true,
ParameterSetName = 'SAML'
)]
[String]$SAMLResponse

)

Expand All @@ -45,58 +55,84 @@ Function New-IDSession {

$LogonRequest['Headers'] = @{'accept' = '*/*' }

#*Start Authentication
$IDSession = $LogonRequest | Start-Authentication -Credential $Credential
switch ($PSCmdlet.ParameterSetName) {

'Credential' {
#*Start Authentication
$IDSession = $LogonRequest | Start-Authentication -Credential $Credential
break
}
'SAML' {
#*Send SAML Assertion
$IDSession = $LogonRequest | Start-SamlAuthentication -SAMLResponse $SAMLResponse
break
}
}

#Set request properties for Advance.
#Set request properties for Next authentication stage.
$LogonRequest.Remove('SessionVariable')
$LogonRequest['Headers'].Add('X-IDAP-NATIVE-CLIENT', $true)

#Set Module Scope variables
Set-Variable -Name TenantId -Value $IDSession.TenantId -Scope Script
Set-Variable -Name SessionId -Value $IDSession.SessionId -Scope Script
#? does SessionId need to be available in script scope?

#The MFA Bit - keep a reference to $IDSession for the MFA Package
$ThisSession = $IDSession
for ($Challenge = 0; $Challenge -lt $(($ThisSession.Challenges).Count); $Challenge++) {
switch ($PSCmdlet.ParameterSetName) {

#Iterate through presented challenges
if ($($IDSession.Summary) -eq 'NewPackage') {
'Credential' {

#Initialise loop and $ThisSession if NewPackage Challenges are presented
$Challenge = 0
#The MFA Bit - keep a reference to $IDSession for the MFA Package
$ThisSession = $IDSession
if ($null -ne $ThisSession.EventDescription) { Write-Warning -Message $ThisSession.EventDescription }
for ($Challenge = 0; $Challenge -lt $(($ThisSession.Challenges).Count); $Challenge++) {

}
#Iterate through presented challenges
if ($($IDSession.Summary) -eq 'NewPackage') {

#Get Current Challenge Mechanisms
$Mechanisms = $ThisSession.Challenges[$Challenge] | Select-Object -ExpandProperty Mechanisms
#Initialise loop and $ThisSession if NewPackage Challenges are presented
$Challenge = 0
$ThisSession = $IDSession
if ($null -ne $ThisSession.EventDescription) { Write-Warning -Message $ThisSession.EventDescription }

#select challenge mechanism
$Mechanism = Select-ChallengeMechanism -Mechanisms $Mechanisms
}

try {
#Get Current Challenge Mechanisms
$Mechanisms = $ThisSession.Challenges[$Challenge] | Select-Object -ExpandProperty Mechanisms

#answer challenge mechanism
$Answer = Get-MechanismAnswer -Mechanism $Mechanism -Credential $Credential
#select challenge mechanism
$Mechanism = Select-ChallengeMechanism -Mechanisms $Mechanisms

#*Advance Authentication
$IDSession = $LogonRequest | Start-AdvanceAuthentication -Mechanism $Mechanism -Answer $Answer
try {

} catch {
#answer challenge mechanism
$Answer = Get-MechanismAnswer -Mechanism $Mechanism -Credential $Credential

throw $PSItem
#*Advance Authentication
$IDSession = $LogonRequest | Start-AdvanceAuthentication -Mechanism $Mechanism -Answer $Answer

}
} catch {

throw $PSItem

}

if ($($IDSession.Summary) -eq 'NewPackage') {

if ($($IDSession.Summary) -eq 'NewPackage') {
#New Package Recieved, decrement counter so we go round the loop again to evaluate.
$Challenge--

#New Package Recieved, decrement counter so we go round the loop again to evaluate.
$Challenge--
}

}

break
}

'SAML' {
#*Get Saml ID Token
$IDSession = $LogonRequest | Complete-SamlAuthentication
break
}
}

switch ($IDSession.Summary) {
Expand Down
Loading

0 comments on commit 536794f

Please sign in to comment.