Skip to content

Commit 374f4a8

Browse files
Add FIDO2 authentication support and related tests
- Implemented Invoke-FIDO2Authentication function for FIDO2 authentication flow. - Added ConvertFrom-Base64UrlString function for Base64Url decoding. - Created tests for New-PASSession and ConvertFrom-Base64UrlString. - Updated documentation for New-PASSession to include new parameters. - Added DSInternals.Win32.WebAuthn.dll and its license.
1 parent ab68aff commit 374f4a8

File tree

11 files changed

+617
-22
lines changed

11 files changed

+617
-22
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
Describe $($PSCommandPath -Replace '.Tests.ps1') {
2+
3+
BeforeAll {
4+
#Get Current Directory
5+
$Here = Split-Path -Parent $PSCommandPath
6+
7+
#Assume ModuleName from Repository Root folder
8+
$ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf
9+
10+
#Resolve Path to Module Directory
11+
$ModulePath = Resolve-Path "$Here\..\$ModuleName"
12+
13+
#Define Path to Module Manifest
14+
$ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1"
15+
16+
if ( -not (Get-Module -Name $ModuleName -All)) {
17+
18+
Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop
19+
20+
}
21+
22+
$Script:RequestBody = $null
23+
$psPASSession = [ordered]@{
24+
BaseURI = 'https://SomeURL/SomeApp'
25+
User = $null
26+
ExternalVersion = [System.Version]'0.0'
27+
WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
28+
StartTime = $null
29+
ElapsedTime = $null
30+
LastCommand = $null
31+
LastCommandTime = $null
32+
LastCommandResults = $null
33+
}
34+
35+
New-Variable -Name psPASSession -Value $psPASSession -Scope Script -Force
36+
37+
}
38+
39+
40+
AfterAll {
41+
42+
$Script:RequestBody = $null
43+
44+
}
45+
46+
InModuleScope $(Split-Path (Split-Path (Split-Path -Parent $PSCommandPath) -Parent) -Leaf ) {
47+
48+
Context 'Mandatory Parameters' {
49+
50+
$Parameters = @{Parameter = 'InputString' }
51+
52+
It 'specifies parameter <Parameter> as mandatory' -TestCases $Parameters {
53+
54+
param($Parameter)
55+
56+
(Get-Command ConvertFrom-Base64UrlString).Parameters["$Parameter"].Attributes.Mandatory | Should -Be $true
57+
58+
}
59+
60+
}
61+
62+
Context 'Base64Url Decoding' {
63+
64+
It 'decodes Base64Url string without padding' {
65+
$base64Url = 'SGVsbG8gV29ybGQ'
66+
$result = ConvertFrom-Base64UrlString -InputString $base64Url
67+
$resultString = [System.Text.Encoding]::UTF8.GetString($result)
68+
$resultString | Should -Be 'Hello World'
69+
}
70+
71+
It 'decodes Base64Url with URL-safe characters (dash and underscore)' {
72+
$base64Url = 'PDw_Pz8-Pg'
73+
$result = ConvertFrom-Base64UrlString -InputString $base64Url
74+
$result | Should -Not -BeNullOrEmpty
75+
}
76+
77+
It 'handles padding correctly' {
78+
$base64Url = 'YWJj'
79+
$result = ConvertFrom-Base64UrlString -InputString $base64Url
80+
$resultString = [System.Text.Encoding]::UTF8.GetString($result)
81+
$resultString | Should -Be 'abc'
82+
}
83+
84+
It 'converts Base64Url to byte array' {
85+
$base64Url = 'VGVzdA'
86+
$result = ConvertFrom-Base64UrlString -InputString $base64Url
87+
$result.GetType().BaseType.Name | Should -Be 'Array'
88+
}
89+
90+
}
91+
92+
}
93+
94+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
Describe $($PSCommandPath -Replace '.Tests.ps1') {
2+
3+
BeforeAll {
4+
#Get Current Directory
5+
$Here = Split-Path -Parent $PSCommandPath
6+
7+
#Assume ModuleName from Repository Root folder
8+
$ModuleName = Split-Path (Split-Path $Here -Parent) -Leaf
9+
10+
#Resolve Path to Module Directory
11+
$ModulePath = Resolve-Path "$Here\..\$ModuleName"
12+
13+
#Define Path to Module Manifest
14+
$ManifestPath = Join-Path "$ModulePath" "$ModuleName.psd1"
15+
16+
if ( -not (Get-Module -Name $ModuleName -All)) {
17+
18+
Import-Module -Name "$ManifestPath" -ArgumentList $true -Force -ErrorAction Stop
19+
20+
}
21+
22+
$Script:RequestBody = $null
23+
$psPASSession = [ordered]@{
24+
BaseURI = 'https://SomeURL/SomeApp'
25+
User = $null
26+
ExternalVersion = [System.Version]'0.0'
27+
WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
28+
StartTime = $null
29+
ElapsedTime = $null
30+
LastCommand = $null
31+
LastCommandTime = $null
32+
LastCommandResults = $null
33+
}
34+
35+
New-Variable -Name psPASSession -Value $psPASSession -Scope Script -Force
36+
37+
}
38+
39+
40+
AfterAll {
41+
42+
$Script:RequestBody = $null
43+
44+
}
45+
46+
InModuleScope $(Split-Path (Split-Path (Split-Path -Parent $PSCommandPath) -Parent) -Leaf ) {
47+
48+
Context 'Mandatory Parameters' {
49+
50+
$Parameters = @(
51+
@{Parameter = 'BaseURI' },
52+
@{Parameter = 'UserName' }
53+
)
54+
55+
It 'specifies parameter as mandatory' -TestCases $Parameters {
56+
57+
param($Parameter)
58+
59+
(Get-Command Invoke-FIDO2Authentication).Parameters["$Parameter"].Attributes.Mandatory | Should -Be $true
60+
61+
}
62+
63+
It 'specifies parameter LogonRequest as optional' {
64+
65+
(Get-Command Invoke-FIDO2Authentication).Parameters["LogonRequest"].Attributes.Mandatory | Should -Be $false
66+
67+
}
68+
69+
}
70+
71+
Context 'Platform Requirements' {
72+
73+
BeforeEach {
74+
$IsWindowsPlatform = (-not (Test-IsCoreCLR)) -or $IsWindows
75+
}
76+
77+
It 'requires Windows platform' {
78+
if (-not $IsWindowsPlatform) {
79+
{ Invoke-FIDO2Authentication -BaseURI 'https://pvwa.example.com' -UserName 'testuser' -LogonRequest @{} } | Should -Throw '*Windows*'
80+
}
81+
}
82+
83+
}
84+
85+
Context 'Input Validation' {
86+
87+
It 'accepts BaseURI parameter' {
88+
$params = (Get-Command Invoke-FIDO2Authentication).Parameters['BaseURI']
89+
$params | Should -Not -BeNullOrEmpty
90+
$params.ParameterType.Name | Should -Be 'String'
91+
}
92+
93+
It 'accepts UserName parameter' {
94+
$params = (Get-Command Invoke-FIDO2Authentication).Parameters['UserName']
95+
$params | Should -Not -BeNullOrEmpty
96+
$params.ParameterType.Name | Should -Be 'String'
97+
}
98+
99+
It 'accepts LogonRequest parameter' {
100+
$params = (Get-Command Invoke-FIDO2Authentication).Parameters['LogonRequest']
101+
$params | Should -Not -BeNullOrEmpty
102+
$params.ParameterType.Name | Should -Be 'Hashtable'
103+
}
104+
105+
}
106+
107+
Context 'Help Content' {
108+
109+
It 'has a synopsis' {
110+
$help = Get-Help Invoke-FIDO2Authentication
111+
$help.Synopsis | Should -Not -BeNullOrEmpty
112+
}
113+
114+
It 'has a description' {
115+
$help = Get-Help Invoke-FIDO2Authentication
116+
$help.Description | Should -Not -BeNullOrEmpty
117+
}
118+
119+
It 'has examples' {
120+
$help = Get-Help Invoke-FIDO2Authentication
121+
$help.Examples | Should -Not -BeNullOrEmpty
122+
}
123+
124+
}
125+
126+
}
127+
128+
}

Tests/New-PASSession.Tests.ps1

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,69 @@ Describe $($PSCommandPath -Replace '.Tests.ps1') {
12371237

12381238
}
12391239

1240+
Context 'Gen2 with FIDO2' {
1241+
1242+
BeforeEach {
1243+
1244+
Mock Assert-VersionRequirement -MockWith {}
1245+
1246+
Mock Invoke-FIDO2Authentication -MockWith {
1247+
[PSCustomObject]@{
1248+
'CyberArkLogonResult' = 'AAAAAAA\\\REEEAAAAALLLLYYYYY\\\\LOOOOONNNNGGGGG\\\ACCCCCEEEEEEEESSSSSSS\\\\\\TTTTTOOOOOKKKKKEEEEEN'
1249+
}
1250+
}
1251+
1252+
Mock Get-PASServer -MockWith {
1253+
[PSCustomObject]@{
1254+
ExternalVersion = '14.6'
1255+
}
1256+
}
1257+
1258+
Mock Get-PASLoggedOnUser -MockWith {
1259+
@{'UserName' = 'TestUser' }
1260+
}
1261+
1262+
$psPASSession.ExternalVersion = '14.6'
1263+
$psPASSession.WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
1264+
1265+
}
1266+
1267+
It 'sends request with UserName parameter' {
1268+
New-PASSession -BaseURI 'https://pvwa.cyberark.com' -type FIDO2 -UserName 'TestUser'
1269+
Assert-MockCalled Invoke-FIDO2Authentication -Times 1 -Exactly -Scope It
1270+
1271+
}
1272+
1273+
It 'sends request with expected parameters' {
1274+
New-PASSession -BaseURI 'https://pvwa.cyberark.com' -type FIDO2 -UserName 'TestUser'
1275+
Assert-MockCalled Invoke-FIDO2Authentication -ParameterFilter {
1276+
1277+
$BaseURI -eq 'https://pvwa.cyberark.com/PasswordVault' -and $UserName -eq 'TestUser'
1278+
1279+
} -Times 1 -Exactly -Scope It
1280+
1281+
}
1282+
1283+
It 'throws error when UserName is not provided' {
1284+
{ New-PASSession -BaseURI 'https://pvwa.cyberark.com' -type FIDO2 } | Should -Throw 'Username is required for FIDO2 authentication. Use -UserName parameter.'
1285+
}
1286+
1287+
It 'sets expected BaseURI' {
1288+
1289+
New-PASSession -BaseURI 'https://pvwa.cyberark.com' -type FIDO2 -UserName 'TestUser'
1290+
$Script:psPASSession.BaseURI | Should -Be 'https://pvwa.cyberark.com/PasswordVault'
1291+
1292+
}
1293+
1294+
It 'sets expected authorization header' {
1295+
1296+
New-PASSession -BaseURI 'https://pvwa.cyberark.com' -type FIDO2 -UserName 'TestUser'
1297+
$psPASSession.WebSession.Headers['Authorization'] | Should -Be 'AAAAAAA\\\REEEAAAAALLLLYYYYY\\\\LOOOOONNNNGGGGG\\\ACCCCCEEEEEEEESSSSSSS\\\\\\TTTTTOOOOOKKKKKEEEEEN'
1298+
1299+
}
1300+
1301+
}
1302+
12401303
}
12411304

12421305
}

0 commit comments

Comments
 (0)