Arch2Arch Tab BEA.com
« August 2007 | Main | February 2008 »

September 2007 Archives

Bill Dettelback's Blog

William Dettelback's Homepage
Bill currently works on the AquaLogic Enterprise Security team. His focus is on customers implementing SOA Security, particularly Authorization and Entitlement solutions. Bill has been helping customers develop solutions in Financial Services, Telecommunications and Healthcare for BEA since 2002. Bill has a Bachelor's of Science in Computer Science and Master's of Science in Computer Science from New Jersey Institute of Technology.



Securing POJOs with Spring AOP and ALES

Posted by BillDet on September 19, 2007 at 2:10 PM | Permalink | Comments (2) | TrackBack (0)

I was pulled into a customer discussion a few weeks ago by our sales team, specifically to talk about how ALES could be used with frameworks like Spring.  We haven't done any formal engineering on a Spring integration, but I felt that in the spirit of the Spring Framework, it couldn't be that hard to find some synergies between it and the security framework in ALES.

Not being a Spring guru, I took a look at the latest version (2.0) and realized that a lot had changed since I'd last looked at it over a year ago.  One thing that caught my eye was the new AOP framework.  Clearly, when it comes to doing authorizations in your code, AOP seems like a nice apporoach, and the Spring folks seem to have made it about as simple as possible to get started with it.

Spring AOP supports aspect join points at the method level.  In plain English, this means you can dynamically inject some code either before, after, or "around" a method invocation.  This is very much the use case for authorization decisions in an application- before you execute the transferFunds() method, better make sure the user is authorized.

AOP helps to solve the problem of performing authorizations in an application without having to manually track down and intercept each method call you wish to protect.  Using AOP, you can simply have Spring do the work for you.  On the flight back from BEAWorld last week, I found myself with a full laptop battery and a desire to try this out, so...

The first thing to do is identify a Java method you want to protect.  Let's take a simple example- the buying and selling of securities:

public interface TradeService
{
   public long buy(String cusip, int amount, int price);
   public long sell(String cusip, int amount, int price);
   public int getTotalSold();
   public int getTotalBought();
}

Our primary concern is with the buy() and sell() methods.  There may be complex policies that dictate when and how a user can perform these transactions- we don't want to code these in our app- let's let ALES handle them.

Naturally, we don't want our methods to have any awareness that they are under protection by ALES.  This is a central design pattern in Spring- separation of concerns.  We should be able to test our TradeService implementation without having ALES running.  This keeps our test client fairly clean:

TradeService ts = (TradeService)context.getBean("TradeService");
System.out.println("Start buying.");
for ( int k=1; k <= 10; k++ )
   try {
      ts.buy("037833100", 900*k, 150);
   } catch (Exception e)
   { System.out.println("Purchase DENIED"); }
System.out.println("Done buying.");

System.out.println("Now selling " + ts.getTotalBought() + " shares.");
   try {
      ts.sell("037833100", ts.getTotalBought(), 160);
   } catch (Exception e)
   { System.out.println("Sale DENIED"); }
System.out.println("Done selling.");

Just a quick note on our TradeService object- with Spring you don't use the new operator, but rather let Spring get you an object reference via a label - hence the context.getBean("TradeService") call.

Now here's the magic of AOP- we can tell Spring to automagically surround our calls to buy() and sell() with calls to ALES.  If ALES says go, then we continue along as if nothing happened.  If ALES says no, then we can throw an exception.  Here is the complete Spring configuration file:

<!-- ALES Specific Beans -->
<bean id="ALES" class="com.bea.ales.examples.springaop.ALES">
   <constructor-arg value="jssm"/>
   <property name="atnHandler" ref="ATNHandler"/>
</bean>
<bean id="ATNHandler" class="com.bea.ales.examples.springaop.AuthenticationHandler">
   <constructor-arg value="system"/>
   <constructor-arg value="weblogic"/>
</bean>

<bean id="BuyAuthorizationAspect" class="com.bea.ales.examples.springaop.AuthorizationAspect">
   <property name="ales" ref="ALES"/>
   <property name="action" value="execute"/>
   <property name="clippingNode" value="pojo"/>
   <property name="context">
      <props>
         <prop key="totalBought">$1I</prop>
      </props>
   </property>
</bean>

<bean id="SellAuthorizationAspect" class="com.bea.ales.examples.springaop.AuthorizationAspect">
   <property name="ales" ref="ALES"/>
   <property name="action" value="execute"/>
   <property name="clippingNode" value="pojo"/>
   <property name="context">
   <props>
      <prop key="cusip">$0</prop>
      <prop key="price">$2I</prop>
   </props>
   </property>
</bean>

<!-- Our Application Bean -->
<bean id="TradeService" class="com.bea.ales.examples.springaop.TradeServiceImpl"/>

<!-- Wire up authorization aspects -->
<aop:config>
   <aop:aspect ref="BuyAuthorizationAspect">
      <aop:pointcut id="BuyCutATZ"
         expression="execution(* com.bea.ales.examples.springaop.TradeService.buy(..))"/>
      <aop:around pointcut-ref="BuyCutATZ" method="authorize"/>
   </aop:aspect>
   <aop:aspect ref="SellAuthorizationAspect">
      <aop:pointcut id="SellCutATZ"
         expression="execution(* com.bea.ales.examples.springaop.TradeService.sell(..))"/>
      <aop:around pointcut-ref="SellCutATZ" method="authorize"/>
   </aop:aspect>
</aop:config>

Top to bottom, we define a series of beans (just POJOs) to encapsulate the ALES Java API and handle authentication (I ran this example from Eclipse and not in an app server).  Then we define two beans that are the actual Aspects themselves (these are just a POJO) with some properties set according to the access calls we expect them to make.

The key section is the <aop:config> bit- here we "wire up" our aspect POJO with our specific methods in our application POJO.  You can see that we've chosen the <aop:around> advice which means our aspect can inject code "around" the method call.  This is important, because it may happen that ALES says we cannot actually call the requested method and we need to be able to take alternative action.

If you think about what this is doing, we're actually setting up our Policy Enforcement Point thru configuration instead of Java code.  This is crucial- ALES acts as the Policy Decision Point (PDP) and Spring AOP acts as the Policy Enforcement Point (PEP).  Since Spring is actually calling ALES on your behalf, it's impossible for a developer to accidentally forget to make the call to the PDP.  Even more important (perhaps) is that you can take off the authorization calls with a single change to the <aop:config> section of this file and none of your code is touched.

Now the aspect code itself.  Surprisingly this is a small amount of code- basically all we need to do is call out to ALES and get back a decision.  Based upon that decision, we can proceed with the intended method call or throw an exception:

public class AuthorizationAspect
{
   private ALES ales;
   private String action;
   private String clippingNode;
   private AccessResult accessResult;
   private Properties context;
   public void setAles( ALES a ) { ales = a; }
   public void setAction( String a ) { action = a; }
   public void setClippingNode( String a ) { clippingNode = a; }
   public void setContext(Properties p) { context = p; }
   public AuthorizationAspect()
   {
      action = "execute"
      clippingNode = "pojo"
   }
   public Object authorize(ProceedingJoinPoint call) throws Throwable
   {
      try {
         String resourceName = clippingNode + "/"
                + call.getSignature().getDeclaringTypeName()
                + "." + call.getSignature().getName();
         accessResult = ales.getAtzSvc().isAccessAllowed(
                ales.getIdentity(),
                new RuntimeResource( resourceName, "exampleResource" ),
                new RuntimeAction( action, "exampleAction" ),
                createContext(call) );
      } catch (Exception e ) {
         e.printStackTrace();
         return null;
      }
      if ( accessResult.isAllowed() )
      {
         Object point = null;
         point = call.proceed();
         return point;
      }
      else {
         throw new Exception( "ATZ Denied by ALES!");
      }
   }

}

The aspect itself tries to be as generic as possible- most authorization decisions are exactly the same and all that changes are the resource name, the user identity and some context.  As you can see, I've made the resource clipping node and application context a property that can be changed in the Spring configuration itself.  This is a debatable decision because one might argue that this opens a security vulnerability.  On the other hand, hard coding it in the source makes it harder to change- so there is a trade off.

The resource name itself took some thinking- at first I was going to manually enter some logical names (e.g. /app/buy or /app/sell) and map them in as properties to my aspect.  But after thinking about it, I realized that Java already gives us a unique resource label- the fully qualified class name and method name!  To boot, Spring AOP will tell us what this is inside the aspect code itself.  This gives us the following resources (under the pojo node):

I decided to hardcode the action to be "execute".  Clearly any action will do, but it just felt right that policies enforcing method execution should use the "execute" action.

The key line in the aspect is where we conditionally do point = call.proceed().  This is the heart of the aspect- we are either moving forward with the intended call or rejecting it based upon what ALES comes back with.

Finally, let's look at the policies:

As you can see, we are only allowed to buy if the total amount bought is less than 5000 shares, and we can only sell for a particular cusip when the price is under $170.

Overall, I'm pretty satisfied with the ability to use ALES and Spring AOP together.  I think that with some elbow grease we could create a fully generic aspect class that handles not only dynamic context setting but also dynamic handling of the response context from ALES (using policy responses to filter SQL queries anyone?).

If only the flight home from BEAWorld had been just a bit longer...



February 2008

Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29  


Search this blog:


Archives

February 2008
September 2007
August 2007
July 2007
June 2007
May 2007

Recent Entries

Securing POJOs with Spring AOP and ALES


Powered by
Movable Type 3.31