Editor's Note: This is the second article in a series in which the authors propose patterns in the following five categories: Partitioning, Scope, Security, Navigation, and Data Volume Control. Part 1 contained descriptions of the first two categories. This week, the authors discuss Security, Navigation, and Data Volume Control.
Most non-trivial web and enterprise applications have security requirements, and these fall into the following areas:
The security subsystems of most applications will need to provide more than one of the above mechanisms, and frequently all of them. Web applications do not generally implement encryption and message integrity mechanisms themselves, because the HTTPS/SSL technology incorporated into browsers and web servers is sufficient to provide these.
Most of the time, developers spend time and effort building authentication and access control subsystems, even though these features are ostensibly part of the J2EE specification. The reason for this wheel reinvention is that the standard J2EE security mechanisms are often inadequate for the purposes of many applications.
Standard authentication schemes typically return Boolean values to signify permission/denial, whereas an application may require further information, such as whether this is a first-time user, or whether the user's password has expired and must be changed. Similarly, authorization tags in EJB deployment descriptors control access to components, but are not fine-grained enough to enforce, for example, monetary limits on transactions, an essential requirement of many financial applications.
In other words, most attempts to reinvent the security wheel at the application level are aimed at going beyond the coarse-grained, black-or-white logic provided by the J2EE container.
To provide the fine-grained and nuanced security advice required by real-world applications, which J2EE does not offer.
Problem and Solution
Given the need for an arbitrarily fine-grained, multi-valued response to authentication, session validation and access control requests, we propose a special design pattern for such situations. In this pattern, any request to a subsystem providing such services will be accompanied by a single parameter -- an "Access Context." The Access Context object will, broadly speaking, hold information about the user, the function they are attempting to perform, and an optional Value Object representing the parameters to that function.
The subsystem that is called will then analyze these parameters and return a nuanced response that contains more information than just "yes" or "no."
This Nuanced Response wrapper object may contain a status code, an optional qualifier, and an optional set of descriptions. The status code could be an unqualified yes. It could also be one of several values representing an unqualified no, or it could be one of several values representing a qualified yes. If the response is a qualified yes, the associated qualifier object will contain more details, and the client is assumed to know how to interpret these. The accompanying descriptions may similarly represent the set of all status messages that led to this final status. Exact implementations may vary in detail, but the outline solution is for all such calls to have a similar signature, i.e., a single Access Context parameter and a returned value that is a Nuanced Response.
The positive consequence of the Access Context/Nuanced Response pattern is a standard and straightforward mechanism that can be used without great effort once set up. It is capable of delivering adequately fine-grained authentication, session validation and access control for most applications.
The negative consequence of this pattern is the increased initial complexity of the solution. This complexity can be mitigated by having experienced developers code the initial implementations of its use, so that less-experienced developers can use them as templates.
To encapsulate the logic required to answer complex security and state-management queries.
Problem and Solution
An Advisor is our term for the component that accepts an Access Context and returns a Nuanced Response. The Advisor pattern, as we mentioned before, may be used for authentication, session validation, access control, and other similar functions.
For example, a simple way to implement access control functionality would be to delegate it to a specialized Advisor component that determines if a proposed action is permissible or not. The pattern is called Advisor because it does not enforce rules; it merely indicates what should be done by returning an arbitrarily fine-grained Nuanced Response. It is up to the calling component to act on the advice given. Trivial or non-critical business functions may perform their logic without calling an access control Advisor, for example.
The major positive consequence of the Advisor design pattern stems from its encapsulation of all verification logic in a single component or subsystem, which makes it easier to maintain. User roles, for example, can be managed entirely within an access control Advisor without having to be exposed to any other part of the application. An Advisor also acts as a facade for any rules engine it may use, allowing the application to start with a set of simple rules and expand it into a more intelligent mechanism as time goes by.
The negative consequence of this design pattern is that the application's rules are only enforced if components call the Advisor and act upon its advice. If a developer neglects to code a call to an access control Advisor at the start of a business function, for example, then the function becomes freely accessible.
To enforce the application of security and state management rules.
Problem and Solution
The Interceptor pattern is meant to address the drawback of the Advisor pattern by taking away the discretion of calling components to check and enforce rules. It uses a reliable mechanism to always perform such checks before control is passed to such a component. It is not a substitute for the Advisor pattern, but merely an add-on to ensure that the advice of the Advisor is binding.
The new, red-hot technology known as Aspect-Oriented Programming (AOP) is an extremely elegant way to implement the Interceptor pattern.
Obviously, the main positive consequence of the Interceptor design pattern is the increased assurance that rules will be complied with. It also takes away responsibility for rule enforcement from business components, making them simpler.
The negative consequences of the pattern may stem from the need to master new technologies that implement it well (such as AOP), although Interceptors can be coded using regular Java programming techniques, as well. Another consequence is that discretionary bypassing of access control checks (which may be justified in less critical cases, for performance reasons) may be harder to implement.
To pre-emptively block access to unauthorized business functions.
Problem and Solution
There is a design requirement often referred to as "pre-emptive access control." The idea is that if the user is not permitted to perform a certain action, the application should not provide them with the button or menu item to trigger it in the first place. They should only see what they can access.
The Need to Know design pattern is a kind of server-modified Client pattern, in which the server determines the functions that the user may perform and only generates the front-end components corresponding to those functions. (The process of determining which functions are allowed may, in turn, use Advisor and Access Context/Nuanced Response patterns.)
Sometimes, perhaps for marketing reasons, it may be required to display even functions that are not accessible, albeit in a disabled form. (This is a way of saying, "See what extra goodies you can access if you sign up for our Platinum membership?") The Need to Know pattern can support such a requirement as well, when used in conjunction with Advisor and Access Context/Nuanced Response.
The positive consequence of the Need to Know design pattern is a more natural and intuitive application. It locks the stable door before the security horse has bolted.
There is no real negative consequence to the pattern, unless the extra processing required to suppress unauthorized navigation capability is deemed wasteful!
To provide a convenient facade for a set of cooperating security components.
Problem and Solution
The Gatekeeper is a complex Security pattern, which is why we have saved it for last. It uses the Advisor, Access Context/Nuanced Response, and (optionally) Stateless Channel patterns to create a comprehensive security framework for an application. It is a specialized form of the GoF (the "Gang of Four": Gamma, Helms, Johnson, and Vlissides, authors of Design Patterns) Facade design pattern that is most useful for channel-independent business logic, such as that implemented by EJB.
The basic idea is that the entire logic of the application tier is hidden behind a Gatekeeper facade, which performs some coordination functions to simplify the design of other components.
The first contact of a client with the server occurs in the form of an authentication request to the Gatekeeper, which is the only externally visible component on the server. The authentication request contains a single Access Context parameter. The Gatekeeper consults an authentication Advisor, passing it the Access Context, and receives a Nuanced Response in return. The login is either allowed or rejected in an unqualified manner, or it is allowed in a qualified way (e.g., "First login -- change password", "Password expired -- force change", etc.).
If the response is an unqualified yes, the Gatekeeper then activates a State Management component and gets it to generate a session token, which it then passes back to the client as part of the Nuanced Response. Otherwise, it merely returns the original Nuanced Response. Whenever it is called, the State Management component records the session and its expiry time.
(Note that the session token can be managed using the Stateless Channel pattern from this point on.)
Subsequent accesses from the client are to the Gatekeeper as before, but they now consist of requests to business functions. All of the associated Access Context objects must now contain the session token, in addition to the Value Object that holds the parameters to the business function. The Gatekeeper consults a session validation Advisor using this Access Context, and the Advisor returns a Nuanced Response specifying whether the session is valid, invalid, or expired. The session validation Advisor is just an interface implemented by the State Management component. If the session is valid, the State Management component resets the expiry time of the session to keep it alive.
If the session is valid, the Gatekeeper presses ahead with the business function; otherwise, it returns the Nuanced Response forthwith to the client.
It is possible to implement an Interceptor pattern at this stage by having the Gatekeeper consult an access control Advisor before deciding whether to call the business function. If the Advisor says no, the Gatekeeper returns the Nuanced Response to the client and doesn't call the business function at all.
Another option would be to call the business function straightaway and let it decide whether to make the call to the Advisor or not.
Either way, the Gatekeeper acts as the go-between for the client and the business function, and the access control Advisor is called some time before the business logic is executed.
Note that the business functions can themselves implement the Advisor pattern, in that they can advise the Gatekeeper (through a Nuanced Response) on whether they succeeded or not, and if not, what kind of error or warning condition they encountered. The Gatekeeper will then return the Nuanced Response object returned by the business function. This is, in fact, the most natural way to code the application's business functions, once the Advisor/Access Context/Nuanced Response framework is in place.
In the J2EE context, the Gatekeeper and all Advisors are best implemented as Stateless Session Beans. The Gatekeeper is the only EJB that will have a remote interface. Other EJBs (security-related as well as business-related) will only have local interfaces. This ensures that external clients can only see the Gatekeeper. They can never directly access any other component. The security tags in the deployment descriptor can be used to enforce the rule that all access to other components can only occur through the Gatekeeper. The additional checks performed by the Gatekeeper will provide further security around the application's business functions. This combination of container-level and application-level security can be very effective.
We can see that interposing a Gatekeeper facade between clients (or channels) and application logic makes the design much more modular by clearly delineating responsibility for various security and business functions, and imposing a standard and consistent calling convention. It is highly secure, and caters to all of the major security concerns outlined at the beginning of this section (assuming that SSL is used to ensure privacy and data integrity). This is the major positive consequence of the Gatekeeper pattern.
The major negative consequence is that the relative complexity of this set of cooperating components makes it overkill for simpler applications. But if an open source implementation is readily available (we hope to provide one), it should be relatively simple to incorporate it into any application and enjoy its substantial benefits.
Navigation refers to the way in which the user moves through the screens of a web application.
To provide an explicitly recognizable navigation mechanism for novice users.
Problem and Solution
A Tour Guide is our name for any set of components whose existence is explicitly for the purposes of helping a user navigate an application. Menus are the best example; tree-structured outliners are another. Hyperlinks can be Tour Guides, too, if they stand "outside" of the data (i.e., a hyperlink that says Click here).
The Tour Guide pattern is useful when navigation components must be explicitly identified as such. It is recommended for applications with a large number of casual users, who may not be familiar with the logic of the application.
The positive consequence of the Tour Guide design pattern is that the application is readily understandable, even to casual users.
The negative consequence of the pattern is its "kludginess." Any navigation scheme that does not weave itself into the natural fabric of the application by linking data items naturally to one another is, in a sense, redundant and ugly. The justification for this criticism will become clear when we discuss the Iceberg pattern.
To present application data in a naturally linked fashion for intuitive traversal.
Problem and Solution
Consider a hypothetical Internet home banking application.
The user logs in, and sees a list of their accounts with the latest available balances. Each of the account names is a hyperlink, and clicking on any one displays a screen with the details of that account, including, say, the overdraft limits applicable. The current and available balances are displayed in a totals row, but the rows above it are shown collapsed into a "transactions" row in a way that invites the user to click to expand it. When clicked, the screen refreshes to display the last twenty transactions that resulted in the previously shown current and available balances. This is the transaction history. Clicking on any transaction record brings up more details about that transaction, and so on.
Navigating backwards is just as natural. Every screen displays the customer's name and (if applicable) the account name. Clicking on the customer's name takes the user back to the home page that lists all of the customer's accounts. Clicking on the account name takes the user back to the account details page.
What is important to note is that there is no explicit navigation component in this application -- no menus, no special links. Moving through the various screens of the application is naturally tied to the data items displayed, because that is how a user would logically traverse this data.
Our name for this pattern is Iceberg, because each piece of data displayed as a link hints at the greater detail that lies underneath.
The major positive consequences of the Iceberg design pattern are elegance and economy. An application designed with this pattern shows a deep understanding of the way its users actually work with data. It shows that rather than "cop out" with a cookie-cutter design that classifies all its functions under menu items and displays a weak home page, the designers have taken the pains to identify the central focus of the user and display that data in their home page. The paths to all secondary data items flow from the data items on this page.
The pattern's very sophistication can lead to some negative consequences. Novice users may find themselves asking, "Where's the menu? Why doesn't this screen tell me what I can do?" Clearly, the Iceberg pattern is more suitable for tightly integrated applications with trained users. The natural and intuitive flow provided by the pattern will deliver productivity payoffs in such situations.
Most often, consciously or otherwise, designers provide both Tour Guide and Iceberg elements for navigation. This redundancy seems to be beneficial, as it supports novice users as well as more sophisticated ones. Applications employing metaphors may also end up using both Tour Guide and Iceberg elements.
To coordinate and guide user actions so as to maximize system efficiency.
Problem and Solution
An unseen factor in user interface design is management policy. Should the user be in control, or should the system tell the user what to do? This dichotomy often appears in systems with both clerical and executive users. Executive users like to be in control. They like to be able to direct the system and break away at will from set ways of looking at data. Interestingly, executive users also provide the requirements specifications that say how clerical users must interact with the system. The leeway given to clerical users is normally much lesser than that enjoyed by executives.
In such cases, the system displays the data that the users are deemed to need at the time, and nudges them in the direction of the actions they must perform. Little user discretion is possible in such applications.
Consider a hypothetical system where clerical users have two main functions: data entry and reconciliation. Reconciliation consists of matching different data records that were previously entered. Both data entry and reconciliation need to proceed at a more or less equal pace to achieve optimal transaction throughput, although reconciliation requires a certain number of records to be entered first.
On first logging in, users are shown data entry screens, which keep redisplaying blank forms as earlier data is saved. At a certain point, the system determines that a sufficient backlog of data has built up to enable reconciliation to begin. Some users may now find their screens refreshing to display reconciliation functions. They therefore find themselves being nudged in that direction, with the system maintaining the balance of the two functions to maximize throughput. The users have little discretion in their navigation of screens.
This is an example of the Taskmaster pattern, and is applicable whenever user actions have to be guided in a desired direction, rather like sheep being shepherded into paddocks by sheepdogs. It is particularly relevant when the system as a whole is the only entity that has the overall profile of the users and current data, and is the only one capable of determining the most appropriate tasks to be performed next, i.e., for applications requiring load-balancing across users.
The lack of user choice need not be total, merely constrained. For example, users could be shown a set of records and required to choose any one from the displayed list.
The main positive consequence of the Taskmaster pattern is increased efficiency -- factory-floor, assembly-line efficiency.
There are no real negative consequences to the pattern, if used judiciously. Clerical users with transaction targets are often grateful to be relieved of choice. As long as the decisions are being made for them, their job is made easier.
Inadvertent queries that retrieve huge amounts of data are a potential problem, and not just because they may display pages a mile long. Runaway database queries can bog down the server, choke the network, or both. Some mechanism needs to be put in place to ensure that only sane amounts of data get sent back to the client for display.
The following are some of the patterns that can be used to implement data volume control.
To reduce the impact of large queries on the overall system.
Problem and Solution
Any user of a web-based email program understands this pattern. The user is shown a list of, say, the 20 most recent messages in their inbox, with links provided to scroll back to earlier messages. On following this link, a similar page with the previous 20 messages is shown, and the user now has the option to scroll further back or scroll forward to the original set.
This is a pattern that affects not only the user interface, but also the entire data retrieval logic. The server is "throttled" to force the retrieval of only a subset of the total number of data records to be displayed. The subsets are usually distinguished by the identifiers of their first and last records, or some suitable surrogate, and these identifiers are used to control which records to retrieve next.
Borrowing a term from networking theory, we call this the Sliding Window pattern.
The positive consequence of the Sliding Window pattern is that the application gains a readily understood mechanism to control data retrieval.
The negative consequence of the pattern is its complexity, as compared to a straightforward retrieval of all records. It is therefore probably unnecessary when the likely number of records to be retrieved is manageable.
To reduce the impact of large queries on the overall system while providing simpler information to guide user actions.
Problem and Solution
The previous pattern (Sliding Window) breaks up a record set into chunks at the same level of detail. But it is possible to reduce data volume by summarization as well.
For example, consider a Taskmaster screen that displays new, modified, and deleted records for action by a user. The user has to choose a record from one of these three sets and proceed with an appropriate action. In making this decision, the user should be guided by the number of records marked "urgent," as well as by the total number of records in each set. Clearly, it is unnecessary to display the complete listing of all three sets in such a case.
What the user needs on this screen is a set of summary rows that look something like the following:
New records: 1 urgent, 10 total Modified records: 0 urgent, 20 total Deleted records: 0 urgent, 5 total
The user has sufficient information from the summary to make a decision. He or she will probably deal with the urgent new record first, and then tackle the modified records, because they are the biggest set.
Note the hyperlinks on the summary rows. The display uses the Iceberg pattern to lead the user to greater detail.
If the number of records in a given set is extremely large, it may be necessary to employ the Sliding Window pattern to display it when the user uncovers the Iceberg.
The positive consequence of the Summary pattern is a well-understood, simplified interface. It is similar to the Need to Know pattern, except that its purpose is not security but data volume control. Summary information also has advantages in terms of human comprehension, quite apart from data volume control, so the use of this pattern should take into account all of those factors.
There are no real negative consequences to the pattern. There is some processing involved in calculating summary information. If this effort outweighs the savings gained by not displaying the detailed data directly, then it is probably unnecessary.
To avoid the need for unnecessary data retrieval.
Problem and Solution
For certain kinds of user queries, where the required final response is known to be a limited set of data records, it may be worthwhile to force the user to refine their query, rather than waste effort in displaying large numbers of unnecessary data records. A simple message such as "Your query retrieved an abnormally large number of records. Please refine your query and try again" may be sufficient.
Though the Search Refinement pattern is relatively trivial, an explicit identification of this "user tuning" strategy may be in order because it is a somewhat unconventional solution.
The main positive consequences of the Search Refinement pattern are the simplicity and elegance of the solution at the user-interface level.
The main negative consequence is the added complexity required to judge whether
a query is likely to retrieve a large number of rows. In SQL terms, a
may need to be performed before every
select in order to implement this pattern.
We have presented here a number of techniques that we have found ourselves using more than once in our profession as J2EE architects and developers.
Many of these are simple and obvious, but we hope that the set has value for developers in our field. We know from experience that they work well in the appropriate contexts.
We definitely see scope for more Web and Enterprise Architecture Design Patterns, as well as more categories (such as Page Layout patterns, for example). We would love to hear from other practitioners about patterns that worked for them.
We also hope that with the popularization of the patterns we have described here, web and enterprise architects will be able to discuss designs much more succinctly:
"... I suggest we make the Operations Clerk's home page a Taskmaster, with each displayed task being an Iceberg. The Operations Supervisor will get essentially the same page, with more options provided using Need to Know. I don't think there's any need for a Tour Guide, because it's a tight application with only trained internal users ..."
If our paper helps designers communicate sophisticated concepts with a compact vocabulary, reuse tried-and-tested techniques, and get to spend less time at work and more with their families, then the warm glow of satisfied pleasure will be all ours.
Ganesh Prasad is an architect with Westpac Banking Corporation, Australia's third-largest bank.
Rajat Taneja is a contractor with Sun Microsystems, Australia.
Vikrant Todankar is a senior consultant with EDS Australia, on assignment to the Commonwealth Bank of Australia, Australia's second-largest bank.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.