Fine-grained Java EE authorization using Enum-based access control lists with EAz: Part 3: EAz access visualization framework and graphical interface

Java™ developers attempting to exert fine-grained control over access to application resources quickly reach the limits of built-in Java Platform, Enterprise Edition (Java EE) declarative authorization. Part 1 of this three-part series on Enum-based Authorization (EAz) described the basic architecture of a complete Access Control List (ACL) implementation in Java 5. Part 2 described the usage and implementation of an EAz authorization solution. Part 3 concludes this series by illustrating a technique for integrating EAz into a graphical interface, implementing a JavaServer™ Faces solution to the problem of using a Web application to graphically represent which discrete permissions are available to a user or group in a Web framework. This content is part of the IBM WebSphere Developer Technical Journal.

Robert Patt-Corner (rpatt-corner@proqual.net), Chief Technical Officer, Proqual-IT

Robert Patt-Corner architects, designs, and develops enterprise applications for business areas including healthcare, document management, alerting and workflow services, and predictive information gathering. He is Chief Technical Officer at ProQual-IT, focusing on service-oriented architectures. Previously, he was Chief Technical Architect at Noblis (formerly Mitretek Healthcare), leading the team that developed an automated, Web-based healthcare alert service. Robert's certifications include WebSphere Administration, Rational Application Development, and Lotus Administration and Development. You can contact Robert at rpc@dorsetwest.com or rpatt-corner@proqual.net, and you can view his Web site at www.dorsetwest.com or www.proqual.net.



Keys Botzum, Senior Technical Staff Member , EMC

Keys Botzum is a Senior Technical Staff Member with IBM Software Services for WebSphere. Mr. Botzum has over 10 years of experience in large scale distributed system design and additionally specializes in security. Mr. Botzum has worked with a variety of distributed technologies, including Sun RPC, DCE, CORBA, AFS, and DFS. Recently, he has been focusing on J2EE and related technologies. He holds a Masters degree in Computer Science from Stanford University and a B.S. in Applied Mathematics/Computer Science from Carnegie Mellon University. Mr. Botzum has published numerous papers on WebSphere and WebSphere security. Additional articles and presentations by Keys Botzum can be found at http://www.keysbotzum.com, as well as on IBM developerWorks WebSphere. He is also co-author of IBM WebSphere: Deployment and Advanced Configuration.


developerWorks Professional author
        level

27 February 2008

Introduction

Enum-based Authorization (EAz, pronounced "easy") provides a way to implement a complete Access Control List (ACL) implementation in Java 5, including discrete binary permissions, arbitrary named sets of permissions, methods for applying and rapidly testing access control on protected resources, and a means to display the truth table of a particular access control using JavaServer Faces (JSF).

Part 1 of this series described the basic architecture of a complete Access Control List (ACL) implementation in Java 5, and Part 2 described the usage and implementation of an EAz authorization solution, building on the example from Part 1. This article continues with the virtual campus scenario, used to illustrate the earlier articles in the series, to show how a complex authorization model can be implemented through EAz. See the previous articles for more details on the evolution of this solution.

Reviewing the sample scenario

Below, Figure 1 reiterates the virtual campus layout, Table 1 describes the groups and individuals taking part in the example, and Figure 2 shows the ACLs that you will implement in this article using the EAz framework.

Figure 1. Example virtual campus layout
Figure 1. Example virtual campus layout
Table 1. Groups and individuals for virtual campus example
IdentifierTypeGroups
Campus A usersGroup---
Campus B usersGroup---
Campus A Engineers (Engineers)Group---
Campus A Biologists (Biologists)Group---
Campus A Cleaning staffGroup---
Jane LinnaeusIndividualCampus A users, Biologists
Jim FermiIndividualCampus A users, Engineers
Stan the YetiIndividualCampus A users, Biologists
Ken LayIndividualCampus A users, Campus A Cleaning Staff
Danny DafoeIndividualCampus A users
Carla BonheurIndividualCampus B users

As in Part 1, assume the following access rules:

  • Only Campus A users can enter Campus A; only Campus B users can enter Campus B.

And within the Campus A users:

  • Biologists and Engineers can enter their own buildings and public spaces in it; in addition, Biologists can enter the Engineering building.
  • Cleaning staff for Campus A can enter any room except the labs.
  • Jim Fermi is allowed to enter his office in the Engineering Building, Private Office 2.
  • Jim Fermi and Stan the Yeti are the only ones allowed to enter the Engineering Building Secure Lab 3.
  • Jane Linnaeus is allowed to enter her Biology Building Private Office 5,
  • Only Stan the Yeti can enter the Biology Building Secure Lab 6.

The campuses, buildings, and rooms can be secured as shown in Figure 2.

Figure 2. ACL structure for virtual campus example
Figure 2. ACL structure for virtual campus example

See Part 1 for additional details of the virtual campus example, the EAz concept of operations, and details of the major EAz architectural structures.


Requirements for a graphical display of authorization information

Any authorization framework of substantial capability will enable an application to implement a complex and rich set of authorization rules. Understanding and maintaining the rules can be extremely difficult unless there is a way to visualize them succinctly and modify them with minimal reference to pure programming constructs, like Access Control Lists (ACLs). Two types of displays are particularly useful:

  • A display of the actions that can be performed on a secured resource, and the users or groups that are configured to perform each action.
  • A display of the users or groups that are configured to perform any action on a resource, and the actions each user or group is configured to perform.

Table 2 shows a typical display of actions for the virtual campus example, and Table 3 shows users and groups. For the remainder of this article, the term actors will refer to any combination of named users or groups.

Table 2. Configuration actions with original ACL
ACLACTION_ENTER
campusACAMPUS_A_USERS
engrBldgCAMPUS_A_CLEANERS
CAMPUS_A_BIOLS
CAMPUS_A_ENGRS
engrBldgRoom2PRINCIPAL/Jim Fermi
CAMPUS_A_CLEANERS
engrBldgSecureLab3PRINCIPAL/Jim Fermi
PRINCIPAL/Stan the Yeti
biolBldgCAMPUS_A_CLEANERS
CAMPUS_A_BIOLS
biolBldgRoom5CAMPUS_A_CLEANERS
PRINCIPAL/Jane Linnaeus
biolBldgSecureLab6PRINCIPAL/Stan the Yeti
Table 3. Configuration actors with original ACL
ACLCAMPUS_A_ USERSCAMPUS_A_ CLEANERSCAMPUS_A_ BIOLSCAMPUS_A_ ENGRSPRINCIPAL/ Jim FermiPRINCIPAL/ Stan the YetiPRINCIPAL/ Jane Linnaeus
campusAACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
engrBldgACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
ENTER
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
engrBldgRoom2ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
engrBldgSecureLab3ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
ENTER
ACTION_
NO_ACTION
biolBldgACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
biolBldgRoom5ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
biolBldgSecureLab6ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION

As you can see, the tables display identical data, but convey very different information to the human observer. Table 2, organized by actions in the columns, is useful for quickly seeing who is configured to perform a given action, whereas Table 3, organized by actors in the columns, is useful for quickly seeing what actions an actor of interest is configured to perform. Both tables were produced by the EAz visualization framework introduced in this article.

The ability to produce -- and manipulate -- tables of this sort is a key capability for any authorization framework.

Configuration and permission

Configuration and permission aren’t the same thing. In Table 3, for example, Jim Fermi is configured to enter a variety of rooms and labs, but is not configured to enter the campus. From the point of view of the individual ACLs securing the resources, this is exactly correct. But ACLs are only half the story of authorization.

Almost every authorization framework -- EAz no exception -- is backed by some kind of custom registry that defines the users and the groups to which they belong. Table 3 doesn’t show Jim’s group memberships, just the ACLs in which he is configured. The ACTION_NO_ACTION that appears next to his name in the row for the campusA ACL simply indicates that he is not configured in the campusA ACL, but he may well be able to enter the campus gate by virtue of another group of which he is a member.

This separation of group membership and ACL configuration is what permits a framework to be flexible and efficient: you manage by exception in the ACLs, and the only time you’ll find Jim’s name explicitly mentioned is when he needs authorization beyond that granted by his group memberships.

The same situation applies to groups. The CAMPUS_A_CLEANERS group is not configured to enter the campus, although it is configured to enter both buildings and all configured rooms except for the secure labs. This example assumes a registry that permits multiple group membership, and the example expects individual campus cleaners to be members of both the CAMPUS_A_USERS and CAMPUS_A_CLEANERS groups. One group gets them into the campus gate; the other gets them into the buildings. Referring back to the original configuration in Table 1, Ken Lay exemplifies a cleaning person with dual group memberships.

Therefore, you need a third kind of view, with both the actor and action permutations that show the permissions of specified actors when they interact with ACLs, taking into account their group memberships in a registry. The difference can be illustrated with Tables 4 and 5, below.

Recall from the earlier articles (and Table 1) that we have configured three individuals for this sort of testing:

  • Daniel Dafoe is a student on CampusA without any additional privileges.
  • Carla Bonheur is a professor visiting for a lecture and needs to be accompanied and let into any gates and buildings she encounters.
  • Ken Lay is a campus cleaner and can go anywhere except the secure labs.

The joint effect of their registry and ACL configurations are showed with the information in Tables 4 and 5, representing the action and actor organization of information, respectively. Again, an ACL framework needs to be able to generate these kinds of displays to be useful, and the tables themselves were generated from the EAz visualization framework. These displays will be referred to as permission displays, since they give an overall view of permissions rather than pure ACL configuration information.

Table 4. Permission actions (Lay, Dafoe, and Bonheur) with original ACL
ACLACTION_ENTERACTION_NO_ACTION
campusADanny Dafoe
Ken Lay
Carla Bonheur
engrBldgKen LayNO ACTORS
engrBldgRoom2Ken LayNO ACTORS
biolBldgKen LayNO ACTORS
biolBldgRoom5Ken LayNO ACTORS
Table 5. Permission actors (Lay, Dafoe, and Bonheur) with original ACL
ACLDanny DafoeCarla BonheurKen Lay
campusAACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
ENTER
engrBldgACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
engrBldgRoom2ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
biolBldgACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
biolBldgRoom5ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER

In the case of permission tables, an ACTION_NO_ACTION entry indicates a true refusal of authorization, since the registry information is taken into account.

With these four kinds of displays (ACL configuration and overall permission with actor and action variants on each), it is easy to understand an authorization framework and its expected operation.

A complicating example

Let's look at an example that complicates the situation, and illustrates the flexibility of the EAz framework at the same time. Suppose you:

  • Open the engrBldgSecureLab3 to all members of the CAMPUS_A_ENGRS group, which includes Jim Fermi, but not Stan the Yeti.
  • Grant Jim Fermi the privilege to lock the lab anytime he wants so that he can work undisturbed.
  • Enable only Ken Lay to enter and clean the lab to clear out all the clutter the engineers leave behind.

Using EAz and our mock registry in properties files, you can accomplish this change in minutes: in a production scenario, the registration would be in LDAP or a database and, therefore, be even easier to implement with an appropriate registry user interface.

When only Jim Fermi and Stan the Yeti were configured to enter Engineering Building Secure Lab 3, the properties file for the Engineering Building Secure Lab 3 ACL looked like Listing 1.

Listing 1. Original ACL for Engineering Building Secure Lab 3
# Format is groupOrPrincipal=permission
PRINCIPAL/Stan\ the\ Yeti=PERM_ENTER
PRINCIPAL/Jim\ Fermi=PERM_ENTER

To apply our changes, you need to modify the file to look like Listing 2.

Listing 2. Revised ACL for Engineering Building Secure Lab 3
# Format is groupOrPrincipal=permission
PRINCIPAL/Stan\ the\ Yeti=PERM_ENTER
PRINCIPAL/Jim\ Fermi=PERM_LOCK_DOOR
PRINCIPAL/Ken\ Lay=PERM_ENTER
CAMPUS_A_ENGRS=PERM_ENTER

Your displays need to change to reflect the changed authorization schema, and should now look like Table 6.

Table 6. Configuration actions with revised ACL (changes are bold)
ACLACTION_ENTERACTION_LOCK_DOOR
campusACAMPUS_A_USERSNO_ACTORS
engrBldgCAMPUS_A_CLEANERS
CAMPUS_A_BIOLS
CAMPUS_A_ENGRS
NO_ACTORS
engrBldgRoom2PRINCIPAL/Jim Fermi
CAMPUS_A_CLEANERS
NO_ACTORS
engrBldgSecureLab3PRINCIPAL/Ken Lay
PRINCIPAL/Stan the Yeti
CAMPUS_A_ENGRS
PRINCIPAL/Jim Fermi
biolBldgCAMPUS_A_CLEANERS
CAMPUS_A_BIOLS
NO_ACTORS
biolBldgRoom5CAMPUS_A_CLEANERS
PRINCIPAL/Jane Linnaeus
NO_ACTORS
biolBldgSecureLab6PRINCIPAL/Stan the YetiNO_ACTORS
Table 7. Configuration actors with revised ACL (changes in bold)
ACLCAMPUS_A_ USERSCAMPUS_A_ CLEANERSCAMPUS_A_ BIOLSCAMPUS_A_ ENGRSPRINCIPAL/ Jim FermiPRINCIPAL/ Ken LayPRINCIPAL/ Stan the YetiPRINCIPAL/ Jane Linnaeus
campusAACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
engrBldgACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
ENTER
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
engrBldgRoom2ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
engrBldgSecureLab3ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
LOCK_DOOR
ACTION_
ENTER
ACTION_
ENTER
ACTION_
NO_ACTION
biolBldgACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
biolBldgRoom5ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
biolBldgSecureLab6ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
ACTION_
NO_ACTION
Table 8. Permission actions Table (Lay, Dafoe, and Bonheur) with revised ACL (changes are bold)
ACLACTION_ENTERACTION_NO_ACTION
campusADanny Dafoe
Ken Lay
Carla Bonheur
engrBldgKen LayNO ACTORS
engrBldgRoom2Ken LayNO ACTORS
biolBldgKen LayNO ACTORS
engrBldgSecureLab3Ken LayNO ACTORS
biolBldgRoom5Ken LayNO ACTORS
Table 9. Permission actors (Lay, Dafoe, and Bonheur) with revised ACL (changes in bold)
ACLDanny DafoeCarla BonheurKen Lay
campusAACTION_
ENTER
ACTION_
NO_ACTION
ACTION_
ENTER
engrBldgACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
engrBldgRoom2ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
engrBldgSecureLab3 ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
biolBldgACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER
biolBldgRoom5ACTION_
NO_ACTION
ACTION_
NO_ACTION
ACTION_
ENTER

As with the earlier tables, all the information above was generated from EAz using the display framework. The only required changes were in the engrBldgSecureLab3 ACL.


The perspective approach to graphical display

Textual tables, like Tables 2 through 9, are essential for displaying and understanding the authorizaton policies of an application, but a Web-based display with potential to actually modify ACLs and registry memberships would be far more useful.

The main technical challenge in developing a maintenance UI is reliable and maintainable composition and Web rendering of configuration and permission tables, like Tables 2 through 9. Once you have an in-memory representation of the ACL configuration or permissions structure in hand, along with a way to bring the representation forward to a Web display, the work of understanding the current policies is done, and the work of maintaining it is vastly simplified, consisting of:

  • Substituting read-write graphical fields for display-only graphical fields.
  • Writing event handlers and service methods that will interpret changes in the UI and modify ACLs and the registry accordingly.

Next is a description of a technique for visualizing and creating a display of permission and configuration tables using JavaServer Faces (JSF). The implementation can be enhanced to create a full ACL maintenance framework in a straightforward way by implementing the graphical field changes and service methods noted above.

Concept of perspective

The key concept behind the visualization framework is that of a perspective, a concept borrowed from the implementation of the Eclipse graphical development environment. In Eclipse, a perspective is a different view of the same underlying objects. Using our own EAz as an example, Figure 3 shows a Web perspective of the visualization framework, and Figure 4 shows the Java perspective of the same framework.

Figure 3. Eclipse Web perspective of EAuthZWeb project
Figure 3. Eclipse Web perspective of EAuthZWeb project
Figure 4. Eclipse Java perspective of EAuthZWeb project
Figure 4. Eclipse Java perspective of EAuthZWeb project

In each perspective, certain aspects of the underlying set of files that make up the project are emphasized, others are rearranged, still others are de-emphasized or hidden altogether. Both perspectives show the Java source in relatively similar form, but the Web perspective shows a special entry for the Web deployment descriptor, while the Java perspective gives greater detail on the breakout and location of various library collections.

The EAz framework approach to visualization is similar, in that you wrap a set of ACLs in an ACLPerspective object, which rearranges the contents of the ACLs in a way that makes visualization easy. This is a classic application of the decorator pattern, and in fact the original name for the ACLPerspective was ACLDecorator, but the object ultimately brings together and provides a viewpoint on multiple ACLs, so it seems inappropriate to imply that the object simply decorates a single ACL.

Design of the ACLPerspective

Figure 5 shows an overview of the structure of the ACLPerspective object. Looking first at its public methods, the ACLPerspective offers three flavors of constructors. It can provide a view into:

  • A list of ACLs. This constructor provides a configuration perspective, where every display element relates directly to the configuration of the ACLs in the list without reference to registry or other external entities. This constructor is used to produce the configuration displays shown in Tables 2 and 3.
  • A single ACL. This is a convenience method for configuration perspectives dealing with a single ACL.
  • A list of ACLs and a list of MockPrincipals. Part 2 introduced the MockPrincipal as a way of encapsulating the non-Java EE registry concepts of users and groups (for example, actors). A MockPrincipal can represent either a single individual with their group memberships, or a group. This third constructor is used for permission-style perpectives of the sort used to construct the displays in Tables 4 and 5. With the permission display constructor, the caller supplies a set of MockPrincipals, and the perspective supplies views of their interactions with the ACLs in the ACL list, taking their group memberships into account.

The four public methods of the ACLPerspective supply callers with actual views and underlying data structures. The two getAcl..Table() methods, one for an actor-oriented table and the other for an action-oriented table, provide the matrix-formatted information for all eight views in Tables 2 through 9. The two getACL...Map() methods give access to the inner data structures of the perspective for custom displays.

Figure 5. Overview of the ACLPerspective and its inner classes
Figure 5. Overview of the ACLPerspective and its inner classes

ActorRelationships and ActionRelationships inner classes

The ACLPerspective uses two inner classes to encapsulate its knowledge of ACL relationships from the point of view of either actors (that is, actors in the columns and actions in the cells), or actions (with actors in the cells). Much of the main work of organizing a presentation of ACL relationships goes on in these inner classes.

Each of the inner classes has a method to add a relationship appropriate to its class, and accessors (getters) to access the relationships it manages internally. For example, the ActorRelationships class has one method to add an actor and its configured or permitted actions, a second one to retrieve a unique list of actors in the instance, and a third one to retrieve permitted or configured actions using actor as a key.

The inner classes implement these functions using an internal map structure and a set. The scope of the relationships in a given instance of one of the inner classes is a single ACL. For example, one instance of an ActorRelationships class holds the knowledge of each actor that is configured or tested for permission for a particular ACL securing a particular ACLHolder resource, and maps each actor to a list of the actions that each actor can carry out. The converse is true of a single ActionRelationships; it maintains knowledge of each action configured or tested for permission on a given ACL, mapping each action to a list of the authorized actors for that action within the context of the single ACL.

Actor and action maps

The outer ACLPerspective class manages overall actor and action maps for a set of ACLs. These two maps hold the essential information for building authorization views. As you can see from the class diagram in Figure 5, the aclActorMap contains an ActorRelationships instance for each ACL in the perspective; the aclActionMap contains an ActionRelationships instance for each ACL in the perspective.

The maps are maintained in parallel and are constructed as part of the class instantiation process. The maps will maintain information on either configuration or permission views depending on how the particular ACLPerspective instance was constructed; for example, with a configuration-style constructor or a permission-style constructor, as discussed earlier.

Thus, after construction, an ACLPerspective instance contains all the information needed for a full view into either the configuration of a set of ACLs, or the permissions granted by them to a specified list of actors.

Perspective tables

The maps in ACLPerspective maintain the core structures, but aren’t directly useful for the general kinds of information presentation you want here. ACLPerspective, therefore, makes table views of each of the maps available, represent the contents of the maps in tabular form. The tables are generated dynamically at run time by the getAclActorTable() and getAclActionTable() accessors, but could just as well be created during construction and cached for efficiency.

Each table is a literal representation of the structures shown in Tables 2 through 9, delivered as a two-dimensional matrix of String[][]:

  • getAclActorTable() delivers a table with actors across the top, ACLHolders down the side, and actions in the cells.
  • getAclActionTable() delivers a complementary table with actions across the top, ACLHolders down the side, and actors in the cells.

Accessing the ACLPerspective

Two (or, optionally, three) things are necessary to access an ACLPerspective:

  • An instance of the EAz authorization manager, introduced in Part 2, which has been enhanced to construct and return ACLPerspectives in the current version of EAz.
  • An ACL or list of ACLs to on which to create a perspective.
  • Optionally, a list of MockPrincipals to determine permissions for. If you supply the MockPrincipals, you’ll get a permission-style perspective; if not, you’ll receive a configuration perspective that is based solely on the configuration information in the ACL or ACLs.

The AuthorizationManager implementation of the ACLPerspectives constructors is a straightforward wrapper method. Listing 3 shows the richest example, which is for the permission-oriented constructor; the other methods are similar but even simpler.

Listing 3. AuthorizationManagerImpl method for obtaining a permissions-oriented ACLPerspective
public ACLPerspective getACLPerspective(List<ACLHolder> aclHolderList,
		List<MockPrincipal> specificActors) {
	List<ACL> aclList = new ArrayList<ACL>();
	for (ACLHolder aclHolder : aclHolderList) {
		aclList.add(aclManager.getACL(aclHolder));
	}
	return new ACLPerspective(aclList, specificActors);
}

Using the ACLPerspective

The same JUnit test harness from Part 2 was used to generate the tables in this article; the process illustrates the key aspects of using an ACLPerspective. Listing 4 shows the Junit test that generates and prints out an aclActorTable showing configuration information for a list of ACLs. This test was used to generate Tables 3 and 7. As you see, once you have an ACLPerspective in hand, dumping it out is as simple as printing its cells.

Listing 4. Generating an actor table using ACLPerspective
@Test
public void testGetMatrixDefaultActors() {
     ACLPerspective perspective = authorizationManager.getACLPerspective(aclHolderList);
     String[][] actorTable = perspective.getAclActorTable();
     for (String[] row : actorTable) {
     	for (String cell : row) {
     		printCell(cell);
     	}
     	System.out.println("\n");
     }
     System.out.println("=========================================================\n\n");
}
private void printCell(String cell){
     int CELLSIZE=20;
     StringBuffer sb = new StringBuffer(cell);
     int pad = CELLSIZE-sb.length();
     if (pad >0) {
     	for(int i=1;i<pad;i++){
     		sb.append(" ");
     	}
     }
vSystem.out.print("["+sb.toString()+"]");
}

The ACLPerspective and all enhancements to support it are available in the download file included with this article.


Using the ACLPerspective in a JavaServer Faces application

JavaServer Faces (JSF) was the technology of choice for perspective display for its inherent virtues and capabilities, and because it enables easy substitution of graphical components. This is particularly interesting for ACL-related views, because substituting an input component for an output component can turn an ACL-related display into an ACL configuration application, when coupled with event listeners to note the change and service methods to interpret and apply it.

More about JSF
A detailed discussion of JavaServer Faces is beyond the scope of this article. If you are unfamiliar with JSF, see Resources for Rick Hightower’s excellent developerWorks article series and Bauke Luitsen Scholtz (BalusC)’s blog for superb JSF examples.

JSF resembles a shared-memory-based graphical framework like AWT (Abstract Window Toolkit) or Swing or SWT (Standard Widget Toolkit). Frameworks like AWT and others run on a single computer and generate displays on a human interface based on a model in memory. The framework responds to events on the interface in ways that affect the model, and all of this happens in the same memory space on the workstation.

JSF effectively distributes some of the memory space on the workstation browser and some to the networked server by offering a set of server-side components that talk model on one end and a rendered language like HTML on the other. The metaphor is inexact, but it conveys the flavor of JSF better than any other I have found. Basically, you’re running something very much like Swing on the server, and translating it to and from HTML (or some other markup language) at the moment you want to display information or receive input.

For the purpose of this article, you need to be concerned with three JSF constructs:

  • A JSP page that describes how to display your content by using JSF custom tags. This will be referred to as a JSF page.
  • A handler class, effectively a JSF backing bean, which constructs the actual graphical view out of JSF components.
  • A configuration file that informs a context that is used by both the JSP page and the handler about each other, and that the handler uses to know about the EAz framework.

JSF pages are usually rich and full of tags, while the JSF backing beans are fairly simple and mainly exist to respond to events, and communicate them to a service layer. In our sample application, however, you need to reverse the complexity because you are displaying dynamic tables. There's no way ahead of time to know, for example, how many columns or rows an aclActorTable or aclActionTable will contain. The table can't be effectively defined by tags in the JSF page, because the only relevant tag handles dynamic numbers of rows, not dynamic numbers of columns.

Project organization

The code in this example is organized into three Eclipse projects, visible in Figures 3 and 4:

  • EAuthZ continues to contain the core EAz framework code, including service methods, core classes, and ACLPerspective.
  • EAuthZWeb and EAuthZWebEAR projects implement the JSF application that accesses and displays ACLPerspectives as needed.

The remainder of this article focuses on the EauthZWeb project and its role in making the ACLPerspective-supplied ACL information available on the Web.

The JSF page

Listing 5 shows the complete JSF page. There isn’t much to it. The line below generates the actual display of one EAz table and is repeated with different bindings for each table you want to display:

<h:panelGroup styleClass="eazPanel" binding="#{authZviewHandler.actorTablePanel}" />

The binding associates a JSF tag (in this case, a panelGroup that renders a table) with a specific method in a specified backing bean (in this case, your authZviewHandler). The instruction in the tag is effectively saying to the JSF framework: When it’s time to generate HTML and you get to this tag, execute the getActorTablePanel() method in the class configured as authZviewHandler in faces-config.xml, and render the JSF PanelGroup component that the method returns, along with its contents.

This dynamic rendering is, as noted, the opposite of most JSF techniques. More typically, the tag tells the JSF framework exactly which JSF components to configure and render in great detail. Here, however, the page has no clue of the shape of our table -- but the handler does, so we reverse the order.

There is an actual DataTable component available in JSF that will create a table of the sort you want, and you’re using it behind the scenes, as you’ll see in the discussion of the handler. However, the DataTable is concealed from the page using a technique learned from BalusC (see Resources) to get around a thorny problem with dynamic datatables and the h:dataTable tag.

The h:dataTable tag implements an implicit loop over the rows in the table, and requires a var attribute, which can be used inside the loop to access the current row. You, on the other hand, have no use for accessing row contents inside the tag, since you have to build up the table from scratch inside the handler to respond to your dynamic table shape. But you do want to be able to have a single handler display a potentially wide range of tables for either a single page or a range of pages.

If you were to use the h:dataTable tag in your JSF page, you would wind up with very dense handler code, requiring more and more complex handler methods for each table you display. An early version of the code used this technique. By building the DataTable entirely inside the handler, you can dispense with its footprint in the JSF page and wind up with very compact and maintainable code for many EAz-related displays.

Listing 5. ViewAuthZ.jsp JSF page
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%-- jsf:pagecode language="java" location="/src/pagecode/ViewAuthZ.java" --%>
<%-- /jsf:pagecode --%>
<%@page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<html>
<head>
<title>ViewAuthZ</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<link rel="stylesheet" type="text/css" href="theme/stylesheet.css"
	title="Style">
<link rel="stylesheet" href="theme/eauthz.css" type="text/css">
</head>
<f:view>
	<body>

	<h:panelGrid styleClass="eazPanel">
	<h:outputText styleClass="eazHeading" value="Actors in the ACLs and their allowed
	actions"/>
	</h:panelGrid>
	<h:panelGroup styleClass="eazPanel" binding="#{authZviewHandler.actorTablePanel}"
	/>

	<h:panelGrid styleClass="eazPanel">
	<h:outputText styleClass="eazHeading" value="Actions in the ACLs and their allowed
	actors"/>
	</h:panelGrid>
	<h:panelGroup styleClass="eazPanel" binding="#{authZviewHandler.actionTablePanel}"
	/>

	<h:panelGrid styleClass="eazPanel">
	<h:outputText styleClass="eazHeading" value="Specific Named Actors and their 
	Actions"/>
	</h:panelGrid>
	<h:panelGroup styleClass="eazPanel" binding="#{authZviewHandler.
	permissionActorPanel}" />

	<h:panelGrid styleClass="eazPanel">
	<h:outputText styleClass="eazHeading" value="Actions in the ACLs for Specific
	Named Actors"/>
	</h:panelGrid>
	<h:panelGroup styleClass="eazPanel" binding="#{authZviewHandler.
	permissionActionPanel}" />
		
	</body>
</f:view>
</html>

Faces configuration and the handler

Since you’re using dynamic rendering, your handler is implementing almost all of the view functionality, supplying your entire display to the h:panelGroup tag in the JSF page. We’ll look at the handler in some detail, since dynamic page rendering in JSF is an under-documented topic, but first let’s quickly look at the JSF configuration.

Listing 6 shows faces-config.xml, located in the WEB-INF directory of your Web application. This file is responsible for configuring your JSF application, and it performs three functions for your current display:

  • Defines a managed bean to represent the authorization manager interface, specifying the implementation class and the name the manager will be known by in the application, such as “authorizationManager.” Application scope effectively means that your authorizationManager is a singleton with only one shared instance in the application.
  • Defines your handler as a second managed bean known to the application as "authZviewHandler" and implemented by the org.eaz.handlers.AuthZViewHandler class. Recall that “authZviewHandler” is the name the JSF page uses to bind the h:panelGroup tag to the backing bean; the managed bean configuration is what makes this binding meaningful.
  • Defines a managed property on your handler and points it right at the authorizationManager bean using the JSF Expression Language (EL) expression #{authorizationManager}. This is the same EL you used in your JSF page to bind your panelGroup to your handler; in this case, you’re telling the JSF framework to insert your (one and only) instance of the authorizationManager into the handler class any time a handler instance is created. The handler’s scope is request, so a new handler will be created with every request. (This is a rudimentary form of dependency injection, as more fully expressed in frameworks like Spring.)
Listing 6. JSF configuration in faces-config.xml
<?xml version="1.0"?>

<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">

<faces-config>

	<managed-bean>
		<managed-bean-name>authorizationManager</managed-bean-name>
		<managed-bean-class>org.eaz.svc.AuthorizationManagerImpl
			</managed-bean-class>
		<managed-bean-scope>application</managed-bean-scope>
	</managed-bean>
	
	<managed-bean>
		<managed-bean-name>authZviewHandler</managed-bean-name>
		<managed-bean-class>org.eaz.handlers.AuthZViewHandler
			</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
		<managed-property>
			<property-name>authorizationManager</property-name>
			<value>#{authorizationManager}</value>
		</managed-property>
	</managed-bean>

</faces-config>

The AuthZViewHandler class implementation

Building the PanelGroup container for your DataTable

Our review of the handler begins with the public HtmlPanelGroup getActorTablePanel() method. Recall that this is the method you bound your <h:panelGroup styleClass="eazPanel" binding="#{authZviewHandler.actorTablePanel}" /> tag to in the JSF section above. The JSF EL supplies the implicit get in interpreting the method name to call for the binding. This particular method builds and embeds a DataTable object in a panel for a configuration invocation of an ACLPerspective based on the actor view. The handler contains a similar method for each <h:panelGroup ... /> binding in the JSF page, and each bound tag renders one table from a differently constructed instance of an ACLPerspective.

As you can see in Listing 7, this starts by creating an HtmlPanelGroup instance; this is the object that is actually bound to the h:panelGroup tag and will render whatever is inside it in an HTML table. Your task is to create a DataTable from your ACLPerspective and insert the DataTable in the HtmlPanelGroup instance.

Use the handler’s dependency-injected reference to your authorizationManager service layer to obtain a list of aclHolder instances. The authorizationManager has been enhanced with code drawn from the JUnit tests from Part 2 to make lists of aclHolder objects and MockPrincipal objects available for testing. (In production, you would pull the aclHolder objects you wanted to visualize from the database according to user- or application-defined criteria.)

Calling again on the authorizationManager service layer, you retrieve an ACLPerspective for your list of testAclHolders, and invoke the perspective’s getAclActorTable method in order to retrieve your tabular information. In this example, you are not supplying a list of named users in the constructor, so the table returned will be a configuration table, not a permissions table.

Your method is configured with a valueBindingDescriptor string in the line that follows: the final String valueBindingDescriptor is a JSF EL expression pointing to the method used to actually populate the rows of your DataTable; in this case, the getActorRows method (remember the implicit “get” in EL method binding expressions) in the current class. The JSF lifecycle implementation will execute a callback against this method in the appropriate lifecycle phase to retrieve the table’s row information. We use a custom private helper method to turn the EL expression string into an actual JSF valueBinding instance. (JSF Version 1.1 uses the ValueBinding class for this purpose. In JSF 1.2 and Java EE 5, you will see a ValueExpression class fulfilling the same function.)

Finally, you invoke your own constructDynamicDataTable method with both the actorTable and the callback binding for row fetches. As you will see, constructDynamicDataTable is able to build a dynamic DataTable to show your actorTable using only these two pieces of information so that it can be used as a utility method to build any ACLPerspective-oriented DataTable.

Add your newly constructed DataTable to the HtmlPanelGroup instance as a child, and return the HtmlPanelGroup to the JSF controller. This process is similar for any ACLPerspective JSF display.

Listing 7. getActorTablePanel() method to construct a DataTable for the ACLPerspective’s aclActorTable
/*
 * We bind to a panel instead of directly to the datatable because the
 * DataTable component requires the page to define the iteration var and we
 * wish to do so in the back end
 */
public HtmlPanelGroup getActorTablePanel() {
	if (actorTablePanel == null) {
		actorTablePanel = new HtmlPanelGroup();
		ACLPerspective perspective = getAuthorizationManager()
				.getACLPerspective(getTestACLHolders());
		String[][] actorTable = perspective.getAclActorTable();
		final String valueBindingDescriptor = "#{authZviewHandler.actorRows}";
		UIData dataTable = constructDynamicDataTable(actorTable,
				createValueBinding(valueBindingDescriptor));
		actorTablePanel.getChildren().add(dataTable);
	}
		return actorTablePanel;
}

Constructing the dynamic DataTable

Listing 8 shows the constructDynamicDataTable method that does the heavy lifting of DataTable construction. You begin by instantiating an HtmlDataTable and setting its ValueBinding to the one supplied as an argument. This effectively sets the callback method on the table so the JSF lifecycle knows what method to call when it’s time to fetch table rows.

Next -- and this is an error prone step -- you set the var attribute of your DataTable to a string value, in this case “rowVar.” You will recall that DataTables execute an implicit loop over their rows, and the var attribute indicates the value of the current row during the iteration. For you, this means that when you create binding expressions to display table contents, you need to use the same string you configured for var in the binding expressions with the meaning of "in the current row of the iteration."

DataTable objects are built one column at a time and populated one row at a time. It’s really the indeterminate number of columns that drives us to a dynamic implementation in the handler; rows are dynamic by nature. However, the width of the table, corresponding to the number of columns, is easily available in the handler as the “length” of any row of your perspectiveTable, and so you use perspectiveTable[0].length to set your number of columns.

You then loop over the number of columns in hand, creating and configuring your DataTable’s columns in the process. First, you instantiate a UIColumn object to represent the column, then create a header cell object for the particular column in the form of an HtmlOutputText instance. You want to use headers because, as you’ll see, they can be independently styled in DataTables, which gives you good control over the table’s appearance in the browser. We set the value of the outputText instance to the contents of the perspectiveTable’s cell for the 0th row (a perspectiveTable’s 0th row is explicitly and always a header row to support this function). Finally, you set a style on the header cell and add it to the column as a header using the UIColumn.setHeader() method.

Now, it’s time to add a component to the UIColumn to represent the contents of the column in any row other than the header row. Again, you use an HtmlOutputText instance for the purpose -- and this is exactly the point where you might want to substitute an input or droplist object to implement a maintenance page instead of a display page like this one.

DataTables have header styling, but don’t intrinsically offer a styling capability for the leftmost column of a matrix-like table, so you do this by hand by testing to see if you’re in the 0th (leftmost) column or not and then set the style accordingly.

Finally, you bind your cell component’s value to the var value you defined earlier, using JSF EL. This binding is executed at row creation time. The binding ("#{rowVar[" + i + "]}")) will be interpreted by JSF to mean:

  1. Access the current row of content you are iterating over, using the current value of rowVar to find it.
  2. In that row, look at your current column number as indicated by “i” and use the value you find there as the value of this component.

Add your configured and value-bound component to the current column, and end your column loop iteration by adding the completed column to the children of the DataTable.

Once you’re done building all the columns, the DataTable instance is complete and you return it to your panel where it will be embedded as a child.

Listing 8. Constructing a dynamic DataTable from the perspectiveTable
/*
 * Construct a dynamic data table based on the perspective table passed.
 * Many thanks to BalusC for clarifying a very opaque interface!
 */
private UIData constructDynamicDataTable(String[][] perspectiveTable,
		ValueBinding vb) {

	HtmlDataTable dynamicDataTable = new HtmlDataTable();
	// Bind the actual data
	dynamicDataTable.setValueBinding("value", vb);

	/*
	 * Create a var for the datatable's rows. Must reference this var in the
	 * component binding expression so that the components draw their values
	 * from the correct row of the datatable
	 */
	dynamicDataTable.setVar("rowVar");

	// Get number of columns from the perspective
	int columns = perspectiveTable[0].length;

	// Loop through columns.
	for (int i = 0; i < columns; i++) {

		/*
		 * Create UI column for the dataTable. Note that JSF 1.2 changes
		 * this interface and uses an HtmlColumn
		 */
		UIColumn column = new UIColumn();

		/*
		 * Create header. This gives us control over header styling but
		 * requires us to strip the header row from our table of values so
		 * it doesn't appear twice
		 */
		HtmlOutputText header = new HtmlOutputText();
		header.setValue(perspectiveTable[0][i]);
		header.setStyleClass("eazTableHead");
		column.setHeader(header);

		// Create component for cell contents and add to column.
		HtmlOutputText cellComponent = new HtmlOutputText();

		// Style the first (aclHolder) column differently
		if (i == 0) {
			cellComponent.setStyleClass("eazTableHead");
		} else {
			cellComponent.setStyleClass("eazColumnClass");
		}

		/*
		 * Value binding must match the dataTable's var, in this case
		 * "rowVar"
		 */

		cellComponent.setValueBinding("value",
				createValueBinding("#{rowVar[" + i + "]}"));
		column.getChildren().add(cellComponent);

		// Add column to datatable.
		dynamicDataTable.getChildren().add(column);
	}
	return dynamicDataTable;
}

Filling the DataTable row content

Complete your exploration of the handler by looking at one of the methods used to build row content for the DataTable. This method is configured in the valueBinding for the DataTable and must reference the same flavor of perspective table (actor or action, configuration or permission) used to build the DataTable itself -- or else, the headings and contents will not match. Retaining your focus on the configuration display for actors, let’s walk through the public List getActorRows() method in Listing 9, referenced by the EL method binding expression "#{authZviewHandler.actorRows}".

By now, the ACLPerspective usage should be familiar. The important thing to remember is that the perpective retrieved for the rows must be the same as the perspective retrieved to build the DataTable and its columns. The private List getRows(String[][] perspectiveTable) method, also shown in Listing 9, strips the top row from your perspective table, since you’ve already used the top row to configure a heading when you built your DataTable.

Listing 9. Service layer protection in the AuthorizationManagerImpl
/*
 * Returns a list of rows from the perspective relating aclHolders in rows
 * to actors specified in the ACLs in columns
 */
public List getActorRows() {
	ACLPerspective perspective = getAuthorizationManager()
			.getACLPerspective(getTestACLHolders());
	String[][] actorTable = perspective.getAclActorTable();
	// return actor rows;
	return getRows(actorTable);
}

/*
 * Private utility method to strip the headers from a perspective table and
 * convert it to a list
 */
private List getRows(String[][] perspectiveTable) {
	List rowList = new ArrayList();
	for (int i = 1; i < perspectiveTable.length; i++) {
		rowList.add(perspectiveTable[i]);
	}
	return rowList;
}

Displaying the results

Figure 6 shows the actual display of the JSF Web page from this example, with a rendered and styled table for each of the variants of the ACLPerspective.

Figure 6. JSF display of the variants of our ACLPerspective
Figure 6. JSF display of the variants of our ACLPerspective

Conclusion

This article illustrated a technique for visualizing application actions, groups, and actors, and their relationship to EAz permissions, in a graphical interface. This method provides easy-to-understand insight into an application’s authorization policies and can be extended to construct a management console interface for authorization management.

Developers can use the overall EAz framework and its techniques to implement a robust, flexible, and extensible authorization mechanism for any Java application. EAz enhances (but does not supplant) existing Java EE authorization mechanisms, manages by authorization by exception, and can be used for cases as simple as named users or simple groups, and as complex as authorization based on multiple group membership, inherited Access Control Lists and differing access controls for different organizational memberships.


More in this series


Download

DescriptionNameSize
COde sampleEAZArticle3Final.zip41 KB

Resources

Learn

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=291647
ArticleTitle=Fine-grained Java EE authorization using Enum-based access control lists with EAz: Part 3: EAz access visualization framework and graphical interface
publish-date=02272008