How can I force mod_rewrite to send user info component of a URI?
A colleague recommended I repost this from StackOverflow to ServerFault:
This has been driving me crazy. I have a web application that's being served via Apache Web Server. The database server that backs the application is Apache CouchDB, which exposes an HTTP API to retrieve documents and stream attachments.
I've secured the CouchDB database by providing a security object, which only allows certain users to access data within the database, and returns 401 for anonymous requests to HTTP endpoints.
I want to be able to map public URLs to document attachments stored within this database. So, I've attempted to create a rewrite rule inside my .htaccess file that proxies requests from certain URLs directly to CouchDB, while hardcoding the user credentials, like so:
## DOWNLOAD STREAM:
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule download/(.*) http://user:[email protected]:5984/database/$1 [P]
In an ideal world, the above example would take the following URL:
http://example.com/download/UUID/attachment.ext
And proxy it to:
http://user:[email protected]:5984/database/UUID/attachment.ext
This method does indeed proxy the request to CouchDB, but omits the userinfo component of the URI scheme. So, the request is treated as anonymous and I get a 401 error. The attachment is only streamed if I remove security from the database.
I've spent a couple of hours reading up on Apache configuration and experimenting to no avail. Web searches are fruitless because of all the related queries with similar keywords.
How can I ensure that mod_rewrite includes the username and password provided in the rewrite rule when it proxies to CouchDB?
I figured it out! Rather than including the username:password as part of the URI scheme, the Authorization header needs to be set independently. The following solution works completely within a .htaccess
file, which is important since OS X periodically blows away settings inside VirtualHost sites:
SetEnvIf Request_URI ^/download/* ADD_COUCH_BASIC_AUTH
RequestHeader set Authorization "Basic XXXXXXXXXXXX" env=ADD_COUCH_BASIC_AUTH
## DOWNLOAD STREAM
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule download/(.*) http://127.0.0.1:5984/database/$1 [P]
The way this works: we use SetEnvIf
to check whether the request path matches the path we want to proxy, and if so, set an arbitrary environment variable ADD_COUCH_BASIC_AUTH
On the subsequent line, we add a Basic Auth header to the outgoing request, only if the environment variable we set exists. So, the basic auth header will only be added when requesting a resource via /download/
, thus sending authentication credentials to CouchDB.
Note: you'll have to Base64-encode your username:password credentials, and replace XXXXXXXXXXX
with the encoded value. An easy way to do this, on a Mac:
echo -n 'user:pass' | openssl base64
Hope this helps somebody besides me!