Public/Import-ADFSTkMetadata.ps1
#Requires -Version 5.1 #Requires -RunAsAdministrator function Import-ADFSTkMetadata { [CmdletBinding(DefaultParameterSetName = 'AllSPs', SupportsShouldProcess = $true)] param ( [Parameter(ParameterSetName = 'SingleSP', Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] $EntityId, [Parameter(ParameterSetName = 'SingleSP', Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] $EntityBase, [string]$ConfigFile, [string]$LocalMetadataFile, [string[]]$ForcedEntityCategories, [Parameter(ParameterSetName = 'AllSPs')] [switch] $ProcessWholeMetadata, [switch]$ForceUpdate, [Parameter(ParameterSetName = 'AllSPs')] [switch] $AddRemoveOnly, #The time in minutes the chached metadatafile live [int] $CacheTime = 15, #The maximum SPs to add in one run (to prevent throttling). Is used when the script recusrive calls itself [int] $MaxSPAdditions = 80, [switch]$Silent, [switch]$criticalHealthChecksOnly, #If this switch is not provided the memory cache will be deleted [switch] $PreserveMemoryCache ) process { #$CompatibleConfigVersion = "1.3" #Check if we should avoid deleting memory cache if (!$PSBoundParameters.ContainsKey('PreserveMemoryCache') -or ($PSBoundParameters.ContainsKey('PreserveMemoryCache') -and $PreserveMemoryCache -eq $false)) { Remove-ADFSTkCache -AttributeMemoryCache } #Get All paths if ([string]::IsNullOrEmpty($Global:ADFSTkPaths)) { $Global:ADFSTkPaths = Get-ADFSTKPaths } try { # Add some variables $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider $utf8 = new-object -TypeName System.Text.UTF8Encoding # load configuration file if (!(Test-Path ( $ConfigFile ))) { throw (Get-ADFSTkLanguageText cFileDontExist -f $ConfigFile) } else { [xml]$Settings = Get-Content ($ConfigFile) } # set appropriate logging via EventLog mechanisms if (Verify-ADFSTkEventLogUsage) { #If we evaluated as true, the eventlog is now set up and we link the WriteADFSTklog to it Write-ADFSTkLog -SetEventLogName $Settings.configuration.logging.LogName -SetEventLogSource $Settings.configuration.logging.Source } else { # No Event logging is enabled, just this one to a file Write-ADFSTkLog (Get-ADFSTkLanguageText importEventLogMissingInSettings) -MajorFault } #Check against compatible version #if ([float]$Settings.configuration.ConfigVersion -lt [float]$CompatibleConfigVersion) #{ # Write-ADFSTkLog (Get-ADFSTkLanguageText importIncompatibleInstitutionConfigVersion -f $Settings.configuration.ConfigVersion, $CompatibleConfigVersion) -MajorFault #} if ($PSBoundParameters.ContainsKey('criticalHealthChecksOnly') -and $criticalHealthChecksOnly -ne $false) { $healthCheckResult = Get-ADFSTkHealth -ConfigFile $ConfigFile -HealthCheckMode CriticalOnly } else { $healthCheckResult = Get-ADFSTkHealth -ConfigFile $ConfigFile -HealthCheckMode Full } if ($healthCheckResult -eq $false) { Write-ADFSTkLog "The Health Check of ADFS Toolkit did not pass! Check earlier log entries to see what's wrong." -MajorFault } #region Get static values from configuration file $mypath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\') Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importStarted) -EntryType Information Write-ADFSTkLog (Get-ADFSTkLanguageText importCurrentPath -f $Global:ADFSTkPaths.modulePath) -EventID 1 #endregion #region Get SP Hash if ([string]::IsNullOrEmpty($Settings.configuration.SPHashFile)) { Write-ADFSTkLog (Get-ADFSTkLanguageText importMissingSPHashFileInConfig -f $ConfigFile) -MajorFault } else { $SPHashFile = Join-Path $Global:ADFSTkPaths.cacheDir $Settings.configuration.SPHashFile Write-ADFSTkLog (Get-ADFSTkLanguageText importSettingSPHashFileTo -f $SPHashFile) -EventID 2 } if (Test-Path $SPHashFile) { try { $SPHashList = Import-Clixml $SPHashFile } catch { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importCouldNotImportSPHashFile) $SPHashFileItem = Get-ChildItem $SPHashFile Rename-Item -Path $SPHashFile -NewName ("{0}_{1}.{2}" -f $SPHashFileItem.BaseName, ([guid]::NewGuid()).Guid, $SPHashFileItem.Extension) $SPHashList = @{} } } else { $SPHashList = @{} } #endregion #region Getting Metadata #Cached Metadata file #$CachedMetadataFile = Join-Path $Settings.configuration.WorkingPath -ChildPath $Settings.configuration.CacheDir | Join-Path -ChildPath $Settings.configuration.MetadataCacheFile $CachedMetadataFile = Join-Path $Global:ADFSTkPaths.cacheDir $Settings.configuration.MetadataCacheFile Write-ADFSTkLog (Get-ADFSTkLanguageText importSettingCachedMetadataFile -f $CachedMetadataFile) -EventID 3 if ($LocalMetadataFile) { try { $MetadataXML = new-object Xml.XmlDocument $MetadataXML.PreserveWhitespace = $true $MetadataXML.Load($LocalMetadataFile) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importSuccessfullyLoadedLocalMetadataFile) -EntryType Information } catch { Write-ADFSTkLog (Get-ADFSTkLanguageText importCouldNotLoadLocalMetadataFile) -MajorFault -EventID 4 } } if ($MetadataXML -eq $null) { # $UseCachedMetadata = $false # if (($CacheTime -eq -1 -or $CacheTime -gt 0) -and (Test-Path $CachedMetadataFile)) #CacheTime = -1 allways use cached metadata if exists # { # if ($CacheTime -eq -1 -or (Get-ChildItem $CachedMetadataFile).LastWriteTime.AddMinutes($CacheTime) -ge (Get-Date)) # { # $UseCachedMetadata = $true # try # { # #[xml]$MetadataXML = Get-Content $CachedMetadataFile # $MetadataXML = new-object Xml.XmlDocument # $MetadataXML.PreserveWhitespace = $true # $MetadataXML.Load($CachedMetadataFile) # # if ([string]::IsNullOrEmpty($MetadataXML)) # { # Write-ADFSTkLog (Get-ADFSTkLanguageText importCachedMetadataEmptyDownloading) -EntryType Error -EventID 5 # $UseCachedMetadata = $false # } # } # catch # { # Write-ADFSTkLog (Get-ADFSTkLanguageText importCachedMetadataCorruptDownloading) -EntryType Error -EventID 6 # $UseCachedMetadata = $false # } # } # else # { # $UseCachedMetadata = $false # Remove-Item $CachedMetadataFile -Confirm:$false # } # } # # if (!$UseCachedMetadata) # { # # #Get Metadata URL from config # if ([string]::IsNullOrEmpty($Settings.configuration.metadataURL)) # { # $metadataURL = 'https://localhost/metadata.xml' #Just for fallback # } # else # { # $metadataURL = $Settings.configuration.metadataURL # } # # Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importDownloadingMetadataFrom) -EntryType Information # # try # { # Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importDownloadingFromTo -f $metadataURL, $CachedMetadataFile) -EntryType Information # # $webClient = New-Object System.Net.WebClient # $webClient.Headers.Add("user-agent", "ADFSToolkit") # $webClient.DownloadFile($metadataURL, $CachedMetadataFile) # # Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importSuccesfullyDownloadedMetadataFrom -f $metadataURL) -EntryType Information # } # catch # { # Write-ADFSTkLog (Get-ADFSTkLanguageText importCouldNotDownloadMetadataFrom -f $metadataURL) -MajorFault -EventID 7 # } # # try # { # Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importParsingMetadataXML) -EntryType Information # $MetadataXML = new-object Xml.XmlDocument # $MetadataXML.PreserveWhitespace = $true # $MetadataXML.Load($CachedMetadataFile) # #$MetadataXML = [xml]$Metadata.Content # Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importSuccessfullyParsedMetadataXMLFrom -f $metadataURL) -EntryType Information # } # catch # { # Write-ADFSTkLog (Get-ADFSTkLanguageText importCouldNotParseMetadataFrom -f $metadataURL) -MajorFault -EventID 8 # } # } $MetadataXML = Get-ADFSTkMetadata -CacheTime $CacheTime -CachedMetadataFile $CachedMetadataFile -metadataURL $Settings.configuration.metadataURL } # Assert that the metadata we are about to process is not zero bytes after all this if (Test-Path $CachedMetadataFile) { $MyFileSize = (Get-Item $CachedMetadataFile).length if ((Get-Item $CachedMetadataFile).length -gt 0kb) { Write-ADFSTkLog (Get-ADFSTkLanguageText importMetadataFileSize -f $MyFileSize) -EventID 9 } else { Write-ADFSTkLog (Get-ADFSTkLanguageText importCachedMetadataFileIsZeroBytes -f $CachedMetadataFile) -EventID 10 } } #endregion #Verify Metadata Signing Cert if ($Global:ADFSTkSkipMetadataSignatureCheck -ne $true) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importVerifyingSigningCert) -EntryType Information Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importEnsuringSHA256) -EntryType Information Update-SHA256AlgXmlDSigSupport if (Verify-ADFSTkSigningCert $MetadataXML.EntitiesDescriptor.Signature.KeyInfo.X509Data.X509Certificate) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importSuccessfullyVerifiedMetadataCert) -EntryType Information } else { Write-ADFSTkLog (Get-ADFSTkLanguageText importMetadataCertIncorrect) -MajorFault -EventID 11 } #Verify Metadata Signature Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importVerifyingMetadataSignature) -EntryType Information if (Verify-ADFSTkMetadataSignature $MetadataXML) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importSuccessfullyVerifiedMetadataSignature) -EntryType Information } else { Write-ADFSTkLog (Get-ADFSTkLanguageText importMetadataSignatureFailed) -MajorFault -EventID 12 } } #region Read/Create file with $RawAllSPs = $MetadataXML.EntitiesDescriptor.EntityDescriptor | ? { $_.SPSSODescriptor -ne $null } $myRawAllSPsCount = $RawALLSps.count Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importTotalNumberOfSPs -f $myRawAllSPsCount) if ($ProcessWholeMetadata) { Write-ADFSTkLog (Get-ADFSTkLanguageText importProcessingWholeMetadata) -EntryType Information -EventID 13 $AllSPs = $MetadataXML.EntitiesDescriptor.EntityDescriptor | ? { $_.SPSSODescriptor -ne $null } $myAllSPsCount = $ALLSPs.count Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importNumberOfSPsAfterFilter -f $myAllSPsCount) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importCalculatingChanges) $AllSPs | % { $SwamidSPs = @() $SwamidSPsToProcess = @() } { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cWorkingWith -f $_.EntityID) $SwamidSPs += $_.EntityId if (Check-ADFSTkSPHasChanged $_) { $SwamidSPsToProcess += $_ } #else #{ # Write-ADFSTkVerboseLog "Skipped due to no changes in metadata..." #} } { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cDone) $n = $SwamidSPsToProcess.Count Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importFoundXNewChangedSPs -f $n) $batches = [Math]::Ceiling($n / $MaxSPAdditions) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importBatchCount -f $batches) if ($n -gt 0) { if ($batches -gt 1) { for ($i = 1; $i -le $batches; $i++) { $ADFSTkModuleBase = Join-Path $Global:ADFSTkPaths.modulePath ADFSToolkit.psm1 Write-ADFSTkLog (Get-ADFSTkLanguageText importWorkingWithBatch -f $i, $batches, $ADFSTkModuleBase) -EventID 14 $runCommand = "-Command & {" if ($Global:ADFSTkSkipNotSignedHealthCheck -eq $true) { $runCommand += '$Global:ADFSTkSkipNotSignedHealthCheck = $true;' } $runCommand += "Import-ADFSTkMetadata -MaxSPAdditions $MaxSPAdditions -CacheTime -1 -ConfigFile '$ConfigFile'" if ($PSBoundParameters.ContainsKey("Silent") -and $Silent -ne $false) { $runCommand += " -Silent" } if ($PSBoundParameters.ContainsKey("criticalHealthChecksOnly") -and $criticalHealthChecksOnly -ne $false) { $runCommand += " -criticalHealthChecksOnly" } if ($PSBoundParameters.ContainsKey("ForceUpdate") -and $ForceUpdate -ne $false) { $runCommand += " -ForceUpdate" } if ($PSBoundParameters.ContainsKey("WhatIf") -and $WhatIf -ne $false) { $runCommand += " -WhatIf" } $runCommand += " ;Exit}" Start-Process -WorkingDirectory $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\') -FilePath "$env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList "-NoExit", $runCommand -Wait -NoNewWindow Write-ADFSTkLog (Get-ADFSTkLanguageText cDone) -EventID 15 } } else { $SwamidSPsToProcess | % { Processes-ADFSTkRelyingPartyTrust $_ } } } # Checking if any Relying Party Trusts show be removed $NamePrefix = $Settings.configuration.MetadataPrefix $Sep = $Settings.configuration.MetadataPrefixSeparator $FilterString = "$NamePrefix$Sep" Write-ADFSTkLog (Get-ADFSTkLanguageText importCheckingForRemovedRPsUsingFilter -f $FilterString) -EventID 16 $CurrentSwamidSPs = Get-ADFSRelyingPartyTrust | ? { $_.Name -like "$FilterString*" } | select -ExpandProperty Identifier if ($CurrentSwamidSPs -eq $null) { $CurrentSwamidSPs = @() } #$RemoveSPs = Compare-ADFSTkObject $CurrentSwamidSPs $SwamidSPs | ? SideIndicator -eq "<=" | select -ExpandProperty InputObject $CompareSets = Compare-ADFSTkObject -FirstSet $CurrentSwamidSPs -SecondSet $SwamidSPs -CompareType InFirstSetOnly Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importFoundRPsToRemove -f $CompareSets.MembersInCompareSet) if ($ForceUpdate) { foreach ($rp in $CompareSets.CompareSet) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cRemoving -f $rp) try { Remove-ADFSRelyingPartyTrust -TargetIdentifier $rp -Confirm:$false -ErrorAction Stop Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cDone) } catch { Write-ADFSTkLog (Get-ADFSTkLanguageText cCouldNotRemove -f $rp, $_) -EntryType Error -EventID 17 } } } else { foreach ($rp in ($CompareSets.CompareSet | Get-ADFSTkAnswer -Caption (Get-ADFSTkLanguageText importDoYouWantToRemoveRPsNotInMetadata))) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cRemoving -f $rp) try { Remove-ADFSRelyingPartyTrust -TargetIdentifier $rp -Confirm:$false -ErrorAction Stop Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cDone) } catch { Write-ADFSTkLog (Get-ADFSTkLanguageText importCouldNotRemove -f $rp, $_) -EntryType Error -EventID 18 } } } } } elseif ($PSBoundParameters.ContainsKey('MaxSPAdditions') -and $MaxSPAdditions -gt 0) { Write-ADFSTkLog (Get-ADFSTkLanguageText importProcessingXRPs -f $MaxSPAdditions) -EntryType Information -EventID 19 $AllSPsInMetadata = $MetadataXML.EntitiesDescriptor.EntityDescriptor | ? { $_.SPSSODescriptor -ne $null } $i = 0 $n = 0 $m = $AllSPsInMetadata.Count - 1 $SPsToProcess = @() do { if (Check-ADFSTkSPHasChanged $AllSPsInMetadata[$i]) { $SPsToProcess += $AllSPsInMetadata[$i] $n++ } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importSkippedNoChanges) } $i++ } until ($n -ge $MaxSPAdditions -or $i -ge $m) $SPsToProcess | % { Processes-ADFSTkRelyingPartyTrust $_ } } elseif (! ([string]::IsNullOrEmpty($EntityID) ) ) { #Enter so that SP: N is checked against the can and ask if you want to force update. Insert the hash! Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText cWorkingWith -f $EntityID) if ([string]::IsNullOrEmpty($EntityBase)) { $sp = $MetadataXML.EntitiesDescriptor.EntityDescriptor | ? { $_.entityId -eq $EntityId } } else { $sp = $MetadataXML.EntitiesDescriptor.EntityDescriptor | ? { $_.entityId -eq $EntityId -and $_.base -eq $EntityBase } } if ($sp.count -gt 1) { $sp = $sp[0] Write-ADFSTkLog (Get-ADFSTkLanguageText importMoreThanOneRPWithEntityID -f $EntityId) -EntryType Warning -EventID 29 } if ([string]::IsNullOrEmpty($sp)) { Write-ADFSTkLog (Get-ADFSTkLanguageText importNoSPsFound) -MajorFault -EventID 20 } else { Processes-ADFSTkRelyingPartyTrust $sp } } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importNothingToDo) } Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText importScriptEnded) } Catch { Throw $_ } } } # SIG # Begin signature block # MIIRbgYJKoZIhvcNAQcCoIIRXzCCEVsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUrnpzkJYn9lC3d7CeLU1o2RI0 # 03iggg51MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV # BAYTAlVTMSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNV # BAsTKEdvIERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN # MTQwMTAxMDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAO # BgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdv # RGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmlj # YXRlIEF1dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEAv3FiCPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjH # MgGxBT4HTu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6 # or6KFWp/3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T # 3UYH3go+6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6e # MAo5zvGIgPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51ir # uF9G/M7EGwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB # /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/e # MB8GA1UdIwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgw # JjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQr # MCkwJ6AloCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNV # HSAEPzA9MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2Rh # ZGR5LmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEack # e+1bMc8dH2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVn # OQoWCcWgOJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYgg # HFCJyNwq9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY # 7NmuHDKOKHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzds # yqUvMQg3qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcY # QFHfjDCmrzCCBNAwggO4oAMCAQICAQcwDQYJKoZIhvcNAQELBQAwgYMxCzAJBgNV # BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRow # GAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UEAxMoR28gRGFkZHkgUm9v # dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjAeFw0xMTA1MDMwNzAwMDBaFw0z # MTA1MDMwNzAwMDBaMIG0MQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTET # MBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4x # LTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEz # MDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAt # IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueDLENSvdr3Uk2Lr # MGS4gQhswwTZYheOL/8+Zc+PzmLmPFIc2hZFS1WreGtjg2KQzg9pbJnIGhSLTMxF # M+qI3J6jryv+gGGdeVfEzy70PzA8XUf8mha8wzeWQVGOEUtU+Ci+0Iy+8DA4HvOw # JvhmR2Nt3nEmR484R1PRRh2049wA6kWsvbxx2apvANvbzTA6eU9fTEf4He9bwsSd # YDuxskOR2KQzTuqz1idPrSWKpcb01dCmrnQFZFeItURV1C0qOj74uL3pMgoClGTE # FjpQ8Uqu53kzrwwgB3/o3wQ5wmkCbGNS+nfBG8h0h8i5kxhQVDVLaU68O9NJLh/c # wdJS+wIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC # AQYwHQYDVR0OBBYEFEDCvSeOzDSDMKIz1/tss/C0LIDOMB8GA1UdIwQYMBaAFDqa # hQcQZyi27/a9BUFuIMGU2g/eMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6 # Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LWcyLmNybDBGBgNVHSAEPzA9MDsGBFUd # IAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBv # c2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEACH5skxDIOLiWqZBL/6FfTwTvbD6c # iAbJUI+mc/dXMRu+vOQv2/i601vgtOfmeWIODKLXamNzMbX1qEikOwgtol2Q17R8 # JU8RVjDEtkSdeyyd5V7m7wxhqr/kKhvuhJ64g33BQ85EpxNwDZEf9MgTrYNg2dhy # qHMkHrWsIg7KF4liWEQbq4klAQAPzcQbYttRtNMPUSqb9Lxz/HbONqTN2dgs6q6b # 9SqykNFNdRiKP4pBkCN9W0v+pANYm0ayw2Bgg/h9UEHOwqGQw7vvAi/SFVTuRBXZ # Cq6nijPtsS12NibcBOuf92EfFdyHb+5GliitoSZ9CgmnLgSjjbz4vAQwATCCBRww # ggQEoAMCAQICCDeMqUwECkf0MA0GCSqGSIb3DQEBCwUAMIG0MQswCQYDVQQGEwJV # UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UE # ChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2Rh # ZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENl # cnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTIwMDEwODExMjIyNFoXDTIxMDMw # ODE4NTgwMFowXjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNV # BAcTBk90dGF3YTEVMBMGA1UEChMMQ0FOQVJJRSBJbmMuMRUwEwYDVQQDEwxDQU5B # UklFIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZhfCjFqiT # mN1uLoySixnwaOjf/ZAL9P6SvjlCaBA2mutoorEgnzUP8HnOIcvMRgEMPmpaZ8eg # M93Bmx9d41xoarsQpCN3DhYOo+b3fWnPucVtpxbul2OFePv63mw/uvr+dqkv4b/f # 3Tg+ilQbpsNonbvh9MKEFv8Pn9koj0ySV+qxz34PxTVAe6g//pel3/3i9fqilCnI # Ecx4zg/+NKBeOWROSs4oXo3IvBjVrunmz+YuieSr78TqIE6hD8JF2q1wKwfMB3+x # 7dEXZAus9WtIU/qITATtEfO9QAgrrYL4F1MLN+osSp8my5eCOjnLTQc47q574V3z # QhsIHW7yBXLdAgMBAAGjggGFMIIBgTAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG # CCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDA1BgNVHR8ELjAsMCqgKKAmhiRodHRw # Oi8vY3JsLmdvZGFkZHkuY29tL2dkaWcyczUtNS5jcmwwXQYDVR0gBFYwVDBIBgtg # hkgBhv1tAQcXAjA5MDcGCCsGAQUFBwIBFitodHRwOi8vY2VydGlmaWNhdGVzLmdv # ZGFkZHkuY29tL3JlcG9zaXRvcnkvMAgGBmeBDAEEATB2BggrBgEFBQcBAQRqMGgw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHkuY29tLzBABggrBgEFBQcw # AoY0aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dk # aWcyLmNydDAfBgNVHSMEGDAWgBRAwr0njsw0gzCiM9f7bLPwtCyAzjAdBgNVHQ4E # FgQUUPnMg2nmYS8l7rmax3weVkrgz5AwDQYJKoZIhvcNAQELBQADggEBAIYabiAR # aY4KhO6oWgNHPOBjoHuqUH7NwRGN/ztYJznRBZbdD50smoK5GR0FvUZ8TXhYoZOa # zXe4NlFM4e6YcudU+EA/OF+sZHFBWziz1VS6U3sS+cGyJcxvelSoid0q3W3i9/Zy # 6Nv2kk/DEJp49O47mPNovpL15yykX3Vo26GwC9peo4s/cKMzthmgrcF2uLkT+LW4 # 4xKhaL7nBTGDMhjno+a3t00SWCId7wzgQadIJ1QlFOKm0xgmuiW3LIqCG0apvaOf # vWKTPKq68q+FbDPOO48oKrvw1c9K/m8gcnBLz6PX1REVIs5u3pvdOYBCz6uXyKxn # t+Q5jDEK0NskLu0xggJjMIICXwIBATCBwTCBtDELMAkGA1UEBhMCVVMxEDAOBgNV # BAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFk # ZHkuY29tLCBJbmMuMS0wKwYDVQQLEyRodHRwOi8vY2VydHMuZ29kYWRkeS5jb20v # cmVwb3NpdG9yeS8xMzAxBgNVBAMTKkdvIERhZGR5IFNlY3VyZSBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgLSBHMgIIN4ypTAQKR/QwCQYFKw4DAhoFAKB4MBgGCisGAQQB # gjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK # KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFNSI4gg0 # dLjvSsBomLjxR8+jAVJxMA0GCSqGSIb3DQEBAQUABIIBAMknm4mq7qvHEV3qAS1W # HMyDblNNtMuiywRa3oTWMKGJfV53Xe2HoEFNQpF+ECL6uRnmrOhCNjySyBRNDsH4 # PgHTYm/FQlhn02zdpN0MfYTr8Tv4sNCAxHM8blzPfdVzd3eJIMH+Wr8lSPnD7a5+ # 8II7P5XMdLovj1qmnhHmQbxJTDJXTknDUETiAvBWhKzqkppnuli7Wel+LBRtQNkl # BzNXFP/rRPZwaGdWxYCRKomGxNT08Fe7bMOIN0MQi6gHKu5w8bVPLT8vWlaiEyW9 # eHgrOyeQeGW5CzxpRLD+aeM+Jvc/efqQtVJd1n2FE+eXi25H922tO5A0nce07eEo # Ysg= # SIG # End signature block |