Add support for source IP auth behind a proxy
authorJeff Godin <jgodin@tadl.org>
Wed, 7 Aug 2013 21:19:32 +0000 (17:19 -0400)
committerJeff Godin <jgodin@tadl.org>
Wed, 7 Aug 2013 21:19:32 +0000 (17:19 -0400)
When using a proxy in front of your web server(s), the web server
sees the IP address of the proxy, and not the actual IP address of
the client making the requests.

This prevents you from using standard Apache directives to limit
access to a set of specific source IP addresses. While there are
Apache modules available that can help in this situation, we also
have the option of performing the access control within iNCIPit
itself.

This commit adds support for relying on the X-Forwarded-For HTTP
header to determine the actual IP of the client.

SECURITY NOTE: Your proxy MUST set/modify the X-Forwarded-For HTTP
header for this feature to work. If your proxy passes the header
unmodified, not only will your authorized clients likely be unable
to access the script, but unauthorized clients can easily spoof the
header to gain access.

To use, in the [access] section of iNCIPit.ini:

- set load_balancer_ip to the IP of your proxy
- set allowed_client_ips to a comma-delimited list of authorized IP
  addresses

If your proxy speaks to your backend servers via HTTP, you will also
need to set permit_plaintext to "yes" (case insensitive).  You must
then rely on your proxy to enforce the use of HTTPS, or trust your
authorized clients to always use HTTPS.

Signed-off-by: Jeff Godin <jgodin@tadl.org>
iNCIPit.cgi
iNCIPit.ini-example

index 6e3a215..07f500f 100644 (file)
@@ -40,6 +40,41 @@ my $U = "OpenILS::Application::AppUtils";
 
 my $conf = load_config( 'iNCIPit.ini' );
 
+# reject non-https access unless configured otherwise
+unless ($conf->{access}->{permit_plaintext} ~= m/^yes$/i) {
+    unless ($ENV{HTTPS} eq 'on') {
+        print "Content-type: text/plain\n\n";
+               print "Access denied.\n";
+               exit 0;
+    }
+}
+
+# TODO: support for multiple load balancer IPs
+my $lb_ip = $conf->{access}->{load_balancer_ip};
+
+# if we are behind a load balancer, check to see that the
+# actual client IP is permitted
+if ($lb_ip) {
+    my @allowed_ips = split(/ *, */, $conf->{access}->{allowed_client_ips});
+
+       my $forwarded = $ENV{HTTP_X_FORWARDED_FOR};
+       my $ok = 0;
+
+       foreach my $check_ip (@allowed_ips) {
+               $ok = 1 if ($check_ip eq $forwarded);
+       }
+
+    # if we have a load balancer IP and are relying on
+    # X-Forwarded-For, deny requests other than those
+    # from the load balancer
+    # TODO: support for chained X-Forwarded-For -- ignore all but last
+       unless ($ok && $ENV{REMOTE_ADDR} eq $lb_ip) {
+        print "Content-type: text/plain\n\n";
+               print "Access denied.\n";
+               exit 0;
+       }
+}
+
 my $xmlpost = CGI::XMLPost->new();
 my $xml     = $xmlpost->data();
 
index 7360699..64d7105 100644 (file)
@@ -1,3 +1,8 @@
+[access]
+#permit_plaintext    = no
+#load_balancer_ip    = 127.0.0.1
+#allowed_client_ips  = 192.0.2.2, 192.0.2.3
+
 [auth]
 username = EXAMPLE
 password = EXAMPLE