Implementing HTTP Authentication for Web Applications
The Apache modules (mod_csp*.so/dll and CSPa*[Sys].so/dll) to allow HTTP authentication to be controlled by InterSystems IRIS®.
HTTP authentication of web requests is normally carried out between the web server and client (browser). Because of this, it is not usually possible to implement HTTP authentication in custom request handlers hosted by the web server – such as CGI programs and web server API-based request handlers. Of course, such extensions can issue a 401 Authorization Required response header and, in response to this, the browser displays the HTTP login dialog. However, in the subsequent request, the web server intercepts the user's login details and attempts to authenticate the user using its own built-in functionality. The username and password are not, at least in the first instance, passed along to the request handling extension until the web server has authenticated the user on its own terms.
This scheme presents a problem for users of third-party development technologies (such as CSP) who wish to perform HTTP authentication locally (and programmatically) within their technology of choice.
The feature described here overcomes these technical difficulties and allows users to perform HTTP authentication in the InterSystems IRIS environment for Apache-hosted web applications. Users of Apache can choose between the three approaches described in the following sections.
Standard HTTP authentication in Apache (mod_auth)
This method is the standard mechanism provided by Apache (through the mod_auth module) and does not involve the Web Gateway. It is mentioned here for the sake of completeness.
As an example, the basic parameters required for protecting the CSP samples using Apache-based authentication are shown in the following configuration block (httpd.conf):
<Location "/csp/samples/">
AuthType Basic
AuthName "CSP samples"
AuthUserFile conf/csp.pwd
require valid-user
</Location>
Where:
AuthType is the type of authorization required (usually Basic).
AuthName is the realm.
AuthUserFile is the file (relative to the web server root) holding usernames and their associated passwords (in encrypted form). This file is created and maintained by the Apache htpasswd utility.
The require parameter lists the users who may access the protected resource (the CSP samples in this case). The valid-user argument indicates that the user must be defined in the username/password file (as declared in AuthUserFile).
Apache provides for users to be grouped together in user 'groups' – see the AuthGroupFile directive for further details:
https://httpd.apache.org/docs/2.4/mod/mod_authz_groupfile.html#authgroupfile
Authenticating in CSP at the Same Time as the Request is Processed.
This is the preferred (and best performing) method for implementing HTTP authentication in web applications.
The basic parameters required for protecting the CSP samples using CSP-based authentication are shown in the following Apache configuration block (httpd.conf):
<Location "/csp/samples/">
AuthType Basic
AuthName "CSP samples"
require valid-user
AuthCSPEnable On
AuthBasicAuthoritative Off
</Location>
The parameters AuthType, AuthName and require are the standard Apache parameters used for triggering authentication.
The additional AuthCSPEnable parameter instructs the CSP module to bypass the authentication checks that would otherwise be performed by Apache (in mod_auth) and pass the user's name and password, along with the original web request, to InterSystems IRIS for authentication. The web application must check the user using the following CGI environment variables:
-
AUTH_TYPE: This is Basic.
-
REMOTE_USER: The user's name.
-
AUTH_PASSWORD: The user's password (as plain text).
If the user can be successfully authenticated based on the values held in these parameters then the application should continue and process the request (i.e. return the requested CSP resource). If not, it should return a HTTP 401 Authorization Required response which, at the very least, should be something like:
HTTP/1.1 401 Authorization Required
WWW-Authenticate: Basic realm="CSP samples"
Content-Type: text/html
Connection: close
<html>
<head><title>401 Authorization Required</title>
</head><body> <h1>Authorization Required</h1>
<p> The server could not verify that you are authorized
to access the application. Check your username and password.
</p>
<hr>
</body>
</html>
On receiving this message the browser redisplays the login dialog unless the user has used-up all his/her login attempts (usually 3) in which case the message following the header is displayed instead.
Users can implement this method of authentication by modifying the login page. If a request comes in and the user does not have the necessary privileges to run the application then the login page is called, the processing for which can extract the authentication information from the request (such as AUTH_TYPE, REMOTE_USER and AUTH_PASSWORD). If these parameters are correct, the login script can then redirect control to the application page that was originally requested. It should not be necessary to repeat the authentication procedure for all public pages provided the InterSystems security control layer is deployed.
Authenticating in CSP before the Request is Processed.
This is an alternative method for implementing HTTP authentication in InterSystems IRIS. It is intended primarily for cases where performing authentication at request-processing time in the web application would be awkward or time consuming.
In this method, the user is authenticated by calling a dedicated authentication class. The Web Gateway performs this check before dispatching the original request to InterSystems IRIS. When the user's details have been successfully checked by the authentication class, the web application need not perform any further any further checking.
Of course, this method bears the overhead of processing two requests (to InterSystems IRIS) per web request: one for authentication and one for actually dealing with the request for the CSP resource.
The basic parameters required for implementing this method of authentication are shown in the following Apache configuration block (httpd.conf):
<Location "/csp/samples/">
AuthType Basic
AuthName "CSP samples"
require valid-user
AuthCSPEnable On
AuthCSPClass /csp/samples/%CSP.HTTPAuthentication.cls
AuthBasicAuthoritative Off
</Location>
The parameters AuthType, AuthName, require and AuthCSPEnable are the same as for method (2).
The additional AuthCSPClass parameter defines a class that performs user authentication. The class must extend %CSP.PageOpens in a new tab and, using the appropriate CGI environment variables, should check the user's login details and return either a 200 OK response header if the operation is successful or a 401 Authorization Required response header if not.
A simple authentication class in which user login details are checked against records held in the %Users file is shown below:
Class %CSP.HTTPAuthentication Extends %CSP.Page
{
ClassMethod OnPreHTTP() As %Boolean
{
Set %response.ContentType = "text/html"
Set %session.Preserve = 0
Quit 1
}
ClassMethod OnPage() As %Status
{
Set crlf=$Char(13,10)
Set type=%request.GetCgiEnv("AUTH_TYPE", "")
Set user=%request.GetCgiEnv("REMOTE_USER", "")
Set pwd=%request.GetCgiEnv("AUTH_PASSWORD", "")
Set httpauth=%request.GetCgiEnv("HTTP_AUTHORIZATION", "")
If httpauth'="" {
Set type=$Piece(httpauth," ",1)
Set user=$system.Encryption.Base64Decode($Piece(httpauth," ",2))
Set pwd=$Piece(user,":",2)
Set user=$Piece(user,":",1)
}
Set auth=0
If $ZConvert(type,"L")'="basic" Set auth=1
If auth=0,user'="",$Get(^%Users(user))=pwd Set auth=1
If auth=1 {
Write "HTTP/1.1 200 OK"_crlf
Write "Content-Type: text/html"_crlf
Write "Content-Length: 0"_crlf
Write "Connection: close"_crlf_crlf
}
Else {
Write "HTTP/1.1 401 Authorization Required"_crlf
Write "WWW-Authenticate: Basic realm=""CSP samples"""_crlf
Write "Content-Type: text/html"_crlf
Write "Content-Length: 0"_crlf
Write "Connection: close"_crlf_crlf
}
Quit $$$OK
}
ClassMethod OnHTTPHeader(ByRef OutputBody As %Boolean) As %Status
{
Quit $$$OK
}
}
For methods (1) and (3) a custom error page can be specified for login failure by using the Apache ErrorDocument directive. For example:
ErrorDocument /error/my_authentication_error.html
Of course, for method (2) the text of the error message is controlled by the web application.