General-Purpose Authentication and Authorization for Webapps
Security is something that no application can afford to ignore, and it is a particularly large challenge for web applications. A web application deployed on the Internet is subject to potential attack from anywhere, whereas an application contained on an internal intranet has at least fewer locations from which it is vulnerable to attack (usually). The HTTP protocol, which most web applications rely on, was not intended as a secure or session-oriented protocol at all. As a result, web applications must make use of a number of techniques to layer security onto this protocol. Those of who are not in the business of wheel-reinventing will immediately look about for a framework, preferably based on existing standards, to provide these services for us. Sometimes, however, no one framework is a perfect fit for the job at hand. We might want some of the features of one framework, but other features that are only available in another. In this article we'll use as a backdrop for our discussion an open source project designed for just such a purpose, the Keel meta-framework. Its security design is a practical example of a security structure that can be applied to many different projects.
The first step in figuring out what someone is allowed to do is to figure out who they are, in a provable manner. Java provides the Java Authentication and Authorization Service (JAAS) API for just this purpose. By selecting and configuring the proper LoginModule (or modules, as more than one can be used) we can easily take advantage of a substantial number of different authentication mechanisms, including LDAP, Microsoft's Active Directory (which is close but not quite LDAP-compliant), file-based and even database-based authentication. Open source LoginModule implementations exist for all of these options, as well as for many more. Multiple LoginModules can even be used to request the user authenticate themselves by more than one means - perhaps a passphrase and a biometric signature, for example.
Ideally, we will use a existing component to provide the front-end for JAAS's LoginModules (which are UI-independent), enabling us to verify the identity of our users with little or no actual coding required. Many frameworks also provide all of the trimmings needed for a complete authentication solution, including a way for a user to request a new password, verify their email address, and other similar operations.
Okay, now we've established, with some degree of certainty (which we'll revisit in a moment), who this user is. In a web application, this does us little good unless we have a way to associate this identity with subsequent requests. Otherwise, the user would have to re-establish their identity with every page request made, and for some reason users seem to find this quite tedious!
The answer, of course, is sessions, which the servlet API keeps track of for us quite handily. In a stateless protocol, there must be some identifier passed with each request so that a session can be associated with it. This can be done via either a temporary cookie, or if cookies are turned off or not available, by 'encoding' each request - including the session identifier as a parameter to each request. In a distributed environment, however, this session must be synchronized with a per-user context on all available application servers. For example, a user logs in and makes a request of the application. It so happens that server "a" handles this request, and records some information about the state of the user's progress in the application. Some web application servers, such as the latest versions of Tomcat, provide a way for multiple instances of the web server to automatically synchronize session information between each other. This handles the web-application layer - but if we are using a multi-tiered application server, we're not out of the woods yet. If the next request the user makes is handled by application server "b", the context may not be available. Keel provides a simple mechanism for ensuring context sharing between application servers, whether on the same machine or distributed in a cluster, allowing sessions to be maintained not only with the web server, but with distributed application servers as well.
As most web-developers know, http can be combined with the secure sockets layer protocol (SSL) to encrypt communications between the browser and the server, as well as providing verification of the identity of the server via the use of a certificate. Developers who have set up servers such as Tomcat are familiar with the process of creating or installing the necessary server-side certificate. (As an aside, the recent introduction in some environments of "SSL filtering", intended for virus and other content-checking, significantly reduces the level of security provided by SSL - it is something to be cautious of). So, SSL can give us a certain amount of assurance that the communication channel is not intercepted, and provides some verification to the user that the site they are talking to is in fact they site it claims to be. Of course, a site using a self-signed certificate is essentially only asserting on their own authority that they are who they claim to be - a certificate signed by a third party (several companies provide this service) adds an additional level of assurance.
Fewer developers, however, have tackled the issue of client-side certificates. These certificates, installed in the client's browser, can provide the same kind of confirmation to the server as the server-side certificates do for the client. They provide an additional confirmation that the client is in fact who they say they are. One issue with https that can arise is that a secure session is distinct from a non-secure session with the same client. This means that using, for instance, a secure https connection for logging in doesn't necessarily mean that the login data will be available to the remaining application. Again, this is an area where your framework should take care of the details, synchronizing secure session data and regular session data, and making sure that requests designated as requiring secure connection are always handled via https. Client-side certificates can also be used to provide some assurance that both ends of a Web-Services communication are who they say they are - but that's another article.