An ISAPI Filter for Netware Authentication
Programmed by Rick Osborne <rick@rixsoft.com>
NWAuth is an ISAPI authentication filter DLL for web servers running on Novell Netware networks. It authenticates users against Netware trees and contexts, and has a caching feature to speed up responses. Additionally, it is compiled to use the Netware client DLLs dynamically, so client upgrades should not break the install.
This document should be included with any distributions of the NWAuth DLL(s). The latest version of this document should always be found at <http://www.rixsoft.com/NWAuth/index.html>. The latest version of the NWAuth DLL(s) should be found at <http://www.rixsoft.com/NWAuth/NWAuth.zip>. The standard distribution of this package should include this help file, the NWAuth source code (in C++), and Debug and Release versions of the NWAuth DLLs.
This software is distributed under the terms of the GPL. You may make any changes you want, but you must notify me of them, and you must not redistribute this software without making the user aware of your changes. This software is free for non-commercial or governmental use. Commercial or Governmental users should contact me about licensing.
Installation is divided into 4 parts: Netware Client Configuration, Registry Settings, Web Server Configuration, and Debugging.
The first thing you will need to do is install the latest Novell Netware client, which is available for free from the Novell web site. NWAuth has been tested against version 4.70. While earlier versions may also work, they have not been tested against.[1] Note that the Microsoft Netware client that comes with Windows will not work; you must have the Novell client.
The installation doesn't require anything special. Once you have the client installed and have rebooted, you should be able to use it to login to your tree and context. A good rule of thumb is that if you can interactively use the client to login then NWAuth will be able to do it, as well. If you are relatively unfamiliar with Netware (as I was when I started this project), the client can actually help you with some of the registry configuration items later on. Make sure you note the Tree and Context that you are logging into.
Much of NWAuth's behavior can be controlled with the correct registry settings on the web server. All of the values are stored in the HKLM\Software\NWAuth key. None of them are actually required for the DLL to run (with the possible exception of NTUser and NTPassword) but they are there to make your life easier, so use them!
This should be a list of the URLs that the DLL is going to authenticate against.[2] The web server will call NWAuth for each and every file that gets requested from your site. If you have just a part of your site that is going to need Netware authentication, then you can tell NWAuth to quickly pass off authentication responsibility for anything outside of that part. This will speed up the processing of your files quite a bit. For example, if I have a virtual directory /members/ that is the only part of the site that needs authentication, then URLFilterList should list just that directory. If you have multiple directories, then put each of them into URLFilterList. The default is /, which will try to authenticate everything. Note, however, that NWAuth is also smart enough to quickly defer authentication if there is no user information present. That is, if the browser has not supplied the WWW-Authenticate header, then NWAuth will not even try to authenticate an empty user.
If your Netware schema consists of only one tree, or most of your users will only be logging into one tree, then this setting will make things a bit easier for your users, and therefore you. With this setting, the user will not have to explicitly specify a tree to authenticate against. See The End-User for more information.
If your Netware schema is really simple and most (or all) of your users will be logging into only one context, then this setting will make it absolutely trivial for them to login. This setting will allow them to leave off an explicit context, and use just their username. See The End-User for more information.
Once NWAuth has authenticated the Netware user, it has to pass back a valid NT user account to the web server, so that the web server will know what security context to run the request as. Right now, NWAuth only supports logging in as one user. This setting holds the username for the NT account. See Web Server Configuration for more information.
This setting is used with NTUser to create a security context for the request, and is the password for the NT user account. See Web Server Configuration for more information.
When the user explicitly specifies a tree to login to, this setting allows you to configure how the username will be parsed to find that tree. This is a list of split characters, and defaults to "/\:;". See The End User for more details.
This setting controls the amount of tree/context/user/password combinations are cached. The higher this number is, the less chances you have of thrashing a user and having to re-authenticate, but more memory is used. Obviously, this does not need to be higher than the total number of users on your network. Note that cache space is allocated as needed, and is garbage collected when necessary, so setting this too high isn't a Bad Thing. The default is 100 elements.
This setting will make a tree/context/user/password combination in the cache expire and be deleted after a certain amount of time. A lower setting will make NWAuth rely more heavily on Netware, while a higher setting may induce discrepancies if a user changes their Netware password. The default is 3 minutes.[3]
Once you have all the registry keys in place, you should create your NT user account. This account is sort of like the IUSR_* account that comes with IIS, or the nobody account on Unix, if you are familiar with them. The web server needs a security context to run the request in. In this way, the web server can tell what files the users have access to, and what they should be allowed to do with dynamic scripts. Since your users are authenticating against Netware and therefore don't have NT domain accounts, you will need to create this dummy NT user to provide the security context. This user should have access to the areas that are authenticated by NWAuth. The NTUser and NTPassword registry settings hold the account information for this user. You should test that your access is correct by logging into the web server as the NT user and making sure that it has the correct rights to the required areas.
The next step is to install the DLL as an ISAPI filter on your web server software. You will need to refer to your web server software's documentation on how to do this. For Microsoft's Internet Information Server, you will need the ISAPI Filters tab on the Properties dialog for your web site in the IIS Management Console. Depending on your server software, you may or may not need to restart the service. Note that while your web server software may require the NWAuth DLL to be in a specific place, NWAuth has no restrictions on where it can live.
The standard distribution of NWAuth comes with Debug and Release versions of the DLL. The Debug version outputs a small amount of debugging information to a log file at <c:\nwauth.log>. Since the debugging output goes to the hard disk, and it is single-threaded to prevent corruption, the Debug version of the DLL should not be used in a production environment. It is simply there to help you solve initial configuration problems. You should install it initially and then replace it later with the Release version, once the configuration is finalized.
When users visit your web site they will need to know their tree, context, username, and password. For simple Netware schemas some of this information may default to a preset configuration and make things a bit easier for the user. However, we will start with the most complex and then special-case our way down to the easiest and most desirable setup.
When the user's web browser gives the standard Username/Password prompt, the easy part will be the password. The password will always be the password, and it is case-sensitive. The username is a bit trickier. First, let's say that I am user rosborne, and I log into the PHOENIX_INTL tree under the Users.Phoenix_HQ context. NWAuth is modeled after the NT environment, and therefore uses its conventions. For the purposes of NWAuth, the Netware tree is used like an NT domain. The Netware context is appended to the username, in the standard typeless naming convention for container lists. For more information, see the Novell web site, specifically the tutorial on NDS naming. Given the user I just made up, my fully-qualified login username would look like:
PHOENIX_INTL\rosborne.Users.Phoenix_HQ
Note the convention: a backslash separates the tree from the context. This is where the TreeDelimiters registry setting comes into play. This setting tells NWAuth what characters delimit a tree from a username. With the default setting ("/\;:") all of the following are parsed the same:
PHOENIX_INTL\rosborne.Users.Phoenix_HQ
PHOENIX_INTL/rosborne.Users.Phoenix_HQ
PHOENIX_INTL:rosborne.Users.Phoenix_HQ
PHOENIX_INTL;rosborne.Users.Phoenix_HQ
I recommend either using the default or one of the slashes. The colon (:) is used as a username/password delimiter in URLs, so I don't recommend using it as a tree delimiter. Most users should be used to using one of the slashes.
Obviously, users aren't going to want to type all of this in every time the want to login to the system. For complex Netware schemas there isn't much choice. For simple schemas, however, you can make your users' lives a bit easier. If most of your users will be logging into the same tree, you can specify a default tree with the DefaultTree setting. This won't override the user if they explicitly enter a different tree, but it will allow the user to drop the tree from their login. If I set up my default tree as PHOENIX_INTL, then I can login as:
rosborne.Users.Phoenix_HQ
There is also the DefaultContext setting that will allow the same action for the user's context. If I set my default context as Users.Phoenix_HQ, then I can login as:
PHOENIX_INTL\rosborne
Logically, if both defaults are in place, then I can login as simply:
rosborne
Just to make things clear: the DefaultTree and DefaultContext settings work well together, but do not have to rely on each other. For example, if I had another tree, PHOENIX_ADMIN, that also had a Users.Phoenix_HQ context, then I could just set the DefaultContext and leave the tree to be explicitly defined. Or, if most of my users logged into one tree then I could set it as the default and make the minority of the users explicitly state the tree. The same works for contexts.
NWAuth was programmed using Microsoft's Visual C++ 6.0 with Service Pack 3 applied. It currently uses SGI's implementation of the Standard Template Library, instead of the default STL library that came with VC6. It is compiled only with optimizations for speed, but not for processor, etc.
The DLL exports the standard ISAPI functions (DllMain, HttpFilterProc, and GetFilterVersion) as well as a function to do tree/context/user/password validation, NWValidateUser. The declaration for NWValidateUser is as follows:
INT WINAPI NWValidateUser(char* tree, char* context, char* username, char* password);
There is also a test application, nwauthtest.cpp, which can be compiled. It does command-line verification of tree/context/username/password combinations, wich can save you time in configuring the server initially.
Netware authentication is abstracted into the NWValidator class. It has only one public member function:
int ValidateUserInTreeContext(const char* tree, const char* context, const char* username, const char* password);
A NWValidator object will attempt to load the Netware DLLs upon construction and unload them upon destruction. In this way, many validations can occur without having to constantly reinitialize the Netware environment. Since the ISAPI functions create one of these objects when the DLL loads, the same environment will be used for all subsequent calls and the environment will not be unloaded until the DLL is unloaded.
The cache is implemented as an STL hash_map, with a std::string key of "Username.Context.Tree".[4] Garbage collection occurs whenever the cache exceeds the MaxCacheElements setting.
This was a complete rewrite from the Alpha. I managed to get rid of MFC, replacing it with STL in the necessary places, tried to OO it a bit, and changed from static to dynamic linking. As a result, the size and lag are now a fraction of what they were.
This version, while functional, was a complete abomination. It used statically-linked Netware libraries and MFC. If you happen to find a copy of this version anywhere, obliterate it.