Applies to: Server!
Version(s): 4.0.16 - 5.x
Warning:    this articles refers to an older version of our software

Note: in order to use the code posted in this article you need to be running at least version 4.0.16 or greater of Server!

As you all know, Server! already supports its own internal users, as well as Windows and Active Directory users (and groups, depending on the license type). Yet, some of our customers need to implement totally custom authentication methods, often based on their own user databases.

In this article, we will show one way to do so. This is clearly just meant to serve as an example, and real-life scenarios require some further customization to the DB and the script posted here. But it’s a fairly decent starting point.

So, the background scenario for this example is:

  • our users’ authentication data are stored in a Microsoft(R) Access database
  • in our DB, each user is associated with a “category” (in this case his/her department: sales, marketing, …)
  • for the sake of this example, all users’ passwords are set to “password” (without quotes)
  • the script is pretty sophisticated because besides authenticating the user, it will load a user profile that belongs to the “category” of the user from the main Server! user-base

So let’s start taking a look at our user database:

As you can see, it’s pretty intuitive. Just 3 columns: UNAME contains the username, PWORD contains the SHA1 hash code of the password (all users’ password is “password” as stated above, that’s why in the screenshot all users have the same SHA1 in the PWORD field), and then there is a third column called CATEGORY that basically identifies which department the user belongs to.

Now, since none of the above usernames will actually be present in Server!’s user-base, we need to make sure that Server! allows them to at least try to authenticate. This can be done by creating a catch-all user profile in the main user-base, which is a user profile which username is only a single * (star/asterisk), as shown in the pictures here below.

Now that we have a dummy “catch-all” user profile, we will need an actual user profile for each category (department) in our database, because these will be the user profiles our users will be impersonating after a successful authentication against our external database.

Now that everything is ready from a user configuration standpoint, we need to write a script that:

  • connects to our custom database
  • runs a query to see if there is a user profile with a certain username and password hash
  • if so, loads the proper category user profile and allows the user to authenticate
  • if the query fails, authentication is rejected and an email is sent to the sysadmin

The script we need looks pretty much like this:

// Make sure you customize the 2 constants here below, to reflect your own
// actual database file and email address...
  databasefile = 'C:\Projects\TestDB.mdb';
  emailaddr = '';
  conn: TADOConnection;
  qry: TADOQuery;
  // Let's start assuming that the user will FAIL the authentication (just for safety)
  Session.UserAuthenticated := false;
  // Now let's query the DB to see if the requested user/password pair exists
  conn := TADOConnection.Create(nil);
  qry := TADOQuery.Create(nil);
  qry.Connection := conn;
    conn.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0'+
                             ';Data Source='+databasefile+
                             ';Persist Security Info=False';
    conn.LoginPrompt := false;
    conn.Connected := true;
    qry.SQL.Text := 'SELECT * FROM MYUSERS WHERE UNAME='''+Session.ReqUsername+''' AND PWORD='''+StrSHA1(Session.ReqPassword)+'''';
    if not qry.EOF then
      AddToLog('Record found, user is of type: '+qry.Fields[3].AsString);
      Session.UserAuthenticated := true;
      AddToLog('No record found, user was not authenticated');
    conn.Connected := false;
    qry.Connection := nil;
  // Finally, if we get here and the user is STILL NOT authenticated, send an email...
  if not Session.UserAuthenticated then
    SendMail(emailaddr, '[AUTH REFUSED]', 'Authentication refused for '+Session.ReqUsername+' with password '+Session.ReqPassword, '');

The last step, but very important, is to tell Server! when exactly the above script should be run. We do so by associating the script to the “OnAuthPassword” event handler of the * user profile. By doing so, Server! will execute the script every time a user tries password authentication, and let the script determine whether the authentication should be considered successful or not.

Here’s a screenshot of the Server! Web Configuration Manager with the script properly associated with the correct event in the * user local Event Handlers tab.

And that's really pretty much all there is to it.

Your Server! will now authenticate users against your custom database.