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 Syncplify.me Server!
As you all know, Syncplify.me 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 to 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 Syncplify.me 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 Syncplify.me Server!’s user-base, we need to make sure that Syncplify.me 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... const databasefile = 'C:\Projects\TestDB.mdb'; emailaddr = 'put_your@email.here'; var conn: TADOConnection; qry: TADOQuery; begin // 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; try 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)+''''; qry.Open; qry.First; if not qry.EOF then begin AddToLog('Record found, user is of type: '+qry.Fields[3].AsString); Session.User.LoadFromDB(qry.Fields[3].AsString); Session.UserAuthenticated := true; end else AddToLog('No record found, user was not authenticated'); qry.Close; conn.Connected := false; finally qry.Connection := nil; qry.Free; conn.Free; end; // 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, ''); end.
Last step, but very important, is to tell Syncplify.me 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, Syncplify.me 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 Syncplify.me Server! Web Configuration Manager with the script properly associated to the correct event in the * user local Event Handlers tab.
Ready to test our brand new custom authentication script? OK! Let’s run any FTP client (yes, even the DOS command-line client if you want, why not) and try to log in as user “john” with password “password”.
Success! The user “john” was found in the custom database, his password was verified using the hash in the custom database, and then he was granted access by impersonating the “sales” user profile in Syncplify.me Server!, exactly as specified in the custom database.