ActionForward forward = proceed(..);
Collection col = getRS(request);
Iterator i = col.iterator();
The code for PostfilterSingle is very similar yet simpler, since only one data record is being examined.
A distinguishing feature of the aspects defined above is that they are all stateless and singleton aspects. Unlike prior approach [4][5], we do not need to associate any user profile information with the authentication aspects. This is mainly due to the accepted convention in Web application development that user-related information is stored in the session object which is available in the aspect code through the exposed request object argument.
Finally we make some note about the advice type we chose. One may argue that the authentication and precheck aspects should be implemented as before advice instead of around advice. We disagree with this for two reasons. Firstly, by definition, in normal case before advice cannot prevent the intercepted method from execution, yet this is exactly what access control enforcement requires. Secondly, throwing access denied exceptions in before advice significantly increases the complexity of exception handling in the target application, and may make the aspects invasive.
4.2 Aspect Composition Issues
Having defined these abstract aspects, we can then apply them to implement the access control rules specified by security administrator. This can be done by defining concrete aspects inheriting from them that include the proper pointcut designators and the required constraint or filter methods. However, there are some conditional execution dependencies between these access control aspects. In particular, when required at the same join points, the Postfilter aspects should not be executed before the Precheck aspect finished successfully, whose execution in turn should be preceded by that of an Authentication aspect. These restrictions are very close to the condhard (x, y) constraint defined in [14]4.
The straightforward implementation described above simply cannot ensure that these constraints are satisfied. We must use the
“declare precedence” construct of AspectJ to enforce the ordered execution of these three aspects. Yet this may not completely
4 More will be said about the cond(x, y) constraint in Section 5.
resolve the issue, for it is not uncommon that, during program maintenance time, an authentication aspect is carelessly left out or misplaced at a join point where certain access control is required.
This would violate the conditional execution dependency. To avoid the damage which may result from such human errors, we decided to look for alternative implementations.
4.3 Alternative Implementation
One way to achieve our goal is to use per-object stateful authentication aspects to store user authentication records, as suggested by [14]. But this would make our code more complicated and lead to a proliferation of unnecessary aspect instances, as we stated above that we can take advantage of the session object used in Web applications for this purpose. Hence we decided to take another route to resolve the composition issue.
Ideally, we wish to be able to construct a composition aspect out of an authentication aspect, a precheck aspect, and maybe a postfilter aspect to ensure the conditional execution dependencies between them. Yet AspectJ has no such aspect composition mechanism for our purpose, so we choose to use aspect extension and other OO techniques to implement it. All the four abstract aspects defined earlier must be revised. In addition, we added a new abstract aspect, AAAspect, and a few helper classes to fulfill our requirements. They form a small aspect framework. Figure 3 illustrates the relationships among these aspects and classes.
Figure 3: The Structure of the Alternative Aspects The AAAspect is the root aspect that acts as a factory for producing the required authentication verification objects:
public abstract aspect AAAspect { abstract pointcut pc(..);
abstract protected String getAuthType();
private static Hashtable authTable = new Hashtable();
static {
authTable.put("PWDAuth",PWDAuth.getInstance());
authTable.put("DCAuth", DCAuth.getInstance());
… // for other authentication schemes}
protected Authentication getAuthObj(){ //factory return (Authentication)
according to the result of executing the getAuthType() method, which is defined in sub-aspects.
The Authentication aspect extends the AAAspect. It factors out the common code structure of conducting user authentication verification check and leaves to its sub-aspects, e.g., PWDAuthAspect, the specifications regarding where to weave in the checking code (pointcut) and which type of authentication to use. For each authentication type, there will be an authentication object containing the code to verify that a user has passed the authentication check, e.g., PWDAuth. They are instantiated from subclasses of the Authentication class, which prescribes the interface for confirming authentication checks (i.e., isAuthenticated()). As the confirmation check is independent of application state, all authentication objects are instantiated once only and accessed through a static method, getInstance(), following the Singleton pattern [7]. Furthermore, each authentication object will specify its own user authentication page for login re-direction.
In this alternative implementation, the advice in all of the revised Precheck and Postfilter aspects must first get a proper authentication object and make a call to its isAuthenticated() method. This will ensure that access control enforcement is preceded by a proper user authentication. Similarly, the advice in the postfilter aspects must, in addition, include the code of access constraint check before proceeding to execute the intercepted method and filter out unauthorized contents. For space’s sake, we show only the code for the revised PostfilterCollection aspect:
public abstract aspect PostfilterCollection { abstract protected Boolean
constraint(HttpServletRequest request);
abstract protected String getErrorMessage();
abstract protected boolean filter
(HttpServletRequest request,Object data);
abstract protected Collection
getRS(HttpServletRequest request);
protected abstract void mask(Object data);
private void remove(Iterator i) {i.remove();}
ActionForward around(..) : pc(..) {
Authentication auth = getAuthObj();
if (auth.isAuthenticated(request)) { if (constraint(request)) {
ActionForward forward = proceed(..);
Collection col = getRS(request);
return forwardToErrorPage(request,mapping);
} else // login re-direction
return mapping.findForward(auth.forwardTo());
} }
aspects.
5. DISCUSSION
Software Engineering Properties
As demonstrated above, the MVC architectural style lays a good foundation for modularizing access control. And we can take full advantage of the MVC-based Struts framework to achieve a complete separation of access control enforcement. Furthermore, the way an access control aspect is implemented have a direct correspondence to an access control rule. These features definitely make our access control implementation qualify for software engineering properties such as comprehensibility, analyzability, and adaptability.
Our aspects also support very good evolvability since the main dependency between our approach and Struts is the interface of user action (i.e. the execute() method). As long as it remains unchanged, it is very unlikely that we need to change our approach. For example, since Version 1.1, Struts also supports method-based dispatch units through a new class called DispatchAction. Yet, all those dispatchable methods in a dispatch action class must have the same signature as the execute() method.
Hence all we need to change is the method names in pointcut designators.
Our aspect framework supports multiple user authentication types.
Not only function-level access control but also data filtering can be easily realized in a non-invasive manner. We argue that we have achieved a very good balance between serving the needs of a wide range of access control requirements and that of incurring minimal impact on the structure of underlying applications. As a case study, we have successfully applied this aspect framework to re-engineer the access control part of an open-source B2C E-Commerce application, JPetstore [12] with very little adaptation.
Aspect Composition
Nevertheless, in the process we did feel confused by issues of aspect reuse and aspect composition. As discussed earlier, at shared join points, we must have all the required aspects and maintain the conditional execution dependencies among them.
Yet, in our first implementation, the authentication, precheck and postfilter aspects are defined separately and get applied to each join point individually. This may lead to undesirable runtime exceptions or even security breach. For lack of proper aspect reuse and composition mechanisms in AspectJ, we are forced to design an alternative implementation where the code that should be reused (i.e., authentication and prechck aspects) is simply duplicated in the composition aspects (i.e., precheck and postfilter aspects.)
Earlier work on aspect reuse in AspectJ [10][19] did not properly address the issues involved. The recent work of Nagy et al [14]
introduced the notion of control constraint, cond(x, y), between two aspects x and y, which to a very large extent clarified the essence of this issue. However, we still do not feel the issue is completely resolved. In particular, the definition of cond(x, y) focuses on only the dependencies between two aspects at shared join points; nothing about their relations with the intercepted method is considered. This fits well with the behaviors of before
6
and after advice, but not with that of around advice. By nature, around advice concerns the execution of the intercepted method and it is the internal logic of around advice that will determine whether to resume the intercepted method, or continue executing the next advice in the case there are multiple around advice anchored at same join point. Therefore, we claim that the cond(x, y) constraint does not completely capture the conditional execution dependency between two around advice.
The peculiarity of around advice leads us to re-think what the proper forms for aspect composition should be and what linguistic mechanisms an AOP tool should provide for them. Recently, some new Java-based AOP tools, instead of proposing language extensions, take the approach of supporting AOP via runtime libraries and, in some sense, blur the distinction between aspects and classes. Just before sending out this position paper, we ran across a radical proposal that advocates the unification of aspects with classes [15]. Does this mean that we could compose aspects just like how we do for objects?
JBoss AOP
We decided to take a quick look into these tools and chose the recently released JBoss AOP [11] as our target of investigation.
We report our preliminary findings as follows. There is no new aspect abstraction in JBoss AOP; any Java class can become an aspect as long as it implements a special interface, namely Interceptor5, and puts the advice code in a special method called invoke. The pointcut designators are separated from aspect definition and defined in an XML configuration file, in which the target classes and the interceptors to weave in are linked. The advice in an aspect (interceptor) all takes the form similar to the around advice in AspectJ. For example, the following is the code skeleton for authentication verification in JBoss AOP.
public abstract class Authentication
implements Interceptor { abstract protected String forwardTo();
abstract protected boolean
isAuthenticated(HttpServletRequest request);
// advice body
public Object invoke(Invocation invocation) throws Throwable { Object[] arguments = ((MethodInvocation) invocation).getArguments();
... // get info exposed at join point if (isAuthenticated(request)) return invocation.invokeNext();
else
return // login re-direction
forwardToSignonPage(mapping, forwardTo());
}
...//some auxiliary definitions }
The invocation object passed to an advice is similar to the thisJoinPoint object available in an advice of AspectJ. In addition, it has an invokeNext() method that does the same thing as the proceed() does for around advice in AspectJ.
5 We used an earlier verion of JBoss AOP for our study. The latest version (1.0.0 Final) has made some generalizations: an aspect can include multiple advices, yet all of which must have a specific signature, and an interceptor is an aspect with only one advice named "invoke".
Basically, both aspect suites defined earlier can be easily adapted to JBoss AOP. Yet our goal is to see whether those access control aspects can be composed in an object-oriented manner, since aspect instances in JBoss AOP are just like object instances.
However, it turns out that the nature of around advice makes this attempt fruitless. Firstly, we tried inheritance and defined the precheck aspect as a sub-aspect of the authentication aspect. In order to reuse the authentication advice in the precheck aspect, we have to twist the code of both aspects6. Secondly, we tried the HAS-A composition and embedded an authentication aspect instance into the precheck aspect. Again, we have to make some workarounds that change both aspects to compose them properly7. Despite these unsuccessfully efforts, we continued exploring the undocumented API of JBoss AOP. What we find interesting is that there is another invokeNext(Interceptors []) method declared in the Invocation interface of JBoss AOP. It enables us to define composite aspects and install them at selected join points just like atomic aspects. For instance, the following is the code for a generic composite aspect:
public abstract class Composite
implements Interceptor { //constituent aspects
protected Interceptor[] intcptArray;
// assemble other aspects into “intcprArray”
abstract protected void assembleAdvice();
public String getName() {
return "CompositeAspects";
}
public Object invoke(Invocation invocation) throws Throwable { assembleAdvice();
return invocation.invokeNext(intcptArray);
} }
It simply assembles a composite aspect out of an array of interceptors and uses the invokeNext(Interceptors []) method to trigger the execution of the constituent advice8. The VIPOrder rule stated earlier can then be implemented by composing an authentication aspect and a precheck aspect in a straightforward manner as follows:
public class VIPCombo extends Composite { public String getName() { return "VIPCombo"; } protected void assembleAdvice() {
PWDAuth auth = PWDAuth.getInstance();
VIPOrder vip = VIPOrder.getInstance();
intcptArray = new Interceptor[] { auth, vip };
} }
6 Afterwards, we realized that what we did is something like emulating the “inner” construct of Beta [13] in Java. Inheritance in Beta assumes a different semantics. An inherited method in a superclass has precedence over the inheriting method in a subclass, and may refer the inheriting one through the “inner”
construct [3]. This discovery seems worth further study.
7 We overload the authentication advice with an extra parameter and pass the proper “this” argument to it so that we can choose the right proceeding path to follow in the advice. This is similar to the situation described in [6], where object composition and message forwarding are used to simulate inheritance.
8 This is reminiscent of the chained advice described in [9], though no concrete implementation in AspectJ is provided therein.
7
Informatica vol.26(2), 2002, pp. 141-149.
we had wished for. The first one is about aspect instantiation which is not so essential to the composition issue and thus omitted here. The second issue matters most since we found that the mechanism we used above is not truly compositional. In particular, we cannot compose an aspect out of atomic aspects and composite aspects arbitrarily. In a composite aspect, only the last constituent aspect can be composite, too. These findings confirm our thinking that the issues of aspect composition are far from trivial and merit further investigation.
[6] Fröhlich, P.H., Inheritance Decomposed, Inheritance Workshop, European Conference on Object-Oriented Programming (ECOOP), Malaga, Spain, 11 June 2002.
[7] Gamma, Helm, Johnson and Vlissides: Design Patterns. A.
W. L., 1995. ISBN 0-201-63361-2.
[8] Goodwin, R., Goh, S.F., and Wu, F.Y. Instance-level access control for business-to-business electronic commerce, IBM System Journal, vol. 41, no. 2, 2002.
6. CONCLUSION
[9] Hanenberg, S. and Schmidmeier, A., Idioms for Building Software Frameworks in AspectJ, 2nd AOSD Workshop on Aspects, Components, and Patterns for Infrastructure Software (ACP4IS), Boston, MA, March 17, 2003.In this position paper, we have reported our experience in designing access control aspects for Web applications. We showed that the MVC architectural style lays a good foundation for modularizing access control, and we can take full advantage of the MVC-based Struts framework to achieve a complete separation of access control enforcement. The access control aspects we presented have achieved a very good balance between serving the needs of a wide range of access control requirements and that of incurring minimal impact on the structure of underlying applications.
[10] Hanenberg, S. and Unland, R., Using and Reusing Aspects in AspectJ, Workshop on Advanced Separation of Concerns in Object-Oriented Systems, OOPSLA, Oct. 2001.
[11] JBoss AOP website: http://www.jboss.org/products/aop, document download site: http://docs.jboss.org/aop/aspect-framework/
[12] Johnson, R. The JPetstore Demo Application, Shipped with the Spring Framework. http://www.springframework.org/
On the other hand, we have also identified the issues of reusing and composing around advice. We described the problems we ran into while designing the access control aspects. An alternative aspect framework was developed that achieved guaranteed conditional execution at the cost of code duplication. Along the line we further explored the issues in the context of JBoss AOP, where aspects are plain Java classes with methods of a specific signature. We found that conventional object composition and inheritance cannot support advice reuse directly as we would expect. In contrast, Beta-like inheritance and its inner construct may suit our purpose. Furthermore, we pointed out the asymmetric nature of the chained aspect composition mechanism provided by JBoss AOP. Although these preliminary findings are not very positive, yet they have shed some light on the strong and weak points of the aspect composition mechanisms provided in current AOP languages and tools.
[13] Madsen, O.L., Moller-Pedersen, B., and Nygaard, K., Object-Oriented Programming in the Beta Programming Language, Addison-Wesley (ACM Press), 1993.
[14] Nagy, I., Bergmans, L., Aksit, M., Declarative Aspect Composition, Workshop on Software engineering Properties of Languages for Aspect Technologies (SPLAT04), 2004.
[15] Rajan, H. and Sullivan, K. Classpects: Unifying Aspect- and Object-Oriented Language Design, Technical Report CS-2004-21, Department of Computer Science, University of Virginia, Sept 2004.
[16] Sun Microsystems, Java Authentication and Authorization Service (JAAS), http://java.sun.com/products/jaas/index.jsp [17] Vanhaute, B., De Win, B., and De Decker, B., Building
Frameworks in AspectJ, ECOOP 2001, Workshop on Advanced Separation of Concerns, pp.1-6.
7. REFERENCES
[1] The Apache Struts Web Application Framework:
http://struts.apache.org/ [18] Verhanneman, T., Jaco, L., De Win, B., Piessens, F., and Joosen, W., Adaptable Access Control Policies for Medical Information Systems, Proc. of Distributed Applications and Interoperable Systems, 2003, Paris, France, LNCS 2893, pp.
133-140.
[2] The AspectJ website: http://www.eclipse.org/aspectj/
[3] Bracha, G. and Cook, W., Mixin-based inheritance. In Proc.
ACM Conf. on Object-Oriented Programming, Systems, Languages and Applications, October 1990.
[4] De Win, B., Joosen, W., and Piessens, F., AOSD & Security:
a practical assessment, Workshop on Software engineering Properties of Languages for Aspect Technologies (SPLAT03), 2003, pp. 1-6.
[19] Wohlstadter, E., Keen, A.W., S. Jackson, and Devanbu, P., Accommodating Evolution in AspectJ, Workshop on Advanced Separation of Concerns in Object-Oriented Systems, OOPSLA 2001, October 2001
8