Automatic HTTP Basic Authentication with mod_proxy

Let's say you need to access a resource that's protected by HTTP Basic authentication but the system you're using doesn't support it.

Like, say, Google Calendar. >:| Google Calendar can subscribe to outside ical feeds, but not ones that are protected with a username and password. You might want to set up a limited user in your calendar server to add events to a Google Calendar, but if you don't want to open that up to the whole world, you're kinda stuck. Fortunately Google does now support accessing ical feeds over HTTPS, so it's only Google you need to worry about. Anyway, this is a general solution, so that's the last we need to mention Google Calendar.

You can use Apache's mod_proxy, mod_rewrite, mod_setenvif, and mod_headers to make this happen by proxying the access for the remote service. First create a random URL. Longer will be better if you want to make it hard to guess. uuidgen output is sufficient for normal situations. Then create a config in Apache, whereever your server definition is. It'll look something like this:


RewriteEngine On
SSLProxyEngine on</p>

RewriteCond %{REQUEST_URI} ^/34506a81-1a6d-4596-beaf-580da9c98cca$
SetEnvIf REQUEST_URI "/34506a81-1a6d-4596-beaf-580da9c98cca" DOAUTH
RequestHeader set Authorization "Basic dXNlcjpwYXNzd29yZA==" env=DOAUTH
RewriteRule /34506a81-1a6d-4596-beaf-580da9c98cca https://www.example.com/my/path [P,L]
ProxyPassReverse /34506a81-1a6d-4596-beaf-580da9c98cca https://www.example.com/my/path
</code>

Breaking it down:


RewriteEngine On
SSLProxyEngine on

Here we turn on the rewrite engine and also the ability to proxy to https resources.


RewriteCond %{REQUEST_URI} ^/34506a81-1a6d-4596-beaf-580da9c98cca$

Here we check if this is the resource we're concerning ourselves with. If you're going to have a bunch of these, by all means setup a RewriteMap file to keep your config file sane. This is is simplified for the sake of illustration


SetEnvIf REQUEST_URI "/34506a81-1a6d-4596-beaf-580da9c98cca" DOAUTH

Now we're checking again, this time with the intent of setting an environment variable so we can pass state along to the next rule. If you're using a map, this might be NOAUTH= something.

RequestHeader set Authorization "Basic dXNlcjpwYXNzd29yZA==" env=DOAUTH

Here we're actually setting the authentication. But only if the environment variable is set, which means we've matched this resource. So where does that magic string come from? It's HTTP Basic Auth, which is easily created with a moment in Python:


$ python
Python 2.7.10 (default, Sep 8 2015, 17:20:17)
[GCC 5.1.1 20150618 (Red Hat 5.1.1-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> hash = base64.b64encode(b'user:password')
>>>
>>> print hash
dXNlcjpwYXNzd29yZA==

Just copy and paste that in, to the config, or into your map file to match the URI.


RewriteRule /34506a81-1a6d-4596-beaf-580da9c98cca https://www.example.com/my/path [P,L]

Finally, the proxy. Any requests for our uuid will get proxied to the real resource. [P,L] means 'proxy' and 'this is the last step for this request'.

ProxyPassReverse /34506a81-1a6d-4596-beaf-580da9c98cca https://www.example.com/my/path

And this is boilerplate to make mod_proxy fix up any references in the header of the proxy response back to the uuid URI so redirects and the like will work properly. With that in place, restart your apache and give it a test drive. You technically could run this over plain HTTP, but it seems like a really bad idea if there's any private information at all on the proxied resource.