DSCResources/ArcGIS_Server_TLS/ArcGIS_Server_TLS.psm1
<#
.SYNOPSIS Creates a SelfSigned Certificate or Installs a SSL Certificated Provided and Configures it with Server .PARAMETER Ensure Take the values Present or Absent. - "Present" ensures the certificate is installed and configured with the Server. - "Absent" ensures the certificate configured with the Server is uninstalled and deleted(Not Implemented). .PARAMETER SiteName Site Name or Default Context of Server .PARAMETER SiteAdministrator A MSFT_Credential Object - Primary Site Adminstrator. .PARAMETER CertificateFileLocation Certificate Path from where to fetch the certificate to be installed. .PARAMETER CertificatePassword Sercret Certificate Password or Key. .PARAMETER CName CName with which the Certificate will be associated. .PARAMETER PortalEndPoint #Not sure - Adds a Host Mapping of Portal Machine and associates it with the certificate being Installed. .PARAMETER RegisterWebAdaptorForCName #Not Sure - Registers a Web Adaptor for the Given CName so it is accessible from this endpoint. .PARAMETER EnableSSL #Not Sure - Boolean to indicate to whether to enable SSL on Server Site .PARAMETER ImportOnly #Not Sure - Boolean to indicate to if the Certificate is be created or Imported #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $SiteName ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false $null # TODO } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $SiteName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $CertificateFileLocation, [System.String] $CertificatePassword, [System.String] $CName, [System.String] $PortalEndPoint, [System.Boolean] $RegisterWebAdaptorForCName, [System.Boolean] $EnableSSL, [System.Boolean] $ImportOnly ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false if($CertificateFileLocation -and -not(Test-Path $CertificateFileLocation)){ throw "Certificate File '$CertificateFileLocation' is not found or inaccessible" } $ServiceName = 'ArcGIS Server' $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $InstallDir = (Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir $RestartRequired = $false if(-not(Test-HardenedSSLOnArcGISServerJVM -InstallDir $InstallDir)){ Write-Verbose 'Hardening SSL on ArcGIS Server JVM' Set-HardenedSSLOnArcGISServerJVM -InstallDir $InstallDir $RestartRequired = $true } $FQDN = Get-FQDN $env:COMPUTERNAME $ServerUrl = "http://$($FQDN):6080" $ServerHttpsUrl = "https://localhost:6443" Wait-ForUrl -Url "$($ServerUrl)/$SiteName/admin/" $Referer = $ServerUrl $token = Get-ServerToken -ServerEndPoint $ServerURL -ServerSiteName $SiteName -Credential $SiteAdministrator -Referer $Referer if($EnableSSL) { # Get the current security configuration Write-Verbose 'Getting security config for site' $secConfig = Get-SecurityConfig -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -Referer $Referer if(-not($secConfig.sslEnabled)) { # Enable HTTPS on the securty config Write-Verbose 'Enabling HTTPS on security config for site' $enableResponse = EnableHTTPS-OnSecurityConfig -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -SecurityConfig $secConfig -Referer $Referer # Changing the protocol will cause the web server to restart. Write-Verbose "Waiting for Url '$ServerHttpsUrl/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerHttpsUrl/$SiteName/admin/" -SleepTimeInSeconds 15 -MaxWaitTimeInSeconds 90 } } if($CName) { if($PortalEndPoint -and ($PortalEndPoint -as [ipaddress])) { Write-Verbose "Adding Host mapping for $PortalEndPoint" Add-HostMapping -hostname $PortalEndPoint -ipaddress $PortalEndPoint } elseif($CName -as [ipaddress]) { Write-Verbose "Adding Host mapping for $CName" Add-HostMapping -hostname $CName -ipaddress $CName } # Get the machine name in the site $MachineName = $FQDN $allMachines = Get-Machines -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -Referer $Referer if(-not($allMachines.machines | Where-Object { $_.machineName -ieq $MachineName })) { $MachineName = $env:COMPUTERNAME if(-not($allMachines.machines | Where-Object { $_.machineName -ieq $MachineName })){ throw "Not able to find machine in site with either hostname $MachineName or fully qualified domain name $FQDN" } } # Get the machine details Write-Verbose "Get Machine details for [$MachineName]" $machine = Get-MachineDetails -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -MachineName $MachineName -Referer $Referer $NewCertIssuer = $null if($CertificateFileLocation -and $CertificatePassword) { $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($CertificateFileLocation,$CertificatePassword,'DefaultKeySet') $NewCertIssuer = $cert.Issuer Write-Verbose "Issuer for the supplied certificate is $NewCertIssuer" } $CertForMachine = Get-SSLCertificateForMachine -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName -SSLCertName $CName $ExistingCertIssuer = $CertForMachine.Issuer Write-Verbose "Existing Cert Issuer $ExistingCertIssuer" if(($ExistingCertIssuer -eq $null) -or ($NewCertIssuer -and ($ExistingCertIssuer -ine $NewCertIssuer))) { if($CertForMachine) { Write-Verbose "Certificate with CName $CName already exists for machine $MachineName. Deleting it" try { Delete-SSLCertForMachine -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName -SSLCertName $CName } catch { Write-Verbose "[WARNING] Error deleting SSL Cert with CName $CName. Error:- $_" } }else{ Write-Verbose "Certificate for CName $CName not found" } if($CertificateFileLocation -and $CertificatePassword) { # Import the Supplied Certificate Write-Verbose "Importing Supplied Cerficate with Alias $CName" Import-ExistingCertificate -ServerUrl $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer ` -MachineName $MachineName -CertAlias $CName -CertificatePassword $CertificatePassword ` -CertificateFilePath $CertificateFileLocation }else { # Generate a Self signed cert Write-Verbose 'Generating SelfSignedCertificate' Generate-SelfSignedCertificate -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -MachineName $MachineName ` -CertAlias $CName -CertCommonName $CName -CertOrganization $CName -Referer $Referer } if($ImportOnly) { Write-Verbose "Import Only Scenario. No need to update certificate alias for Machine" }else { # Update the SSL Cert for machine Write-Verbose "Updating SSL Certificate for machine [$MachineName]" $machine.webServerCertificateAlias = $CName Update-SSLCertificate -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -MachineName $MachineName -MachineProperties $machine -Referer $Referer } } # Adding an SSL Certificate will cause the web server to restart. Wait for it to come back Write-Verbose "Waiting for Url '$ServerHttpsUrl/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerHttpsUrl/$SiteName/admin" -SleepTimeInSeconds 15 -MaxWaitTimeInSeconds 120 -HttpMethod 'GET' if(-not($ImportOnly)) { Write-Verbose "Desired CName:- $CName Check if machine is using this" $machineDetails = Get-MachineDetails -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName Write-Verbose "WebCertificateAlias :- $($machineDetails.webServerCertificateAlias)" if($CName -ine $machineDetails.webServerCertificateAlias) { $machineDetails.webServerCertificateAlias = $CName Write-Verbose "Updating SSL Certificate to have Desired CName:- $CName" Update-SSLCertificate -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -MachineName $MachineName -Referer $Referer -MachineProperties $machineDetails # Updating an SSL Certificate will cause the web server to restart. Write-Verbose "Waiting for Url '$ServerURL/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerHttpsUrl/$SiteName/admin" -SleepTimeInSeconds 20 -MaxWaitTimeInSeconds 150 -HttpMethod 'GET' } }else { Write-Verbose "Import Only Scenario. No need to update certificate alias for Machine" } $GeoEventServiceName = 'ArcGISGeoEvent' $GeoEventService = Get-Service -Name $GeoEventServiceName -ErrorAction Ignore if($GeoEventService.Status -ieq 'Running') { ### ### If the SSL Certificate is changed. Restart the GeoEvent Service so that it will pick up the new certificate ### try { Write-Verbose "Restarting Service $GeoEventServiceName" Stop-Service -Name $GeoEventServiceName -Force -ErrorAction Ignore Write-Verbose 'Stopping the service' Wait-ForServiceToReachDesiredState -ServiceName $GeoEventServiceName -DesiredState 'Stopped' Write-Verbose 'Stopped the service' }catch { Write-Verbose "[WARNING] While Stopping Service $_" } try { Write-Verbose 'Starting the service' Start-Service -Name $GeoEventServiceName -ErrorAction Ignore Wait-ForServiceToReachDesiredState -ServiceName $GeoEventServiceName -DesiredState 'Running' Write-Verbose "Restarted Service $GeoEventServiceName" }catch { Write-Verbose "[WARNING] While Starting Service $_" } } if($RegisterWebAdaptorForCName) { $WebAdaptorsForServer = Get-WebAdaptorsConfigForServer -ServerUrl $ServerUrl -SiteName $SiteName ` -Token $token.token -Referer $Referer $WebAdaptorUrl = "http://$($CName)/$SiteName" $WebAdaptorForHttpPort = $WebAdaptorsForServer.webAdaptors | Where-Object { ($_.httpPort -eq 80 -and $_.httpsPort -eq 443) } | ForEach-Object { if($_ -and $_.id -and ($_.webAdaptorURL -ine $WebAdaptorUrl)) { Write-Verbose "Unregistering the current web adaptor with id $($_.id) for (http port 80, https port 443) that does not match $WebAdaptorUrl" UnRegister-WebAdaptorForServer -ServerUrl $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -WebAdaptorId $_.id } } $WebAdaptorsForServer = Get-WebAdaptorsConfigForServer -ServerUrl $ServerUrl -SiteName $SiteName ` -Token $token.token -Referer $Referer $ExistingWebAdaptor = $WebAdaptorsForServer.webAdaptors | Where-Object { $_.machineName -ieq $CName -and $_.webAdaptorURL -ieq $WebAdaptorUrl } if(-not($ExistingWebAdaptor)) { #Register the CName as a (dummy) web adaptor for server Write-Verbose "Registering the CName '$CName' as a Web Adaptor with Url 'https://$($CName)/$SiteName'" Register-WebAdaptorForServer -ServerUrl $ServerURL -Token $token.token -Referer $Referer -SiteName $SiteName ` -WebAdaptorUrl $WebAdaptorUrl -MachineName $CName -HttpPort 80 -HttpsPort 443 $WebAdaptorsForServer = Get-WebAdaptorsConfigForServer -ServerUrl $ServerURL -SiteName $SiteName ` -Token $token.token -Referer $Referer $VerifyWebAdaptor = $WebAdaptorsForServer.webAdaptors | Where-Object { $_.machineName -ieq $CName } if(-not($VerifyWebAdaptor)) { throw "Unable to verify the web adaptor that was just registered for $($CName)" } } else { Write-Verbose "Web Adaptor with CName '$CName' and Url '$WebAdaptorUrl' already exists" } }else { Write-Verbose "Not needed to register web adaptor" } } if($RestartRequired) { Write-Verbose "Restarting Service $ServiceName" Stop-Service -Name $ServiceName -Force Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Stopped' Start-Service -Name $ServiceName Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Running' Write-Verbose "Restarted Service $ServiceName" } Write-Verbose "Waiting for Url '$ServerURL/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerURL/$SiteName/admin" -SleepTimeInSeconds 10 -MaxWaitTimeInSeconds 60 -HttpMethod 'GET' Write-Verbose 'Verifying that security config for site can be retrieved' $config = Get-SecurityConfig -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -Referer $Referer Write-Verbose "SSLEnabled:- $($config.sslEnabled)" } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $SiteName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $CertificateFileLocation, [System.String] $CertificatePassword, [System.String] $CName, [System.String] $PortalEndPoint, [System.Boolean] $RegisterWebAdaptorForCName, [System.Boolean] $EnableSSL, [System.Boolean] $ImportOnly ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false if($CertificateFileLocation -and -not(Test-Path $CertificateFileLocation)){ throw "Certificate File '$CertificateFileLocation' is not found or inaccessible" } [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null $result = $false $FQDN = Get-FQDN $env:COMPUTERNAME $ServerUrl = "http://$($FQDN):6080" Wait-ForUrl -Url "$($ServerUrl)/$SiteName/admin/" -MaxWaitTimeInSeconds 60 -HttpMethod 'GET' $Referer = $ServerUrl $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName $SiteName -Credential $SiteAdministrator -Referer $Referer if(-not($token.token)){ throw "Unable to retrieve token for Site Administrator" } if($EnableSSL) { $secConfig = Get-SecurityConfig -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer $result = ($secConfig -and $secConfig.sslEnabled) Write-Verbose "SSL Enabled:- $result" } $CertWithCNameExists = $false if($result -or (-not($EnableSSL))) { # SSL is enabled # Check the CName and issues on the SSL Certificate Write-Verbose "Checking Issuer and CName on Certificate" $NewCertIssuer = $null if($CertificateFileLocation -and $CertificatePassword) { Write-Verbose "Examine certificate from $CertificateFileLocation" $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($CertificateFileLocation, $CertificatePassword, 'DefaultKeySet') $NewCertIssuer = $cert.Issuer Write-Verbose "Issuer for the supplied certificate is $NewCertIssuer" } $certNames = Get-AllSSLCertificateCNamesForMachine -ServerHostName $FQDN -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN if($ImportOnly) { Write-Verbose "Import Only Scenario. Check if Certificate exists" if($certNames.certificates -icontains $CName) { Write-Verbose "Certificate with $CName already exists for Machine $FQDN" $CertWithCNameExists = $true }else{ Write-Verbose "Certificate with $CName not found for Machine $FQDN" } } else { $CertForMachine = Get-SSLCertificateForMachine -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN -SSLCertName $CName $ExistingCertIssuer = $CertForMachine.Issuer Write-Verbose "Existing Cert Issuer $ExistingCertIssuer" if($CertForMachine -eq $null){ Write-Verbose "Cert on machine is null" } if($NewCertIssuer -and ($ExistingCertIssuer -ine $NewCertIssuer)){ Write-Verbose "New Cert does not match existing cert" Write-Verbose "Existing:- $ExistingCertIssuer New:- $NewCertIssuer" } if(($CertForMachine -eq $null) -or ($NewCertIssuer -and ($ExistingCertIssuer -ine $NewCertIssuer))) { Write-Verbose "Certificate with CName $CName not found on machine '$FQDN' or the Issuer $($CertForMachine.Issuer) is different on the ArcGIS Server" } else { Write-Verbose "Certificate with CName $CName and required issuer $ExistingCertIssuer already exists on machine $FQDN on the ArcGIS Server" if($CName){ Write-Verbose "Desired CName:- $CName. Checking if machine is using this" $machineDetails = Get-MachineDetails -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN if($CName -ieq $machineDetails.webServerCertificateAlias) { Write-Verbose "WebServerCertificateAlias '$($machineDetails.webServerCertificateAlias)' matches Desired CName of '$CName'" $CertWithCNameExists = $true $result = $true }else { Write-Verbose "WebServerCertificateAlias '$($machineDetails.webServerCertificateAlias)' does not match Desired CName of '$CName'" } } } } } if(-not($CertWithCNameExists)) { Write-Verbose "Certificate with CName does not exist as expected" $result = $false }else { Write-Verbose "Certificate with CName exists as expected" $result = $true } if($result) { Write-Verbose "Checking if JVM has SSL Configuration Hardened" $ServiceName = 'ArcGIS Server' $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $InstallDir = (Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir $IsHardened = Test-HardenedSSLOnArcGISServerJVM -InstallDir $InstallDir if(-not($IsHardened)) { Write-Verbose 'JVM is not hardened for SSL' $result = $false } } if($result -and $CName -and $RegisterWebAdaptorForCName) { Write-Verbose "Checking Web Adaptors" $WebAdaptorsForServer = Get-WebAdaptorsConfigForServer -ServerUrl $ServerUrl -SiteName $SiteName ` -Token $token.token -Referer $Referer $ExistingWebAdaptor = $WebAdaptorsForServer.webAdaptors | Where-Object { $_.machineName -ieq $CName } if(-not($ExistingWebAdaptor)) { Write-Verbose "Web Adaptor not found with CName $CName" $result = $false } } Write-Verbose "Returning $result from Test-TargetResource" if($Ensure -ieq 'Present') { $result } elseif($Ensure -ieq 'Absent') { (-not($result)) } } function Test-HardenedSSLOnArcGISServerJVM { [CmdletBinding()] param( [string] $InstallDir ) $hardened = $false $PropsFile = Join-Path $InstallDir 'framework\runtime\jre\lib\security\java.security' if(Test-Path $PropsFile){ Get-Content $PropsFile| ForEach-Object { if($_.StartsWith('jdk.tls.disabledAlgorithms=')){ $splits = $_.ToString().Split('=') $trimmed = $splits[$splits.Length-1].Replace(' ','').Split(',') if(($trimmed -icontains 'SSLV3') -and ($trimmed -icontains 'RC4') -and ($trimmed -icontains 'RC4')) { Write-Verbose "ArcGIS Server JVM has all the neccessary TLS algorithms disabled" $hardened = $true } } } } $hardened } function Set-HardenedSSLOnArcGISServerJVM { [CmdletBinding()] param( [string] $InstallDir ) $hardened = $false $PropsFile = Join-Path $InstallDir 'framework\runtime\jre\lib\security\java.security' if(Test-Path $PropsFile){ $Text = @() $Changed = $false Get-Content $PropsFile| ForEach-Object { if($_.ToString().StartsWith('jdk.tls.disabledAlgorithms=')){ Write-Verbose "Updating $_ to 'jdk.tls.disabledAlgorithms=SSLv3, DHE, RC4'" $Text += 'jdk.tls.disabledAlgorithms=SSLv3, DHE, RC4' $Changed = $true } else { $Text += $_ } } if($Changed){ Set-Content -Path $PropsFile -Value $Text } } } function EnableHTTPS-OnSecurityConfig { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, $SecurityConfig ) if(-not($SecurityConfig)) { throw "Security Config parameter is not provided" } $UpdateSecurityConfigUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/security/config/update" $props = @{ f= 'json'; token = $Token; Protocol = 'HTTP_AND_HTTPS'; authenticationTier = $SecurityConfig.authenticationTier; allowDirectAccess = $SecurityConfig.allowDirectAccess } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = $null $res = Invoke-WebRequest -Uri $UpdateSecurityConfigUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 300 if($res -and $res.Content) { Write-Verbose $res.Content $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $UpdateSecurityConfigUrl $response } } function Delete-SSLCertForMachine { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName, [string]$SSLCertName ) $DeleteSSlCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslcertificates/$SSLCertName/delete" $props = @{ f= 'json'; token = $Token; } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Uri $DeleteSSlCertUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response $response } function Generate-SelfSignedCertificate { [CmdletBinding()] param([string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName, [string]$CertAlias, [string]$CertCommonName, [string]$CertOrganization, [string]$ValidityInDays = 1825 ) $GenerateSelfSignedCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslcertificates/generate" $props = @{ f= 'json'; token = $Token; alias = $CertAlias; commonName = $CertCommonName; organization = $CertOrganization; validity = $ValidityInDays } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Uri $GenerateSelfSignedCertUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 150 $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $GenerateSelfSignedCertUrl $response } function Import-ExistingCertificate { [CmdletBinding()] param( [string]$ServerUrl, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName, [string]$CertAlias, [string]$CertificatePassword, [string]$CertificateFilePath ) $ImportCACertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslcertificates/importExistingServerCertificate" [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # Allow self-signed certificates $props = @{ f= 'json'; token = $Token; alias = $CertAlias; certPassword = $CertificatePassword } $res = Upload-File -url $ImportCACertUrl -filePath $CertificateFilePath -fileContentType 'application/x-pkcs12' -formParams $props -Referer $Referer -fileParameterName 'certFile' if($res -and $res.Content) { $response = $res | ConvertFrom-Json Check-ResponseStatus $response -Url $ImportCACertUrl } else { Write-Verbose "[WARNING] Response from $ImportCACertUrl was null" } } function Get-SecurityConfig { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer ) $GetSecurityConfigUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/security/config/" $props = @{ f= 'json'; token = $Token; } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } Write-Verbose "Url:- $GetSecurityConfigUrl" $res = $null try { $res =Invoke-WebRequest -Uri $GetSecurityConfigUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 30 -ErrorAction Ignore if($res -and $res.Content) { #Write-Verbose "Response:- $($res.Content)" $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $GetSecurityConfigUrl $response }else { Write-Verbose "[WARNING] Response from $GetSecurityConfigUrl was null" } } catch{ Write-Verbose "[EXCEPTION] ArcGIS_Server_TLS Get-SecurityConfig Error:- $_" $null } } function Update-SSLCertificate { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$MachineName, [string]$Referer, $MachineProperties, [int]$MaxAttempts = 5, [int]$SleepTimeInSecondsBetweenAttempts = 30 ) $UpdateSSLCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/edit" $MachineProperties.psobject.properties | foreach -begin {$h=@{}} -process {$h."$($_.Name)" = $_.Value} -end {$h} # convert PSCustomObject to hashtable $h.JMXPort = $MachineProperties.ports.JMXPort $h.OpenEJBPort = $MachineProperties.ports.OpenEJBPort $h.NamingPort = $MachineProperties.ports.NamingPort $h.DerbyPort = $MachineProperties.ports.DerbyPort $h.ports = $null $h.f = 'json' $h.token = $Token $cmdBody = To-HttpBody $h $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer} [bool]$Done = $false [int]$Attempt = 1 while(-not($Done) -and $Attempt -le $MaxAttempts) { $AttemptStr = '' if($Attempt -gt 1) { $AttemptStr = "Attempt # $Attempt" } Write-Verbose "Update SSLCert Name $AttemptStr" try { $res = Invoke-WebRequest -Uri $UpdateSSLCertUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 150 -ErrorAction Ignore if($res -and $res.Content) { #Write-Verbose $res.Content $response = $res.Content | ConvertFrom-Json if(($response.status -ieq 'error') -and $response.messages){ Write-Verbose "[WARNING]:- $($response.messages -join ',')" }else { Check-ResponseStatus $response -Url $UpdateSSLCertUrl $Done = $true } }else { Write-Verbose "Response from $UpdateSSLCertUrl is null" Start-Sleep -Seconds $SleepTimeInSecondsBetweenAttempts $Done = $true } } catch { if($Attempt -ge $MaxAttempts) { Write-Verbose "[WARNING] Update failed after $MaxAttempts. Last Response:- $($_)" #throw "Update failed after $MaxAttempts. Error:- $($_)" } Start-Sleep -Seconds $SleepTimeInSecondsBetweenAttempts } $Attempt++ } $response } function Get-Machines { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer ) $GetMachinesUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/" $props = @{ f= 'json'; token = $Token } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Uri $GetMachinesUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 150 $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response $response } function Get-MachineDetails { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName ) $props = @{ f= 'json'; token = $Token; } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $GetMachineDetailsUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/" $res = Invoke-WebRequest -Uri $GetMachineDetailsUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 150 $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $GetMachineDetailsUrl $response } function Register-WebAdaptorForServer { [CmdletBinding()] param( [string]$ServerUrl, [string]$SiteName, [string]$Token, [string]$Referer, [string]$WebAdaptorUrl, [string]$MachineName, [int]$HttpPort = 80, [int]$HttpsPort = 443 ) [string]$RegisterWebAdaptorsUrl = $ServerUrl.TrimEnd('/') + "/$SiteName/admin/system/webadaptors/register" $WebParams = @{ token = $Token f = 'json' webAdaptorURL = $WebAdaptorUrl machineName = $MachineName httpPort = $HttpPort.ToString() httpsPort = $HttpsPort.ToString() isAdminEnabled = 'true' } [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # Allow self-signed certificates $HttpBody = To-HttpBody $WebParams $Headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $HttpBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Method Post -Uri $RegisterWebAdaptorsUrl -Headers $Headers -Body $HttpBody -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 300 #Write-Verbose $res.Content $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $RegisterWebAdaptorsUrl $response } function UnRegister-WebAdaptorForServer { [CmdletBinding()] param( [string]$ServerUrl, [string]$SiteName, [string]$Token, [string]$Referer, [string]$WebAdaptorId ) [string]$UnRegisterWebAdaptorsUrl = $ServerUrl.TrimEnd('/') + "/$SiteName/admin/system/webadaptors/$WebAdaptorId/unregister" $WebParams = @{ token = $Token f = 'json' } [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # Allow self-signed certificates $HttpBody = To-HttpBody $WebParams $Headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $HttpBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Method Post -Uri $UnRegisterWebAdaptorsUrl -Headers $Headers -Body $HttpBody -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 300 Write-Verbose $res.Content $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $UnRegisterWebAdaptorsUrl $response } function Get-WebAdaptorsConfigForServer { [CmdletBinding()] param( [string]$ServerUrl, [string]$SiteName, [string]$Token, [string]$Referer ) [string]$GetWebAdaptorsUrl = $ServerUrl.TrimEnd('/') + "/$SiteName/admin/system/webadaptors" $WebParams = @{ token = $Token f = 'json' } [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # Allow self-signed certificates $HttpBody = To-HttpBody $WebParams $Headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $HttpBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Method Post -Uri $GetWebAdaptorsUrl -Headers $Headers -Body $HttpBody -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing -TimeoutSec 30 $response = $res.Content | ConvertFrom-Json Check-ResponseStatus $response -Url $GetWebAdaptorsUrl $response } function Get-AllSSLCertificateCNamesForMachine { [CmdletBinding()] param( [string]$ServerHostName = 'localhost', [string]$SiteName = 'arcgis', [string]$Token, [string]$Referer, [string]$MachineName ) Invoke-ArcGISWebRequest -Url "http://$($ServerHostName):6080/$SiteName/admin/machines/$MachineName/sslcertificates/" -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' } function Get-SSLCertificateForMachine { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName, [string]$SSLCertName ) $CertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslcertificates/$SSLCertName" $props = @{ f= 'json'; token = $Token; } $cmdBody = To-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } try { $res = Invoke-WebRequest -Uri $CertUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing ### Response is not valid JSON. Hence use Regex #Write-Verbose "Response $($res.Content)" if(-not($res.Content)){ Write-Verbose "[WARNING] Response from $CertUrl is NULL" $null }else { if($res.Content.IndexOf('error') -gt -1){ $json = $res.Content | ConvertFrom-Json $errMsgs = ($json.messages -join ', ') if($errMsgs -and ($errMsgs.IndexOf('Could not find resource or operation') -lt 0)) { Write-Verbose "[WARNING] Response from $CertUrl is $errMsgs" } $null }else { $IssuerValue = $null $Issuer = [regex]::matches($res.Content, '"Issuer":(\w*)"([A-Za-z =,\.0-9\-]+)\"') $Issuer.Groups | %{ if($_.Value -and $_.Value.Length -gt 0){ $Pos = $_.Value.IndexOf('"Issuer"') if($Pos -gt -1) { $Str = $_.Value.Substring($Pos + '"Issuer"'.Length) $Pos = $Str.IndexOf('"') if($Pos -gt -1) { $Str = $Str.Substring($Pos + 1) } $IssuerValue = $Str.TrimEnd('"') } } } Write-Verbose "Issuer Value:- $IssuerValue" $CN = if($IssuerValue) { ($IssuerValue.Split(',') | ConvertFrom-StringData).CN } else { $null } Write-Verbose "CN:- $CN" @{ Issuer = $IssuerValue CName = $CN } } } } catch{ # If no cert exists, an error is returned Write-Verbose "[WARNING] Error checking $CertUrl Error:- $_" $null } } Export-ModuleMember -Function *-TargetResource |