diff --git a/modules/authcache_varnish/authcache_varnish.module b/modules/authcache_varnish/authcache_varnish.module index 753ada0..0a379b4 100644 --- a/modules/authcache_varnish/authcache_varnish.module +++ b/modules/authcache_varnish/authcache_varnish.module @@ -28,6 +28,12 @@ function authcache_varnish_boot() { * present. Otherwise return FALSE. */ function authcache_varnish_request_validate() { + $passphrase = variable_get('authcache_varnish_passphrase'); + if (isset($passphrase)) { + $passphrase_header = variable_get('authcache_varnish_passphrase_header', 'HTTP_X_AUTHCACHE_VARNISH_PASSPHRASE'); + return (isset($_SERVER[$passphrase_header]) && $_SERVER[$passphrase_header] === $passphrase); + } + if (variable_get('authcache_varnish_validate_reverse_proxy_address', TRUE)) { // Fail if reverse proxy is not configured in settings.php. if (!variable_get('reverse_proxy', 0)) { diff --git a/modules/authcache_varnish/authcache_varnish.test b/modules/authcache_varnish/authcache_varnish.test index 75d821f..f325ca2 100644 --- a/modules/authcache_varnish/authcache_varnish.test +++ b/modules/authcache_varnish/authcache_varnish.test @@ -266,9 +266,13 @@ class AuthcacheVarnishTestDefaultValidation extends DrupalUnitTestCase { unset($_SERVER['HTTP_X_VARNISH']); unset($_SERVER['HTTP_X_FORWARDED_FOR']); unset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']); + unset($_SERVER['HTTP_X_AUTHCACHE_VARNISH_PASSPHRASE']); + unset($_SERVER['HTTP_X_CUSTOM_PASSPHRASE_HEADER']); $this->variableDel('authcache_varnish_validate_reverse_proxy_address'); $this->variableDel('authcache_varnish_header'); + $this->variableDel('authcache_varnish_passphrase'); + $this->variableDel('authcache_varnish_passphrase_header'); } /** @@ -405,4 +409,50 @@ class AuthcacheVarnishTestDefaultValidation extends DrupalUnitTestCase { $_SERVER['REMOTE_ADDR'] = $this->untrustedIp; $this->assertIdentical(FALSE, authcache_varnish_request_validate(), 'Reject request when X-Forwarded-For is empty'); } + + /** + * Request has correct X-Authcache-Varnish-Passphrase. + */ + public function testValidatePassphraseHeader() { + $this->variableSet('authcache_varnish_passphrase', 'sEcr3t!'); + + $_SERVER['REMOTE_ADDR'] = $this->proxyIp; + $_SERVER['HTTP_X_AUTHCACHE_VARNISH_PASSPHRASE'] = 'sEcr3t!'; + $this->assertIdentical(TRUE, authcache_varnish_request_validate(), 'Accept request when proxy passphrase matches'); + + $_SERVER['REMOTE_ADDR'] = $this->untrustedIp; + $_SERVER['HTTP_X_AUTHCACHE_VARNISH_PASSPHRASE'] = 'sEcr3t!'; + $this->assertIdentical(TRUE, authcache_varnish_request_validate(), 'Accept request when proxy passphrase matches, even from untrusted ip'); + } + + /** + * Request has correct custom passphrase header. + */ + public function testValidateCustomPassphraseHeader() { + $this->variableSet('authcache_varnish_passphrase', 'sEcr3t!'); + $this->variableSet('authcache_varnish_passphrase_header', 'HTTP_X_CUSTOM_PASSPHRASE_HEADER'); + + $_SERVER['REMOTE_ADDR'] = $this->proxyIp; + $_SERVER['HTTP_X_CUSTOM_PASSPHRASE_HEADER'] = 'sEcr3t!'; + $this->assertIdentical(TRUE, authcache_varnish_request_validate(), 'Accept request when proxy passphrase matches'); + + $_SERVER['REMOTE_ADDR'] = $this->untrustedIp; + $_SERVER['HTTP_X_CUSTOM_PASSPHRASE_HEADER'] = 'sEcr3t!'; + $this->assertIdentical(TRUE, authcache_varnish_request_validate(), 'Accept request when proxy passphrase matches, even from untrusted ip'); + } + + /** + * Request has the wrong X-Authcache-Varnish-Passphrase. + */ + public function testRejectPassphraseIfNotIdentical() { + $this->variableSet('authcache_varnish_passphrase', 'sEcr3t!'); + + $_SERVER['REMOTE_ADDR'] = $this->proxyIp; + $_SERVER['HTTP_X_AUTHCACHE_VARNISH_PASSPHRASE'] = 'lEak3d!'; + $this->assertIdentical(FALSE, authcache_varnish_request_validate(), 'Reject request when proxy passphrase does not match, even from trusted ip'); + + $_SERVER['REMOTE_ADDR'] = $this->untrustedIp; + $_SERVER['HTTP_X_AUTHCACHE_VARNISH_PASSPHRASE'] = 'lEak3d!'; + $this->assertIdentical(FALSE, authcache_varnish_request_validate(), 'Reject request when proxy passphrase does not match'); + } } diff --git a/modules/authcache_varnish/example.vcl b/modules/authcache_varnish/example.vcl index 8762241..cc5fac0 100644 --- a/modules/authcache_varnish/example.vcl +++ b/modules/authcache_varnish/example.vcl @@ -410,6 +410,23 @@ sub vcl_miss { set bereq.http.X-Authcache = 1; } /* END required authcache ESI header */ + + // /** + // * Example 1: Use a passphrase to validate proxy requests. + // * + // * The standard Drupal way to verify whether a request came in via a proxy + // * is to compare the X-Forwarded-For header to a whitelist. By default + // * Authcache Varnish uses the same method. This fails however, if this + // * check is carried out by the webserver (e.g., when using Nginx with the + // * realip module). + // * + // * In that case, set a passphrase on the request and configure the same in + // * settings.php, e.g.: + // * + // * $conf['authcache_varnish_passphrase' = 'correct horse battery staple'; + // * + // */ + // set req.http.X-Authcache-Varnish-Passphrase = "correct horse battery staple"; } sub vcl_fetch {