theforeman/smart-proxy — pull request #137 by Ginja (2014-02-28 01:35:35+00:00)
Title: Fixed error with using :trusted_hosts: when using Passenger to serve requests

Related to this bug report - http://projects.theforeman.org/issues/2259

When using Passenger to serve requests, the requests.env hash does not contain a REMOTE_HOST key, causing lines 72 & 73 on lib/smart_proxy.rb to throw an error. Below is a snippet of what requests.env contains when using Passenger & WEBrick:

Using Passenger (information scrubbed):

{"SERVER_SOFTWARE"=>"Apache/2.2.15 (CentOS)", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_NAME"=>"FQDN", "SERVER_ADMIN"=>"root@localhost", "SERVER_ADDR"=>"IP", "SERVER_PORT"=>"8443", "REMOTE_ADDR"=>"IP", "REMOTE_PORT"=>"50778", "REQUEST_METHOD"=>"GET", "QUERY_STRING"=>"", "HTTPS"=>"on", ...}

Using WEBrick (information scrubbed):

{"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/puppet/ca", "QUERY_STRING"=>"", "REMOTE_ADDR"=>"IP", "REMOTE_HOST"=>"FQDN", "REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"https://FQDN:8443/puppet/ca", "SCRIPT_NAME"=>"", "SERVER_NAME"=>"FQDN", "SERVER_PORT"=>"8443", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/2.0.0/2014-02-24) OpenSSL/1.0.1e", ...}

In order to resolve this issue I changed the appropriate lines to use REMOTE_ADDR, which is always returned. However, this presented a new problem as the :trusted_hosts: checks expect a FQDN, and REMOTE_ADDR is always an IP (unlike REMOTE_HOST, which is always a hostname). So I've also added a reverse DNS check to the process, and use the returned value for the check. This adds a little bit of security, and keeps with tradition.

Alternatively, we could be more lenient and allow the request to continue if either the hostname or IP is contained within :trusted_hosts:.

remote_fqdn = Resolv.new.getname(request.env["REMOTE_ADDR"])
if !(SETTINGS.trusted_hosts & [request.env["REMOTE_ADDR"], remote_fqdn.downcase]).any?