Framework/Core/SVT/Services/AppService.ps1
#using namespace Microsoft.Azure.Commands.AppService.Models Set-StrictMode -Version Latest class AppService: SVTBase { hidden [PSObject] $ResourceObject; hidden [PSObject] $WebAppDetails; hidden [PSObject] $AuthenticationSettings; hidden [bool] $IsReaderRole; AppService([string] $subscriptionId, [string] $resourceGroupName, [string] $resourceName): Base($subscriptionId, $resourceGroupName, $resourceName) { $this.GetResourceObject(); } AppService([string] $subscriptionId, [SVTResource] $svtResource): Base($subscriptionId, $svtResource) { $this.GetResourceObject(); } hidden [PSObject] GetResourceObject() { if (-not $this.ResourceObject) { # Get App Service details $this.ResourceObject = Get-AzureRmResource -ResourceName $this.ResourceContext.ResourceName ` -ResourceType $this.ResourceContext.ResourceType ` -ResourceGroupName $this.ResourceContext.ResourceGroupName if(-not $this.ResourceObject) { throw ("Resource '$($this.ResourceContext.ResourceName)' not found under Resource Group '$($this.ResourceContext.ResourceGroupName)'") } # Get web sites details $this.WebAppDetails = Get-AzureRmWebApp -Name $this.ResourceContext.ResourceName ` -ResourceGroupName $this.ResourceContext.ResourceGroupName try { $this.AuthenticationSettings = Invoke-AzureRmResourceAction -ResourceType "Microsoft.Web/sites/config/authsettings" ` -ResourceGroupName $this.ResourceContext.ResourceGroupName ` -ResourceName $this.ResourceContext.ResourceName ` -Action list ` -ApiVersion $this.ControlSettings.AppService.AADAuthAPIVersion ` -Force ` -ErrorAction Stop $this.IsReaderRole = $false; } catch { if(($_.Exception | Get-Member -Name "HttpStatus" ) -and $_.Exception.HttpStatus -eq "Forbidden") { $this.IsReaderRole = $true; } } } return $this.ResourceObject; } [ControlItem[]] ApplyServiceFilters([ControlItem[]] $controls) { $serviceFilterTag = "AppService"; if([Helpers]::CheckMember($this.ResourceObject, "Kind")) { if($this.ResourceObject.Kind -eq "functionapp") { $serviceFilterTag = "FunctionApp"; } } $result = @(); $result += $controls | Where-Object { $_.Tags -contains $serviceFilterTag }; return $result; } hidden [ControlResult] CheckAppServiceCustomDomainWithSSLConfig([ControlResult] $controlResult) { # Get custom domain URLs $customHostNames = $this.ResourceObject.Properties.HostNames | Where-Object { -not $_.EndsWith(".azurewebsites.net") }; # Combine custom domain name and SSL configuration TCP if(($customHostNames | Measure-Object).Count -gt 0) { $controlResult.AddMessage([MessageData]::new("Custom domains are configured for resource " + $this.ResourceContext.ResourceName), $customHostNames); $SSLStateNotEnabled = $this.ResourceObject.Properties.hostNameSslStates | Where-Object { (($customHostNames | Measure-Object) -contains $_.name) -and ($_.sslState -eq 'Disabled')} | Select-Object -Property Name if($null -eq $SSLStateNotEnabled) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("SSL configuration for resource " + $this.ResourceContext.ResourceName + " is enabled for all custom domains", $this.ResourceObject.Properties.hostNameSslStates)); } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("SSL configuration for resource " + $this.ResourceContext.ResourceName + " is not enabled for all custom domains", $this.ResourceObject.Properties.hostNameSslStates)); } } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Custom domains are not configured for resource " + $this.ResourceContext.ResourceName, $this.ResourceObject.Properties.HostNames)); } return $controlResult; } hidden [ControlResult] CheckAppServiceADAuthentication([ControlResult] $controlResult) { try { if($this.IsReaderRole) { $controlResult.AddMessage([VerificationResult]::Manual, [MessageData]::new("Control can not be validated due to insufficient access permission on resource")); } else { $aadSettings = New-Object PSObject Add-Member -InputObject $aadSettings -MemberType NoteProperty -Name "Enabled" -Value $this.AuthenticationSettings.Properties.enabled Add-Member -InputObject $aadSettings -MemberType NoteProperty -Name "ClientId" -Value $this.AuthenticationSettings.Properties.ClientId $AADEnabled = $false if($this.AuthenticationSettings.Properties.enabled -eq $True) { if($null -ne $this.AuthenticationSettings.Properties.ClientId) { $AADEnabled = $True; } } if($AADEnabled) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("AAD Authentication for resource " + $this.ResourceContext.ResourceName + " is enabled", $aadSettings)); } else { $controlResult.AddMessage([VerificationResult]::Verify, [MessageData]::new("Verify that AAD Authentication for resource " + $this.ResourceContext.ResourceName + " is enabled", $aadSettings)); $controlResult.SetStateData("App Service AAD settings", $aadSettings); } } } catch { throw; } return $controlResult; } hidden [ControlResult] CheckAppServiceRemoteDebuggingConfiguration([ControlResult] $controlResult) { if($this.WebAppDetails.SiteConfig.RemoteDebuggingEnabled) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Remote debugging for resource " + $this.ResourceContext.ResourceName + " is turned on", ($this.WebAppDetails.SiteConfig | Select-Object RemoteDebuggingEnabled))); } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Remote debugging for resource " + $this.ResourceContext.ResourceName + " is turned off", ($this.WebAppDetails.SiteConfig | Select-Object RemoteDebuggingEnabled))); } return $controlResult; } hidden [ControlResult] CheckAppServiceWebSocketsConfiguration([ControlResult] $controlResult) { if($this.WebAppDetails.SiteConfig.WebSocketsEnabled) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Web sockets for resource " + $this.ResourceContext.ResourceName + " is enabled", ($this.WebAppDetails.SiteConfig | Select-Object WebSocketsEnabled))); } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Web sockets for resource " + $this.ResourceContext.ResourceName + " is not enabled", ($this.WebAppDetails.SiteConfig | Select-Object WebSocketsEnabled))); } return $controlResult; } hidden [ControlResult] CheckAppServiceAlwaysOnConfiguration([ControlResult] $controlResult) { if($this.WebAppDetails.SiteConfig.AlwaysOn) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Always On feature for resource " + $this.ResourceContext.ResourceName + " is enabled", ($this.WebAppDetails.SiteConfig | Select-Object AlwaysOn))); } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Always On feature for resource " + $this.ResourceContext.ResourceName + " is not enabled", ($this.WebAppDetails.SiteConfig | Select-Object AlwaysOn))); } return $controlResult; } hidden [ControlResult] CheckAppService64BitPlatformConfiguration([ControlResult] $controlResult) { if($this.WebAppDetails.SiteConfig.Use32BitWorkerProcess) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("32-bit platform is used for resource " + $this.ResourceContext.ResourceName, ($this.WebAppDetails.SiteConfig | Select-Object Use32BitWorkerProcess))); } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("64-bit platform is used for resource " + $this.ResourceContext.ResourceName, ($this.WebAppDetails.SiteConfig | Select-Object Use32BitWorkerProcess))); } return $controlResult; } hidden [ControlResult] CheckAppServiceDotNetFrameworkVersion([ControlResult] $controlResult) { $dotNetFrameworkVersion = $this.WebAppDetails.SiteConfig.NetFrameworkVersion $splitVersionNumber = $this.ControlSettings.AppService.LatestDotNetFrameworkVersionNumber.split(".") # Compare App Service Net Framework version with latest Net Framework version from configuration $isCompliant = $dotNetFrameworkVersion.CompareTo($splitVersionNumber[0] + "." + $splitVersionNumber[1]) -eq 0 if($isCompliant) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Latest .Net Framework version is used for resource " + $this.ResourceContext.ResourceName, ($this.WebAppDetails.SiteConfig | Select-Object NetFrameworkVersion))); } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Latest .Net Framework version is not used for resource " + $this.ResourceContext.ResourceName, ($this.WebAppDetails.SiteConfig | Select-Object NetFrameworkVersion))); } return $controlResult; } hidden [ControlResult] CheckAppServiceInstanceCount([ControlResult] $controlResult) { # Get number of instances $sku = (Get-AzureRmResource -ResourceId $this.ResourceObject.Properties.ServerFarmId).Sku if($sku.Capacity -ge $this.ControlSettings.AppService.Minimum_Instance_Count) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("SKU for resource " + $this.ResourceContext.ResourceName + " is :", $sku)); } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("SKU for resource " + $this.ResourceContext.ResourceName + " is :", $sku)); } return $controlResult; } hidden [ControlResult] CheckAppServiceBackupConfiguration([ControlResult] $controlResult) { try { if($this.IsReaderRole) { $controlResult.AddMessage([VerificationResult]::Manual, [MessageData]::new("Control can not be validated due to insufficient access permission on resource")); } else { $backupConfiguration = Get-AzureRmWebAppBackupConfiguration ` -ResourceGroupName $this.ResourceContext.ResourceGroupName ` -Name $this.ResourceContext.ResourceName ` -ErrorAction Stop $isCompliant = $False If ($null -ne $backupConfiguration) { # Backup must be enabled and retention period days must be more than 365 and backup start date is less than current time (backup has been already started) # and at least one backup is available If($backupConfiguration.Enabled -eq $True -and ` ($backupConfiguration.RetentionPeriodInDays -eq $this.ControlSettings.AppService.Backup_RetentionPeriod_Forever -or $backupConfiguration.RetentionPeriodInDays -ge $this.ControlSettings.AppService.Backup_RetentionPeriod_Min) -and` $backupConfiguration.StartTime -le $(Get-Date) -and $backupConfiguration.KeepAtLeastOneBackup -eq $True) { $isCompliant = $True } } if(-not $isCompliant) { $controlResult.VerificationResult = [VerificationResult]::Failed; if($null -ne $backupConfiguration) { $controlResult.AddMessage([MessageData]::new("Configured backup for resource " + $this.ResourceContext.ResourceName + " is not as per the security guidelines. Please make sure that the configured backup is inline with below settings:-")); $controlResult.AddMessage([MessageData]::new("Enabled=True, StorageAccountEncryption=Enabled, RetentionPeriodInDays=0 or RetentionPeriodInDays>=365, BackupStartTime<=CurrentTime, KeepAtLeastOneBackup=True", $backupConfiguration)); } else { $controlResult.AddMessage([MessageData]::new("Backup for resource " + $this.ResourceContext.ResourceName + " is not configured", $backupConfiguration)); } } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Backup for resource " + $this.ResourceContext.ResourceName + " is enabled", $backupConfiguration)); } } } catch { if(($_.Exception).Response.StatusCode.value__ -eq 404) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Backup for resource " + $this.ResourceContext.ResourceName + " is not configured")); } else { throw $_ } } return $controlResult; } hidden [ControlResult] CheckAppServiceDiagnosticLogsConfiguration([ControlResult] $controlResult) { $diagnosticLogsConfig = New-Object PSObject Add-Member -InputObject $diagnosticLogsConfig -MemberType NoteProperty -Name "HttpLoggingEnabled" -Value $this.WebAppDetails.SiteConfig.HttpLoggingEnabled Add-Member -InputObject $diagnosticLogsConfig -MemberType NoteProperty -Name "DetailedErrorLoggingEnabled" -Value $this.WebAppDetails.SiteConfig.DetailedErrorLoggingEnabled Add-Member -InputObject $diagnosticLogsConfig -MemberType NoteProperty -Name "RequestTracingEnabled" -Value $this.WebAppDetails.SiteConfig.RequestTracingEnabled $isCompliant = $diagnosticLogsConfig.HttpLoggingEnabled -eq $true -and ` $diagnosticLogsConfig.DetailedErrorLoggingEnabled -eq $true -and ` $diagnosticLogsConfig.RequestTracingEnabled -eq $true if($isCompliant) { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("Diagnostics logs for resource " + $this.ResourceContext.ResourceName + " are enabled", $diagnosticLogsConfig)); } else { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("All configurations of diagnostics logs for resource " + $this.ResourceContext.ResourceName + " are not enabled", $diagnosticLogsConfig)); } return $controlResult; } hidden [ControlResult] CheckAppServiceHttpCertificateSSL([ControlResult] $controlResult) { $hostNames = $this.ResourceObject.Properties.HostNames | Where-Object { -not $_.EndsWith(".scm.azurewebsites.net") }; $isPass = 0 if(($hostNames | Measure-Object).Count -gt 0) { $hostNames | ForEach-Object{ try { $request = [System.Net.WebRequest]::Create('http://'+$_) $response = $request.GetResponse() $responceURL = $response.ResponseUri.OriginalString $response.Close() $scheme = ([System.Uri]$responceURL).Scheme if($scheme -eq "https") { $controlResult.AddMessage([MessageData]::new("HTTP requests are not allowed for resource " + $this.ResourceContext.ResourceName, $responceURL)); } else { $isPass = If ($isPass -lt 2) { 2 } Else { $isPass } $controlResult.AddMessage([MessageData]::new("HTTP requests are allowed for resource " + $this.ResourceContext.ResourceName, $responceURL)); } } catch [System.Management.Automation.MethodInvocationException] { $isPass = If ($isPass -lt 1) { 1 } Else { $isPass } $controlResult.AddMessage([MessageData]::new("Default Host URL is not reachable or self-signed certificate is used", $request.Address.OriginalString)); } } } if($isPass -eq 0) { $controlResult.VerificationResult = [VerificationResult]::Passed } ElseIf ($isPass -eq 1) { $controlResult.VerificationResult = [VerificationResult]::Verify $controlResult.SetStateData("Host urls", $hostNames); } else { $controlResult.VerificationResult = [VerificationResult]::Failed $controlResult.SetStateData("Host urls", $hostNames); } return $controlResult; } hidden [ControlResult] CheckAppServiceLoadCertAppSettings([ControlResult] $controlResult) { if($this.IsReaderRole) { $controlResult.AddMessage([VerificationResult]::Manual, [MessageData]::new("Control can not be validated due to insufficient access permission on resource")); } else { $appSettings = $this.WebAppDetails.SiteConfig.AppSettings $appSettingParameterList = $null if(($appSettings| Measure-Object).Count -gt 0) { $appSettingParameterList = $appSettings | Where-Object { $_.Name -eq $this.ControlSettings.AppService.LoadCertAppSettings -and $_.Value -eq "*"} } if($null -ne $appSettingParameterList) { $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("'WEBSITE_LOAD_CERTIFICATES' parameter defined equal to '*' is found in App Settings for resource " + $this.ResourceContext.ResourceName)); } else { $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("'WEBSITE_LOAD_CERTIFICATES' parameter defined equal to '*' is not found in App Settings for resource " + $this.ResourceContext.ResourceName)); } } return $controlResult; } } # SIG # Begin signature block # MIIkAgYJKoZIhvcNAQcCoIIj8zCCI+8CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBTCtziS4NSnZ3H # OHdWTh/D/Eygcif6UYMrMtxsVcx0VKCCDZMwggYRMIID+aADAgECAhMzAAAAjoeR # pFcaX8o+AAAAAACOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMTYxMTE3MjIwOTIxWhcNMTgwMjE3MjIwOTIxWjCBgzEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UECxMETU9Q # UjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMIIBIjANBgkqhkiG9w0B # AQEFAAOCAQ8AMIIBCgKCAQEA0IfUQit+ndnGetSiw+MVktJTnZUXyVI2+lS/qxCv # 6cnnzCZTw8Jzv23WAOUA3OlqZzQw9hYXtAGllXyLuaQs5os7efYjDHmP81LfQAEc # wsYDnetZz3Pp2HE5m/DOJVkt0slbCu9+1jIOXXQSBOyeBFOmawJn+E1Zi3fgKyHg # 78CkRRLPA3sDxjnD1CLcVVx3Qv+csuVVZ2i6LXZqf2ZTR9VHCsw43o17lxl9gtAm # +KWO5aHwXmQQ5PnrJ8by4AjQDfJnwNjyL/uJ2hX5rg8+AJcH0Qs+cNR3q3J4QZgH # uBfMorFf7L3zUGej15Tw0otVj1OmlZPmsmbPyTdo5GPHzwIDAQABo4IBgDCCAXww # HwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0OBBYEFKvI1u2y # FdKqjvHM7Ww490VK0Iq7MFIGA1UdEQRLMEmkRzBFMQ0wCwYDVQQLEwRNT1BSMTQw # MgYDVQQFEysyMzAwMTIrYjA1MGM2ZTctNzY0MS00NDFmLWJjNGEtNDM0ODFlNDE1 # ZDA4MB8GA1UdIwQYMBaAFEhuZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEsw # SaBHoEWGQ2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0Nv # ZFNpZ1BDQTIwMTFfMjAxMS0wNy0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsG # AQUFBzAChkVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p # Y0NvZFNpZ1BDQTIwMTFfMjAxMS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkq # hkiG9w0BAQsFAAOCAgEARIkCrGlT88S2u9SMYFPnymyoSWlmvqWaQZk62J3SVwJR # avq/m5bbpiZ9CVbo3O0ldXqlR1KoHksWU/PuD5rDBJUpwYKEpFYx/KCKkZW1v1rO # qQEfZEah5srx13R7v5IIUV58MwJeUTub5dguXwJMCZwaQ9px7eTZ56LadCwXreUM # tRj1VAnUvhxzzSB7pPrI29jbOq76kMWjvZVlrkYtVylY1pLwbNpj8Y8zon44dl7d # 8zXtrJo7YoHQThl8SHywC484zC281TllqZXBA+KSybmr0lcKqtxSCy5WJ6PimJdX # jrypWW4kko6C4glzgtk1g8yff9EEjoi44pqDWLDUmuYx+pRHjn2m4k5589jTajMW # UHDxQruYCen/zJVVWwi/klKoCMTx6PH/QNf5mjad/bqQhdJVPlCtRh/vJQy4njpI # BGPveJiiXQMNAtjcIKvmVrXe7xZmw9dVgh5PgnjJnlQaEGC3F6tAE5GusBnBmjOd # 7jJyzWXMT0aYLQ9RYB58+/7b6Ad5B/ehMzj+CZrbj3u2Or2FhrjMvH0BMLd7Hald # G73MTRf3bkcz1UDfasouUbi1uc/DBNM75ePpEIzrp7repC4zaikvFErqHsEiODUF # he/CBAANa8HYlhRIFa9+UrC4YMRStUqCt4UqAEkqJoMnWkHevdVmSbwLnHhwCbww # ggd6MIIFYqADAgECAgphDpDSAAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD # VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv # ZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5 # MDlaFw0yNjA3MDgyMTA5MDlaMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIw # MTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQ # TTS68rZYIZ9CGypr6VpQqrgGOBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULT # iQ15ZId+lGAkbK+eSZzpaF7S35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYS # L+erCFDPs0S3XdjELgN1q2jzy23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494H # DdVceaVJKecNvqATd76UPe/74ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZ # PrGMXeiJT4Qa8qEvWeSQOy2uM1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5 # bmR/U7qcD60ZI4TL9LoDho33X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGS # rhwjp6lm7GEfauEoSZ1fiOIlXdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADh # vKwCgl/bwBWzvRvUVUvnOaEP6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON # 7E1JMKerjt/sW5+v/N2wZuLBl4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xc # v3coKPHtbcMojyyPQDdPweGFRInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqw # iBfenk70lrC8RqBsmNLg1oiMCwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMC # AQAwHQYDVR0OBBYEFEhuZOVQBdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQM # HgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud # IwQYMBaAFHItOgIxkEO5FAVO4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0 # dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0Nl # ckF1dDIwMTFfMjAxMV8wM18yMi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUF # BzAChkJodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0Nl # ckF1dDIwMTFfMjAxMV8wM18yMi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGC # Ny4DMIGDMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp # b3BzL2RvY3MvcHJpbWFyeWNwcy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcA # YQBsAF8AcABvAGwAaQBjAHkAXwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZI # hvcNAQELBQADggIBAGfyhqWY4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4s # PvjDctFtg/6+P+gKyju/R6mj82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKL # UtCw/WvjPgcuKZvmPRul1LUdd5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7 # pKkFDJvtaPpoLpWgKj8qa1hJYx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft # 0N3zDq+ZKJeYTQ49C/IIidYfwzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4 # MnEnGn+x9Cf43iw6IGmYslmJaG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxv # FX1Fp3blQCplo8NdUmKGwx1jNpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG # 0QaxdR8UvmFhtfDcxhsEvt9Bxw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf # 0AApxbGbpT9Fdx41xtKiop96eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkY # S//WsyNodeav+vyL6wuA6mk7r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrv # QQqxP/uozKRdwaGIm1dxVk5IRcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIV # xTCCFcECAQEwgZUwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAA # AI6HkaRXGl/KPgAAAAAAjjANBglghkgBZQMEAgEFAKCBsDAZBgkqhkiG9w0BCQMx # DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq # hkiG9w0BCQQxIgQgxA7F3JkVvTiWoITZs1teZrdyZnc0M6KPBP7bkwF8AogwRAYK # KwYBBAGCNwIBDDE2MDSgEoAQAEEAegBTAEQASwAyADUAMqEegBxodHRwczovL2Fr # YS5tcy9henNka29zc2RvY3MgMA0GCSqGSIb3DQEBAQUABIIBAA4sQtgNu0ZOGgme # U38QsCNA+DPBVdcMVnb+B3fKAn+nKSgExCRW4A7QIYEApMRmGqpgTV4wdDkf0QwK # c7geUUnGpCa7E+0ygVQMCLb/89vRWQjl5ylLUYJkR1AjaZDohwKQTM/ZvVR4YjeL # lR0AIOVSwgpWrzO7Lu7QNYM8fPioKa1UECRyR9AciXdyuJk52ZBhO28mGkh96Q5b # AZeu+PO0aWEafMnP5BCrSgKhJrUtZSEoUXocVTp4rJZoRjwcRKAJOfHDx3b7Cgjt # Z0E6x9SFBMBX0qwqmbVRSuDiOGpx4K0ydGIePK2Jzmy22LZOoRpVVFmvvJrYsEyi # fcYmdzShghNNMIITSQYKKwYBBAGCNwMDATGCEzkwghM1BgkqhkiG9w0BBwKgghMm # MIITIgIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBPQYLKoZIhvcNAQkQAQSgggEsBIIB # KDCCASQCAQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQgW9ud+44UmAOZ # a+tRiX1G9bSKVyTCywtJMVDpVhX2tM4CBlmtv368QBgTMjAxNzA5MDUwOTM3MTIu # MTk1WjAHAgEBgAIB9KCBuaSBtjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0Ug # RVNOOjk4RkQtQzYxRS1FNjQxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt # cCBTZXJ2aWNloIIO0DCCBnEwggRZoAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcN # AQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAw # BgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEw # MB4XDTEwMDcwMTIxMzY1NVoXDTI1MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt # U3RhbXAgUENBIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCp # HQ28dxGKOiDs/BOX9fp/aZRrdFQQ1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVT # JwQxH0EbGpUdzgkTjnxhMFmxMEQP8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q # 6vVHgc2/JGAyWGBG8lhHhjKEHnRhZ5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h # /EbBJx0kZxJyGiGKr0tkiVBisV39dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+ # 79BL/W7lmsqxqPJ6Kgox8NpOBpG2iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4 # zfy8wMlEXV4WnAEFTyJNAgMBAAGjggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAd # BgNVHQ4EFgQU1WM6XIoxkPNDe3xGG8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBT # AHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw # FoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDov # L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0 # XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0 # cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAx # MC0wNi0yMy5jcnQwgaAGA1UdIAEB/wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0G # CCsGAQUFBwIBFjFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BT # L2RlZmF1bHQuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBs # AGkAYwB5AF8AUwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4IC # AQAH5ohRDeLG4Jg/gXEDPZ2joSFvs+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efw # eL3HqJ4l4/m87WtUVwgrUYJEEvu5U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt0 # 70IQyK+/f8Z/8jd9Wj8c8pl5SpFSAK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQi # PM/tA6WWj1kpvLb9BOFwnzJKJ/1Vry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93F # SguRJuI57BlKcWOdeyFtw5yjojz6f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4a # rgRCg7i1gJsiOCC1JeVk7Pf0v35jWSUPei45V3aicaoGig+JFrphpxHLmtgOR5qA # xdDNp9DvfYPw4TtxCd9ddJgiCGHasFAeb73x4QDf5zEHpJM692VHeOj4qEir995y # fmFrb3epgcunCaw5u+zGy9iCtHLNHfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaY # LeqN4DMuEin1wC9UJyH3yKxO2ii4sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL # 32N79ZmKLxvHIa9Zta7cRDyXUHHXodLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4 # L7zPWAUu7w2gUDXa7wknHNWzfjUeCLraNtvTX4/edIhJEjCCBNowggPCoAMCAQIC # EzMAAACdIJxWd1XUKJoAAAAAAJ0wDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTAwHhcNMTYwOTA3MTc1NjQxWhcNMTgwOTA3MTc1NjQx # WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UE # CxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjk4RkQtQzYxRS1FNjQx # MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjANBgkq # hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0kSYnBFaKhouqp9TXW1dvLZZdpHAJlsD # 5shsX6Mq60wARnQ4FL8qeF2wI0zsbmBI7EnkW3WmcP3z1K5Vbo69BB9nPRn9MXKC # lKFzsS688BzU2+8huMaptMbCRgcumcw+IQvDLkjfDGp1xTWO11mcqztIfp6y4PxU # lt4TRzlC0G7WS/2/DKTwC+X66MiIi+6c+3XhxEvoyw5kzlfeYKh6Ss5lHLhlliNi # O38FT1lm3ekN1fh8vsBM3nsKlhvMVTkEbwYIQTi79RnftXoEdwUc4uyMx/Gxml5H # bsyyHqPalniB7vAHmIBRvroKFB5+njpZJKFXcwz+QUROlsJUUQ+pxQIDAQABo4IB # GzCCARcwHQYDVR0OBBYEFLyGCMpbalrK5L3My4K0FUjqh+WhMB8GA1UdIwQYMBaA # FNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j # cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBDQV8y # MDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6 # Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIwMTAt # MDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJ # KoZIhvcNAQELBQADggEBAH/eJCG9We+01otxylmRvi6oRoK7j99kHX3mKgu8KGdL # /vl3v7X0TqT96EoPPmcis1aJbZcIWuwjFPV5KhNXjJIXnQYh6vOo6hs73NuEmkv3 # chX2n48nqP+l4tYgiZVNQKkVYF65lwHXMAv/QmprVtnsWlw2A4DMFi1qwbkzZE/b # Xmt/2G/AroGlOO06zl1yGoxMFctfk4yy3aoALeP9ZCipqb4QHf4V3CePH46kA+qO # N9sEJVMf4TJ69zsikMzcKg3BXoYJ1T5W76sloHrLMkBY9r0JW7bJ/3tHeXSGpYad # 2CINV17hqA3GJk4C9v069gGs95e8uZEOYdud0++mNmmhggN5MIICYQIBATCB46GB # uaSBtjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV # BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsG # A1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjk4RkQtQzYxRS1F # NjQxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiUKAQEw # CQYFKw4DAhoFAAMVABgNrLOMaDCz+HQZsnjOgCs1Lwj6oIHCMIG/pIG8MIG5MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMQ0wCwYDVQQLEwRNT1BS # MScwJQYDVQQLEx5uQ2lwaGVyIE5UUyBFU046NERFOS0wQzVFLTNFMDkxKzApBgNV # BAMTIk1pY3Jvc29mdCBUaW1lIFNvdXJjZSBNYXN0ZXIgQ2xvY2swDQYJKoZIhvcN # AQEFBQACBQDdWK08MCIYDzIwMTcwOTA1MDQ1NzMyWhgPMjAxNzA5MDYwNDU3MzJa # MHcwPQYKKwYBBAGEWQoEATEvMC0wCgIFAN1YrTwCAQAwCgIBAAICCx8CAf8wBwIB # AAICGfkwCgIFAN1Z/rwCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoD # AaAKMAgCAQACAxbjYKEKMAgCAQACAwehIDANBgkqhkiG9w0BAQUFAAOCAQEAXx7C # hhJLdt3IxXL5XlEtbvtaM3D5dLryCCrpdVxdBa8tiJ9KNN+Obl1U11Ptn8IEf2iv # lYllx4OYSyVJIMJaDDULZ8L6Ha3jFrFY1t14JXF/fXn7uCfB408U5MUTd6kt1UzZ # Vu06E9UBmTIdP92fk9ynKvTcTPdjHm9FMwvSaM17+aYxiWJi5Tx0j6m2JsWF56Jn # pM8kmeurcKe5nv02ZXHKdApMQ3LUkTuXLb3KaqguPGdfcrRrbbOCZgCzZgBtOwo3 # 1XKC9v2PTMJHe9ovRm29n8otiFWSz5m7XJbliLnRUrEMoRDv8hhYfwjt/ySci+xc # kmf+ayYRDN2K/LZ6CzGCAvUwggLxAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwAhMzAAAAnSCcVndV1CiaAAAAAACdMA0GCWCGSAFlAwQCAQUAoIIB # MjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIBFY # wmmdUkDVHsB48rM2U9QTzirXLJFDDPapYMRJUd9xMIHiBgsqhkiG9w0BCRACDDGB # 0jCBzzCBzDCBsQQUGA2ss4xoMLP4dBmyeM6AKzUvCPowgZgwgYCkfjB8MQswCQYD # VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3Nv # ZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAJ0gnFZ3VdQomgAAAAAAnTAWBBSt # 1PgXjDVCOF2A6cFXHHztiVNYzTANBgkqhkiG9w0BAQsFAASCAQBoMURxngEAC4+z # DcOfoolw/BnmhJsB6Vu690Lu0apL1nrcex9QeDQHW+TT42Kz+QzWBJtSGbRGk7YU # SK9PY2YEB/RCTc72Ou3QUpGnMI6kRQpaUNNQZR3SzYXKwthUshUIu228krKJbIpy # fTxsofUnZ4OF0pVEeVLTBuG5ym6yHqF5wFs3sBrnxdmbytYnlrAHYGU2Z+YDTnmK # w19VPR3OlpDPC9Khm6PVnlalc7LmgcE4f/KVwFSwxg78vt1Ov19mbmS1+BZmbXvv # R2RHn10C/yrMRL9r0GuLW64zIsBiImAs/NU4z/zxE2bXWBPTOu0i5Q2e32zvtMmF # nz8NGzfi # SIG # End signature block |