Domino and User Authentication

 — Mk II

This web page details the method I've used to prevent Intranet users in a Domino environment being prompted to enter their name and password multiple times when attempting to access a database to which they do not have permission.

Mk II ? I previously used a PAGE element when doing the authentication but found the lack of access to Domino fields and CGI variables far too limiting. It meant the javascript had to hard code the name of the database, for example. I now use a NAVIGATOR element, that never actually gets shown but allows the use of a standard $$NavigatorTemplate form.

Your environment

You are running IBM Lotus Domino as the back-end server for your Intranet (or browser-accessible application). You have defined an ACL on a database that gives certain users rights; some users can edit, other can read, others are blocked entirely.

Incidentally, you cannot use Anonymous as an ACL setting (except for NO ACCESS and no checkboxes ticked) if you want this tip to work. In an Intranet environment it is unlikely that you would be allowing Anonymous access anyway. Even if you wanted everyone in the Domino directory access you would probably use a group.

I'm assuming that your Server document does NOT allow anonymous access - that is, Domino will ALWAYS prompt your users for a name and password (but see my note on using IIS below).

The problem



A user, who is not named explicitly nor in a group in the database's ACL, and who attempts access to the application will be prompted 3 times by Domino for a username and password until he gets an "authorization failure" message in his browser.

Not very useful to anyone, even if you customise the $$ReturnAuthorizationFailure form.

Why 3 times? Well this appears to be your browser (Internet Explorer 5+) that does this. When a password is required it receives a 401 response from the server. The browser then prompts you for a user name and password and passes that onto the server. If it gets another 401 it just repeats the process 3 times (duh!) presumably in the hope you'll type a correct combination of user name and password. After 3 times Domino gives up.

The solution

Instead of just re-prompting users for a user name and password, display a page that details the problem and gives them a route to correct the error. User friendly and avoids help desk calls.

How to do it

First, let's get the ACL right.
  1. Give the LocalDomainServers and Notes Administrators MANAGER access.
  2. Give everyone who should have access an entry either as an individual or as a group. You can use as many groups as you need, and set the access as Reader, Author, Editor etc. Note that for security purposes, the maximum Internet access is usually set to Editor.
  3. Create a role of UNAUTHORISED.
  4. Finally, set the DEFAULT access to NO ACCESS, but tick the READ and WRITE Public Documents. Tick the UNAUTHORISED role for this user.
  5. Here's a screen shot on how it should look:

Then open the database up in design mode.
  1. Create a navigator called WebLaunch.
  2. By default the navigator is accessible to Public Access Users. Put another way, there is no way to set or unset this access!
  3. The WEBLAUNCH navigator contents are not important and never displayed to users. It is used as a hidden navigational tool simply because you cannot set the launch properties of a database to a FORM. It is, however, a good idea to just add a comment to the main navigator body to describe what you are doing for future maintenance.
  4. Now create a Form called $$NavigatorTemplate for WebLaunch. This form will not be displayed to authorised users, but unauthorised ones will get to see the contents. Make sure the form is accessible to Public Users:

    Create some pass thru HTML on the form saying soothing things like "Oops! Sorry, you don't seem to be authorised to use this application. For further help contact...". Because this is a form (not a page) element, you have access to any CGI and Notes variables you need. I'll leave you with the actual design!

    Put the entire HTML in an containing DIV block with an ID of "Error" and "style=display:none". This ensures that your page remains blank until we want to display it.
  5. Now we need to decide whether to display the page or not. Quite simply, if the incoming user has a role called [UNAUTHORISED] then they get shown the page and not forwarded on. If they do not have this role, then they get transparently forwarded onto the real entry form of the database.

    To determine a user's role, include a Computer For Display (CFD) field at the top of the form, with a formula of @Subset(@UserRoles;-1). This will remove the $$Web Client role that all web users get. Put the field inside a named SPAN element called UserRole with a "style=display:none" like this:
    <SPAN id="UserRole" style="display:none">[FIELD]</SPAN>
  6. Create a further CFD field in a SPAN element called ServerDBPath like this:
    <SPAN id="ServerDBPath" style="display:none">[FIELD]</SPAN>
  7. The formula for the CFD field (call it what you will, its name is never used) is:
    @Name([CN];@ServerName) + "/" + @WebDbName +"/"
  8. In the JSHeader write some javaScript to retrieve this value and either make the currently hidden content visible, or else redirect the user to another page. The javascript function looks like this:
    function getRole() {

      if (document.getElementById("UserRole").innerText == "[Unauthorised]") {

       //alert ("Permissions failure! Contact Administration Support");
       //display the form contents to the user and stop processing!
       document.getElementById("Error").style.display = "block";

      }else {
       //alert("Your role is that of " + document.getElementById("UserRole").innerText );
       //redirect the user to the required entry point of the database
       window.top.location = "http://" +
       document.getElementById("ServerDBPath").innerText +
       "TrueLaunchPage";
      }
    }
    Note the two alerts that you can uncomment out for debugging.
  9. Finally, in the onLoad section of the form, enter the following javascript:
    getRole()

 

Finally, set the launch properties of the database.

  1. So that when opened in a browser it opens up a designated navigator, called WebLaunch. You can always change these names when you've got it all working.

That's all there is to it! Users with unauthorised (default) permissions get to see a pretty "Unauthorised" page, whilst authorised users don't even know they have been redirected to the true entry page of the application!

Security questions

If you're thinking that users could bypass the security on the database by book marking (or otherwise typing in a URL that goes directly to) a form or view in the database then it won't happen. This is because the ACL on the database will prevent them and they will get the old, boring prompt for a username and password. As if this article had never been written, in fact.

A word of warning however. Access rights are accumulative. So if you assign the role of "[Unauthorised]" to a generic "Everyone" group, and then give other groups actual access permissions, then ALL groups will get the role of [Unauthorised] assigned. Better to just leave the DEFAULT ACL setting with the role and all groups to NOT have a role assigned at all.

Incidentally, the above restriction doesn't apply if you assign individuals to the ACL; this is because an individual entry overrides all group rights, even when roles have been assigned.

Using this in an IIS environment

If you use Microsoft's IIS (part of Windows 2000) as a "front end" for all http requests then this will work just the same, unless you allow anonymous communication between IIS and Domino (which is not recommended anyway).

In a traditional IIS/Domino setup, IIS handles all http requests, initially anyway. It then passes the requests onto Domino if there is a ".nsf" in the request. Under Domino 5.x the http task doesn't even run on Domino and all communication is via a special linking module. Under Domino 6.x, the http requests is augmented with some authentication information and passed to Domino as a standard http message, albeit on a port other than 80 (possibly 81 or 9080, for example).

The advantage of using IIS, is that the concept of "anonymous" users has no meaning. By virtue of logging in to your Windows PC, and hence the domain or workgroup, you are "known" to Windows. That user information is what is passed to Domino. You never get prompted to input a name and (Intranet) password by Domino when using IIS.

How it works

In case you're not that familiar with the inner workings of Domino, HTML and javascript, here is a quick run down of how this all works.

The user attempts to launch your web page (in an Intranet, for example). He types in, say, "http://intranet/phonebook.nsf" expecting to see the phone book application.

You, the designer, have set the phonebook.nsf application to launch a navigator called WebLaunch when instigated from a browser. Domino finds the navigator, then checks to see whether you've designed a template for it. It finds the $$NavigatorTemplate for WebLaunch FORM, and uses that as a presentation template to show that navigator. But because you have not added a special field called $$NavigatorBody it never actually displays the Navigator, just the FORM contents (which you have cunningly designed to be user-friendly and helpful).

The form has a computed-for-display ROLE field on it that Domino calculates before converting it to HTML. This now allows you to interrogate the form with javascript and extract that value. If you detect that the user has the [Unauthorised] role assigned to him then he gets to see the (pretty) form.

Otherwise he gets transparently and silently redirected to the application's true home page/starting point.

And finally...

Did you get this tip to work? Is it unclear in places. I admit I'm aiming it at seasoned Domino/Web developers so maybe I've presumed too much.

I'd appreciate any feedback on it, good or bad, so that I can incorporate any suggestions and refine it accordingly. Would a sample database be of use, for example?