Janus Web Server security: Difference between revisions

From m204wiki
Jump to navigation Jump to search
 
(6 intermediate revisions by 2 users not shown)
Line 554: Line 554:


==Form-based user authentication==
==Form-based user authentication==
<var class="product">Sirius Mods</var> provides several facilities for
<var class="product">Janus</var> provides several facilities for
presenting form-based user authentication.
presenting form-based user authentication.
Still, however, the
Still, however, the HTTP protocol has limitations that force some tradeoffs in design
HTTP protocol has limitations that force some tradeoffs in design
and complexities in the code to support that design.
and complexities in the code to support that design.


Line 568: Line 567:
Clearly, this would be unacceptable.
Clearly, this would be unacceptable.
So after a user has successfully logged in, the fact that the
So after a user has successfully logged in, the fact that the
user has logged in to a particular userid must somehow be maintained between
user has logged in to a particular userid must somehow be maintained between pages.
pages.
   
   
<var class="product">Janus Web Server</var> provides basically three options for maintaining a login session:
<var class="product">Janus Web Server</var> provides basically three options for maintaining a login session:
Line 967: Line 965:
limitations and oddities.
limitations and oddities.
Still, it is probably a good choice in many environments.
Still, it is probably a good choice in many environments.
===WWW-Authenticate and Authorization Headers===
Under Model 204 7.7 and later, the complete <var>Authorization</var> request header can be accessed and the <var>WWW-Authenticate</var> response header set.


<var>Authorization</var> can be accessed via the standard <var>$web_hdr_parm</var> functions. For example, to copy this header into a longstring one can do:
===Authorization and WWW-Authenticate headers===
Under Model 204 7.7 and later, you can access the complete <code>Authorization</code> request header, and you can set the <code>WWW-Authenticate</code> response header.
 
<ul>
<li>To access <code>Authorization</code>, use the standard <var>$Web_Hdr_Parm</var> functions. For example, to copy this header into a <var>Longstring</var>:
<p class="code">%auth    is longstring
<p class="code">%auth    is longstring
%ls = $web_hdr_parm_lstr("Authorization")
%ls = [[$Web_Hdr_Parm_Lstr|$web_hdr_parm_lstr]]("Authorization")
</p>
</p>
Note however that outside of <var>NEWSESCMD</var> processing, <code>$web_hdr_parm_lstr("Authorization")</code> and other <var>$web_hdr_parm</var> functions will always indicate that this header is a null string.
<p>
Janus Web does <var class="term">not</var> uppercase the value for the “Authorization” header.</p>
<p class="note"><b>Note:</b> Outside of <var>[[NEWSESCMD (JANUS DEFINE parameter)|NEWSESCMD]]</var> processing, <code>$Web_hdr_parm_lstr("Authorization")</code> and other <var>$web_hdr_parm</var> functions will always indicate that this header is a null string. </p></li>


Also, one can set the the <var>WWW-Authenticate</var> response header with something like:
<li>You can set the the <code>WWW-Authenticate</code> response header with a statement like this:
<p class="code">%rc = $web_response("WWW-Authenticate", -
<p class="code">%rc = $web_response("WWW-Authenticate", -
         'Digest realm="Rocketlandia", qop="auth,auth-int", ' -
         'Digest realm="Rocketlandia", qop="auth,auth-int", ' -
         'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", ' -
         'nonce="' %nonce:stringToHex '", ' -
         'opaque="5ccc069c403ebaf9f0171e9517f40e41"' -
         'opaque="' %opaqueStringToHex '"' -
       )
       )
</p>
</p>
<p>
Although you could do this prior to Model 204 7.7, the <code>WWW-Authenticate</code> response header would only have an effect if a <code>401 Unauthorized</code> response was sent, and in that case, Janus Web would always put its own <code>WWW-Authenticate</code> header in front of the one set by <var>$Web_Response</var> and browsers would use that one instead. Under Model 204 7.7, if the <code>WWW-Authenticate</code> response header is set, Janus Web does not add its own. </p></li>
</ul>
<p>
How one uses these headers is an extremely advanced topic, and it requires deep understanding of the HTTP authentication protocols. Such information is beyond the scope of this reference, though you can find plenty of information about it on the Internet. </p>


==User access control==
==User access control==

Latest revision as of 22:30, 30 August 2016

Security, for all computer systems, is the attempt to limit capabilities within a system to the appropriate users. These capabilities can include controlling the system, updating data or even simply viewing certain pieces of information. Generally, security can be broken down into four components:

  1. Hardware security. Flow of data is limited to a particular physical line.
  2. Encryption. Data is encrypted to prevent being stolen or changed by a third party.
  3. User authentication. Users are reliably identified.
  4. Access control. Access to data or functionality is limited to particular authenticated users.

For VTAM and other 3270 networks, hardware security used to be quite important as data was typically sent along a single line to a specific machine making it very difficult to intercept or see data on one machine when it was intended for another. Modern local area network technology, on the other hand, often makes it quite easy to intercept or see data on one machine when it was intended for another. This is true as much for 3270 applications that are running over network 3270 emulators as for web applications. While technologies such as switched-ethernet and correctly configured routers and gateways make hardware security feasible, this technology is not ubiquitous and it is difficult to be certain that it is all configured correctly to ensure security. Because of this, it is generally not a good idea to depend on hardware security in a modern local area network.

A word of caution is due here. Many sites feel that the lack of hardware security on a local network is irrelevant as long as there is security between the local network and the internet or any other wide area network. While this might be true at the very smallest sites where all users are authorized for all activities so that security is mainly a matter of trust among all users, it is not true at most larger sites. Local users, that is those inside the organizational firewall, are not only the ones with the greatest ability to break security (because of the lack of local network hardware security) but they are often the ones with the greatest motivation to bypass security. As such, local network security should generally be treated as important as internet security.

Encryption

In the web world, encryption usually means SSL (Secure Sockets Layer) which provides a simple way of encrypting data between a browser and a web server. SSL ensures that data travelling over an SSL connection between browser and server is encrypted so that no other users can easily decrypt the data, even if the other users can see the entire datastream being passed back and forth.

There are basically two ways to provide SSL encryption for Janus Web Server:

  1. Have a proxy server perform the encryption, and have the proxy server communication with Janus Web Server over a standard unencrypted HTTP connection.
  2. Have the Janus Network Security feature provide SSL support inside the Model 204 region.

The advantages of the first approach are:

  • Having encryption performed by a proxy server moves the processing required for expensive public-key/private-key operations off the mainframe onto possibly less expensive platforms leaving mainframe cycles free for database processing.
  • Having encryption performed by external proxy servers makes it possible to have “proxy farms” that make it easy to distribute the expensive public-key/private-key operations over multiple machines.
  • An organization-wide proxy server or server farm can be used to provide secure access to a number of different web servers.
  • There is no need to purchase Janus Network Security.

The advantages of the second approach are :

  • Because encryption is completely end-to-end, there is no security exposure on the network to which the Model 204 region is connected. This exposure could be reduced by putting the proxy on the same machine as Model 204, but this eliminates most of the benefits of using an external proxy server. Alternatively, the proxy or proxies could be set up on a local network that contains only the proxy server, Model 204, and a firewall. This approach, too, eliminates some of the benefits of using an external proxy server.
  • Generally, proxy servers lose a very useful piece of information, namely the IP address of the browser.

In any case, it is strongly recommended that any connections over which secure data is to be transmitted use encryption. Probably one of the most common and important pieces of secure information is user passwords. Because of the risk of transmitting unencrypted passwords over a network, Janus Web Server issues a warning message whenever a JANUS WEB ALLOW rule is issued for a non-SSL port that will cause passwords to be transmitted unencrypted over the network.

User authentication

Hardware security and encryption can ensure that communications between a web browser and a web server are protected from eavesdropping by unauthorized users. This does nothing, however, to control the interaction between the end-user and a web-server application. If certain parts of a web-server application or data presented or updated by a web-server application must be limited to certain individuals, it is imperative that the web-server be able to identify end-users to provide appropriate access. This identification process is called "user authentication" because it is an attempt to authenticate the identity of the end-user.

A review of authentication methods

There are many ways for user authentication to be achieved with web-servers: from client certificates, to HTTP userid/password authentication, to application-controlled validation, to truly exotic biometric techniques such as retinal scans or fingerprint readers.

  • Client certificates

    While client certificates (possibly in the guise of smart cards) offer great promise as a convenient form of user authentication, few organizations have the infrastructure and procedures in place to support them. Furthermore, it can be impossible or extremely difficult to integrate client certificate authentication with existing user authentication mechanisms used for 3270 access.

    Still, client certificates are becoming more and more common so should be considered as an option for user authentication. Janus Web Server provides the facilities to make client certificate based validation a possibility. See $Sir_Login for more information on client certificate based user authentication. Because of the complexity of this topic it is also probably a good idea to contact Sirius Software for assistance and advice if such an approach is being contemplated.

  • Application-controlled validation

    Application-controlled validation can be very flexible and might be ideal for certain applications. On the other hand, application-controlled validation can require a lot of work to implement and tends to be more prone to security exposures than user authentication built into a system. In any case, application-controlled validation is a complex topic that is beyond the scope of this document.

  • Biometric user authentication

    While there are those who would have one believe that biometric user authentication is just around the corner and will provide completely secure yet hassle-free access control, the costs, complexities and vulnerabilities of this technology will likely relegate it to the realm of science fiction or, at best, some very specialized applications for some time to come.

  • Form-based authentication

    Sirius Mods provides the facilities that make it possible to build an HTML, form-based user authentication facility. This type of authentication can provide several advantages over the standard HTTP-based authentication schemes:

    • It can provide a friendlier and prettier interface to the end-users because the interface is an HTML page. This HTML page can contain as much information as end-users will need.
    • It can provide input fields for userid, password, and new password.
    • It is much more flexible for returning information about reasons for failed logins, impending password expirations and last access to system by user than an HTTP authentication scheme.

    Form-based authentication has some disadvantages compared to HTTP authentication, however:

    • The interface requires that the user is presented with an HTML page when the user has requested some other page but she has either not logged in or her session has timed out. This means that the login form should probably make some effort to get the user back to where she was when the required login was detected. This is not always a simple thing to do and, regardless, requires a bit of User Language coding. HTTP authentication works out-of-band, that is, a login pop-up window appears independent of the page being requested or posted.
    • The form-based user interface must be built by someone.

    Form-based user authentication can be a very useful alternative to HTTP-based authentication. For more information about form-based user authentication, see "Form-based user authentication".

  • HTTP password authentication

    Still a pretty good option for user authentication with Janus Web Server, HTTP password authentication works as follows from a user's perspective:

    1. When a user requests access to a URL for which she is not authorized, the user is prompted for a userid and password.
    2. This userid and password then allow access to all other URLs available to the entered userid on the same web server port.
    3. Should the user request a URL that is not available to the userid under which she logged on, she will be prompted to enter a new userid and password. If she chooses to do so and the userid and password are correct, subsequent requests will run under the new userid. The user can also choose not to enter a new userid and password and to simply go back to URLs that are available to that user.

    The important thing to keep in mind is that from a user's perspective, a userid and password for a web server port are valid for the life of a browser session. But there is no such thing as a browser "session" with a web server. Each request for a URL is a separate TCP/IP connection between the browser and web server.

    So how is user authentication accomplished with the HTTP protocol?

    • The first time a browser requests a URL on a server that is restricted to one or more userids, the server sends back a completion code of 401 which means that the user is unauthorized to view that URL. The server also sends back response header called "WWW-Authenticate" that contains a value "Basic realm=" followed by some text that is a descriptor of the server or subset of the server to which a userid and password are to apply.
    • This causes the browser to bring up a pop-up window that contains an area for a user to enter a userid and a password. The pop-up window will also contain the text sent by the server after the "Basic realm=".
    • If the user enters a userid and password, the browser re-sends the request for the original URL along with an extra request header parameter, "Authorization". The Authorization header parameter has a value that contains the base64-encoded userid and password as entered by the user. Note that this userid and password is easily decoded by anyone that has access to data being transferred from browser to server so it is recommended that it only be sent over an encrypted (SSL) connection.
    • If the userid and password are valid and allow access to the requested URL, the server simply returns the "contents" of the URL to the browser.
    • On all subsequent requests to the same web-server port, the browser sends the last successful Authorization header with the request for each URL, whether or not a particular URL is restricted by userid. This is because the browser has no way of knowing which URLs are protected and rather than risking the receipt of a 401 status from the server it simply sends the Authorization header just in case. If a URL is unprotected, a server can (and Janus Web Server will) ignore the userid and password sent in the Authorization header parameter.
    • If the userid and password sent by the browser are valid but the userid is not authorized to view the URL, a server can send a completion code of 401 "Unauthorized" to the browser which will cause the browser to bring up a logon pop-up window, allowing the end-user to logon to a different userid, one that might have access to the requested URL. This is the default action for Janus Web Server. A server can also simply return a 403 "Forbidden" status to the browser or it can send (or redirect) to a page that explains the problem.

Web security realms

One unfortunate aspect of most browser implementations is that they do not present the text returned with a 401 completion code in the logon pop-up window. With Janus Web Server, this means that an end-user would not be able to distinguish a

%rc = $Web_Done(401, 'Userid required')

from a

%rc = $Web_Done(401, 'Userid ' WITH $Userid WITH ' not authorized to view URL')

unless the user clicks on the "Cancel" button or its equivalent in the logon pop-up window. At this point, a web page sent by the server along with the error status would be displayed. This page could contain any level of detail but it is, in a certain sense, too late. With Janus Web Server server, incidentally, the web page sent with any status other than a 200 "OK" will be a dynamically generated page that simply contains the text of the status with the explanation "Unable to process browser request."

The only piece of information that can be sent by a server that would appear in a logon pop-up window is the "realm" which is sent by the server in the WWW-Authenticate response header tag. Unfortunately, there is no standard for how a browser displays the realm, so whatever is sent for the realm might appear syntactically correct on one browser but syntactically incorrect (or at least a bit odd) on another browser. Furthermore, as one might expect, the realm is used by the browser for purposes other than for display in the logon pop-up window. Specifically, the realm is used as a way a browser associates particular passwords with particular parts of a web site.

For example, suppose a browser receives a 401 "Unauthorized" with the realm set to Model 204 administration. The user enters a valid userid and password, say userid SWEENY and password TODD, and receives the requested URL and several subsequent URLs from the same server. Then the user switches to a path on the server for which SWEENY is not authorized. The user receives a 401 "Unauthorized" but this time with the realm set to Human resources. Then the user enters a new valid userid and password, BENJAMIN and BARKER, and gets access to the requested URL.

Suppose the browser then requests another URL, sending userid BENJAMIN and password BARKER, but receives a 401 "Unauthorized" response from the server with the realm set again to Model 204 administration. In this case, the browser should realize that the old userid and password of SWEENY and TODD apply to the requested URL, and it should send the request again with this userid and password combination without re-prompting the user for them. In this way, a user might switch back and forth between URLs that require different userids without constantly being prompted for userids and passwords. Of course, whether browsers actually do this is a browser implementation issue and should be tested with browsers that are to be supported.

Note that it might be tempting to use the realm to allow users to use the same userid and password with different servers. This will not (or at least should not) work because the browser should not send a password from one server to another server even if the realm passed with a 401 "Unauthorized" is identical between the servers. If it did, it would be possible for an unscrupulous individual in control of one server to get users' passwords from another server by simply sending a 401 "Unauthorized" to the browser with realm set appropriately.

Note that even if browsers don't send the password automatically, careless users can still be tricked into giving up their passwords for one server while accessing another by setting the realm to the same value as another server. Of course, a user might accidentally type in a userid and password for one server when accessing another no matter what one does.

In any case, the use of the web realm in managing multiple userids and passwords to access a single server can be at odds with the use of the web realm to simply pass information into the logon pop-up window. Janus Web Server sets a default web realm of the words "Model 204" followed by the jobname (or virtual machine userid) of the Online in parentheses. This can be overridden by the WEBREALM parameter on the JANUS DEFINE command for a port or by the $Web_Realm function.

Changing passwords

One fairly common end-user operation in a userid/password based authentication environment is the changing of passwords. In user access based on persistent connections such as 3270 or client-server sessions, password changes present no special challenges. Users can change their passwords with some standard mechanism, often at logon time and if successful, the new password has no affect on the current session only coming into play on a subsequent login.

HTTP user authentication, however, presents some special challenges to providing a simple, intuitive password change mechanism to end users. The first problem is that HTTP is connectionless so the fact that a password change has no effect until a subsequent logon is cold comfort — a subsequent logon is the next page requested for a protected URL. This would not be a severe problem, however, if HTTP had the notion of password changes built into it — it doesn't. Put simply, a large part of the problem is that there is no way for a server to tell a browser that a user has changed her password and what the new password is. This means that even though a user might have successfully changed her password, the browser will have the previous password saved and will try to use it on the next request for a page from the server. Janus Web Server has a wide variety of facilities for helping to work around these limitations, but none of these are wholly satisfactory because of the limitations of the HTTP protocol.

So how can a user change her password with Janus Web Server? The simplest mechanism is that when the user first accesses a protected URL on a web server and receives the 401 "Unauthorized" response from the server and the browser brings up the logon pop-up window, the user can enter a new password after the current password separated by the colon (oldpassword:newpassword). When Janus Web Server receives such a password, and if the current (old) password is valid for the userid, the password is changed and processing continues.

Another mechanism is an APSY subsystem can be written that runs with system manager privileges and can be accessed via a JANUS WEB ON rule. This subsystem could put up an HTML form that when posted causes the subsystem to issue a LOGCTL C command for the logged in user. This becomes difficult, however, if authorization is being done via RACF, ACF2 or Top Secret where a LOGCTL C command is not appropriate. It might still be possible to write an application that changes the user password via a job submitted with USE $JOB but this becomes very complicated, presents some difficult timing problems and introduces even more security exposures.

The advantage of the first approach is that it requires no programming and will work easily with external authorizers. The advantage of the second approach is that it can provide a friendlier interface to the end-user and can be accessed even after a user has successfully logged into a server. Because current browsers have no "change password" option, to change a password with the first approach a user would have to either exit and re-enter the browser or request a URL that would cause a 401 "Unauthorized" to be issued by the server causing the browser to redisplay a logon pop-up window allowing the user to change her password. This URL would have to have code behind it to be clever enough to not send a 401 "Unauthorized" after a successful password changed. One way this could be accomplished is with a NEWPASSWORD exception handler.

A third password change mechanism is also available to Janus Web Server sites, namely the use of NEWPASSF or NEWPASSF2 fields. Basically, by specifying either NEWPASSF or NEWPASSF2 on the JANUS WEB ALLOW rule for a URL or set of URLs, Janus Web Server is informed that a POST (form submission) for that URL is to cause a password change and that the new password is in a form field whose name is specified after the NEWPASSF or NEWPASSF2 parameter. Obviously, the NEWPASSF or NEWPASSF2 field should be an <input type="password"> field so that the user's password does not appear on her workstation. This approach, from an end-user perspective, looks identical to the approach where an APSY subsystem issues LOGCTL C commands. The chief advantages of this approach are that the password changes occur at a "lower level" and so are in some sense more secure, that user passwords don't "float around" in application code where they might somehow be divulged and that it doesn't require the writing of the application code to issue the LOGCTL command. In addition, this approach works when an external authorizer is being used.

Regardless of the mechanism used to change a user's password, the next question that arises is what to do after that. The problem is that after a password has been changed, the browser still believes that the user's password for the server is either oldpassword:newpassword if the logon pop-up window password change mechanism was used or oldpassword if a form-based mechanism was used. For the logon pop-up window oldpassword:newpassword mechanism and the NEWPASSF mechanism Janus Web Server's default behavior is to immediately issue a 401 "Unauthorized" even though the password change was successful! While this might seem counter-intuitive, it immediately notifies the browser that it's current password for the server is no longer valid. The user can then "tell" the browser her new password by entering it in the logon pop-up window. This might be preferable to the user getting the pop-up window somewhat later or perhaps several times because the browser simultaneously started multiple requests for protected embedded images in the page that instigated the password change.

The other advantage of immediately issuing a 401 "Unauthorized" after a password change is that the browser is informed that its saved password is no longer valid without a failed login that can cause the logging of a security violation. If the 401 "Unauthorized" is deferred, it will only occur after a failed login attempt with the old password which will, if using an external authorizer like RACF, Top Secret, or ACF2 cause a login failure to be logged. If, in spite of these advantages, an immediate 401 "Unauthorized" after a password change is deemed undesirable, a site can suppress it by specifying NEWPASSWORDC (NEW PASSWORD Continue) on a port definition or by specifying a JANUS WEB ON NEWPASSWORD rule.

Unfortunately, without training or advance warning an end-user would probably be puzzled to receive a logon pop-up window immediately after or some time after changing her password. The user might wonder if her password change failed and might try logging on with her old password or perhaps try changing her password again causing yet another logon pop-up window to appear. There are several ways one might mitigate this problem, none of them ideal:

  1. If using a password change HTML form, the page containing the form can contain an explanation that after a successful password change the user will receive a pop-up window requiring re-entry of the new password. Unfortunately, this depends on end-users reading the information presented to them and understanding it, something that cannot always be counted on.
  2. A JANUS WEB ON NEWPASSWORD exception handler can be written that returns a page that contains text like "Congratulations, you've successfully changed your password; reload the page or click here to receive a logon pop-up window where you can enter your new password.". Alternatively, a JANUS WEB REDIRECT NEWPASSWORD rule can be written to redirect to a page containing similar text. The problem with this approach is that it s a bit cumbersome, causing the end-user to go through three or more interactions with the web server just to change her password. This might not be considered a big problem if password changes are relatively infrequent (as they probably should be). Another problem might be that it would be difficult to set up such a mechanism so that a user can pick up where she left off. Once again, if password changes are not too frequent, it might not be too horrible to simply leave the end-user to her own devices to get back to where she was.
  3. In any case, the web realm can be set (probably in a NEWPASSWORD exception handler) with $Web_Realm to contain text like "Password has been changed, re-enter new password". While this adds a bit of explanation to the logon pop-up window, the explanation might be syntactically stilted or worse in the context of the surrounding text placed there by the browser, and this misuse of the web realm could cause other problems with browser password management.

Password expiration

Another password management feature that users of session-based interfaces take for granted but poses great difficulties for web-based user authorization is password expiration. With session-based systems a user with a soon to expire password is informed of this at logon time, perhaps given a opportunity to change her password and then allowed to run applications. In addition, if a user's password is expired, the user is informed of this and then either told to enter a new password or to logon again, changing her password at logon time.

With the HTTP protocol, a user's first interaction with a web server can be at any URL and so every userid protected URL should, in theory, be able to present a "password about to expire" message. But certainly it's a daunting task to design every URL so that it can contain such a message. With Janus Web Server, a better approach might be to write a procedure that gets run for every connection (the CMD on the port definition) that checks for a "password about to expire" message and redirects the browser to a URL that informs the end-user of the situation or simply presents a page with this information. Note, however, that some mechanism such as session cookies must be used to prevent presenting the warning page more than once per browser session. To check for "password about to expire" messages from an external authorizer, Janus Web Server programs can use the $Web_Num_LogMsg and $Web_LogMsg functions. The $Web_Num_Logmsg and $Web_Logmsg functions can also be used to inform users of other potential problems that session based interfaces provide at logon time such as failed logon attempts. Not all external authorizers might warn users of impending password expiration, however, and it might just be considered too much trouble to warn users of impending password expiration. It might be decided to simply wait until a password expires and then deal with the situation.

This brings us to the second problem. When a password is expired, it results in a login failure. When using a session based interface, the login failure is accompanied with a message indicating the reason for the login failure — expired password — so that the user understands that she typed the userid and password correctly but must change her password. But with a web browser there is no "standard" way of informing the end-user the reason a logon failed. Janus Web Server's default behavior for a logon that failed because of an expired password is to simply treat it as any other logon failure and send a 401 "Unauthorized" to the browser which simply brings up a logon pop-up window on the user's workstation. With no appropriate feedback, the end-user might believe that she has mistyped her password and simply re-enter it, causing yet another password expired logon failure, resulting in yet another logon pop-up window.

To deal with this problem, a LOGONERR exception handler should be written to try to determine the cause of a logon failure (probably with the $Web_Num_Logmsg and $Web_Logmsg functions). For a password expiration situation, the LOGONERR exception handler could either:

  • Send a 401 "Unauthorized" to the browser but also set the realm with $Web_Realm to text that indicates the password has expired. This misuse of the web realm might cause problems, as explained in "Changing passwords".
  • Send or redirect to an HTML page that explains to the user that her password has expired and that the password field in the next logon pop-up window that the user receives should be filled in with oldpassword:newpassword because the user's password has expired. Some mechanism such as session cookies must be used to allow the explanatory page to alternate with logon pop-up windows.
  • Send or redirect to (the latter is probably preferable) an HTML form that allows the user to change her password as explained in "Changing passwords". This page could contain text explaining the reason for the unexpected appearance of the change password form.

Some security systems change a user's password every few minutes and end-users are provided with smart-cards the give the user their password for the minute. Because HTTP user authentication resends and so reverifies the user password with every request, it does not work very well with automatic password change systems: each time a user's password changes the user is forced to login again. Sirius Mods provides login sessions via either the SSLSES or SESCOOKIE port definition parameters that allow login sessions to be held independent of the password of the moment. This support is essential to allow HTTP user authentication to work correctly in a automatic password change environment.

Form-based user authentication

Janus provides several facilities for presenting form-based user authentication. Still, however, the HTTP protocol has limitations that force some tradeoffs in design and complexities in the code to support that design.

Maintaining login sessions

The first thing required to perform form-based authentication is a method for maintaining login sessions. Without login sessions, each request (that is, each page) would require user authentication, which means that in a form-based system, every page would bring up a login form. Clearly, this would be unacceptable. So after a user has successfully logged in, the fact that the user has logged in to a particular userid must somehow be maintained between pages.

Janus Web Server provides basically three options for maintaining a login session:

  1. Binding a userid to an SSL session.

    The SSL protocol has a concept of "session" that is highly secure and reliable. If the SSLSES parameter is specified on the Janus port definition, Janus Web Server will internally associate a userid with an SSL session after a successful login, so it bypasses user authentication on subsequent requests for that session.

    The disadvantages of this approach are:

    • It requires Janus Network Security.
    • It can be defeated by a proxy server that shares a single SSL session among multiple users.

    It is not known if any proxy server actually does this, but it is at least a theoretical possibility.

  2. Using Janus Web Server session cookies.

    The SESCOOKIE parameter on a port definition indicates that Janus Web Server is to create a session cookie on a successful login that contains the userid and other validation information. While a user that spies a session cookie, say by using a network snoop utility, can send the cookie to Janus Web Server and get unauthorized access to a system, this is not really a new exposure, since any user that can spy the session cookie can also spy the user password and so gain unauthorized access simply by using the other user's password.

    The important thing about Janus Web Server session cookies is that it is impossible to spoof the cookies without spying such a cookie. This is because the validation information in the session cookies is based on and verified against random data that is kept on the Janus Web Server. To spoof a session cookie would require access to this random data, which Janus Web Server makes more or less impossible.

    The one downside to this approach is that it uses cookies and runs directly into the myth that cookies are not "secure," whatever that means. While this is a myth and is somewhat akin to saying that software is not secure (well, yes, it can be), myth can be a difficult thing to fight.

  3. Using application-generated cookies.

    While you can use this approach, and it might even provide some extra functionality over Janus Web Server session cookies, this is not really recommended. First, this technique will cause the NEWSESCMD command to be run on every request, since the NEWSESCMD will be responsible for validating the cookie. Whereas for Janus Web Server session cookies, Janus Web Server does the cookie validation under the covers without any User Language being run. This, of course, means more overhead for application-generated cookies. Furthermore, it is extremely difficult to generate application cookies that are not spoofable (that is, can be generated without knowledge of a user's password).

    It might be tempting just to place the user's password in a cookie. While this would work, it would be somewhat dangerous: the password would then be sitting in the browser's cookies, which might be viewable locally. This issue can be ameliorated by using a secure cookie with SSL.

The simplest way to do form-based user authentication is to use a port's NEWSESCMD command whenever user authentication is required. If using Janus Web Server SSL sessions or Janus Web Server session cookies, this would be whenever the following occurred:

  • A userid-protected page is requested and no user session is yet established.
  • The session has timed out.
  • The requested page is not available to the user for which a session is established (but is available to other users).

If neither built-in Janus Web Server session technique is used, the NEWSESCMD is run for every request to a userid-protected page. For simplicity, subsequent discussion will assume that Janus Web Server sessions of one kind or another are used.

Offering login immediately or after redirection

When the NEWSESCMD command is run, either as an included procedure or as an APSY subsystem, the first decision that must be made is whether to present a login form immediately or to redirect to a special login URL.

The advantage of the immediate-login approach is that there is then no need to try to help the user get back to where she was when the login page came up, since the URL for the login page would be the same as for the originally requested URL. While there is something to be said for this approach, it might be viewed as somewhat "tacky" from an HTTP perspective, since from the browser's perspective the contents of a URL are the password page. Depending on the browser, certain user actions navigating to or from such a password prompt page could result in the password page being brought up at an inappropriate time, such as when a user has a session established.

The redirect approach is "cleaner" from an HTTP perspective, but it can make it difficult to get the user back to where she was when the login page was brought up. This can be especially problematic if a user's session times out, which leaves two choices:

  1. Not bother (forcing the user to get back to where she was herself)

    Not bothering offers simplicity and is no worse than session timeouts on a 3270 application (which always force a user to log back in and navigate to where she was).

  2. Make an effort to get back (knowing that some cases, such as a POST, will not work)

    The typical approach to allowing a login page to return a user from where she came is by saving the current URL in a cookie or as part of the isindex data for the login page on the redirect. Both ways are threatened by the 255-byte string-length limit in Model 204, but they would work reasonably for most "normal" URLs. The cookie approach could be made to work for even longer URLs by using multiple cookies as needed, though of course, this is somewhat more work.

    Typically, the redirect approach would start out with some code in the NEWSESCMD program that checks the current URL, and if it is not the login URL, the code redirects to the login URL (after perhaps tucking aside the current URL):

    %url = $web_hdr_parm('URL') IF %URL NE '/LOGIN' THEN %rc = $WEB_SET_COOKIE('LOGINURL', - $web_hdr_parm('URL') With '?' - With $web_hdr_parm('ISINDEX') - , , '/LOGIN') %rc = $web_redirect('/LOGIN') Stop End If

Setting up Web rules for login

The next issue is the appropriate JANUS WEB ALLOW rules for the login URL. One option is to make the URL public for GETs but require login for POSTs. While this might work, it provides a fairly complicated interface, so it is not recommended. Another approach is simply to always require a user login for the URL and so, hopefully, force a user login. The following JANUS WEB rules would accomplish this:

JANUS WEB WEBPORT DISALLOW /LOGIN JANUS WEB WEBPORT ALLOW /LOGIN USER *

One problem with this approach is that if a user requests this URL and already has a login session, the NEWSESCMD command would not be run. This would mean that the ON rule for the login URL should cause a page that redirects to some standard home page, sends an "already logged in" page back to the user, or does a $Web_End_Ses and redirects back to itself. This latter option might look like a redirect loop to some browsers, so it might not be honored unless the login URL processing bothers to change the URL by appending some random isindex data onto the end of it as in:

%rc = $web_end_ses %rc = $web_redirect('/login?junk=' With $web_date) Stop

This approach would also be useful if certain URLs are only allowed to specific userids. In this case, a user might have a login session active but be redirected to the login URL anyway because the logged in userid does not have access to the requested URL. One unfortunate aspect of the dummy isindex data approach, however, is that it creates "junk" browser cache entries for the login URL.

A generally better approach would be to use rules that guarantee that the NEWSESCMD command will always be run when the URL is requested. This can be accomplished by allowing the login URL only to a bogus userid, as is accomplished by the following web rules:

JANUS WEB WEBPORT DISALLOW /LOGIN JANUS WEB WEBPORT ALLOW /LOGIN USER ','

Given this approach, all processing for the login URL will always take place in the NEWSESCMD processing, which is quite convenient.

Displaying a login form

Once processing a login URL, the first step is to display a form that lets the user log in:

%rc = $web_on Html <html> <head><title>Login page</title></head> <body> <form action={$WEB_FORM_ACTION}> <table> User <input type="text" name="userid" value="{%USERID}" maxlength=8 size=10> User <input type="password" name="password" maxlength=8 size=10> <input type="submit" value="Login">

  </form>
  </body>
  </html>

End Html

Notes:

  • $Web_On is essential for outputting any HTML in NEWSESCMD processing, since by default NEWSESCMD processing does not send terminal output to the browser.
  • The value of %USERID could come from a default userid for the user's IP address, or from a POST for the login URL that either did not result in a successful logon or that got a "password about to expire" message from an external authorizer.

One of the advantages of form-based user authentication over HTTP user authentication is that the form could be built with an entry field for a new password. This simply requires an extra couple of lines on a form, like the following:

<tr><td>New password <td><input type="password" name="password" maxlength=8 size=10> <tr><td>Verify new password <td><input type="password" name="password" maxlength=8 size=10>

The login page could, of course, also contain organizational news or security policies.

Processing a posted login form

Once presented with a login form, the user would enter a userid and password and possibly a new password, then submit the form. The NEWSESCMD command would again be run, this time for a POST of the form.

The NEWSESCMD processing should detect the POST, validate the incoming data, then try to do a login for the userid and password. Some basic checks would look something like this:

%userid = $web_form_parm('USERID') If %userid = '' Then %error = 'Userid required' Jump To SHOWFORM End If %password = $web_form_parm('PASSWORD') If %password = '' Then %error = 'Userid required' Jump To SHOWFORM End If

Note that the null password check is especially crucial, because $Sir_Login would do a trusted login if a null password is passed to it. Without the null password check, any user could log on to another user's ID simply bu not entering a password. Other checks could be added before trying a login; for example, users could be limited to specific IP addresses:

%userid = $web_form_parm('USERID') IP: In File IPAUTH Fd USERID = %userid End Find %ipaddr = $web_ipaddr For 1 Record In IP IPA: Feo IPADDR If Value In IPA EQ %ipaddr Then Jump To IPOK End If End For End For %error = %userid With - ' not allowed from IP address ' With - %ipaddr Jump To SHOWFORM IPOK:

After basic validation of form parameters, the userid and password can be used in an a login attempt. This can be done with the $Sir_Login function, as in:

%rc = $sir_login(%userid, ,%password)

The second parameter for $Sir_Login is an account ID. $Sir_Login returns a 0 if the login succeeded and a 1 if it failed. $Sir_Login also has optional parameters to allow password changes and to have login messages captured to a $list or to a Stringlist object.

Capturing messages to a $list, for example, can be especially useful to provide meaningful information to the end-user about why a login failed and perhaps to determine that a password is about to expire (and so to insist that the user change her password):

%list = $listnew %rc = $sir_login(%userid, ,%password, %newpassword, , %list) If %rc Then %error = $listinf(%list, 1) Jump To SHOWFORM End If If $index($listinf(%list, 1), 'will expire') Then %error = 'Password about to expire, ' With 'new password required.' Jump To SHOWFORM End If

If a login fails, the appropriate action is to display the login form again, perhaps with the error messages indicating the reason for the login failure, and perhaps with the userid filled in with the userid with which the user had attempted to log in. The form could either be redisplayed with a $Web_Done or a $Web_Form_Done. $Web_Form_Done is the preferred approach because it eliminates the POST entries from the browser cache.

The problem with using $Web_Form_Done in this context, though, is that there will be no userid to help distinguish requests for the same URL from different users, so it would be possible for one user to see another user's login error page. While this would not be a security concern, it would certainly be very confusing for end-users. This is not an issue if every user will be coming in from a unique IP address, but if that is not the case, the WEBCOOKID port definition parameter should be set to ensure proper functioning of $Web_Form_Done in NEWSESCMD processing.

Some external authorizers provide information on a successful login indicating the user's last successful login time (and perhaps dates and times of failed login attempts). One way to provide this information to the end-user is with a login confirmation page that might look something like this:

Html <html> <head> <title>Login to {%USERID} successful</title> </head> <body> Congratulations, you have successfully logged in as {%USERID}. The following messages were returned by ACF2: <pre> End Html For %i From 1 To $listcnt(%list) Print $listinf(%list, %i) End For Html <br><center> <a href="{%CONTINUE}">Get to work.</a> </center> </body> </html> End Html

In the above example, %continue could be set to a standard home URL or to the URL that initially redirected to the login page. It could even be a null string, resulting in empty quotes ("") which indicate that the current URL should be accessed (which would make sense if the login forms are brought up directly from any userid-protected URL).

If no login confirmation page is wanted, the NEWSESCMD code could simply Stop and let normal URL processing take over if the login form was simply displayed as a response to a request to a userid-protected URL. If the login page was the result of a redirect, a successful login could immediately redirect back to a continuation page, either a standard start page or the page that caused the redirect to the login page:

For %i From 1 To $listcnt(%list) %msg = $listinf(%list, %i) %cookiename = 'Loginmsg' With %i %rc = $web_set_cookie(%cookiename, %msg) End For %rc = $web_redirect(%continue) Stop

The setting of the cookies in the above example is only done so any login messages could be displayed on some or all application pages, perhaps in a standard header or footer. If this is deemed more trouble than it's worth, the cookie code is totally unnecessary.

Note that any displays of forms from a NEWSESCMD should be considered ephemeral, that is, the browsers should be told not to cache them. There are numerous ways to accomplish this, but unfortunately none definitely works with all browsers. Some or all of the following statements might reduce the cache-life of a NEWSESCMD page:

%rc = $web_expire($web_date - 1000000) %rc = $web_last_modified($web_date) %rc = $web_response('Pragma', 'No-cache')

Form-based user authentication can provide a much friendlier and flexible user interface than HTTP user authentication. Unfortunately, it also involves considerable work to set up, and as with any user authentication, it runs afoul of various HTTP limitations and oddities. Still, it is probably a good choice in many environments.

Authorization and WWW-Authenticate headers

Under Model 204 7.7 and later, you can access the complete Authorization request header, and you can set the WWW-Authenticate response header.

  • To access Authorization, use the standard $Web_Hdr_Parm functions. For example, to copy this header into a Longstring:

    %auth is longstring %ls = $web_hdr_parm_lstr("Authorization")

    Janus Web does not uppercase the value for the “Authorization” header.

    Note: Outside of NEWSESCMD processing, $Web_hdr_parm_lstr("Authorization") and other $web_hdr_parm functions will always indicate that this header is a null string.

  • You can set the the WWW-Authenticate response header with a statement like this:

    %rc = $web_response("WWW-Authenticate", - 'Digest realm="Rocketlandia", qop="auth,auth-int", ' - 'nonce="' %nonce:stringToHex '", ' - 'opaque="' %opaqueStringToHex '"' - )

    Although you could do this prior to Model 204 7.7, the WWW-Authenticate response header would only have an effect if a 401 Unauthorized response was sent, and in that case, Janus Web would always put its own WWW-Authenticate header in front of the one set by $Web_Response and browsers would use that one instead. Under Model 204 7.7, if the WWW-Authenticate response header is set, Janus Web does not add its own.

How one uses these headers is an extremely advanced topic, and it requires deep understanding of the HTTP authentication protocols. Such information is beyond the scope of this reference, though you can find plenty of information about it on the Internet.

User access control

Once a user is logged into a Janus Web Server thread, the userid can be used to control access to URLs. One mechanism available with Janus Web Server is JANUS WEB ALLOW rules that specify the userid or userids that can access a URL or set of URLs. If the current userid is not authorized to access the requested URL, Janus Web Server's default behavior is to send a 401 "Unauthorized" to the browser. This causes the browser to present a logon pop-up window to the end-user allowing her to enter a different userid and password, one that has access to the requested URL.

Unfortunately, there is no way for an end-user to distinguish a logon pop-up window resulting from a failed logon from one caused by a "userid not authorized" situation. A confused end-user might believe that she mistyped her password and try again, only to get the same error. Furthermore, many users might only have one userid and password, so the ability to change userid would be cold comfort.

Even worse, the 401 "Unauthorized" would convince the browser that the userid and password it has for the server are no longer valid, so it will force the user to re-enter it, even when it goes back to a URL it has already accessed with that userid and password. This problem can be ameliorated through clever use of the web realm as described in "User authentication", but such a use of the realm interferes with the use of the web realm as a means of getting messages into the logon pop-up window.

Janus Web Server provides the ability to write an UNAUTHORIZED exception handler that can better handle a "user not authorized for URL" situation. An UNAUTHORIZED exception handler could simply send the following if it is known that the end-user does not have an alternate userid:

$web_done(403, 'Forbidden')

Or it could send:

$web_done(401, 'Valid userid but unauthorized to access URL')

setting the realm with $Web_Realm to either get an appropriate message in the logon pop-up window or to facilitate multiple userid/password processing for the browser and end-user. The UNAUTHORIZED exception handler could also redirect to, or simply present, an HTML page that explains the authorization problem. That explanatory page could have a link that points to a URL that will make a userid switch possible.

It might be deemed desirable to use APSY subsystem security in addition to or instead of JANUS WEB ALLOW rules to control access to certain web applications. Careless use of APSY subsystem security could cause an attempt by an end-user to access a URL for which she is not authorized to pass a "raw" Model 204 error message to the end-user such as:

M204.0998: UNABLE TO ENTER THE SIRMON SUBSYSTEM

While this might be deemed acceptable, it does not allow the user to switch userids (if this is feasible), nor does it at least present the end-user with a good explanation of what just happened.

An older approach used a "wrapper procedure" to invoke a subsystem and then deal with the error situation if the user was not allowed into the subsystem (or if the subsystem was not started for some reason). For example, a web rule might specify:

JANUS WEB WEBPPORT ON /MAINT/* OPEN FILE WRAPPER CMD 'INCLUDE MAINT'

And procedure MAINT in file WRAPPER might look like

* Invoke the MAINT subsystem MAINT Begin %rc = $web_redirect('/subsyserr') End

If the subsystem MAINT is successfully entered, and issues a $Web_Done, the $Web_Redirect would cause this message to be logged to the audit trail but would be otherwise harmless:

M204.1029: USER CONNECTION LOST (PHONE WAS HUNG UP)

The wrapper procedure could, of course, be considerably more sophisticated and could even invoke a second subsystem that tries to determine the reason the subsystem didn't send a page (with a $Web_Done) and take appropriate action.

Instead of the wrapper approach, however, a user's inability to enter a subsystem can be more gracefully handled with a NODONE exception handler. For example, the following two web rules indicate that any request for a URL that begins with /MAINT/ should cause the subsystem MAINT to be invoked, but if that subsystem does not issue an explicit $Web_Done (possibly because the user is not allowed to enter the subsystem), the subsystem NODONESYS is to be invoked:

JANUS WEB WEBPPORT ON /MAINT/* CMD MAINT NOAUTODONE JANUS WEB WEBPPORT ON NODONE CMD NODONESYS

NODONESYS could try to determine the cause of the error and take appropriate action, perhaps issuing:

$web_done(401, 'Not authorized for MAINT subsys')