Private/Cloud-ACL-Conversion.ps1
|
function ConvertTo-ACLUserEncoding { <# .SYNOPSIS Encodes user/group IDs for OpenNebula ACL rules. .DESCRIPTION Converts user IDs, group IDs, or wildcard to the encoded format required by OpenNebula ACLs. .PARAMETER UserID Individual user ID to encode .PARAMETER GroupID Group ID to encode .PARAMETER All Use wildcard (all users) .EXAMPLE ConvertTo-ACLUserEncoding -UserID 4 Returns: 4294967300 .EXAMPLE ConvertTo-ACLUserEncoding -GroupID 1 Returns: 8589934593 .EXAMPLE ConvertTo-ACLUserEncoding -All Returns: 17179869184 #> [CmdletBinding(DefaultParameterSetName='User')] param( [Parameter(Mandatory=$true, ParameterSetName='User')] [int]$UserID, [Parameter(Mandatory=$true, ParameterSetName='Group')] [int]$GroupID, [Parameter(Mandatory=$true, ParameterSetName='All')] [switch]$All ) switch ($PSCmdlet.ParameterSetName) { 'User' { # Individual user: 2^32 + user_id return [Math]::Pow(2, 32) + $UserID } 'Group' { # Group: 2^33 + group_id return [Math]::Pow(2, 33) + $GroupID } 'All' { # All users: 2^34 return [Math]::Pow(2, 34) } } } #function ConvertTo-ACLResourceEncoding { # <# # .SYNOPSIS # Encodes resource types and IDs for OpenNebula ACL rules. # #> # # [CmdletBinding()] # param( # [Parameter(Mandatory=$true)] # [ValidateSet( # 'VM', 'HOST', 'NET', 'IMAGE', 'USER', 'TEMPLATE', 'GROUP', 'DATASTORE', # 'CLUSTER', 'DOCUMENT', 'ZONE', 'SECGROUP', 'VDC', 'VROUTER', 'MARKETPLACE', # 'MARKETPLACEAPP', 'VMGROUP', 'VNTEMPLATE', 'BACKUPJOB' # )] # [string[]]$ResourceType, # # [Parameter(Mandatory=$false)] # [int]$ResourceID = -1, # # [Parameter(Mandatory=$false)] # [int]$GroupID = -1 # ) # # $resourceBits = @{ # 'VM' = [long]0x1000000000 # 2^36 # 'HOST' = [long]0x2000000000 # 2^37 # 'NET' = [long]0x4000000000 # 2^38 # 'IMAGE' = [long]0x8000000000 # 2^39 # 'USER' = [long]0x10000000000 # 2^40 # 'TEMPLATE' = [long]0x20000000000 # 2^41 # 'GROUP' = [long]0x40000000000 # 2^42 # 'DATASTORE' = [long]0x1000000000000 # 2^48 # 'CLUSTER' = [long]0x80000000000 # 2^43 # 'DOCUMENT' = [long]0x100000000000 # 2^44 # 'ZONE' = [long]0x200000000000 # 2^45 # 'SECGROUP' = [long]0x400000000000 # 2^46 # 'VDC' = [long]0x800000000000 # 2^47 # 'VROUTER' = [long]0x2000000000000 # 2^49 # 'MARKETPLACE' = [long]0x4000000000000 # 2^50 # 'MARKETPLACEAPP' = [long]0x8000000000000 # 2^51 # 'VMGROUP' = [long]0x10000000000000 # 2^52 # 'VNTEMPLATE' = [long]0x20000000000000 # 2^53 # 'BACKUPJOB' = [long]0x40000000000000 # 2^54 # } # # # Infrastructure types that cannot use @group selector # $infrastructureTypes = @('HOST', 'GROUP', 'CLUSTER', 'ZONE', 'VDC', 'DATASTORE') # # # Check if trying to use group selector with infrastructure types # if ($GroupID -ge 0) { # $hasInfraType = $ResourceType | Where-Object { $_ -in $infrastructureTypes } # if ($hasInfraType) { # throw "Group(@) selector cannot be applied to infrastructure types: $($hasInfraType -join ', '). Use wildcard (*) instead." # } # } # # # Calculate resource type mask # [long]$typeMask = 0 # foreach ($type in $ResourceType) { # $typeMask = $typeMask -bor $resourceBits[$type] # } # # # Selector encoding - these bits indicate WHICH resources of that type: # # Bit 32 (0x100000000) = INDIVIDUAL bit - must be set when specifying specific ID # # Bit 33 (0x200000000) = CLUSTER bit # # Bit 34 (0x400000000) = ALL bit # # Bits 0-31 = The actual ID value (when INDIVIDUAL bit is set) # # [long]$selector = 0 # if ($ResourceID -ge 0) { # # Specific resource ID: set INDIVIDUAL bit (bit 32) + add the ID # $selector = [long]0x100000000 + $ResourceID # } # elseif ($GroupID -ge 0) { # # Group-owned resources: set GROUP bit + add group ID # # (Note: this is different from INDIVIDUAL bit) # # Based on OpenNebula source, group ownership uses a different encoding # $selector = [long]0x100000000 + $GroupID # } # else { # # All resources (*): set ALL bit (bit 34) # $selector = [long]0x400000000 # } # # # Combine type mask with selector # $encoded = $typeMask -bor $selector # # Write-Verbose "Type mask: $typeMask (0x$([Convert]::ToString($typeMask, 16)))" # Write-Verbose "Selector: $selector (0x$([Convert]::ToString($selector, 16)))" # Write-Verbose "Combined: $encoded (0x$([Convert]::ToString($encoded, 16)))" # # return $encoded #} # function ConvertTo-ACLResourceEncoding2 { <# .SYNOPSIS Encodes resource types and IDs for OpenNebula ACL rules. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateSet( 'VM', 'HOST', 'NET', 'IMAGE', 'USER', 'TEMPLATE', 'GROUP', 'DATASTORE', 'CLUSTER', 'DOCUMENT', 'ZONE', 'SECGROUP', 'VDC', 'VROUTER', 'MARKETPLACE', 'MARKETPLACEAPP', 'VMGROUP', 'VNTEMPLATE', 'BACKUPJOB' )] [string[]]$ResourceType, [Parameter(Mandatory=$false)] [int]$ResourceID = -1, [Parameter(Mandatory=$false)] [int]$GroupID = -1 ) $resourceBits = @{ 'VM' = [long]0x1000000000 # 2^36 'HOST' = [long]0x2000000000 # 2^37 'NET' = [long]0x4000000000 # 2^38 'IMAGE' = [long]0x8000000000 # 2^39 'USER' = [long]0x10000000000 # 2^40 'TEMPLATE' = [long]0x20000000000 # 2^41 'GROUP' = [long]0x40000000000 # 2^42 'DATASTORE' = [long]0x1000000000000 # 2^48 'CLUSTER' = [long]0x80000000000 # 2^43 'DOCUMENT' = [long]0x100000000000 # 2^44 'ZONE' = [long]0x200000000000 # 2^45 'SECGROUP' = [long]0x400000000000 # 2^46 'VDC' = [long]0x800000000000 # 2^47 'VROUTER' = [long]0x2000000000000 # 2^49 'MARKETPLACE' = [long]0x4000000000000 # 2^50 'MARKETPLACEAPP' = [long]0x8000000000000 # 2^51 'VMGROUP' = [long]0x10000000000000 # 2^52 'VNTEMPLATE' = [long]0x20000000000000 # 2^53 'BACKUPJOB' = [long]0x40000000000000 # 2^54 } # Infrastructure types that cannot use @group selector $infrastructureTypes = @('HOST', 'GROUP', 'CLUSTER', 'ZONE', 'VDC', 'DATASTORE') # Check if trying to use group selector with infrastructure types if ($GroupID -ge 0) { $hasInfraType = $ResourceType | Where-Object { $_ -in $infrastructureTypes } if ($hasInfraType) { throw "Group(@) selector cannot be applied to infrastructure types: $($hasInfraType -join ', '). Use wildcard (*) instead." } } # Calculate resource type mask [long]$typeMask = 0 foreach ($type in $ResourceType) { $typeMask = $typeMask -bor $resourceBits[$type] } # Selector encoding - these bits indicate WHICH resources of that type: # Bit 32 (0x100000000) = INDIVIDUAL bit (#) - for specific resource ID # Bit 33 (0x200000000) = GROUP bit (@) - for group-owned resources ← FIXED! # Bit 34 (0x400000000) = ALL bit (*) - for all resources # Bits 0-31 = The actual ID value [long]$selector = 0 if ($ResourceID -ge 0) { # Specific resource ID (#ID): set INDIVIDUAL bit (bit 32) + add the ID $selector = [long]0x100000000 + $ResourceID } elseif ($GroupID -ge 0) { # Group-owned resources (@GID): set GROUP bit (bit 33) + add group ID $selector = [long]0x200000000 + $GroupID # ← FIXED! Was 0x100000000 } else { # All resources (*): set ALL bit (bit 34) $selector = [long]0x400000000 } # Combine type mask with selector $encoded = $typeMask -bor $selector Write-Verbose "Type mask: $typeMask (0x$([Convert]::ToString($typeMask, 16)))" Write-Verbose "Selector: $selector (0x$([Convert]::ToString($selector, 16)))" Write-Verbose "Combined: $encoded (0x$([Convert]::ToString($encoded, 16)))" return $encoded } function ConvertTo-ACLResourceEncoding { <# .SYNOPSIS Encodes resource types and IDs for OpenNebula ACL rules. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateSet( 'VM', 'HOST', 'NET', 'IMAGE', 'USER', 'TEMPLATE', 'GROUP', 'DATASTORE', 'CLUSTER', 'DOCUMENT', 'ZONE', 'SECGROUP', 'VDC', 'VROUTER', 'MARKETPLACE', 'MARKETPLACEAPP', 'VMGROUP', 'VNTEMPLATE', 'BACKUPJOB' )] [string[]]$ResourceType, [Parameter(Mandatory=$false)] [int]$ResourceID = -1, [Parameter(Mandatory=$false)] [int]$GroupID = -1 ) $resourceBits = @{ 'VM' = [long]0x1000000000 # 2^36 'HOST' = [long]0x2000000000 # 2^37 'NET' = [long]0x4000000000 # 2^38 'IMAGE' = [long]0x8000000000 # 2^39 'USER' = [long]0x10000000000 # 2^40 'TEMPLATE' = [long]0x20000000000 # 2^41 'GROUP' = [long]0x40000000000 # 2^42 'DATASTORE' = [long]0x1000000000000 # 2^48 'CLUSTER' = [long]0x80000000000 # 2^43 'DOCUMENT' = [long]0x100000000000 # 2^44 'ZONE' = [long]0x200000000000 # 2^45 'SECGROUP' = [long]0x400000000000 # 2^46 'VDC' = [long]0x800000000000 # 2^47 'VROUTER' = [long]0x2000000000000 # 2^49 'MARKETPLACE' = [long]0x4000000000000 # 2^50 'MARKETPLACEAPP' = [long]0x8000000000000 # 2^51 'VMGROUP' = [long]0x10000000000000 # 2^52 'VNTEMPLATE' = [long]0x20000000000000 # 2^53 'BACKUPJOB' = [long]0x40000000000000 # 2^54 } # Infrastructure types that cannot use @group selector $infrastructureTypes = @('HOST', 'GROUP', 'CLUSTER', 'ZONE', 'VDC', 'DATASTORE') # Check if trying to use group selector with infrastructure types if ($GroupID -ge 0) { $hasInfraType = $ResourceType | Where-Object { $_ -in $infrastructureTypes } if ($hasInfraType) { throw "Group(@) selector cannot be applied to infrastructure types: $($hasInfraType -join ', '). Use wildcard (*) instead." } } # Calculate resource type mask [long]$typeMask = 0 foreach ($type in $ResourceType) { $typeMask = $typeMask -bor $resourceBits[$type] } # Selector encoding - these bits indicate WHICH resources of that type: # Bit 32 (0x100000000) = INDIVIDUAL bit (#) - for specific resource ID # Bit 33 (0x200000000) = GROUP bit (@) - for group-owned resources ← FIXED! # Bit 34 (0x400000000) = ALL bit (*) - for all resources # Bits 0-31 = The actual ID value [long]$selector = 0 if ($ResourceID -ge 0) { # Specific resource ID (#ID): set INDIVIDUAL bit (bit 32) + add the ID #$selector = [long]0x100000000 + $ResourceID $selector = [long]0x200000000 + $GroupID } elseif ($GroupID -ge 0) { # Group-owned resources (@GID): set GROUP bit (bit 33) + add group ID $selector = [long]0x200000000 + $GroupID # ← FIXED! Was 0x100000000 } else { # All resources (*): set ALL bit (bit 34) $selector = [long]0x400000000 } # Combine type mask with selector $encoded = $typeMask -bor $selector Write-Verbose "Type mask: $typeMask (0x$([Convert]::ToString($typeMask, 16)))" Write-Verbose "Selector: $selector (0x$([Convert]::ToString($selector, 16)))" Write-Verbose "Combined: $encoded (0x$([Convert]::ToString($encoded, 16)))" return $encoded } function ConvertTo-ACLRightsEncoding { <# .SYNOPSIS Encodes rights for OpenNebula ACL rules. .DESCRIPTION Converts permission rights to the encoded format required by OpenNebula ACLs. .PARAMETER Rights Rights to grant. Valid values: USE, MANAGE, ADMIN, CREATE .EXAMPLE ConvertTo-ACLRightsEncoding -Rights "USE" Returns: 1 .EXAMPLE ConvertTo-ACLRightsEncoding -Rights "USE","MANAGE" Returns: 3 #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateSet('USE', 'MANAGE', 'ADMIN', 'CREATE')] [string[]]$Rights ) $rightsBits = @{ 'USE' = 1 # 2^0 'MANAGE' = 2 # 2^1 'ADMIN' = 4 # 2^2 'CREATE' = 8 # 2^3 } $encoded = 0 foreach ($right in $Rights) { $encoded = $encoded -bor $rightsBits[$right] } return $encoded } function ConvertTo-ACLZoneEncoding { <# .SYNOPSIS Encodes zone for OpenNebula ACL rules. .DESCRIPTION Converts zone ID or wildcard to the encoded format required by OpenNebula ACLs. .PARAMETER ZoneID Specific zone ID .PARAMETER All Use wildcard (all zones) .EXAMPLE ConvertTo-ACLZoneEncoding -ZoneID 0 Returns: 4294967296 .EXAMPLE ConvertTo-ACLZoneEncoding -All Returns: 17179869184 #> [CmdletBinding(DefaultParameterSetName='Zone')] param( [Parameter(Mandatory=$true, ParameterSetName='Zone')] [int]$ZoneID, [Parameter(Mandatory=$true, ParameterSetName='All')] [switch]$All ) if ($PSCmdlet.ParameterSetName -eq 'All') { # All zones: 2^34 return [Math]::Pow(2, 34) } else { # Specific zone: 2^32 + zone_id return [Math]::Pow(2, 32) + $ZoneID } } function ConvertFrom-ACLEncoding { <# .SYNOPSIS Decodes an ACL rule to human-readable format. .DESCRIPTION Converts encoded ACL values back to readable format for verification. .PARAMETER ACL ACL object from Get-CloudACL .EXAMPLE Get-CloudACL -ID 5 | ConvertFrom-ACLEncoding #> [CmdletBinding()] param( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [object]$ACL ) process { # This just returns the string representation that's already decoded [PSCustomObject]@{ ID = $ACL.id Rule = $ACL.string User = $ACL.user Resource = $ACL.resource Rights = $ACL.rights Zone = $ACL.zone } } } |