- Setting up nginx in Front of a Domino Server
- Adding Load Balancing to the nginx Setup
- Arbitrary Authentication with an nginx Reverse Proxy
- Domino and SSL: Come with Me If You Want to Live
I had intended that this next part of my nginx thread would cover GeoIP, but that will have to wait: a comment by Tinus Riyanto on my previous post sent my thoughts aflame. Specifically, the question was whether or not you can use nginx for authentication and then pass that value along to Domino, and the answer is yes. One of the aforementioned WebSphere connector headers is
$WSRU - Domino will accept the value of this header as the authenticated username, no password required (it will also tack the pseudo-group "-WebPreAuthenticated-" onto the names list for identification).
So one way to do this would be to hard-code in a value - you could disallow Anonymous access but treat all traffic from nginx as "approved" by giving it some other username, like:
proxy_set_header $WSRU "CN=Web User/O=SomeOrg";
Which would get you something, I suppose, but not much. What you'd really want would be to base this on some external variable, such as the user that nginx currently thinks is accessing it. An extremely naive way to do that would be to just set the line like this:
proxy_set_header $WSRU $remote_user;
Because nginx doesn't actually do any authentication by default, what this will do will be to authenticate with Domino as whatever name the user just happens to toss in the HTTP Basic authentication. So... never do that. However, nginx can do authentication, with the most straightforward mechanism being similar to Apache's method. There's a tutorial here on a basic setup:
With such a config, you could make a password file where the usernames match something understandable to Domino and the password is whatever you want, and then use the
$remote_user name to pass it along. You could expand this to use a different back-end, such as LDAP, and no doubt the options continue from there.
What had me most interested is the possibility of replacing the DSAPI login filter I wrote years ago, which is still in use and always feels rickety. The way that authentication works is that I set a cookie containing a BASE64-encoded and XOR-key-encrypted version of the username on the XPages side and then the C code looks for that and, if present, sets that as the user for the HTTP request. This is exactly the sort of thing this header could be used for.
One of the common nginx modules (and one which is included in the
nginx-extras package on Ubuntu) adds the ability to embed Lua code into nginx. If you're not familiar with it, Lua is a programming language primarily used for this sort of embedding. It's particularly common in games, and anyone who played WoW will recognize its error messages from misbehaved addons. But it fits just as well here: I want to run a small bit of code in the context of the nginx request. I won't post all of the code yet because I'm not confident it's particularly efficient, but the modification to the nginx site config document is enlightening.
First, I set up a directory for holding Lua scripts - normally, it shouldn't go in /etc, but I was in a hurry. This goes at the top of the nginx site doc:
Once I did that, I used a function from a script I wrote to set an nginx variable on the request to the decoded version of the username in the
location / block:
set_by_lua $lua_user ' local auth = require "raidomatic.auth" return getRaidomaticAuthName() ';
Once you have that, you can use the variable just like any of the build-in ones. And thus:
proxy_set_header $WSRU $lua_user;
With that set, I've implemented my DSAPI login on the nginx site and I'm free to remove it from Domino. As a side benefit, I now have the username available for SSO when I want to include other app servers behind nginx as well (it works if you pass it LDAP-style comma-delimited names, to make integration easier).
Another Potential Use: OAuth
While doing this, I thought of another perfect use for this kind of thing: REST API access. When writing a REST API, you don't generally want to use session authentication - you could, by having users POST to ?login and then using that cookie, but that's ungainly and not in-line with the rest of the world. You could also use Basic authentication, which works just fine - Domino seems to let you use Basic auth even when you've also enabled session auth, so it's okay. But the real way is to use OAuth. Along this line, Tim Tripcony had written oauth4domino.
In his implementation, you get a new session variable -
sessionFromAuthToken - that represents the user matching the active OAuth token. Using this reverse-proxy header instead, you could inspect the request for an authentication token, access a local-only URL on the Domino server to convert the token to a username (say, a view URL where the form just displays the user and expiration date), and then pass that username (if valid and non-expired) along to Domino.
With such a setup, you wouldn't need
sessionFromAuthToken anymore: the normal
session variable would be the active user and the app will act the same way no matter how the user was authenticated. Moreover, this would apply to non-XSP artifacts as well and should work with reader/author fields... and can work all the way back to R6.
Now, I haven't actually done any of this, but the point is one could.
So add this onto the pile of reasons why you should put a proxy server (nginx or otherwise) in front of Domino. The improvements to server and app structure you can make continue to surprise me.