Saturday, November 22, 2008

Leverage FlexSession to secure java based amf destination

Flex is gaining popularity in enterprise world. Authentication & authorization are common requirement of an enterprise application. To achieve this we often provide a login screen as the entry point to the application. Login screen validates user's credentials and based on role user will see various menu options and screens. 
Typical flex application consists of one or more swf file hosted on the net and remote service deployed as amf destinations. Using flex remoting application can talk to various backend systems based on ColdFusion, java etc. 
So where is the question of security. Flex app won't let you in unless you login to the application and flex app would let you perform only those operations available to your role.
Lets see how a java based remote object would look like. Before that lets consider this requirement
  • Two type of user: Read Only User & R/W user
  • Read-only user can see data on a screen
  • Read/Write user can read as well as update data on that screen
So, java backend class will have 3 main API exposed via remoting 
  • public User login(String username, String password) throws AuthException
  • public MyData getData() 
  • public void updateData(MyData data)
Login screen makes remote call to login() API to validate credentials and get users detail including roles. Based on role UI shows/hides the Update button to view/update data on post login screen.
Everything looks good but note that all the above 3 APIs are publicly exposed! Its very easy to forget about the fact that any remoting client, knowing the call details, will be able to invoke any of those exposed APIs. Thats where flex session would be useful to secure the APIs. Let see code snippet to get better picture.
public User login(String username, String password) throws AuthException
{
User user = myBusObj.login(username, password);
registerSession(user);
}
public MyData getData() throws AuthException
{
checkSession(reqRole);
return myBusObj.getData();
}
public void updateData(MyData data) throws AuthException
{
checkSession(reqRole);
return myBusObj.updateData(data);
}
private void registerSession(User user)
{
FlexContext.getFlexSession().setAttribute("AUTH_USER", user);
}
private void checkSession(String reqRole)
{
if(FlexContext.getFlexSession() == null || FlexContext.getFlexSession().getAttribute("AUTH_USER") == null || FlexContext.getFlexSession().getAttribute("AUTH_LEVEL") == null) throw new AuthException("some error message");
//check users role and compare with reqRole. if req role not present throw auth exception
}
With the above code in place, remote APIs can only called by authenticated & authorized clients. Find more detail on Flex Session here

Saturday, September 6, 2008

How to invoke web service with complex arguments in ColdFusion

Here is an excellent article describing how we can call web service with complex input arguments in ColdFusion. If you are well versed in WSDL, it may be easier to figure out and construct the input parameter as struct, array and simple types.
I am not good at understanding the WSDL and easily mapping those complex types to CF struct of array of struct of... Lets see if we have alternative ways to deal with the complex types.
Lets try to consume the web service described by below WSDL:
Dumping the webservice object will clearly show Method=createInvoice(com.test.vo.Invoice) and Return Type=com.test.vo.Invoice 
   <cfdump var="#createObject('webservice', 'http://myhost/above_test.wsdl')#">
Won't it be nice if we can just populate the value object Invoice and pass it the createInvoice() method?  But when I try to create an instance of com.test.vo.Invoice using createObject('java', 'com.test.vo.Invoice'), it throws Object Instantiation Exception. ColdFusion does like the idea of creating objects of axis generated classes?  No problem. We can still load these classes using Axis class loader (may not be a good idea though).
<cfset ws = createObject('webservice', 'http://adey03/java/testws.wsdl') />
<cfset invoice = ws.getClass().getClassLoader().loadClass("com.test.vo.Invoice").newInstance() />
<cfdump var="#invoice#">
...
<cfset account= ws.getClass().getClassLoader().loadClass("com.test.vo.Account").newInstance() />
<cfdump var="#account#">
...
<cfset address= ws.getClass().getClassLoader().loadClass("com.test.vo.Address").newInstance() />
<cfdump var="#address#">
...
<cfset product= ws.getClass().getClassLoader().loadClass("com.test.vo.Product").newInstance() />
<cfdump var="#product#">
Above code will clearly describe the composite objects like Invoice, Account etc. So we just need to follow simple steps after that: 
-create and populate Address, Account, Product 
-create and populate Invoice 
-call the web service method createInvoice() and pass the invoice object created above. 
Isn't it little more object oriented than struct of array of struct of...:-)

Thursday, September 4, 2008

JavaScript : form.submit is not a function

I was just trying to submit an HTML form using document.formname.submit() method and was getting these error on different browser. document.formname.submit is not a function Uncaught TypeError: Property 'submit' of object #HTMLForm element is not a function Thats weird! It worked all the time. I was clueless why JavaScript would behave like this...? Yeah, that was a silly mistake. I didn't realize that I named the submit button as 'submit' and that why javascript is failing. We may do this kind of mistakes every now and then...