FortiAuth-Import.psm1
Write-Verbose 'Importing from [C:\projects\fortiauth-import\FortiAuth-Import\private]' # .\FortiAuth-Import\private\bypassCertificatePolicy.ps1 function GetTrustAllCertsPolicy () { # Trust all certs as we don't use an internal CA add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ return $(New-Object TrustAllCertsPolicy) } function SetCertificatePolicy ($Func) { [System.Net.ServicePointManager]::CertificatePolicy = $Func } function GetCertificatePolicy () { return [System.Net.ServicePointManager]::CertificatePolicy } # .\FortiAuth-Import\private\callAPI.ps1 function Invoke-FortiAuthRestMethod { #[CmdletBinding()] Param( [Parameter(Position = 0, Mandatory)] [string] $Resource, [ValidateSet("Get", "Post", "Delete", "Patch")] [string] $Method, [hashtable] $Options, [hashtable] $Body ) if ($null -ne $Script:FortiAuth) { # Check if we even have a ticket Write-Error "Please connect using Connect-FortiAuth." return $false } # Code from other project that might be useful at a later date. # It's used to get a new session ticket. # if ((Get-Date).Ticks -le $Script:FortiAuth.Expire) # { # Connect-PveServer -Server $Script:FortiAuth.Server # } # Bypass ssl checking or servers without a public cert or internal CA cert if ($Script:FortiAuth.BypassSSLCheck) { $CertificatePolicy = GetCertificatePolicy SetCertificatePolicy -Func (GetTrustAllCertsPolicy) } # Setup Headers and cookie for splatting switch ($Method) { Get { $splat = PrepareGetRequest } Post { $splat = PreparePostRequest($Body) } Delete { $splat = PrepareGetRequest } Patch { $splat = PreparePatchRequest($Body)} Default { $splat = PrepareGetRequest } } $Query = "?" If ($Options) { $Options.keys | ForEach-Object { $Query = $Query + "$_=$($Options[$_])&" } $Query = $Query.TrimEnd("&") } else { $Query = "" } $Uri = "https://$($Script:FortiAuth.Server)/api/v1$($Resource)" $response = Invoke-RestMethod -Uri "$($Uri)$($Query)" -Credential $(Import-Clixml -Path $Script:FortiAuth.StoredCredential) @splat -ErrorVariable $e if ($e) { return $false } if ($Script:FortiAuth.BypassSSLCheck) { # restore original cert policy SetCertificatePolicy -Func $CertificatePolicy } return $response.data } function PreparePatchRequest ($Body) { $request = New-Object -TypeName PSCustomObject -Property @{ Method = "Patch" Headers = @{"Accept" = "application/json"} Body = $Body ContentType = "application/json" } return $request } function PreparePostRequest($Body) { $request = New-Object -TypeName PSCustomObject -Property @{ Method = "Post" Headers = @{"Accept" = "application/json"} Body = $Body ContentType = "application/json" } return $request } function PrepareGetRequest() { $request = @{ Method = "Get" Headers = @{"Accept" = "application/json"} ContentType = "application/json" } return $request } function PrepareDeleteRequest() { # $cookie = New-Object System.Net.Cookie -Property @{ # Name = "AuthCookie" # Path = "/" # Domain = $Script:FortiAuth.Server # Value = $Script:FortiAuth.Ticket # } # $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession # $session.cookies.add($cookie) $request = New-Object -TypeName PSCustomObject -Property @{ Method = "Delete" #Headers = @{CSRFPreventionToken = $Script:FortiAuth.CSRFPreventionToken} Headers = @{"Accept" = "application/json"} #WebSession = $session ContentType = "application/json" } return $request } Write-Verbose 'Importing from [C:\projects\fortiauth-import\FortiAuth-Import\public]' # .\FortiAuth-Import\public\Connect.ps1 <# .SYNOPSIS Create a new session to connect with a Fortinet Authenticator appliance .DESCRIPTION Long description .EXAMPLE Connect-FortiAuth -Server 10.0.0.10 -UserName "root" -APIKey "asdfghjklqwertyuio" .EXAMPLE To bypass an invalid certificate where you aren't using an internal CA Connect-FortiAuth -Server 10.0.0.10 -UserName "root" -APIKey "asdfghjklqwertyuio" -BypassSSLCheck .EXAMPLE Connect-FortiAuth -Server 10.0.0.10 -Crediential (Get-Crediential) .NOTES General notes #> function Connect-FortiAuth { [CmdletBindings()] param ( [Parameter(Mandatory = $true)] [ValidateNotNull()] [ValidateScript( { (Test-Connection -ComputerName $_ -Count 1 -ErrorAction Ignore) } )] $Server, [Parameter(Mandatory = $false)] [Alias("User", "Account")] [string] $UserName, [Parameter(Mandatory = $false)] [Alias("Key", "Password")] [string] $APIKey, [switch] $BypassSSLCheck, [pscredential] $Crediential, # Stored Credential Path [string] $Path = "$($MyInvocation.MyCommand.Path)/Credential.xml" ) begin { } process { $Script:FortiAuth.Server = $Server $Script:FortiAuth.StoredCredential = "$($MyInvocation.MyCommand.Path)/Credential.xml" $Script:FortiAuth.BypassSSLCheck = $BypassSSLCheck if ($Crediential) { # Are we getting credentials? $mycreds = $Crediential Export-Clixml -Path $Script:FortiAuth.StoredCredential -InputObject $mycreds } elseif ($Username -and $APIKey) { # Are we makeing our credentials from raw username and apikey? $secpasswd = ConvertTo-SecureString $APIKey -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ($Username, $secpasswd) Export-Clixml -Path $Script:FortiAuth.StoredCredential -InputObject $mycreds } else { # Are we using the stored credentails? if ($PSScriptRoot -and $(Test-Path -Path $Script:FortiAuth.StoredCredential)) { # Found stored credentials so nothing to do! #$mycreds = Import-Clixml -Path $Script:FortiAuth.StoredCredential } else { # No credetials nor username/apikey specified so prompt for them $mycreds = Get-Credential -Message "Username and API Key as the Password" Export-Clixml -Path $Script:FortiAuth.StoredCredential -InputObject $mycreds } } # Do a test connection to see if everything works or not. $response = Invoke-FortiAuthRestMethod -Resource "/" -Method Get if ($response) { # All is good. } } end { } } Export-ModuleMember -Cmdlet Connect-FortiAuth # .\FortiAuth-Import\public\Tokens.ps1 Function Get-Token { Param( [string] $Token ) $response = Invoke-FortiAuthRestMethod -Resource "fortitokens/" -Method Get -Options @{ limit = 1 } if ($response.meta.total_count -gt 10) { return Invoke-FortiAuthRestMethod -Resource "fortitokens/" -Method Get -Options @{ limit = $($response.meta.total_count) } } else { $response = Invoke-FortiAuthRestMethod -Resource "fortitokens/" -Method Get $data = $returnedData.objects if ($returnedData.meta) { do { $returnedData = Invoke-FortiAuthRestMethod -Resource "fortitokens/$($returnedData.meta.next)" -Method Get $data = $data + $returnedData.objects }while ($returnedData.meta.next) } return $data } } Export-ModuleMember -Cmdlet Get-Token # .\FortiAuth-Import\public\UserGroups.ps1 Function Get-UserGroup { Param( [ValidateNotNullOrEmpty()] $Name, [ValidateNotNullOrEmpty()] $Id ) if ($Id) { $returnedData = Invoke-FortiAuthRestMethod -Resource "usergroups/$($Id)/" -Method Get $data = $returnedData.objects return $data } elseif ($Name) { $returnedData = Invoke-FortiAuthRestMethod -Resource "usergroups/" -Method Get $data = $returnedData.objects if ($returnedData.meta) { do { $returnedData = Invoke-FortiAuthRestMethod -Resource "usergroups/$($returnedData.meta.next)" -Method Get $data = $data + $returnedData.objects }while ($returnedData.meta.next) } $data | ForEach-Object { [PSCustomObject]@{ Name = $_.Name Id = $_.idtype } } return $data } else { Write-Log -Message "Group $Name$Id not found" -EventID 100 -Level Error -Method $Script:FortiAuth.LogMethod return $false } } Function Add-UserToGroup { Param( [ValidateNotNullOrEmpty()] $GroupID, [ValidateNotNullOrEmpty()] $UserID ) $UserList = (Get-UserGroup -Id $GroupID).Id # Create data object that will be output, and new user(s) to current list $Data = @{users = $UserList} $Data.users = $Data.users + $UserID $Data.users = $Data.users | ForEach-Object { "/api/v1/localusers/$($_)/" } $returnedData = Invoke-FortiAuthRestMethod -Resource "usergroups/$($GroupID)/" -Method Patch -Body $Data return $returnedData } Export-ModuleMember -Cmdlet Add-UserToGroup, Get-UserGroup # .\FortiAuth-Import\public\Users.ps1 Function Remove-TokenFromUser { [CmdletBindings()] Param( [ValidateNotNullOrEmpty()] $ID ) Set-User -ID $ID -TokenAuth $false -TokenSerial "" -TokenType "" } Function Get-User { Param( ) $returnedData = Invoke-FortiAuthRestMethod -Resource "localusers/" -Method Get $data = $returnedData.objects if ($returnedData.meta) { do { $returnedData = Invoke-FortiAuthRestMethod -Resource "localusers/$($returnedData.meta.next)" -Method Get $data = $data + $returnedData.objects }while ($returnedData.meta.next) } return $data } <# .SYNOPSIS Changes User information .DESCRIPTION Changes User Information, such as Token, Password, Last Name, Email, etc. .PARAMETER ID ID of user in the server's database, can be found with Get-User. .PARAMETER Create If set then a new user will be created. .PARAMETER TokenAuth If true, then the user will be using a token. .PARAMETER TokenSerial The serial number of the token. .PARAMETER TokenType The type of token that will be used, accepts ftk,�ftm,�email,�or sms. .PARAMETER Passcode The passcode or password for user authentication. .PARAMETER Expire The number of days till the account expires, used with Passcode/Password. Note: the api requires ISO-8601 formatted user expiration time in UTC, but this is taken care of. .PARAMETER MobileNumber Mobile number for sms resets. Must follow international number format: +[country_code]-[number] .PARAMETER Email Email of the user. .PARAMETER Active If set then the user account is active. .PARAMETER FirstName First Name of user. .PARAMETER LastName Last Name of user. .PARAMETER Address Address of user. .PARAMETER City City of user. .PARAMETER State State of user. .PARAMETER Country Country of user. Note: Must be a country code from ISO-3166 list, but this is in the Parrameter Set. .PARAMETER Custom1 Custom1 of user. .PARAMETER Custom2 Custom2 of user. .PARAMETER Custom3 Custom3 of user. .EXAMPLE Set-User -ID '1' -TokenAuth -TokenSerial "abcdef123456789" -TokenType ftk -Active .NOTES General notes #> Function Set-User { #[CmdletBindings()] Param( [ValidateNotNullOrEmpty()] $ID, [switch] $Create, [Parameter( Mandatory = $True, ParameterSetName = "Token" )] [switch] $TokenAuth, [Parameter( Mandatory = $False, ParameterSetName = "Token" )] $TokenSerial, [Parameter( Mandatory = $True, ParameterSetName = "Token" )] [Parameter( Mandatory = $False, ParameterSetName = "SMS" )] [Parameter( Mandatory = $False, ParameterSetName = "Email" )] [ValidateSetAttribute("ftk", "ftm", "email", "sms")] $TokenType, [Parameter( Mandatory = $True, ParameterSetName = "Passcode" )] [Alias("Password")] $Passcode, [Parameter( Mandatory = $False, ParameterSetName = "Passcode" )] [int] $Expire = 60, [Parameter( Mandatory = $True, ParameterSetName = "SMS" )] [ValidateLength(4, 25)] [ValidatePatternAttribute("\+\d{1,6}\-\d{4,20}")] [string] $MobileNumber, [Parameter( Mandatory = $True, ParameterSetName = "Email" )] [string] $Email, [switch] $Active, [ValidateLength(0, 30)] [string] $FirstName, [ValidateLength(0, 30)] [string] $LastName, [ValidateLength(0, 80)] [string] $Address, [ValidateLength(0, 40)] [string] $City, [ValidateLength(0, 40)] [string] $State, [ValidateSet( 'AX', 'AF', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AR', 'AM', 'AW', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BA', 'BW', 'BV', 'BR', 'IO', 'BN', 'BG', 'BF', 'BI', 'KH', 'CM', 'CA', 'CV', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC', 'CO', 'KM', 'CD', 'CG', 'CK', 'CR', 'CI', 'HR', 'CU', 'CY', 'CZ', 'DK', 'DJ', 'DM', 'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF', 'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GN', 'GW', 'GY', 'HT', 'HM', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IL', 'IT', 'JM', 'JP', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT', 'LU', 'MO', 'MK', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX', 'FM', 'MD', 'MC', 'MN', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'AN', 'NC', 'NZ', 'NI', 'NE', 'NG', 'NU', 'NF', 'MP', 'NO', 'OM', 'PK', 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR', 'QA', 'RE', 'RO', 'RU', 'RW', 'SH', 'KN', 'LC', 'PM', 'VC', 'WS', 'SM', 'ST', 'SA', 'SN', 'CS', 'SC', 'SL', 'SG', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SZ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK', 'TO', 'TT', 'TN', 'TR', 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'UY', 'UZ', 'VU', 'VA', 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW')] [string] $Country, [ValidateLength(0, 255)] [string] $Custom1, [ValidateLength(0, 255)] [string] $Custom2, [ValidateLength(0, 255)] [string] $Custom3 ) $Body = @{ active = $Active } if ($TokenAuth) { if ($TokenType -like "ftk" -or $TokenType -like "ftm") { $Body.token_serial = $TokenSerial $Body.token_auth = $TokenAuth $Body.ftk_only = $True } elseif ($TokenType -like "sms") { $Body.ftk_only = $False $Body.token_auth = $False $Body.mobile_number = $MobileNumber } elseif ($TokenType -like "email") { $Body.ftk_only = $False $Body.token_auth = $False $Body.email = $Email } $Body.token_type = $TokenType } if ($Passcode) { $Body.password = $Passcode $Body.expires_at = (Get-Date).AddDays($Expire).ToUniversalTime() | Get-Date -format s } if ($FirstName) {$Body.first_name = $FirstName} if ($LastName) {$Body.last_name = $LastName} if ($Address) {$Body.address = $Address} if ($City) {$Body.city = $City} if ($State) {$Body.state = $State} if ($Country) {$Body.country = $Country} if ($Custom1) {$Body.custom1 = $Custom1} if ($Custom2) {$Body.custom2 = $Custom2} if ($Custom3) {$Body.custom3 = $Custom3} if ($Create) { $UserList = Get-User $UserList | ForEach-Object { if ($TokenSerial -like $_.token_serial) { # Remove/Unassign token Remove-TokenFromUser -ID $_.id # There shouldn't ever be one token assigned to more than one user break } } $UserList | ForEach-Object { if ($UserName -match $_.username) { # Remove-User -ID $_.id -Server $Server -Resource $Resource -Credentials $Credentials return @{UserFound = $true} } } Invoke-FortiAuthRestMethod -Resource "localusers/$($ID)/" -Method Post -Body $Body } else { Invoke-FortiAuthRestMethod -Resource "localusers/$($ID)/" -Method Patch -Body $Body } } Export-ModuleMember -Cmdlet Remove-TokenFromUser, Get-User, Set-User Write-Verbose 'Importing from [C:\projects\fortiauth-import\FortiAuth-Import\classes]' |