Written by Vaughn Vernon
Solution Pattern
Sign On
Allows an authentic, registered user to establish a session with a system by submitting their predefined credentials. This pattern is also commonly called Login.
[image]
Background
In order to protect system resources from unauthorized usage, the system must ensure that only authentic users are granted access and how all others are denied service. After granting access to the user, the system should also provide a means to relinquish access.
The system needs also to deal gracefully with the situation where where a user forgets their password. Depending on your requirements, you may need greater or lesser secure approaches.
Value and Benefits
The primary value of the Sign On pattern is system security. Security may be necessary because of the sensitivity of user data, whether financial, medical, intellectual, or the like. You want to deny access to individuals who do not have the right to use the system. If there is the potential for loss of revenues on paid-for services (ASP business model or a subscription service, for example), this is a prime reason to secure it. While multiple backend services are available to the registered user, this pattern can make them all available through a single sign on.
Another benefit is to provide a means for registered, authentic users to obtain access to the system if their password is lost/forgotten. Hence, you can secure your system, but avoid spending unreasonable amounts of time supporting those with authentic, but unreachable accounts.
Putting It to Work
This pattern may span every tier in your architecture. For human users who interact with the system via a user interface, this pattern defines the use of a GUI. The pattern also facilitates the authentication of back-office, service-oriented interactions between B2B systems. With such service-oriented B2B systems there is not a GUI, but there must still be a way to check the credentials of the “user,” which in this case is a process running on another system, and likely a remote one at that. Fowler [P of EAA] refers to this as an Integration Gateway within the Service Layer pattern.
So far we’ve identified that there’s a front end to the pattern—a GUI and/or a Service Layer. Next comes another layer that both a GUI and an API must use. If your architecture includes an enterprise framework such as an EJB or COM container (local or distributed), then the next layer is your middle or business tier, as represented by the Remote Façade pattern [P of EAA]. Of course best practices suggest the use of “mini” layers between the front end and the enterprise (such as Business Delegate and Application Service [CoreJ2EE] on opposite ends side of the distributed component), but the enterprise layer is most noteworthy. If you are not using a distributed enterprise layer, then one or more layers should still be employed. For example, you could still use some form of Façade [GoF] to hide access to your next tier.
Most likely the lowest level tier involved in this pattern is your integration tier (also called data tier), which represents the directory service or database containing secure user credentials. Your enterprise façade communicates with your integration tier through a domain object layer. There are several options here, but again your architectural blueprint may already specify what you will use. If you are using Java and a database then this may be an EJB Entity Bean, or a POJO (Plain Old Java Object) via an O-R mapping tool such as TopLink or Hybernate, or JDO, a DOA, or the like. If you are using Java and LDAP then this layer should include the use of JNDI. (I do not recommend the use of EJB Entity Beans here, but I have seen them used for this purpose.) [TODO: What would .NET use to interface with MS SQL Server and/or ActiveDirectory?]
If you are using Java you may want to make use of the Java Authentication and Authorization Service (JAAS) to handle the authentication concerns of this pattern. One observation is that all secured resources must have an implementation of the JAAS Login Module. Unless the vendors of all of the services already provide such a module you are securing access to, you will have to provide implementations yourself. JAAS does have advantages when supporting the signal sign on strategy. If you are not supporting single sign on for multiple secured services, you may not find it advantageous to use JAAS.
[Does .NET have a standard authentication API? State whether it does or not, and if it does briefly explain its use.]
One way or another your software must pass user credentials from the GUI or the Integration Gateway [P of EAA] down to a layer that interfaces with the integration tier and can compare the passed credentials to a set of registered ones.
Use any viable combination of the following strategies to put the Sign On pattern to work. At a minimum you will need to use the Authenticate Credentials and Sign Off strategies. All strategies are backed by standard architecture and design patterns outlined in respective works as previously noted [PofEAA] [Core J2EE] [GoF].
Helpful Links
When users or potential users of the system are presented with a sign on user interface, sometimes they will be unable to provide credentials. For unregistered users it is helpful to provide a link (or a sub-dialog, for non-web GUIs) through which they can register. For registered users it is helpful to provide directions and a link to guide them through recovering a lost or forgotten password. The Registration (page #) pattern also provides this strategy.
Recover Forgotten Credentials
This strategy provides a means to sign on to the system if user credentials are completely or partially unavailable. While we use the term “forgotten,” you may substitute “lost,” or any other appropriate adjective.
The Helpful Links strategy (above) is used to provide the user the ability to initiate interaction with this strategy via the provided GUI once they realize that they must recover their credentials.
The user provides some means of identification, either their registered username or their email address. If they provide a username, then their email address must be associated with it via Fundamental Identity (page #). Either way, you will use their email address to recover the “forgotten” credentials. Emailing information ensures that only users with access to the specific email account will be able to recover the credentials. It is assumed that the requesting individual is the only such user. Even if someone with ill intent requests to recover credentials of another user, the email will only be sent to the email account provided by the person who originally registered. (Observe the similar strategy within the Registration (page #) solution pattern, which ensures that the person who registers is probably who they say they are.) If the real user receives an email informing them that they are recovering user credentials for a specific system with which they registered, then, whether or not they act on the message, no harm is done. The intruder will most likely be bypassed.
How you use email as part of this strategy will further depend on your required level of security. If security is a lower priority then you may simply email the user’s credentials to them in clear text, as is illustrated in the following diagram:
[image]
If security is a higher priority, then email the user a URL that takes them via a browser to a secure Web page that shows them their username and then makes them enter a new password (likely twice). This prevents the clear-text exposure of full credentials over a public network; that is, as long as the web URL your site provides runs over a secure protocol (SSL, via HTTPS).
This strategy may recover both a username and a password. As long as you have record of the user’s unique email address, and the email address is associated with a User (page #) and Fundamental Identity (page #) within your system, you may recover both. However, requiring the user to provide a minimum of a username is more secure.
Use Alternative Credentials
A much less secure alternative strategy to Recover Forgotten Credentials, this strategy is used in conjunction with the question-answer data defined in the User (page #) pattern. As previously noted, this strategy may be considered low security.
Like the Recover Forgotten Credentials strategy, the Helpful Links strategy (above) is used to provide the user the ability to initiate interaction with this strategy via the provided GUI-based links. The next level of presentation displays the question (either canned or user defined) as specified in the User (page #) pattern. The user must then reply accurately with the answer to the question. Whether or not the answer must compare exactly to the original answer (case sensitive, for example) is defined by your requirements and implementation. If the question is answered to the satisfaction of your implementation, then you provide access to the system the same as if the user had provided a proper username and password.
This strategy may also be used in conjunction with Recover Forgotten Credentials. In this case you would require the user to answer the question prior to your sending a recovery-initiating email message. Think of this combination as wearing suspenders with a belt. Either way, you may want to implement the Recover Forgotten Credentials strategy so the user does not have to interact with Use Alterative Credentials continually.
Authenticate Credentials
Assuming that the user knows their credentials, this strategy implements the core purpose of the solution pattern. Using the provided GUI, which should be prominent and easy to navigate to, the user submits their credentials. Per the User (page #) pattern this is generally a username and password. The GUI interacts with an M-V-C controller mechanism ([P of EAA] et al) to pass the username and password to the authentication service. The authentication service interacts with the integration (data) tier, such as a directory service or database, and compares the username and password against the system’s set of registered users. If the username and password match those of a registered user, then the system considers the requester to be authenticated. Otherwise the user is denied access to the system and associated computing resources. The major components found in the reference implementation for this strategy are diagrammed here:
[image]
Case sensitivity is optional, but is highly recommended, especially for passwords. Making passwords case sensitive makes them much more secure. In fact, requiring that passwords be no less than 10 characters and that they contain at least one uppercase letter and at least one digit, will increase your system’s security immensely. [NOTE: Empirical data would be useful here.] Further, if there is concern for the user’s password being compromised, then it would be best if the URL to which credentials are submitted is a secure one, namely SSL; that is, over the HTTPS protocol.
In the case of back-office and partner systems interacting, this strategy circumvents the GUI and accesses the Service Layer API directly to authenticate the “silicon user.”
Preserve User Token
Once the user has been authenticated then some reference to them must be retained for subsequent access to the system. For a web application you will generally store the username, account ID, or even the entire corresponding User object in a long-lived session [NOTE: What does .NET do here?]. I’ll call this object the user token. In some cases such a token may also be stored on the browser as a cookie. However, it is suggested that an in-memory cookie be used. Otherwise, the token could be compromised to other persons.
In the case of the user token being registered as an in-memory cookie with the browser, the cookie is submitted with each request. If a request does not include the cookie, then the user is considered unauthenticated. This will cause that user to be challenged to provide credentials.
In the case of the user token registered with the long-lived session, each time a request is made by the user, their token (again, in the case of a web application) is fetched from their web session and passed along with the request to the business tier. This strategy is illustrated in the introductory diagram for this pattern.
If you determine that the user token must be stored on the client (such as in a browser or as global data in a rich GUI, or for a Service Layer client), then the connection should be secure or the token must be sufficiently encrypted. Otherwise an intruder need only pick off the user token to obtain access to the system and bypass authentication altogether. While it may seem far-fetched, storing the user token on any client GUI mechanism, even if access is managed via a secure protocol, could expose it to compromise. A virus/worm or some other hacker scheme can always disassemble the client-side GUI in search of a user token. Deviants need only motive and access. If the “reward” is high enough, just about no scenario should seem far-fetched. Keeping the token on the web tier as an attribute in the web session or business tier, both behind a firewall, alleviates many security concerns.
Even when a Service Layer or rich GUI is in the mix, you may still maintain a web session in behalf of the user of the rich client, keeping the user token on the server-side. For example, the Apache implementation of the SOAP web services protocol supports session data for each unique client service requester. This is easy for the Apache SOAP implementer to accomplish since the SOAP engine runs in a Java servlet container, which fully supports HTTP servlet sessions.
If you are using .NET [what do we do here?]…
Sign Off
While you may consider this strategy to be a pattern in its own right, we see it as part of the Sign On pattern language. After the user has been authenticated there must be a way for them to relinquish access to the system once they are finished using their current session. Therefore, signing off a system represents the destruction of the user token(s), wherever the may be, and the closing of any system resources that are accessible only by the authenticated user.
If you are implementing a web application using J2EE and store the user token as a session attribute in the presentation tier, then signing off means invalidating the user’s session, which causes it to be destroyed and all related session data to be disassociated:
[code]
If you are using .NET [what do we do here (UI tier-based user token)?]…
If your user token is stored as an in-memory cookie on the browser, then you must successfully request that the browser destroy the cookie.
This strategy may also be provided automatically when a web session times out. Generally the web tier will timeout user sessions at some predetermined time interval of inactivity, such as 30 minutes. When the timeout threshold is reached then the sign off occurs by default as the web container invalidates the user session. If pre-registered, a session listener may be automatically invoked as the session is being closed, allowing the listener to close allocated system resources. You would also use this opportunity to destroy any in-memory browser cookie.
Single Sign On
Single Sign On (SSO) is a complex strategy that provides the means for a user to offer their credentials once and then be granted access to the many heterogeneous systems available on their enterprise. This is necessary because many legacy (and new, for that matter) applications have independent security domains, and the modern user must use many such enterprise applications to accomplish a day’s work. Traditionally a user would have to sign on to each system/application independently of all the others. This is a tedious and frustrating redundant task. It is also mind-bending because a different username and password must likely be remembered for each application.
SSO is costly to develop correctly, and even more costly if you fail at it. I provide a high-level coverage of it here. I highly recommend that you do not implement your own single sign on, but instead purchase a product or obtain a well-supported open source solution.
The short of the SSO solution includes the use of the user token, as was discussed under the Preserve User Token strategy above. Some implementations favor the in-memory browser cookie approach. When the user originally signs on, the user token is preserved. The original sign on may be considered to be against a primary domain. Again, each time that the user makes a request to the same enterprise Web site, the browser’s in-memory cookie is made available to the system. If the user attempts to access to an application or system that is considered a secondary domain that they have not yet accessed, then one of two things generally happens:
-
The newly accessed system determines that the user has not been authenticated. The system challenges the user to provide credentials. The Sign On implementer intercepts the challenge. It uses the in-memory cookie token to look up the user’s credentials for the specific application in the identity and access management data store, and responds to the challenge. The user is authenticated if they have the proper credentials to access the application.
-
The identity and access management service (e.g. the Sign On implementer) knows that the requested URL is one that must be authenticated to be properly used. The access management service proactively accesses the user’s credentials for the specific application, again using the in-memory cookie token to look up the user’s credentials for the specific application in the identity and access management data store, and signs on to the application in behalf of the user.
Both of these approaches are generally accomplished by the access management service interacting with the application via a sign on adapter/connector specifically designed for the application. Such adapters/connectors are generally supplied by the application’s vendor, but may also be custom built if necessary.
While an in-memory browser cookie can be used, a Web session user token may also be used successfully. In either case it requires that the user token be used to gain access to the authentication credentials that the user has for each application. Thus, there may be many such entries managed by the User (page #) pattern.
The user only has the perception that they are only signing on once. In reality they are signing on as often as they would traditionally, except that a back-office component handles the grunt work for them. Note that there may be some other, perhaps less desirable approaches to the actual sign on step for each application:
-
When the user originally signs on to the primary domain, the access management service may use the opportunity to sign on to all systems that the user has access to. This is less efficient on system resources, and the user’s established session may timeout before they try to use it.
-
The user’s credentials are changed to be the same for all systems and applications. The user signs on once and those same credentials are used to sign on to all subsequent systems. This is not a secure approach. If the user’s credentials are compromised, then an un-trusted person can gain access to all available applications.
There is certainly no magic involved here, so expect a significant amount of work if you decide to tackle this problem space on your own. Conventional wisdom says always acquire rather than build for this strategy.
Examples
My J2EE implementation of the basic Sign On solution pattern can be found in the following package, which includes the listed supporting classes, as well as the noted JSP files and our web framework. You may find it convenient to refer to the above diagrams as a roadmap when peering into this code:
[code]
Both the SignOnController and SignOffController run under my simple web framework and are delegated control by the Front Controller [CoreJ2EE] pattern, which is implemented by the following class:
[code]
You may trace all actions from the top layer by examining the JavaServer Pages. The sign on page is a full JSP, while a sign off is managed from within an included page as part of the standard site navigation bar:
[code]
Before drilling down into the SignOnController, first note how the SignOffController affects a sign off (or logout). The Java Servlet API makes it quite easy since all you have to do is invalidate the user session. You must only request that the AbstractDataProvider terminate the session by invoking its endSession() instance method. My Web framework encapsulates this operation, which is basically like a Struts ActionForm:
[code]
The SignOnController has two primary responsibilities. It must first contact the LDAP server to authenticate credentials, and then it must store the user token for each authenticated user in their uniquely allocated Web session. The LDAP server is located behind a few layers. As you can see in the above listing the IdentityManager Remote Façade [P of EAA] represents the enterprise business tier. Next is the domain object layer, which in turn uses a layer of classes that adapt JNDI to my LDAP implementation:
[code]
The secure method for finding a user in the UserFinder class is findSecureUserUsing(). This method simply removes the secret password from the User domain object before returning it to the consumer.
Consequences
You will find the following tradeoffs within the Sign On pattern.
-
Security as Necessary: Particular emphasis is given to recovering the user’s “forgotten” credentials. Use the most secure strategy available per your requirements. Providing a more secure approach to recovering credentials will be more complex. If you are implementing a rich GUI you may require a server-side solution for maintaining user credentials (token) as an added level of security. Also place the URL to which the user credentials are submitted under the control of SSL (HTTPS) if you want to make them much more difficult to intercept.
-
Cleanup Upon Auto Sign Off: If are using a Web tier and your web tier provides timeout-based auto sign off, you may find this a convenient feature. However, as a consequence to auto sign off, you will need to ensure that you close and free up allocated system resources that you associated with the web session. If you don’t do this you could lose access to some precious resources. Generally I avoid maintaining open resources across Web requests, which prevents the possibility of lost resources in the first place. I place the easily disposable user token there. On the other hand, you may require long-lived, open resources to be “pinned” into your session. If so, you’ll have to clean them up when the “silent” sign off occurs.
-
Single Sign On Is Complex: If you don’t require Single Sign On, then avoid it. If you do require it then I recommend acquiring a product that supports it. Since this strategy is so complex, it could be very costly if it is not implemented correctly.
Frameworks and Tools
-
Tools: My reference implementation uses freely available tools such as OpenLDAP for storing user identities. In addition you may find my recommended suite of tools useful, including Tomcat and JBoss, if you are implementing your own solution.
[EOF]