Monday 3 October 2011

Secured Web Services in ColdFusion


One day I just felt the need to create a Secured ColdFusion Web Service and to my wonder I just found good examples of consuming it but none for publishing it. That influenced me to write a  blog for Web Service published in ColdFusion, consumed in ColdFusion and that too in a secured manner using <cfinvoke>/<cfobject>  username/password feature.

Without giving the overview I will just get into the details but before that it's must to understand that how is ColdFusion behaving from client side . From client side when you give username/password in <cfinvoke> tag or <cfobject> tag (see the sample code below), then ColdFusion sends the information as part of the request. The login information is passed to web server using HTTP basic authentication.



Please note that these are just code snippets. I will share the complete code in the end.



You just saw how easy it is to consume a web service in ColdFusion. Publishing also is a very simple task but there is a twist. ColdFusion doesn't give any specific feature to handle the authentication (username/password) sent by client-side(using cfinvoke/cfobject). But that doesn't mean you can not handle it. ColdFusion has already given an awesome feature of <cflogin> and expects the user to authenticate the credentials using that same feature.

Here is snippet of <cflogin> authentication.



Please read the comments inline to understand the code.

We just saw how to catch the username and password sent in request by cfinvoke but the question is where to use it. I will suggest to use this code in Application.cfc instead of web service component. The reason is, it could save you a lot of code rewriting and easy to maintain. You can just write the code once in Application.cfc in onRequestStart() method and for every request it will ask for authorization otherwise will  send UnAuthorized status.

I hope you got an idea of how to consume a web-service with credentials and how to publish a web-service which gives on access on proper authorization.

So now I will post the complete code for doing this. There will be three files namely: securedws.cfm, securedws.cfc and Application.cfc. I am assuming that ColdFusion9(installed in C:\) is used and these files are kept under C:/coldfusion9/wwwroot/securedwebservices/
Please change the URL of webservices in code given below accordingly if your configuration is different.








Please note that for consuming the web-services always prefer <cfinvoke> tag over <cfobject>. cfobject tag has one limitation, it caches the first username/password and then even if you will change the credentials, it will send the first credentials only.

For example, consider that there are two users for your webservice with two credentials lets say: user1/pass1 and user2/pass2.

First lets use cfobject with credentials of first user(user1/pass1) and try to access the web-service. It will send the correct credentials to web-service. Now change the credentials in the same cfobject and use second user's one(user2/pass2) and access the webservice. This time request should have send second user's credentials(user2/pass2) but it actually passes (user1/pass1). You can confirm this behavior using <cfdump output="console" var="#cflogin#"> at server side.

This behavior is only observed with cfobject only and is quite dangerous. So I will suggest you to use cfinvoke.


Feel free to post any queries.

ColdFusion Rocks!!!

Friday 30 September 2011

Add Handler to ColdFusion web services



Well first of all lets understand what does adding Handler to ColdFusion web services mean. As the name suggests, you can create and add your class/function in such a way that whenever there is a request/response to ColdFusion soap based web service, your class/function will be called.

Lets understand it from an example.
You created a service in ColdFusion, but you want your program 'Logger' to be called for every request/response so that you can log the service in your own way. Well as the ColdFusion already gives you logging handlers so lets take a good example.

What if you want to digitally sign your soap messages before sending them through ColdFusion. Its easy, I would suggest to use Apache xml security library and write a simple program in Java to do that. But the twist is how to call that java class everytime you send a soap response in ColdFusion. Well there is the need to add the handlers in ColdFusion web service. So here we go trying our hand at it.

Just follow few easy steps.


  1. Create a simple web service in ColdFusion and try to invoke it. See if its working fine and you are getting the expected result. Now open client-config.wsdd kept in {coldfusion_webroot}\WEB-INF\ folder. Take a back-up of this .wsdd and keep it safe. Open this wsdd in notepad and if you will notice, this .wsdd file is in xml format.
  2.  I will give you a snippet of wsdd file which I have modified.

  3. 
     
    
     
      
      
    
      
     
       
      
      
     
    
      
    .
    .
    .
    
    
    

  4. Check out what all has been mofified in this client-config.wsdd file. First of all look for <requestFlow> tag element in this file(usually this will be the child element of <globalConfiguration> element and will be commented by default). If <requestFlow> is commented then remove the comments around it and add this line in between <requestFlow> opening and closing tags: <handler type="myClass"/>
  5. Also notice that there will be one handler already present in it: <handler type="log"/>. This is ColdFusion's handler to log the requests. You can remove this log handler if you do not want your services to be logged(specially in production servers). Just comment this particular handler eg: <!-- <handler type="log"/> -->
  6. After doing this much there just one more line to be added in this wsdd file.  Notice that there is a <deployment> element tag in the beginning of file and its child is <handler> element tag. This handler is provided by ColdFusion for the very same purpose of logging. We will add our handler somewhat similar to ColdFusion's handler: <handler name="myClass" type="java:myClassName"/>. You can add this just beneath handler provided by ColdFusion. 
  7. Save this client-config.wsdd file and we are half way done. Now lets create one sample class for testing this and we will keep its name as myClassName.java, as we have given this very same name in wsdd file. You can choose whatever name you like but make sure to give the same name in handler. You can also make package but you need to keep it in similar manner in wsdd too eg: <handler name="myClass" type="java:myPackageName.myClassName"/>.
  8. Just as I explained the steps to add the handler in <requestFlow> in client-config.wsdd file, similarly you can also add a handler for <responseFlow> so that you can catch the reponses as well.
I will share a very simple code of java which creates one file in local directory so that we can keep a check that this method is getting called everytime web service is hit, by looking at the timetsamp of file created.


//java code
import java.io.*;
import org.apache.axis.handlers.*;
import org.apache.axis.*;

public class myClassName extends BasicHandler
{
 public void init()
 {
  super.init();
  System.out.println("init is called");
 }

 public void createFile() {
  try{
  File f;
  f=new File("D:\\sample.txt");
  if(!f.exists())
  {
   f.createNewFile();
   //New file has been created to the specified directory
  }
  }catch(IOException e)
  {e.printStackTrace();}
 }

 public void invoke(MessageContext mCtx) throws AxisFault {
  try {
   this.createFile();
  } 
  catch (Exception e) {
   e.printStackTrace();
  }
 }

}
Compile this program and keep the class file in {ColdFusion_documentroot}\lib\
Usually it will be C:\ColdFusion9\lib\

Understanding myClassname.java
  1. First of all I have imported few axis classes which are required for handler
  2. I have also extended the class with BasicHandler class of axis. This class is present in org.apache.xml.handlers.* in axis.jar (found in {ColdFusion_documentroot}\lib folder)
  3. This BasicHandler is an abstract class with invoke(MessageContext) as abstract method which is why its necessary to implement this method. This method throws AxisFault Exception. You can use this method for whatever you have to implement, 
  4. Other than this we have also written init() method. This method will be called first time when your handler(myClassName) will be called.
  5. You can extend this program's functionality to whatever you want.


Well that is it.
Just restart the server(as we have added myClassname.class in lib folder) and access the web service created by you, you will see the file created successfully. 


This way you can add whatever handler you want and as ColdFusion web services are based on Axis, you can take strong benefits of Axis library and do whatever you want with your web services in ColdFusion.


Feel free to post any queries.

ColdFusion Rocks!!!