diff --git a/Modules/VMware.vSphere.SsoAdmin/MobConnect.ps1 b/Modules/VMware.vSphere.SsoAdmin/MobConnect.ps1 new file mode 100644 index 00000000..9a06d970 --- /dev/null +++ b/Modules/VMware.vSphere.SsoAdmin/MobConnect.ps1 @@ -0,0 +1,266 @@ +<# +Copyright 2024 JetStream Software, Inc. +SPDX-License-Identifier: BSD-2-Clause +#> + +class MobConnection { + <# + .NOTES + =================================================== + MOB3 connection object + + Approach borrowed from https://github.com/lamw/vmware-scripts/blob/master/powershell/GlobalPermissions.ps1 + =================================================== + Created on: 11/13/2024 + Github: https://github.com/jetstreamsoft + =================================================== + Usage sample: + $local_user_name = "user@vsphere.local" + $credential = New-Object System.Management.Automation.PSCredential($adminname, $adminpasswd) + $role_id = (Get-VIRole -Name $role_name).ExtensionData.RoleId + + $mobconn = New-Object MobConnection($vcenter_server, $credential, $True) + $mobconn.SetPermissions($local_user_name, $role_id, $True) + $mobconn.Logout() + #> + + hidden [object] $session + hidden [string] $nonce + hidden [string] $vc_address + hidden [bool] $skipCertCheck + + MobConnection([string] $vcenter, [PSCredential] $credential, [bool] $skipCertCheck) { + if ([string]::IsNullOrEmpty($vcenter)) { + Write-Error "vcenter parameter is required" -ErrorAction Stop + } + if ($credential -eq $null) { + Write-Error "credential parameter is required." -ErrorAction Stop + } + + $this.vc_address = $vcenter + $this.session = $null + $this.skipCertCheck = $skipCertCheck + + # vSphere MOB URL that would allow to extract nonce. + $login_mob_url = "https://$($this.vc_address)/invsvc/mob3/?moid=authorizationService&method=AuthorizationService.AddGlobalAccessControlList" + + $sessionvar = $null + # Initial login to vSphere MOB using GET and store session in class variable + $login_params = @{ + "Uri" = $login_mob_url + "SessionVariable" = "sessionvar" + "Credential" = $credential + "Method" = "GET" + } + if ($this.skipCertCheck) { + $login_params["SkipCertificateCheck"] = $True + } + $results = Invoke-WebRequest @login_params + + # Extract hidden vmware-session-nonce which must be included in future requests to prevent CSRF error + # Credit to https://blog.netnerds.net/2013/07/use-powershell-to-keep-a-cookiejar-and-post-to-a-web-form/ for parsing vmware-session-nonce via Powershell + if($results.StatusCode -eq 200) { + $null = $results -match 'name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"' + $this.nonce = $matches[1] + $this.session = $sessionvar + } else { + Write-Error "Failed to login to vSphere MOB with $($results.StatusCode) - $($results.Content)" -ErrorAction Stop + } + } + + [void] SetPermissions([string] $user_domain, [long] $vc_role_id, [bool] $propagate) { + if ($this.session -eq $null) { + Write-Error "Object not logged in, please relogin" -ErrorAction Stop + } + if ([string]::IsNullOrEmpty($user_domain)){ + Write-Error "user_domain parameter is required" -ErrorAction Stop + } + if ($user_domain.Contains('<') -or $user_domain.Contains('>')) { + Write-Error "Invalid user name provided - $user_domain" -ErrorAction Stop + } + + # vSphere MOB URL to private enableMethods + $enable_mob_url = "https://$($this.vc_address)/invsvc/mob3/?moid=authorizationService&method=AuthorizationService.AddGlobalAccessControlList" + + # Prepare permissions request + $request_body = @" + + + $user_domain + false + + $vc_role_id + $propagate + +"@ + # The POST data payload must include the vmware-session-nonce variable + URL-encoded request body + $body="vmware-session-nonce=$($this.nonce)&permissions=$([uri]::EscapeDataString($request_body))" + $enable_params = @{ + "Uri" = $enable_mob_url + "WebSession" = $this.session + "Method" = "POST" + "Body" = $body + } + if ($this.skipCertCheck) { + $enable_params["SkipCertificateCheck"] = $True + } + $results = Invoke-WebRequest @enable_params + if($results.StatusCode -ne 200) { + Write-Error "Failed to assign permissions with $($results.StatusCode) - $($results.Content)" -ErrorAction Stop + } + } + + [bool] IsConnected() { + return $this.session -ne $null + } + + [void] Logout() { + if ($this.session -eq $null) { + Write-Information "Object not logged in" + return + } + # Logout out of vSphere MOB + $logout_mob_url = "https://$($this.vc_address)/invsvc/mob3/logout" + $logout_params = @{ + "Uri" = $logout_mob_url + "WebSession" = $this.session + "Method" = "GET" + } + if ($this.skipCertCheck) { + $logout_params["SkipCertificateCheck"] = $True + } + $results = Invoke-WebRequest @logout_params + $this.session = $null + } +} + +function Connect-VcenterServerMOB { + <# + .NOTES + =========================================================================== + .DESCRIPTION + This function establishes a connection to a vSphere server managed object browser. + + .PARAMETER Server + Specifies the IP address or the DNS name of the vSphere server to which you want to connect. + + .PARAMETER User + Specifies the user name you want to use for authenticating with the server. + + .PARAMETER Password + Specifies the password you want to use for authenticating with the server. + + .PARAMETER Credential + Specifies a PSCredential object to for authenticating with the server. + + .PARAMETER SkipCertificateCheck + Specifies whether server Tls certificate validation will be skipped + + .EXAMPLE + Connect-VcenterServerMOB -Server my.vc.server -User myAdmin@vsphere.local -Password MyStrongPa$$w0rd + + Returns an object with connection of 'myAdmin@vsphere.local' user to MOB of vCenter server 'my.vc.server' +#> + [CmdletBinding()] + param( + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'IP address or the DNS name of the vSphere server')] + [string] + $Server, + + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'User name you want to use for authenticating with the server', + ParameterSetName = 'UserPass')] + [string] + $User, + + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'Password you want to use for authenticating with the server', + ParameterSetName = 'UserPass')] + [VMware.vSphere.SsoAdmin.Utils.StringToSecureStringArgumentTransformationAttribute()] + [SecureString] + $Password, + + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'PSCredential object to use for authenticating with the server', + ParameterSetName = 'Credential')] + [PSCredential] + $Credential, + + [Parameter( + Mandatory = $false, + HelpMessage = 'Skips server Tls certificate validation')] + [switch] + $SkipCertificateCheck) + + Process { + $vCenterMOB = $null + + try { + if ($PSBoundParameters.ContainsKey('Credential')) { + $vCenterMOB = New-Object MobConnection ` + -ArgumentList @( + $Server, + $Credential, + $SkipCertificateCheck) + } else { + $_credential = New-Object System.Management.Automation.PSCredential($User, $Password) + $vCenterMOB = New-Object MobConnection ` + -ArgumentList @( + $Server, + $_credential, + $SkipCertificateCheck) + } + } catch { + Write-Error (FormatError $_.Exception) + } + + return $vCenterMOB + } +} + +function Disconnect-VcenterServerMOB { + <# + .NOTES + =========================================================================== + .DESCRIPTION + This function closes the connection to a vSphere server managed object browser. + + .PARAMETER Server + Specifies the vSphere server MOB connection you want to terminate + + .EXAMPLE + $mySsoAdminConnection = Connect-VcenterServerMOB -Server my.vc.server -User ssoAdmin@vsphere.local -Password 'ssoAdminStrongPa$$w0rd' + Disconnect-VcenterServerMOB -Server $mySsoAdminConnection + + Disconnect a vSphere server managed object browser stored in 'mySsoAdminConnection' varaible +#> + [CmdletBinding()] + param( + [Parameter( + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'MobConnection object')] + [ValidateNotNull()] + [MobConnection] + $Server + ) + + Process { + if ($Server.IsConnected()) { + $Server.Logout() + } + } +}