diff --git a/Modules/VMware.vSphere.SsoAdmin/MobConnect.ps1 b/Modules/VMware.vSphere.SsoAdmin/MobConnect.ps1 new file mode 100644 index 00000000..eecd327d --- /dev/null +++ b/Modules/VMware.vSphere.SsoAdmin/MobConnect.ps1 @@ -0,0 +1,331 @@ +<# +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 Set-VcenterServerGlobalPermission { + <# + .NOTES + =========================================================================== + .DESCRIPTION + This function assigns global permissions associated with role to the specified user. + + .PARAMETER Server + Specifies the vSphere server MOB connection + + .PARAMETER TargetUser + Specifies the full name of the local account to assign permissions to. + + .PARAMETER RoleId + Specifies the vCenter role ID to assign. + Acquire with (Get-VIRole -Name $role_name).ExtensionData.RoleId + + .PARAMETER Propagate + Specifies whether global permission must be propagated to all inventory objects + + .EXAMPLE + $myMobConnection = Connect-VcenterServerMOB -Server my.vc.server -User ssoAdmin@vsphere.local -Password 'MyStrongPa$$w0rd' + Set-VcenterServerGlobalPermission -Server $myMobConnection -TargetUser otheruser@vsphere.local -RoleId -9999 -Propagate + + Assign global permissions associated with role '-9999' to the user 'otheruser@vsphere.local' + propagating the assignment to the whole inventory. +#> + [CmdletBinding()] + param( + [Parameter( + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'MobConnection object')] + [ValidateNotNull()] + [MobConnection] + $Server, + + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'Full name of local user to assign the permission to')] + [ValidateNotNull()] + [string] + $TargetUser, + + [Parameter( + Mandatory = $true, + ValueFromPipeline = $false, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'vCenter ID of the role to assign')] + [long] + $RoleId, + + [Parameter( + Mandatory = $false, + HelpMessage = 'Propagate global permission to all objects')] + [switch] + $Propagate + ) + Process { + $Server.SetPermissions($TargetUser, $RoleId, $Propagate) + } +} + +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 + $myMobConnection = Connect-VcenterServerMOB -Server my.vc.server -User ssoAdmin@vsphere.local -Password 'MyStrongPa$$w0rd' + Disconnect-VcenterServerMOB -Server $myMobConnection + + Disconnect a vSphere server managed object browser stored in 'myMobConnection' varaible +#> + [CmdletBinding()] + param( + [Parameter( + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $false, + HelpMessage = 'MobConnection object')] + [ValidateNotNull()] + [MobConnection] + $Server + ) + + Process { + if ($Server.IsConnected()) { + $Server.Logout() + } + } +} diff --git a/Modules/VMware.vSphere.SsoAdmin/VMware.vSphere.SsoAdmin.psd1 b/Modules/VMware.vSphere.SsoAdmin/VMware.vSphere.SsoAdmin.psd1 index 6b8decf9..e3d4a00d 100644 --- a/Modules/VMware.vSphere.SsoAdmin/VMware.vSphere.SsoAdmin.psd1 +++ b/Modules/VMware.vSphere.SsoAdmin/VMware.vSphere.SsoAdmin.psd1 @@ -12,7 +12,7 @@ RootModule = 'VMware.vSphere.SsoAdmin.psm1' # Version number of this module. -ModuleVersion = '1.3.9' +ModuleVersion = '1.4.0' # Supported PSEditions # CompatiblePSEditions = @() @@ -80,7 +80,9 @@ FunctionsToExport = 'Connect-SsoAdminServer', 'Disconnect-SsoAdminServer', 'Get-SsoTokenLifetime', 'Set-SsoTokenLifetime', 'Get-IdentitySource', 'Set-IdentitySource', 'Remove-IdentitySource', 'Add-ActiveDirectoryIdentitySource', 'Add-LDAPIdentitySource', 'Set-LDAPIdentitySource', - 'Get-SsoAuthenticationPolicy', 'Set-SsoAuthenticationPolicy' + 'Get-SsoAuthenticationPolicy', 'Set-SsoAuthenticationPolicy', + 'Connect-VcenterServerMOB', 'Disconnect-VcenterServerMOB', + 'Set-VcenterServerGlobalPermission' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @()