COM Based IIS Authentication
with AuthentiX

Prior reading: Authentication Tutorial:, Authentication - what it is and how to work with it.

Introduction

This article is for webmasters who wish to protect their premium content directories with usernames and password according to their own specific requirements that are not covered by other AuthentiX validation choices, presently:

AuthentiX protects your IIS website by cookie or by Basic Authentication. You can use either method in combination with a custom AuthentiX plug-in. This tutorial explains how to protect your IIS website by cookie or by Basic Authentication using AuthentiX and your own custom authentication component using the AuthentiX Extensibility SDK.

We'll see how to create a server component in Visual Basic and Visual C++, a kind of component that can be used from Active Server Pages, ISAPI extensions or filters. Then how to use such a component with AuthentiX. Explanations, tips, samples and downloadable source code are provided here and in the evaluation product download. Special considerations for components called from NT services such as IIS are described.

The same component can be used with WebQuota to take advantage of its enhanced capabilities such as

If you wish to move from Basic Authentication to cookie-based protection, please see this additional note here.

Contents:

Introduction
Contents/Index
What can I use the AuthentiX Extensibility SDK for?
What other advantages does it offer?
The AuthentiX Extensibility SDK - Description
General Considerations for server components.
Creating a Visual Basic Server Component
Creating a Visual C++ Server Component
Set up AuthentiX to use the component
AuthentiX COM options
Testing your component
PreBuilt Custom Components
Conclusion


What can I use the AuthentiX Extensibility SDK for?

Starting with the Extensibility SDK samples you can create a component to authenticate via

Another option is to create a component without validating username/password, for example to check visitor IP-addresses, compare against a large database of acceptable IP-addresses.

Or map requests to NT users based on both the username and requested URL, in order to leverage MTS and other NT security mechanisms for users that they don't want to give NT accounts.

The Extensibility SDK is popular with those who need to validate against multiple datasources, with appropriate failovers between them.
Eg, validate by IP address, if that fails then validate against a text file, if that fails then validate against a mainframe via DCOM.
Eg validate against an NT username/password account (perhaps by trying to access an NT protected template file), if that fails then an ODBC database.


Back to index

What other advantages does it offer?

Using the AuthentiX Extensibility SDK offers the following benefits:

Back to index

The AuthentiX Extensibility SDK - Description

AuthentiX communicates with the custom component via a single method with 12 parameters. Each parameter is described. All the samples have this method pre-built to get you started.
AuthentiX Extensibility SDK Definition


Back to index

General Considerations for server components.

There are some general considerations that must be taken into account when creating a component to be called from a NT service as with IIS and AuthentiX. Specifically the component should be non-interactive and should be thread-safe

Since the component will be called from a service, there should be no interaction with the desktop. That means no MsgBoxes and no dialogs. Should you incorporate a function library that throws up dialogs on error conditions, the best that can happen is the thread it is running in will hang, tying up resources. The worst is a service crash. Instead, services and their support functions should send a message to the event log. A support routine is available EventLog that will help you do this.

Since the IIS and AuthentiX environment is multithreaded, the component should be thread-safe. If two threads try to access the same data at the same time, conflicts will occur and may result in a crash. In general avoid global variables. If global variables must be used protect their access using synchronization objects.

The best option is to use only local variables (in function scope). Each thread uses its own stack for local variables so they are quite safe.

Some customers have tried building COM components using .Net. It should be noted that .Net languages are interpreted and thus do not have the performance advantages of purely compiled code.
.Net has garbage collection that occurs at unpredictable intervals. This can cause rather severe performance bottlenecks at random times.
Finally, rather than being completely loaded into memory when first called, .Net components need to load assemblies in real time each time they are called.
Some have reported performance penalties of several orders of magnitude when switching from compiled Basic or compiled C++ to .Net. One customer noted a performance drop from 0.04 seconds to 12 seconds! (6/6/05)


Back to index

Creating a Visual Basic Server Component

In this section we will create a Visual Basic Project configured as a server component, set the name of the project and the main class, create an Authentication method, and compile it into a dll.

With VB5 and VB6 you can create a COM (or ActiveX) component quite easily. Visual Basic produces a file with a "dll" extension, Visual C creates a file with an "ocx" extension. Each must be registered with the system using regsvr32.exe. From the command line you would enter
regsvr32 component.dll

You'll need Windows NT/2000, IIS and VB6 installed on your system.

Fire up VB, and click on the ActiveX Dll:

then click "Open".
In the Project Window, right click on the project name, click on properties, change the project name to "MyAuthVB" and check the "Unattended Execution" check box.

Press OK.

Now click on the class name "Class1 (Class1)" then select the "(Name)" property in the Property Window. Change the name to "Auth".

With a Project Name of MyAuthVB and a class name of Auth, the OLE short name or "ProgID" is
MyAuthVB.Auth
You'll need this ProgID later when we hook the component into AuthentiX. If you wanted to use some methods in this component from ASP, then you would use this ProgID in the call to CreateObject like so:
Set MyAuth = Server.CreateObject("MyAuthVB.Auth")

Now create the Method to be called. To make the function available externally, it must be declared as a "Public Function". Here is a sample for you to begin with:

' return 1 for success
' returns 3 if user not found
' returns 6 if user found and wrong password
' returns 9 if user found and expired
Public Function Authenticate( verifyArg As Long, _
username As String, _
password As String, _
ipAddress As String, _
userAgent As String, _
referrer As String, _
scriptName As String, _
ReservedReturn As String, _
queryString As String, _
bstrReserved2 As String, _
longReserved1 As Long, _
longReserved2 As Long) _
As Integer

If ("Brian" <> username) Then
Authenticate = 3 ' bad username
Exit Function
End If

If ("Young" <> password) Then
Authenticate = 6 ' bad password
Exit Function
End If

Authenticate = 1 ' success
Exit Function
End Function

Here it is in a text file for easy cut and paste.

Next compile the project into a dll. In the File Menu, select "Make MyAuthVB.dll". This will create the ActiveX dll file and register it on your system.

You can test the above Authenticate method from WSH or ASP as follows:

Set MyAuth = Server.CreateObject("MyAuthVB.Auth")
result = MyAuth.Authenticate(1, "Brian", "Young", _
Request.ServerVariables("REMOTE_ADDR"), _
Request.ServerVariables("HTTP_USER_AGENT"), _
Request.ServerVariables("HTTP_REFERER"), _
Request.ServerVariables("SCRIPT_NAME"), _
str1, str2, str3, l1, l2)

5/9/00: One user reported that when using a VB component like this, as well as using ASP pages, then IIS will have a problem when shutting down. His solution was to make the VB component out-of-process, using the VB menu Project-Properties, and setting the project type to an "ActiveX Exe" instead of "ActiveX DLL".

5/21/01: One user had a permissions problem debugging with VB. "I fixed this problem, it was a permissions problem in DCOM. Adding the following Registry entry's and giving "Everyone" access permissions on the VB ASP Debugging entry in the dcomcnfg tool allows you to debug the component.
REGEDIT4
[HKEY_CLASSES_ROOT\CLSID\{70F214BA-94E2-4bdf-8F30-32CB4A905E4D}]
@="VB ASP Debugging"
[HKEY_CLASSES_ROOT\CLSID\{70F214BA-94E2-4bdf-8F30-32CB4A905E4D}\LocalServer32]
@="vb6.exe"
[HKEY_CLASSES_ROOT\AppID\vb6.exe]
"AppId"="{70F214BA-94E2-4bdf-8F30-32CB4A905E4D}"

If your COM component returns values other than the standard values, be sure the values are ABOVE 900. 900 and below are non-user return codes, and will always be converted to BAD_PASSWORD.

Now that we have created and tested the component, it is time to hook it into AuthentiX. If you are not concerned with creating a VC++ component you can skip the next section.

Go to setting up AuthentiX to use the Component


Back to index

Creating a Visual C++ Server Component

Using Visual C++ V6 to create a COM (or ActiveX) component is not hard. Visual C creates a file with an "ocx" extension, Visual Basic produces a file with a "dll" extension. Each must be registered with the system using regsvr32.exe. VC6 registers the component for you automatically when compilation completes. From the command line you would enter
regsvr32 component.dll

You'll need Windows NT/2000, IIS and VC6 installed on your system. Be sure to implement IsInvokeAllowed as described below.

Fire up Visual C, select File, New.
Click on MFC ActiveX Control Wizard, and in the Project name field type "MyAuthC".

Click OK.
In the first step of the control wizard, choose the default settings.

Click Next.
In the second step of the control wizard, click on the Advanced button, and check the Windowless Activation checkbox.

Click OK then click Finished. Click OK on the confirmation dialog.
You have now created a new COM component project in Visual C.
Now we need to create a new Method. Click on the View Menu, and select Class Wizard (alternatively use the Ctrl-W shortcut key). Select the Automation tab.

Now add a Method named Authenticate of return type "Short" with the following parameter list:

long FAR* verify
BSTR FAR* username
BSTR FAR* password
BSTR FAR* ipAddress
BSTR FAR* userAgent
BSTR FAR* referrer
BSTR FAR* scriptName
BSTR FAR* bstrUserString
BSTR FAR* bstrqueryString
BSTR FAR* bstrReserved2
long FAR* longReserved1
long FAR* longReserved2

(Remember if you don't want to do this by hand, there is a prepared sample to help you.)

Click OK, then click the "Edit Code" button to go straight to the source file.

Let's create the body of the function:

short CMyAuthCCtrl::Authenticate( long FAR* verify,
BSTR FAR* username,
BSTR FAR* password,
BSTR FAR* ipAddress,
BSTR FAR* userAgent,
BSTR FAR* referrer,
BSTR FAR* scriptName,
BSTR FAR* bstrUserString,
BSTR FAR* bstrqueryString,
BSTR FAR* bstrReserved2,
long FAR* longReserved1,
long FAR* longReserved2)

{
CString uName = *username;
CString uPass = *password;

if (0 != uName.CompareNoCase("Brian"))
return 3; // bad username

if (0 != uPass.CompareNoCase("Young"))
return 6; // bad password

return 1;
}

Here it is in a text file for easy cut and paste.

If your COM component returns values other than the standard values, be sure the values are ABOVE 900. 900 and below are non-user return codes, and will always be converted to BAD_PASSWORD.

Important - miss this and it won't work!
Next, and very important is to add the function IsInvokeAllowed. If you do not add this function, you will not be able to call any methods in this control!

// absolutely essential and critical
BOOL CMyAuthCCtrl::IsInvokeAllowed(DISPID)
{
return TRUE;
}

Compile the project using the shortcut "Shift-F8".

You can test the above Authenticate method from WSH or ASP as follows:

Set MyAuth = Server.CreateObject("MYAUTHC.MyAuthCCtrl.1")
result = MyAuth.Authenticate(1, "Brian", "Young", _
Request.ServerVariables("REMOTE_ADDR"), _
Request.ServerVariables("HTTP_USER_AGENT"), _
Request.ServerVariables("REMOTE_ADDR"), _
Request.ServerVariables("HTTP_REFERER"), _
Request.ServerVariables("SCRIPT_NAME"), _
str1, str2, str3, l1, l2)

Now that we have created and tested the component, it is time to hook it into AuthentiX.


Back to index

Set up AuthentiX to use the component

First follow the "Beginner's Step by Step" to setup AuthentiX protection for a directory. When you have tested this configuration disable the internal database by unchecking the "By Internal DB" checkbox. Click on the "By COM" tab, enable it, and click the "By Custom COM Component" button. You will see the following dialog:

Two sample components are supplied with the installation of AuthentiX. AUTHCOM.AuthCOMCtrl.1 and AuthXVB1.Auth. The first is a VC++ sample, the second is a VB sample. Both come with source code and are located in the ByCOM installation sub-directory. Each are hard-coded for the user "Brian" with a password of "Young".

Click the Test button. The test will complete successfully.

Using the combo-box, select the alternate component AuthXVB1.Auth.

Note that the dispatch ID changes from 1 to 1610809344 (which is 0x60030000 in decimal). If you declare other methods in your COM component, you may have to adjust the Dispatch ID accordingly. The default values provided correspond to the default Dispatch ID in the server components built previously in this document. They will also match any new component you build according to the previous instructions.

To find alternate numbers, open the dll in oleview program that comes with visual studio. Then it will show the hexadecimal number for each class.

Click the Test button again. The test will complete successfully.

Now you are ready to test your custom COM component live. Type in the Prog ID of your component in the first text-field. If you created the VB component above type in "MyAuthVB.Auth" and select "VB Starts At" radio button. If you created the VC++ component above type in "MYAUTHC.MyAuthCCtrl.1" and select "C++ Starts At" radio button.

Click the Test button again. The test will complete successfully.

Click OK, OK, to save your changes for AuthentiX protection for that directory.

Using a browser and http, type in the URL of your protected directory. You'll be prompted for your username and password. Enter "Brian", "Young". You'll see your protected web pages - success!

Other topics to be covered include "Options" for advanced settings, and "Testing your COM component" where we provide a tool to assist with rapid prototyping and debugging of your component.


Back to index

AuthentiX COM options

Clicking on the Options button in the "By COM" dialog reveals several options for advanced users. Each is described in detail below.


Back to index

Testing your component

If you have already rolled up your sleeves and are developing your component you will have noticed a problem: as soon as you test the component with IIS running, you can no longer compile your changes and create a new version of OCX/DLL file. This is because the component has been loaded by a running process (IIS and the AuthentiX filter) and executable binaries (like your component) can not be modified while they are running.

You need to stop and restart IIS (IIS Admin from the control-panel/Services) each and every time you make a change. Needless to say this considerably slows down the edit/compile/test cycle.

You could test the component each time from the AuthentiX/By-Com/Test button, however you still have to launch AuthentiX select the directory, fire the Test button, and stop AuthentiX. Although AuthentiX is easy to use and setup, this sequence of operations can become tedious. For your convenience a test container "ATestC" is supplied

Look in the ByCOM/ATestC directory. Specify ATestC.exe as the target debug executable in your development environment. This lightweight application will save you time in your development. Remember however that ATestC doesn't multithread or have the login context of IIS.


Back to index

PreBuilt Custom Components

Some commonly requested COM components are available:

Back to index

Conclusion

In this article we have shown how AuthentiX can be used with a custom developed COM component to provide membership protection for specified web-directories.

We have described general requirements for the behaviour of a server component, and given detailed examples of how to create such a component in Visual Basic and Visual C++.

A test tool has been provided to speed the development cycle, and advanced AuthentiX COM options have been described in detail.

Leveraging the functionality of commercial grade software like AuthentiX with its Extensibility SDK provides immediate benefits and significantly compresses development time where your organisation needs to address specific authentication requirements.

Transparent use of the AuthentiX internal cache ensures the speediest website performance with the additional functionality you build. The upgrade path from AuthentiX to WebQuota provides a route to advanced capabilites such as limiting concurrent logins to help detect and prevent account abuse.

About the Author

Kevin Flick is founder and CEO of Flicks Software Inc. a leading provider of membership systems and COM component software.


Copyright © 1998,1999 Kevin Flick
All rights reserved.
This document may not be reproduced or distributed in whole or in part without prior written permission from the author.