Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 95 additions & 4 deletions PowerFGT/Public/Connection.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ function Connect-FGT {
[Parameter(Mandatory = $false)]
[string]$license,
[Parameter(Mandatory = $false)]
[switch]$oldauth = $false,
[Parameter(Mandatory = $false)]
[string[]]$vdom,
[Parameter(Mandatory = $false)]
[boolean]$DefaultConnection = $true
Expand Down Expand Up @@ -186,6 +188,86 @@ function Connect-FGT {
if ($ApiToken) {
$headers += @{ "Authorization" = "Bearer $ApiToken" }
}
elseif ( $oldauth -ne $true ) {
#If there is a password (and a user), create a credentials
if ($Password) {
$Credentials = New-Object System.Management.Automation.PSCredential($Username, $Password)
}
#Not Credentials (and no password)
if ($null -eq $Credentials) {
$Credentials = Get-Credential -Message 'Please enter administrative credentials for your FortiGate'
}
# new api auth method (Seen FortiOS 6.4+)
$postParams = @{
username = $Credentials.username;
password = $Credentials.GetNetworkCredential().Password;
secretkey = $Credentials.GetNetworkCredential().Password;
}

$uri = $url + "api/v2/authentication"
Write-Verbose $uri

try {
$irmResponse = Invoke-RestMethod $uri -Method POST -Body ($postParams | ConvertTo-Json) -SessionVariable FGT @invokeParams
}
catch {
if ($_.Exception.Response.StatusCode.Value__ -eq "401" ) {
throw "Not supported API Authentication method on this FortiGate (try use -oldauth parameter)"
}
else {
Show-FGTException $_
throw "Unable to connect to FortiGate"
}

}

Write-verbose $irmResponse
#Following FortiOS version it is status_code or status...
if ($irmResponse.status_code) {
$status = $irmResponse.status_code
}
else {
$status = $irmResponse.status
}

switch ($status) {
'-1' {
throw "Log in failure. Most likely an incorrect username/password combo"
}
'-4' {
#with FortiOS 7.6.3+, no longer warning when locked account...
throw "Admin is now locked out (Please retry in 60 seconds)"
}
'5' {
#no thing, it is good ! continue
}
'6' {
#no thing, it is good ! continue (with FortiOS 7.6.3+)
}
default {
throw "Authentication failure. Status code: $status $($irmResponse.status_message)"
}
}

#Search crsf cookie and to X-CSRFTOKEN
$cookies = $FGT.Cookies.GetCookies($uri)
foreach ($cookie in $cookies) {
if ($cookie.name -like "ccsrf*" ) {
#before 7.6 it was ccsrftoken_port_xxxx, from 7.6.3+ it is ccsrf_token_port_xxxx
$cookie_csrf = $cookie.value
}
}

# throw if don't found csrf cookie...
if ($null -eq $cookie_csrf) {
throw "Unable to found CSRF Cookie"
}

#Remove extra "quote"
$cookie_csrf = $cookie_csrf -replace '["]', ''
#Add csrf cookie to header (X-CSRFTOKEN)
$headers += @{"X-CSRFTOKEN" = $cookie_csrf }
}
else {
#If there is a password (and a user), create a credentials
if ($Password) {
Expand All @@ -210,8 +292,9 @@ function Connect-FGT {
if ( $iwrResponse.Content[0] -eq "{") {
$json = $iwrResponse.Content | ConvertFrom-Json
$status = $json.status
} else {
$status = $iwrResponse.Content[0]
}
else {
$status = $iwrResponse.Content[0]
}

#check if need token...
Expand Down Expand Up @@ -350,6 +433,7 @@ function Connect-FGT {
$connection.invokeParams = $invokeParams
$connection.vdom = $vdom
$connection.serial = $version.serial
$connection.oldauth = $oldauth
if ($version.results.current.major) {
$connection.version = [version]"$($version.results.current.major).$($version.results.current.minor).$($version.results.current.patch)"
}
Expand Down Expand Up @@ -446,10 +530,17 @@ function Disconnect-FGT {

Process {

$url = "logout"
$method = "DELETE"
$url = "api/v2/authentication"

#old auth use logout url
if ($connection.oldauth) {
$url = "logout"
$method = "POST"
}

if ($PSCmdlet.ShouldProcess($connection.server, 'Proceed with removal of FortiGate connection ?')) {
$null = invoke-FGTRestMethod -method "POST" -uri $url -connection $connection
$null = invoke-FGTRestMethod -method $method -uri $url -connection $connection
if (Test-Path variable:global:DefaultFGTConnection) {
Remove-Variable -name DefaultFGTConnection -scope global
}
Expand Down
7 changes: 7 additions & 0 deletions Tests/common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ else {
$invokeParams.add('SkipCertificateCheck', $SkipCertificateCheck)
$invokeParams.add('httpOnly', $httpOnly)
$invokeParams.add('port', $port)
if ($oldauth -eq "true") {
$script:oldauth = $true
}
else {
$script:oldauth = $false
}
$invokeParams.add('oldauth', $oldauth)

#Make a connection for check info and store version (used for some test...)
$fgt = Connect-FGT @invokeParams
Expand Down
1 change: 1 addition & 0 deletions Tests/credential.ci.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
$script:ipaddress = $env:IPADDRESS
$script:login = $env:LOGIN
$script:password = $env:PASSWORD
$script:oldauth = $env:OLDAUTH
$script:httpOnly = $false
$script:SkipCertificateCheck = $true
$script:ci = $true
Expand Down
1 change: 1 addition & 0 deletions Tests/credential.example.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ $script:httpOnly = $true
#$script:apitoken = "yourtoken"
$script:SkipCertificateCheck = $true
$script:ci = $false
$script:oldauth = $false

#default settings use for test, can be override if needed...
$script:pester_address1 = "pester_address1"
Expand Down
16 changes: 10 additions & 6 deletions Tests/integration/Connection.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

Describe "Connect to a FortiGate (using HTTP)" {
It "Connect to a FortiGate (using HTTP) and check global variable" -Skip:( -not $httpOnly ) {
Connect-FGT $ipaddress -Username $login -password $mysecpassword -httpOnly -port $port
Connect-FGT $ipaddress -Username $login -password $mysecpassword -httpOnly -port $port -oldauth:$oldauth
$DefaultFGTConnection | Should -Not -BeNullOrEmpty
$DefaultFGTConnection.server | Should -Be $ipaddress
$DefaultFGTConnection.invokeParams | Should -Not -BeNullOrEmpty
Expand All @@ -23,11 +23,11 @@ Describe "Connect to a FortiGate (using HTTP)" {
$DefaultFGTConnection | Should -Be $null
}
It "Connect to a FortiGate (using HTTP) with wrong password" -Skip:( -not $httpOnly ) {
{ Connect-FGT $ipaddress -Username $login -password $mywrongpassword -httpOnly -port $port } | Should -throw "Log in failure. Most likely an incorrect username/password combo"
{ Connect-FGT $ipaddress -Username $login -password $mywrongpassword -httpOnly -port $port -oldauth $oldauth } | Should -throw "Log in failure. Most likely an incorrect username/password combo"
}
#TODO: Connect using MFA (token) and/or need to change password (admin expiration)
It "Connect to a Fortigate (using HTTP) with apiToken" -Skip:( -not ($apitoken -ne $null -and $httpOnly -eq $true -and $fgt_version -ge "7.0.0")) {
Connect-FGT -Server $ipaddress -ApiToken $apitoken -port $port -httpOnly
Connect-FGT -Server $ipaddress -ApiToken $apitoken -port $port -httpOnly -oldauth:$oldauth
$DefaultFGTConnection | Should -Not -BeNullOrEmpty
$DefaultFGTConnection.server | Should -Be $ipaddress
$DefaultFGTConnection.invokeParams | Should -Not -BeNullOrEmpty
Expand All @@ -42,7 +42,7 @@ Describe "Connect to a FortiGate (using HTTP)" {

Describe "Connect to a fortigate (using HTTPS)" {
It "Connect to a FortiGate (using HTTPS and -SkipCertificateCheck) and check global variable" -Skip:($httpOnly) {
Connect-FGT $ipaddress -Username $login -password $mysecpassword -SkipCertificateCheck -port $port
Connect-FGT $ipaddress -Username $login -password $mysecpassword -SkipCertificateCheck -port $port -oldauth:$oldauth
$DefaultFGTConnection | Should -Not -BeNullOrEmpty
$DefaultFGTConnection.server | Should -Be $ipaddress
$DefaultFGTConnection.invokeParams | Should -Not -BeNullOrEmpty
Expand All @@ -60,11 +60,11 @@ Describe "Connect to a fortigate (using HTTPS)" {
#This test only work with PowerShell 6 / Core (-SkipCertificateCheck don't change global variable but only Invoke-WebRequest/RestMethod)
#This test will be fail, if there is valid certificate...
It "Connect to a FortiGate (using HTTPS) and check global variable" -Skip:("Desktop" -eq $PSEdition -Or $httpOnly) {
{ Connect-FGT $ipaddress -Username $login -password $mysecpassword } | Should -throw "Unable to connect (certificate)"
{ Connect-FGT $ipaddress -Username $login -password $mysecpassword -oldauth:$oldauth } | Should -throw "Unable to connect (certificate)"
}

It "Connect to a FortiGate (using HTTPS) with wrong password" -Skip:($httpOnly) {
{ Connect-FGT $ipaddress -Username $login -password $mywrongpassword -port $port -SkipCertificateCheck:$SkipCertificateCheck } | Should -throw "Log in failure. Most likely an incorrect username/password combo"
{ Connect-FGT $ipaddress -Username $login -password $mywrongpassword -port $port -SkipCertificateCheck:$SkipCertificateCheck -oldauth:$oldauth } | Should -throw "Log in failure. Most likely an incorrect username/password combo"
}

It "Connect to a Fortigate (using HTTPS) with apiToken" -Skip:($apitoken -eq $null -Or $httpOnly) {
Expand All @@ -79,6 +79,10 @@ Describe "Connect to a fortigate (using HTTPS)" {
$DefaultFGTConnection.version | Should -Not -BeNullOrEmpty
$DefaultFGTConnection.serial | Should -Not -BeNullOrEmpty
}

It "Connect to a FortiGate (using HTTPS) to old (before FortiOS 6.4 without -oldauth)" -Skip:($httpOnly -or $fgt_version -ge "6.4.0" ) {
{ Connect-FGT $ipaddress -Username $login -password $mysecpassword -SkipCertificateCheck -port $port } | Should -throw "Not supported API Authentication method on this FortiGate (try use -oldauth parameter)"
}
}

Describe "Connect to a FortiGate (with post-login-banner enable)" {
Expand Down
17 changes: 17 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,31 @@ stages:
FortiOS60:
name: "FortiOS 6.0"
IPADDRESS: $(IPADDRESS_60)
OLDAUTH: true
FortiOS62:
name: "FortiOS 6.2"
IPADDRESS: $(IPADDRESS_62)
OLDAUTH: true
FortiOS64:
name: "FortiOS 6.4"
IPADDRESS: $(IPADDRESS_64)
OLDAUTH: false
FortiOS70:
name: "FortiOS 7.0"
IPADDRESS: $(IPADDRESS_70)
OLDAUTH: false
FortiOS72:
name: "FortiOS 7.2"
IPADDRESS: $(IPADDRESS_72)
OLDAUTH: false
FortiOS74:
name: "FortiOS 7.4"
IPADDRESS: $(IPADDRESS_74)
OLDAUTH: false
FortiOS76:
name: "FortiOS 7.6"
IPADDRESS: $(IPADDRESS_76)
OLDAUTH: false
steps:
- task: PowerShell@2
displayName: "Test PowerShell Core $(name)"
Expand All @@ -62,6 +69,7 @@ stages:
LOGIN: $(LOGIN)
IPADDRESS: $(IPADDRESS)
PASSWORD: $(PASSWORD)
OLDAUTH: $(OLDAUTH)
- task: PublishTestResults@2
inputs:
testResultsFormat: "NUnit"
Expand All @@ -79,24 +87,31 @@ stages:
FortiOS60:
name: "FortiOS 6.0"
IPADDRESS: $(IPADDRESS_60)
OLDAUTH: true
FortiOS62:
name: "FortiOS 6.2"
IPADDRESS: $(IPADDRESS_62)
OLDAUTH: true
FortiOS64:
name: "FortiOS 6.4"
IPADDRESS: $(IPADDRESS_64)
OLDAUTH: false
FortiOS70:
name: "FortiOS 7.0"
IPADDRESS: $(IPADDRESS_70)
OLDAUTH: false
FortiOS72:
name: "FortiOS 7.2"
IPADDRESS: $(IPADDRESS_72)
OLDAUTH: false
FortiOS74:
name: "FortiOS 7.4"
IPADDRESS: $(IPADDRESS_74)
OLDAUTH: false
FortiOS76:
name: "FortiOS 7.6"
IPADDRESS: $(IPADDRESS_76)
OLDAUTH: false
steps:
- task: PowerShell@2
displayName: "Test PowerShell Core $(name)"
Expand All @@ -118,6 +133,7 @@ stages:
LOGIN: $(LOGIN)
IPADDRESS: $(IPADDRESS)
PASSWORD: $(PASSWORD)
OLDAUTH: $(OLDAUTH)
- task: PowerShell@2
displayName: "Test PowerShell 5 $(name)"
inputs:
Expand All @@ -138,6 +154,7 @@ stages:
LOGIN: $(LOGIN)
IPADDRESS: $(IPADDRESS)
PASSWORD: $(PASSWORD)
OLDAUTH: $(OLDAUTH)
- task: PublishTestResults@2
inputs:
testResultsFormat: "NUnit"
Expand Down