Private/Import-EntraOpsClassificationOverwrites.ps1
|
function Import-EntraOpsClassificationOverwrites { <# .SYNOPSIS Loads classification overwrite definitions from the tenant-specific classification folder and Templates. .DESCRIPTION Shared helper that loads the separated overwrite files and returns normalized overwrite definitions for a specific RBAC system: - Classification_RoleActionOverwrites.json: Down- or upgrade the tier level of individual role definition actions (e.g., "microsoft.directory/bitlockerKeys/key/read" on scope "/*"). An optional ActionType ("Action" or "DataAction", defaults to "Action") declares which plane the actions belong to for RBAC systems that distinguish control/management plane Actions from data plane DataActions (currently Azure). This file is ONLY read from the tenant-specific folder ($FolderClassification/$TenantNameContext) alongside the other customized classification files. A file in the Templates folder is intentionally ignored. Role action overwrites are applied at classification file generation time by Update-EntraOpsClassificationControlPlaneScope (via Invoke-EntraOpsClassificationActionOverwrite) and are baked into the tenant-specific Classification_*.json files. The Get-EntraOpsPrivilegedEAM* cmdlets do not apply them at runtime. - Classification_RoleDefinitionOverwrites.json: Down- or upgrade the tier level of a role definition, identified by RoleDefinitionId and/or RoleDefinitionName (replaces previously hard-coded handling such as ControlPlaneRolesWithoutRoleActions). A named Service replaces or adds only that service; an empty or "*" Service replaces all classifications. A tenant-specific file in $FolderClassification/$TenantNameContext is preferred; otherwise the file in $FolderClassification/Templates is used as fallback. - Classification_ApiPermissionOverwrites.json: Down- or upgrade the tier level of an individual API permission (application or delegated), identified by PermissionValue and, optionally, TargetAppId/PermissionType. Schema is aligned with Classification_ApiPermissions.json entries (PermissionValue/PermissionType/TargetAppId/Category) instead of the RoleDefinitionActions/scope-pattern shape used by Classification_RoleActionOverwrites.json. This file is ONLY read from the tenant-specific folder (no Templates fallback), same as Classification_RoleActionOverwrites.json. Only applicable to RbacSystem "ResourceApps" and applied at classification file generation time by Update-EntraOpsClassificationControlPlaneScope (baked into the tenant-specific Classification_ApiPermissions.json via Invoke-EntraOpsClassificationActionOverwrite, reusing the same nested-schema mechanism as the other RBAC systems). All files contain a JSON array of overwrite entries. For role definition overwrites, Service scopes the overwrite to that classification service; use an empty or "*" Service to replace the entire role. For other overwrite types, Service (Category for API permission overwrites) is used as the service of the overwritten entry. RbacSystem "ResourceApps" (API permissions) is no longer supported in Classification_RoleActionOverwrites.json - such entries are skipped with a warning. Use Classification_ApiPermissionOverwrites.json instead. Every overwrite entry must contain a Justification to document why the classification has been changed. Entries without a Justification are skipped with a warning. .PARAMETER RbacSystem RBAC system to filter overwrite entries for (e.g., "EntraID", "DeviceManagement", "Defender", "IdentityGovernance", "ResourceApps"). .PARAMETER FolderClassification Base folder for classification files. Defaults to $DefaultFolderClassification. .OUTPUTS [PSCustomObject] with three array properties: RoleActionOverwrites, RoleDefinitionOverwrites and ApiPermissionOverwrites. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$RbacSystem, [Parameter(Mandatory = $false)] [string]$FolderClassification = $DefaultFolderClassification ) $RoleActionOverwrites = [System.Collections.Generic.List[object]]::new() $RoleDefinitionOverwrites = [System.Collections.Generic.List[object]]::new() $ApiPermissionOverwrites = [System.Collections.Generic.List[object]]::new() # Translation between the PermissionType values used on Classification_ApiPermissionOverwrites.json entries # (matching Classification_ApiPermissions.json / AppRoleAssignment.RoleType semantics: "Application"/"Delegated") # and the ResourceScope values used internally by Invoke-EntraOpsClassificationActionOverwrite ("Application"/"Delegation"). $PermissionTypeToResourceScope = @{ 'Application' = 'Application' 'Delegated' = 'Delegation' } # Mapping to derive tag value from tier level name if not explicitly defined $TierLevelTagValueMap = @{ 'ControlPlane' = '0' 'ManagementPlane' = '1' 'WorkloadPlane' = '1' # Tier1 sub-plane (cf. Tier1-WorkloadPlane groups / ObjectAdminTierLevel "1" in PrivilegedEAM exports) 'UserAccess' = '2' } $OverwriteFileMap = [System.Collections.Generic.List[object]]::new() # Tenant-specific classification folder (only available after Connect-EntraOps has set $TenantNameContext) $TenantFolder = if (-not [string]::IsNullOrEmpty($TenantNameContext)) { Join-Path -Path $FolderClassification -ChildPath $TenantNameContext } else { $null } # Role action overwrites: ONLY read from the tenant-specific folder, no Templates fallback if ($null -ne $TenantFolder) { $RoleActionFilePath = Join-Path -Path $TenantFolder -ChildPath 'Classification_RoleActionOverwrites.json' if (Test-Path -Path $RoleActionFilePath) { Write-Verbose "Using tenant-specific role action overwrites file: $RoleActionFilePath" $OverwriteFileMap.Add([PSCustomObject]@{ Type = 'RoleAction'; Path = $RoleActionFilePath }) } else { Write-Verbose "No tenant-specific role action overwrites file found at $RoleActionFilePath" } # API permission overwrites (ResourceApps only): ONLY read from the tenant-specific folder, no Templates # fallback - same convention as role action overwrites. $ApiPermissionFilePath = Join-Path -Path $TenantFolder -ChildPath 'Classification_ApiPermissionOverwrites.json' if (Test-Path -Path $ApiPermissionFilePath) { Write-Verbose "Using tenant-specific API permission overwrites file: $ApiPermissionFilePath" $OverwriteFileMap.Add([PSCustomObject]@{ Type = 'ApiPermission'; Path = $ApiPermissionFilePath }) } else { Write-Verbose "No tenant-specific API permission overwrites file found at $ApiPermissionFilePath" } } else { Write-Verbose "No tenant context available, skipping tenant-specific role action and API permission overwrites" } # Role definition overwrites: tenant-specific file preferred, Templates as fallback $RoleDefinitionFilePath = $null if ($null -ne $TenantFolder) { $TenantRoleDefinitionFilePath = Join-Path -Path $TenantFolder -ChildPath 'Classification_RoleDefinitionOverwrites.json' if (Test-Path -Path $TenantRoleDefinitionFilePath) { Write-Verbose "Using tenant-specific role definition overwrites file: $TenantRoleDefinitionFilePath" $RoleDefinitionFilePath = $TenantRoleDefinitionFilePath } } if ($null -eq $RoleDefinitionFilePath) { $TemplateRoleDefinitionFilePath = Join-Path -Path $FolderClassification -ChildPath 'Templates/Classification_RoleDefinitionOverwrites.json' if (Test-Path -Path $TemplateRoleDefinitionFilePath) { Write-Verbose "Using template role definition overwrites file: $TemplateRoleDefinitionFilePath" $RoleDefinitionFilePath = $TemplateRoleDefinitionFilePath } else { Write-Verbose "No role definition overwrites file found in tenant-specific folder or Templates" } } if ($null -ne $RoleDefinitionFilePath) { $OverwriteFileMap.Add([PSCustomObject]@{ Type = 'RoleDefinition'; Path = $RoleDefinitionFilePath }) } if ($OverwriteFileMap.Count -eq 0) { return [PSCustomObject]@{ RoleActionOverwrites = @() RoleDefinitionOverwrites = @() ApiPermissionOverwrites = @() } } foreach ($OverwriteFileEntry in $OverwriteFileMap) { if (-not (Test-Path -Path $OverwriteFileEntry.Path)) { Write-Verbose "Classification overwrite file not found: $($OverwriteFileEntry.Path)" continue } $OverwriteFile = Get-Item -Path $OverwriteFileEntry.Path try { $OverwriteJson = @(Get-Content -Path $OverwriteFile.FullName -Raw | ConvertFrom-Json -Depth 10) } catch { Write-Warning "Failed to parse classification overwrite file $($OverwriteFile.FullName): $_" continue } # Resolve tier level for an overwrite entry, returns $null if invalid $ResolveTierLevel = { param($Entry, $EntryDescription) if ([string]::IsNullOrEmpty($Entry.EAMTierLevelName)) { Write-Warning "Skipping classification overwrite ($EntryDescription) in $($OverwriteFile.Name): EAMTierLevelName is missing." return $null } $TagValue = $Entry.EAMTierLevelTagValue if ([string]::IsNullOrEmpty($TagValue)) { if ($TierLevelTagValueMap.ContainsKey($Entry.EAMTierLevelName)) { $TagValue = $TierLevelTagValueMap[$Entry.EAMTierLevelName] } else { Write-Warning "Skipping classification overwrite ($EntryDescription) in $($OverwriteFile.Name): Unknown EAMTierLevelName '$($Entry.EAMTierLevelName)' and no EAMTierLevelTagValue defined." return $null } } return "$TagValue" } #region Role action overwrites $RoleActionEntries = if ($OverwriteFileEntry.Type -eq 'RoleAction') { @($OverwriteJson) } else { @() } foreach ($Entry in $RoleActionEntries) { if ($null -eq $Entry) { continue } if ("$($Entry.RbacSystem)" -ne $RbacSystem) { continue } # RbacSystem "ResourceApps" (API permissions) is no longer supported here - use # Classification_ApiPermissionOverwrites.json instead (schema aligned with Classification_ApiPermissions.json). if ($Entry.RbacSystem -eq 'ResourceApps') { Write-Warning "Skipping ResourceApps entry in $($OverwriteFile.Name): API permission overwrites are no longer supported in Classification_RoleActionOverwrites.json. Move it to Classification_ApiPermissionOverwrites.json." continue } $Actions = @($Entry.RoleDefinitionActions | Where-Object { -not [string]::IsNullOrEmpty($_) }) if ($Actions.Count -eq 0) { Write-Warning "Skipping role action classification overwrite in $($OverwriteFile.Name): RoleDefinitionActions is missing or empty." continue } if ([string]::IsNullOrEmpty($Entry.Justification)) { Write-Warning "Skipping role action classification overwrite for '$($Actions -join ', ')' in $($OverwriteFile.Name): Justification is required to document the classification change." continue } $TagValue = & $ResolveTierLevel $Entry "role actions: $($Actions -join ', ')" if ($null -eq $TagValue) { continue } $Scopes = @($Entry.RoleAssignmentScopeName | Where-Object { -not [string]::IsNullOrEmpty($_) }) if ($Scopes.Count -eq 0) { $Scopes = @("/*") } # Plane of the overwritten actions (Action = control/management plane, DataAction = data plane). # Defaults to "Action" when omitted, matching the same default used on TierLevelDefinition entries. $ActionType = if ("$($Entry.ActionType)" -eq 'DataAction') { 'DataAction' } else { 'Action' } $RoleActionOverwrites.Add([PSCustomObject]@{ 'RbacSystem' = $RbacSystem 'RoleDefinitionActions' = $Actions 'ActionType' = $ActionType 'RoleAssignmentScopeName' = $Scopes 'ResourceAppId' = $null 'ResourceScope' = $null 'EAMTierLevelName' = $Entry.EAMTierLevelName 'EAMTierLevelTagValue' = $TagValue 'Service' = $Entry.Service 'Justification' = $Entry.Justification 'SourceFile' = $OverwriteFile.Name }) | Out-Null } #endregion #region API permission overwrites (ResourceApps only) $ApiPermissionEntries = if ($OverwriteFileEntry.Type -eq 'ApiPermission') { @($OverwriteJson) } else { @() } foreach ($Entry in $ApiPermissionEntries) { if ($null -eq $Entry) { continue } if ("$RbacSystem" -ne 'ResourceApps') { continue } $PermissionValue = "$($Entry.PermissionValue)" if ([string]::IsNullOrEmpty($PermissionValue)) { Write-Warning "Skipping API permission classification overwrite in $($OverwriteFile.Name): PermissionValue is missing." continue } if ([string]::IsNullOrEmpty($Entry.Justification)) { Write-Warning "Skipping API permission classification overwrite for '$PermissionValue' in $($OverwriteFile.Name): Justification is required to document the classification change." continue } $TagValue = & $ResolveTierLevel $Entry "API permission: $PermissionValue" if ($null -eq $TagValue) { continue } $PermissionType = "$($Entry.PermissionType)" $ResourceScope = if (-not [string]::IsNullOrEmpty($PermissionType) -and $PermissionType -ne 'All' -and $PermissionTypeToResourceScope.ContainsKey($PermissionType)) { $PermissionTypeToResourceScope[$PermissionType] } elseif (-not [string]::IsNullOrEmpty($PermissionType) -and $PermissionType -ne 'All') { Write-Warning "API permission classification overwrite for '$PermissionValue' in $($OverwriteFile.Name): Unknown PermissionType '$PermissionType', expected 'Application', 'Delegated' or 'All'. Treating as 'All'." $null } else { $null } $ApiPermissionOverwrites.Add([PSCustomObject]@{ 'RbacSystem' = 'ResourceApps' 'RoleDefinitionActions' = @($PermissionValue) 'RoleAssignmentScopeName' = @("/") 'ResourceAppId' = if (-not [string]::IsNullOrEmpty($Entry.TargetAppId)) { "$($Entry.TargetAppId)" } else { $null } 'ResourceScope' = $ResourceScope 'EAMTierLevelName' = $Entry.EAMTierLevelName 'EAMTierLevelTagValue' = $TagValue 'Service' = $Entry.Category 'Justification' = $Entry.Justification 'SourceFile' = $OverwriteFile.Name }) | Out-Null } #endregion #region Role definition overwrites $RoleDefinitionEntries = if ($OverwriteFileEntry.Type -eq 'RoleDefinition') { @($OverwriteJson) } else { @() } foreach ($Entry in $RoleDefinitionEntries) { if ($null -eq $Entry) { continue } if ("$($Entry.RbacSystem)" -ne $RbacSystem) { continue } if ([string]::IsNullOrEmpty($Entry.RoleDefinitionId) -and [string]::IsNullOrEmpty($Entry.RoleDefinitionName)) { Write-Warning "Skipping role definition classification overwrite in $($OverwriteFile.Name): RoleDefinitionId or RoleDefinitionName is required." continue } $RoleIdentifier = if (-not [string]::IsNullOrEmpty($Entry.RoleDefinitionName)) { $Entry.RoleDefinitionName } else { $Entry.RoleDefinitionId } if ([string]::IsNullOrEmpty($Entry.Justification)) { Write-Warning "Skipping role definition classification overwrite for '$RoleIdentifier' in $($OverwriteFile.Name): Justification is required to document the classification change." continue } $TagValue = & $ResolveTierLevel $Entry "role definition: $RoleIdentifier" if ($null -eq $TagValue) { continue } $Scopes = @($Entry.RoleAssignmentScopeName | Where-Object { -not [string]::IsNullOrEmpty($_) }) $RoleDefinitionOverwrites.Add([PSCustomObject]@{ 'RbacSystem' = $RbacSystem 'RoleDefinitionId' = $Entry.RoleDefinitionId 'RoleDefinitionName' = $Entry.RoleDefinitionName 'RoleAssignmentScopeName' = if ($Scopes.Count -gt 0) { $Scopes } else { $null } 'EAMTierLevelName' = $Entry.EAMTierLevelName 'EAMTierLevelTagValue' = $TagValue 'Service' = $Entry.Service 'Justification' = $Entry.Justification 'SourceFile' = $OverwriteFile.Name }) | Out-Null } #endregion } if ($RoleActionOverwrites.Count -gt 0 -or $RoleDefinitionOverwrites.Count -gt 0 -or $ApiPermissionOverwrites.Count -gt 0) { Write-Verbose "Loaded $($RoleActionOverwrites.Count) role action, $($RoleDefinitionOverwrites.Count) role definition and $($ApiPermissionOverwrites.Count) API permission classification overwrite(s) for $RbacSystem from $(@($OverwriteFileMap.Path) -join ', ')" } return [PSCustomObject]@{ RoleActionOverwrites = @($RoleActionOverwrites) RoleDefinitionOverwrites = @($RoleDefinitionOverwrites) ApiPermissionOverwrites = @($ApiPermissionOverwrites) } } # SIG # Begin signature block # MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA0NoVBHy1btS8I # JDF2zjxtThSUEeJimx1pXIdvIPUFZ6CCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j # AEkoya49fu0nMA0GCSqGSIb3DQEBDAUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK # ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy # dGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5l # dHdvcmsgQ0EwHhcNMjEwNTMxMDY0MzA2WhcNMjkwOTE3MDY0MzA2WjCBgDELMAkG # A1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAl # BgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb # Q2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOC # Ag8AMIICCgKCAgEAvfl4+ObVgAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC # 5SBLm9qbe7mZXdmbgEvXhEArJ9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Va # qp3cKcniNQfrcE1K1sGzVrihQTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ # 0WeNG0a+RzDVLnLRxWPa52N5RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet # /5oCl8HGUJKbAiy9qbk0WQq/hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNe # GWJoRVfkkIJCu0LW8GHgwaM9ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcV # WiNoidQ+3k4nsPBADLxNF8tNorMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbl # s+V1e9dBkQXcXWnjlQ1DufyDljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZb # MI28iQzV13D4h1L92u+sUS4Hs07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+Nqc # noYsylfzGuXIkosagpZ6w7xQEmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbl # jnX98sy50IdbzAYQYLuDNbdeZ95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEA # AaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLahVDkCw6A/joq8 # +tT4HKbROg79MB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1Ud # DwEB/wQEAwIBBjAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vY3JsLmNlcnR1bS5w # bC9jdG5jYS5jcmwwawYIKwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8v # c3ViY2Eub2NzcC1jZXJ0dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3Np # dG9yeS5jZXJ0dW0ucGwvY3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG # CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEM # BQADggEBAFHCoVgWIhCL/IYx1MIy01z4S6Ivaj5N+KsIHu3V6PrnCA3st8YeDrJ1 # BXqxC/rXdGoABh+kzqrya33YEcARCNQOTWHFOqj6seHjmOriY/1B9ZN9DbxdkjuR # mmW60F9MvkyNaAMQFtXx0ASKhTP5N+dbLiZpQjy6zbzUeulNndrnQ/tjUoCFBMQl # lVXwfqefAcVbKPjgzoZwpic7Ofs4LphTZSJ1Ldf23SIikZbr3WjtP6MZl9M7JYjs # NhI9qX7OAo0FmpKnJ25FspxihjcNpDOO16hO0EoXQ0zF8ads0h5YbBRRfopUofbv # n3l6XYGaFpAP4bvxSgD5+d2+7arszgowggZrMIIEU6ADAgECAhBX5gfP8LabvnxC # XoItEBa/MA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhB # c3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNp # Z25pbmcgMjAyMSBDQTAeFw0yNjEwMDYwODI4MjNaFw0yNzEwMDYwODI4MjJaMIGQ # MQswCQYDVQQGEwJERTEdMBsGA1UECAwUUmhpbmVsYW5kLVBhbGF0aW5hdGUxEjAQ # BgNVBAcMCUxhaG5zdGVpbjEeMBwGA1UECgwVT3BlbiBTb3VyY2UgRGV2ZWxvcGVy # MS4wLAYDVQQDDCVPcGVuIFNvdXJjZSBEZXZlbG9wZXIgVGhvbWFzIE5hdW5oZWlt # MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAphp2ljSmVsRB6gvkEq7A # DUMENpKZiDFoAfF1ktD1nCwaVyI+bJ0ROjHwAn4iJgS+vlBDPOUIw2GLHkiqUhOg # HSwzg6gj45GNmt6zxsKP0zPlhMB/fb0zmz7/F7e3yfKCXLfhbHuk0Es9gJ+8Wmet # 9StVwwSE/K0MpW06GKA9nPWyE4N/ADwigDIj9rsTKJR4cve9w8G1b3zohpUc/qMr # onab+HVw5r9b3sOBnnaXC6zvrX4fovRz1ztwfWjRjILLoFG6mW/TuK5F2ICD3Rhl # 9R2rJWWWhzTDMsQlzvX+/SaM74q3OFpIVNdhvtmWU9pKUBRAyYMijcDqKEFGSzrc # 8JFmGMpP5TuroWF+N21d3px2eARvW1mV0DCfFAH+Og20SH/gVW6/ltQQEkH/z/Zt # 49ARyJrgESLOQtlMCIYSoKISdkk4ml4VUS1E/PcbzXEYj3a7m6DOxcd3WuY03UT9 # cnk3p0LMN6LeLYAZgVY+HRloZlH+kW2SkOHNuWgtXvZhAgMBAAGjggF4MIIBdDAM # BgNVHRMBAf8EAjAAMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jY3NjYTIwMjEu # Y3JsLmNlcnR1bS5wbC9jY3NjYTIwMjEuY3JsMHMGCCsGAQUFBwEBBGcwZTAsBggr # BgEFBQcwAYYgaHR0cDovL2Njc2NhMjAyMS5vY3NwLWNlcnR1bS5jb20wNQYIKwYB # BQUHMAKGKWh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jY3NjYTIwMjEuY2Vy # MB8GA1UdIwQYMBaAFN10XUwA23ufoHTKsW73PMAywHDNMB0GA1UdDgQWBBTBvGyH # MXj1dMbVnxuof9oP4PY7cDBLBgNVHSAERDBCMAgGBmeBDAEEATA2BgsqhGgBhvZ3 # AgUBBDAnMCUGCCsGAQUFBwIBFhlodHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsF # AAOCAgEAkC165c7/r6y3VeEEpNXas9bQs6ZpKPdJffHkf9xoPi4kWvAIWGc4ocG1 # DJLb18RXiDYShDmT5sb/6I08FeipKi2DNJkuOq6yOTJ3S7+hNFIZCyd6i7WKO8ea # P5I+FAbyJP4+5coZoMg45bUa9JoocaJCm+5n7WiCfN7/EQpClW5Trm4+ZMbp7EMN # F1uLJgGCMnN0SsoUarp7PHlqupMxMC4Uhhe+lAP2ytcSIU81L97/qjrADbLWqICk # 9il5iGM+aZndguq/cmfH9rJj4GRZHWnG6WwnzYD9+KgYlRI6em+/9dq+IRiXe2Bs # thUuIaFW7U2gWw8tBTEYm1UBLHdJx+L1gjJCLs5KT/wy5wU32wZxNDqPUQejUC1x # GvU3cKqmLgRq+yNf3gFVfzqIoggyM3U9wQvnk7nBtCkpjXS2hdx4yxzcmrlWsDHr # z6+6/jeyQySzbYUlFmKnc4n9Mw2soHOajEua5poFARVRS5KgUBuiiQ21YFNYzWBo # qGuECaaAI/C5rGxapMJ3dAOBnHw6NLqBet+ZXBJEccX5y89MLlOQu+jDmJP8HieR # qDLlwfhVZnw4RY8Rus43NZBwhNlVuOUXqocHKmJhKNlekda3qsJj93eQBQOxKJcc # w5O08q9jukpH2+yzFAj+7ll33DuNUgWptogc4Awtbx3glzcEvJQwggaCMIIEaqAD # AgECAhAo8HfBHDa9/l90MkdwJy4DMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYT # AlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMT # G0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQTAeFw0yNjAzMTEwNzM0NTRaFw0z # NjAyMjcwNzM0NTRaMFAxCzAJBgNVBAYTAlBMMSEwHwYDVQQKDBhBc3NlY28gRGF0 # YSBTeXN0ZW1zIFMuQS4xHjAcBgNVBAMMFUNlcnR1bSBUaW1lc3RhbXAgMjAyNjCC # AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALi9zfBw+xI12hi2F9uNQBNO # STkTIi13fuh3DiWybI5392bBfJw6tO7zDs7UqP/rejVf4xFTU3XNOPsuOFkP5SPF # snWwn3VJL+NhNhsuujvYsQtaQnvNo1wk46reTgws1L8OFEdKaxgyqT4zOQx81mLw # NZSqXNU9Rrb9oAJWJF4Mydz+C1ebu0D0+vgM3tqAQ8TU203fqgKCPqIdHloaFqH9 # eyR+8tnpmy2hnnN59ZOtmsuHeRwf5iTOhlhf0d/qqquLOSIGPgGVL1Hj5XBUox2O # E7tQRr+l/xxNbL6OuwBO4Aa2EbuxYg37cpXv5i2/lTL4NASB/duf9W4fjA3Ro+GP # +bC54n2OYiM3Cq8z92ejx8F5HWO2e4/75eC95B9tMw/eq7109GDyW2+2ut5Bn0o8 # MXJTERkyystWbqcnUkomA97qfiDCwvpWuOMdfTOksXe9S+xDxOJaCbiyTivgPulx # cT+tfQTRXBr5UwtPvc+INnafOEilzVHA11tv+pHcylryxBc08cUihf/ttqkZS0bm # x3VxQay8uohaTp0//ECA9vYGW51SKdJMJhXvKyIdBLy8WYNchTt8yRITv9Adxg9J # qGujh+TnP1bW3aQjFtlEl7SzgNeI8OVA/CJAWWUuRT3Au9ToOpHy/flrrknhN4he # Ew7/6ILMv4HSsj0YZ4otAgMBAAGjggFQMIIBTDB1BggrBgEFBQcBAQRpMGcwOwYI # KwYBBQUHMAKGL2h0dHA6Ly9zdWJjYS5yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdHNj # YTIwMjEuY2VyMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u # Y29tMB8GA1UdIwQYMBaAFL5UAi+/QGxzQ86sCSVOnkNEGu7gMAwGA1UdEwEB/wQC # MAAwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwv # Y3RzY2EyMDIxLmNybDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8E # BAMCB4AwIgYDVR0gBBswGTAIBgZngQwBBAIwDQYLKoRoAYb2dwIFAQswHQYDVR0O # BBYEFCM5aiirmhKnpKfyH/lFmr+N/oIDMA0GCSqGSIb3DQEBDAUAA4ICAQBm/pOb # rAveTqYFPCSthxNVwBHTW4TfuBQY2KGCdMlH6ALjVPYf2XARNGMTXScR0JQ2/c2L # xLpoHHhRwxFf3d933DhFS165rYj6iPSQKm41rc9AMpTCjMdmai1aK9o870pOzTzL # RhWFVIxm+5Qf+t4V5z14tPoUsAWdfRKD1Zzvzfe5AHlE9rxOZcGROiULxs3Edf7Z # J8RZI0jzD9juj2oEX2XS7BVKuNCK1W0h1mjapv028yqo8UtZh5/1Ib48Yyp88BDY # Shh5PSGUUuS5tYXVfcduIPBe3PdNTYRYdT5VNxkwLgjMzIcr/6SH2fejFJDjnCxj # vXLuarErJg/IdI+hXdGIBDVOGv1zrkF4ktoQvFZIp5DIAYh0GwyUhc87qqn5UaYT # j2+iyiBDSNh7aGCrkuAnqg7Qh7frhX+QhMGeJ9SpLpnG76qN85hLyjvYR6gRYiLT # j8G4fxjqV400/buPw0rBo9yJZyq/8cGdCOLPOYf9qpefTcrZKeO9pg+UJHx8UABb # aTqizRxm8sUSEycccCCFhIit3AI/3wGuSOADeiA676NcQ7+dsP04YvzvdN7pTZNy # g672WpBDJdg0eItHl4yomvNeIOWh1qs4QqOW6TI8Ocsi4uSDTLorxLUDnBTwKQzz # pxd1YUctEgRh32R0J9FkFkeEruJU94RljFr1uDCCBrkwggShoAMCAQICEQCZo4AK # JlU7ZavcboSms+o5MA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAG # A1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVt # IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3Rl # ZCBOZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjE4WhcNMzYwNTE4MDUzMjE4WjBW # MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu # MSQwIgYDVQQDExtDZXJ0dW0gQ29kZSBTaWduaW5nIDIwMjEgQ0EwggIiMA0GCSqG # SIb3DQEBAQUAA4ICDwAwggIKAoICAQCdI88EMCM7wUYs5zNzPmNdenW6vlxNur3r # Lfi+5OZ+U3iZIB+AspO+CC/bj+taJUbMbFP1gQBJUzDUCPx7BNLgid1TyztVLn52 # NKgxxu8gpyTr6EjWyGzKU/gnIu+bHAse1LCitX3CaOE13rbuHbtrxF2tPU8f253Q # gX6eO8yTbGps1Mg+yda3DcTsOYOhSYNCJiL+5wnjZ9weoGRtvFgMHtJg6i671OPX # IciiHO4Lwo2p9xh/tnj+JmCQEn5QU0NxzrOiRna4kjFaA9ZcwSaG7WAxeC/xoZSx # F1oK1UPZtKVt+yrsGKqWONoK6f5EmBOAVEK2y4ATDSkb34UD7JA32f+Rm0wsr5aj # zftDhA5mBipVZDjHpwzv8bTKzCDUSUuUmPo1govD0RwFcTtMXcfJtm1i+P2UNXad # PyYVKRxKQATHN3imsfBiNRdN5kiVVeqP55piqgxOkyt+HkwIA4gbmSc3hD8ke66t # 9MjlcNg73rZZlrLHsAIV/nJ0mmgSjBI/TthoGJDydekOQ2tQD2Dup/+sKQptalDl # ui59SerVSJg8gAeV7N/ia4mrGoiez+SqV3olVfxyLFt3o/OQOnBmjhKUANoKLYlK # mUpKEFI0PfoT8Q1W/y6s9LTI6ekbi0igEbFUIBE8KDUGfIwnisEkBw5KcBZ3XwnH # mfznwlKo8QIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU # 3XRdTADbe5+gdMqxbvc8wDLAcM0wHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61Pgc # ptE6Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDAGA1Ud # HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYI # KwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 # dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv # Y3RuY2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0 # cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQB1iFgP5Y9Q # KJpTnxDsQ/z0O23JmoZifZdEOEmQvo/79PQg9nLF/GJe6ZiUBEyDBHMtFRK0mXj3 # Qv3gL0sYXe+PPMfwmreJHvgFGWQ7XwnfMh2YIpBrkvJnjwh8gIlNlUl4KENTK5DL # qsYPEtRQCw7R6p4s2EtWyDDr/M58iY2UBEqfUU/ujR9NuPyKk0bEcEi62JGxauFY # zZ/yld13fHaZskIoq2XazjaD0pQkcQiIueL0HKiohS6XgZuUtCKA7S6CHttZEsOb # QJ1j2s0urIDdqF7xaXFVaTHKtAuMfwi0jXtF3JJphrJfc+FFILgCbX/uYBPBlbBI # P4Ht4xxk2GmfzMn7oxPITpigQFJFWuzTMUUgdRHTxaTSKRJ/6Uh7ki/pFjf9sUAS # WgxT69QF9Ki4JF5nBIujxZ2sOU9e1HSCJwOfK07t5nnzbs1LbHuAIGJsRJiQ6HX/ # DW1XFOlXY1rc9HufFhWU+7Uk+hFkJsfzqBz3pRO+5aI6u5abI4Qws4YaeJH7H7M8 # X/YNoaArZbV4Ql+jarKsE0+8XvC4DJB+IVcvC9Ydqahi09mjQse4fxfef0L7E3hh # o2O3bLDM6v60rIRUCi2fJT2/IRU5ohgyTch4GuYWefSBsp5NPJh4QRTP9DC3gc5Q # EKtbrTY0Ka87Web7/zScvLmvQBm8JDFpDjCCBrkwggShoAMCAQICEQDn/2nHOzXO # S5Em2HR8aKWHMA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UE # ChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl # cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBO # ZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjA3WhcNMzYwNTE4MDUzMjA3WjBWMQsw # CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQw # IgYDVQQDExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEgQ0EwggIiMA0GCSqGSIb3 # DQEBAQUAA4ICDwAwggIKAoICAQDpEh8ENe25XXrFppVBvoplf0530W0lddNmjtv4 # YSh/f7eDQKFaIqc7tHj7ox+u8vIsJZlroakUeMS3i3T8aJRC+eQs4FF0GqvkM6+W # ZO8kmzZfxmZaBYmMLs8FktgFYCzywmXeQ1fEExflee2OpbHVk665eXRHjH7MYZIz # Nnjl2m8Hy8ulB9mR8wL/W0v0pjKNT6G0sfrx1kk+3OGosFUb7yWNnVkWKU4qSxLv # 16kJ6oVJ4BSbZ4xMak6JLeB8szrK9vwGDpvGDnKCUMYL3NuviwH1x4gZG0JAXU3x # 2pOAz91JWKJSAmRy/l0s0l5bEYKolg+DMqVhlOANd8Yh5mkQWaMEvBRE/kAGzIqg # WhwzN2OsKIVtO8mf5sPWSrvyplSABAYa13rMYnzwfg08nljZHghquCJYCa/xHK9a # cev9UD7Y+usr15d7mrszzxhF1JOr1Mpup2chNSBlyOObhlSO16rwrffVrg/SzaKf # SndS5swRhr8bnDqNJY9TNyEYvBYpgF95K7p0g4LguR4A++Z1nFIHWVY5v0fNVZmg # zxD9uVo/gta3onGOQj3JCxgYx0KrCXu4yc9QiVwTFLWbNdHFSjBCt5/8Q9pLuRhV # ocdCunhcHudMS1CGQ/Rn0+7P+fzMgWdRKfEOh/hjLrnQ8BdJiYrZNxvIOhM2aa3z # EDHNwwIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvlQC # L79AbHNDzqwJJU6eQ0Qa7uAwHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61PgcptE6 # Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMDAGA1UdHwQp # MCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYIKwYB # BQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u # Y29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3Ru # Y2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDov # L3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQC4k1l3yUwV/ZQH # CKCneqAs8EGTnwEUJLdDpokN/dMhKjK0rR5qX8nIIHzxpQR3TAw2IRw1Uxsr2Pli # G3bCFqSdQTUbfaTq6V3vBzEebDru9QFjqlKnxCF2h1jhLNFFplbPJiW+JSnJTh1f # KEqEdKdxgl9rVTvlxfEJ7exOn25MGbd/wGPwuSmMxRJVO0wnqgS7kmoJjNF9zqee # hFSDDP8ZVkWg4EZ2tIS0M3uZmByRr+1Lkwjjt8AtW83mVnZTyTsOb+FNfwJY7DS4 # FmWhkRbgcHRetreoTirPOr/ozyDKhT8MTSTf6Lttg6s6T/u08mDWw6HK04ZRDfQ9 # sb77QV8mKgO44WGP31vXnVKoWVJpFBjPvjL8/Zck/5wXX2iqjOaLStFOR/IQki+E # hn4zlcgVm22ZVCBPF+l8nAwUUShCtKuSU7GmZLKCmmxQMkSiWILTm8EtVD6AxnJh # oq8EnhjEEyUoflkeRF2WhFiVQOmWTwZRr44IxWGkNJC6tTorW5rl2Zl+2e9JLPYf # 3pStAPMDoPKIjVXd6NW2+fZrNUBeDo2eOa5Fn7Brs/HLQff5Xgris5MeUbdVgDrF # 8uxO6cLPvZPo63j62SsNg55pTWk9fUIF9iPoRbb4QurjoY/woI1RAOKtYtTic6aA # Jq3u83RIPpGXBSJKwx4KJAOZnCDCtTGCBqIwggaeAgEBMGowVjELMAkGA1UEBhMC # UEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMb # Q2VydHVtIENvZGUgU2lnbmluZyAyMDIxIENBAhBX5gfP8LabvnxCXoItEBa/MA0G # CWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZI # hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC # ARUwLwYJKoZIhvcNAQkEMSIEID4nyLBhjeHd0SSLwTHLJNQKp9MH8/1FlVuaQQKm # EaciMA0GCSqGSIb3DQEBAQUABIIBgFGyYGYX2comyYskkM7fXggLXk9d5P4q4rRo # nGNa9ZEXcGkrmpgzKNQMnTLYBRh7Ao7zNqld0lkuoV83lh23r9LJPvUxeW0KkdzD # TgWSsgp3HB5DWwPLiv4IiPR3gU/NktlQVRm5xoS7fmlOtydPlx3/ClUgrYpMrkKF # taidl4OXC6mCpu/3WwREKo2yxfxVFRXBey5UqZbIOFz8EoTnkIX3bSq4V5HGXKZr # oS17bz4qMkmB+NqjdC2sBwOxoBH/13Ux31osMiL0iU2PMs0gX4545gBiuoCnhjPn # SCwX/R0KI+DRCJR8PuRkwMxph/wy1ptigy9CzI06wbDndAZId9kTS7sLP5NlHbCa # n22YLsrrDPVFDXe57FI5Ec9yM+O9NX4sRAffUzKo3sYjpXNQVJ8QGr/Tk99h2R60 # CUczYkSVg1kLHzyu6reTLP24wuzi0ciW+ICaXhh31X++ATeiJNbIBPnSgUVsdUWX # IQUXxnh3CiwUwY6C7Z6bPIcUlNR1caGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID # 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0 # ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ # KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD # MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMTMwOTM5NTFaMDcG # CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY # 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDDxvOiE8nb+cwQym1yo410MoGx4pFxeFN6Z # 4xmTHIJEx7Ox9HbRpUy2xks+cj7c8/YwgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ # MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh # MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0 # dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI # hvcNAQEBBQAEggIAk+jOR0Qsmf3h1HQSpkswDKLwrpcHX9l/z/17yzT3lip2ODki # MYPgp2FBwnMDWeMr+LTdUPh4uysp4WIkZovNbk7uDJIJXUp+Pv1kEcZi+iloA/OY # 9VyRrCLQuwIOuDbTudqJ9oQKnaCor6LJUQGtm/AddGysKFmmpCdBOPvrRpkJ8wGF # tTW3z2HIA8/P8Wj7uKwAze/XRvjYaI6Ku8PCLM28G6D9Gl2bHDaVKrViSlai/MDX # VBR/DTR55YfncMEB5YK9BzpO5tW5Az8+0Ry93xUSX70P2Zz8DQswa+FMAXNO7T0x # sxn+fmFXNehT+DUcygt472VShlp8MuXB52BYVzj/Vi2B4OiH+jgBCXIxp6KkeTv+ # Edv8/p4OQuxwzHkn88M3LHy3+hQBKrIg4QJJiuA3WE7kFB5391FQ0Sp/6sdXxzUA # 3BIwte28eAms2TSa7LxWKDaGpSvmQvEqVytqapxBJorT822QuIURcy44moLVW12i # BevoetBNBGE4L2GdKR5GoPpmqRCcA/eV86ENA/SrOS7SfpSE1qb37SuyVO5OT7Lt # IXROLo2RL7UFOT/2+khuE4gWXTEHm2a/P6MWObAD0L3zUg1eYUXeqw2kYe3DnnUM # sWmxM2tPKFa6LEs1K3+fAQ22rJ+Du7wc0RYlCJUCYf12tT3xdM108iWo6N0= # SIG # End signature block |