Showing posts for tag "dsapi"

The DSAPI Login Filter I Wrote Years Ago

May 19, 2014 3:02 PM

Tags: dsapi c

In one of the conversations I had at the meetup yesterday, I was reminded of the DSAPI filter I use on my server for authentication, and remembered I'd yet to properly blog about it.

Years ago, I had a problem: I was setting up an XPages-based forum site for my WoW guild, and I wanted sticky logins. Since my guildies are actual humans and not corporate drones subject to the whims of an IT department, I couldn't expect them to put up with having to log in every browser session, nor did I want to deal with SSO tokens expiring seemingly randomly during normal use. My first swing at the problem was to grossly extend the length of Domino's web sessions and tweak the auth cookie on the server to make it persist between browser launches, but that still broke whenever I restarted the server or HTTP task.

What I wanted instead was a way to have the user authenticate in a way that was separate from the normal Domino login routine, but would still grant them normal rights as a Domino user, reader fields and all. Because my sense of work:reward ratios is terribly flawed, I wrote a DSAPI filter in C. Now, I hadn't written a line of C since a course or two in college, and I hadn't the foggiest notion of how the Domino C API works (for the record, I consider myself as now having exactly the foggiest notion), and the result is a mess. However, it contains the kernel of some interesting concepts. So here's the file, warts, unncessary comments, probable memory leaks or buffer overflows, and all:


The gist of the way my login works is that, when you log in to the forum app, a bit of code (in an SSJS library, because I was young and foolish) finds the appropriate ShortName, does a basic XOR semi-encryption on it, BASE64s the result, and stores it in a cookie. The job of this DSAPI filter, then, is to look for the presence of the cookie, de-BASE64 it, re-XOR it back to shape, and pass the username back to Domino.

Now, the thing that's interesting to me is that, because you've hooked directly into Domino's authentication stack, the server trusts the filter's result implicitly. It doesn't have to check the password and - interestingly - the user doesn't actually have to exist in any known Directory. So you can make up any old thing:

CN=James T. Kirk/OU=Starfleet/O=UFP

Though I do not, in fact, maintain a Directory for the Federation, Domino is perfectly happy to take this name and run with it, generating a full-fledged names list:

Names List: CN=James T. Kirk/OU=Starfleet/O=UFP, *, */OU=Starfleet/O=UFP, */O=UFP

It gets better: you can use any of these names, globs included, in Directory groups or DB-level ACLs and they're included transparently. So I set up a couple groups in the main Directory containing either the full username or "*/OU=Starfleet/O=UFP" and also granted "*/O=UFP" Editor access and an Admin role in the DB itself. Lo and behold:

Names List: CN=James T. Kirk/OU=Starfleet/O=UFP, *, */OU=Starfleet/O=UFP, */O=UFP, Starfleet Captains, Guys Who Aren't As Good As Picard, [Admin]
Access Level: Editor

Now we're somewhere interesting! Though I didn't use it for this purpose (all my users actually exist in a normal Directory), you could presumably use this to do per-app user pools while still maintaining the benefits of Domino-level authentication (reader fields, ACLs, user tracking). With a lot of coordination, you could write your C filter to look for appropriate views in the database matching the incoming HTTP request and only pass through the username when the cookie credentials match a document in the requested app. Really, only the requirements of high performance and the relentless difficulty of writing non-server-crashing C stand in between you and doing some really clever things with web authentication.