Sunday, October 18, 2009

Secured BPEL services


Security is one of the essential  requirement for BPEL services as today BPEL services are mostly used for banking, paying and crediting applications. So BPEL services must be able to secure very reliable and flexible manner. WSO2BPS is the Best solution for it. Also it provides to configure security for your BPEL service in a user friendly manner.

First Lets deploy a simple BPEL in WSO2BPS.


1. Download latest release of WSO2BPS from Here

2. Extract wso2bps-1.1.X.zip  Lets define extracted location as BPS_HOME


3. Start BPS server  Run the wso2server.sh (in unix) or wso2server.bat (in windows) file in the BPS_HOME/bin directory
Once the server starts, point your Web browser to https://localhost:9443/carbon/

4. Deploy BPEL package just click on Add BPEL button and browse the Location of Your BPEL Package.  You can download sample BPEL Package (HelloWorld.zip) from here. Lets used it for further discussions.


In service list you will see our BPEL services (HelloService) and you can invoke this service. (by clicking on "Try this service" in WSO2BPS or Using Soapui).


So above BPEL service has not secured. Any one could be able to invoke it.




Now it is time to secure the our BPEL service


5.Go to Service Dashboard of BPEL service and enable security

You can see there are several QoS configurations for our BPEL service. Lets select the security








6. Select any security Scenarios 


As you can see, 15 security configuration scenarios are pre-defined for our BPEL service. You can use any one out of this Because I am going to write a client that works for all...



Here i am used default key store (wso2carbon.jks) as the Trusted Key Stores and Private key Store.  Or you can simply upload a New key store using BPS UI.



Now lets invoke secured service from security client

7. Create a Java project with SecurityClient.java and client.properties 
 files

8. Add Following configuration parameters to client.properties file

clientRepo = Path for Client repository location. Sample repo can be found in BPS_HOME/samples/axis2Server/repository location. or can download from here (must contains addressing.mar and rampart.mar in module directory)
clientKey =Path for Client's Key Store.  Here I am using same key Store (wso2carbon.jks) which is used to secure BPEL service. you can find it from BPS_HOME/resources/security. You can use any key Store but remember to import BPS cert to client key store and client cert to BPS key store. Because to fulfill the requirement for signing and encryption
securityPolicyLocation=Path for the client side security policy files. You can download 15 policy files from here.
trustStore= This is trusted store that is used for ssl communication on https. It should contains the BPS cert.you can use same key store for this. (wso2carbon.jks)
securityScenarioNo=Security scenario number that used to secure the BPEL service.
SoapAction =You can find it from wsdl
endpointHttp =Http endpont of BPEL service
endpointHttpS=Https endpont of BPEL service
body = Body part of your Soap message


Sample configurations



clientRepo=/home/asela/Wso2/BPS/BPS_Client/Client_Repo
clientKey =/home/asela/Wso2/BPS/BPS_Client/sample_keys/client.jks
clientKey =/home/asela/Wso2/BPS/BPS_Client/sample_keys/wso2carbon.jks
securityPolicyLocation=/home/asela/Wso2/BPS/BPS_Client/security_scenarios
trustStore=/home/asela/Wso2/BPS/BPS_Client/sample_keys/wso2carbon.jks
securityScenarioNo=7
SoapAction =urn:hello
endpointHttp =http://localhost:9763/services/HelloService/
endpointHttpS =https://10.100.1.152:9443/services/HelloService/
body =<p:hello xmlns:p=\"http://ode/bpel/unit-test.wsdl\"> <TestPart>Wso2</TestPart> </p:hello>


9. Copy Following Java code 

it is simple... Nothing to change...



import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.impl.llom.util.AXIOMUtil;
import org.apache.axiom.om.OMElement;
import org.apache.rampart.policy.model.RampartConfig;
import org.apache.rampart.policy.model.CryptoConfig;
import org.apache.rampart.RampartMessageData;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.client.Options;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.callback.CallbackHandler;
import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.util.Properties;

public class SecurityClient implements CallbackHandler {

 public static void main(String srgs[]) {

        SecurityClient securityCl = new SecurityClient();
        OMElement result = null;
          try {
                result = securityCl.runSecurityClient();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(result.toString());

        }

    public OMElement runSecurityClient( ) throws Exception {

        Properties properties = new Properties();
        FileInputStream freader=new FileInputStream("."+File.separator+"src"+File.separator+"client.properties");
        properties.load(freader);
        String clientRepo  = properties.getProperty("clientRepo");
        String endpointHttpS   = properties.getProperty("endpointHttpS");
        String endpointHttp   = properties.getProperty("endpointHttp");
        int securityScenario =Integer.parseInt(properties.getProperty("securityScenarioNo"));
        String clientKey = properties.getProperty("clientKey");
        String SoapAction = properties.getProperty("SoapAction");
        String body = properties.getProperty("body");
        String trustStore=properties.getProperty("trustStore");
        String securityPolicy =properties.getProperty("securityPolicyLocation");

        OMElement result = null;


        System.setProperty("javax.net.ssl.trustStore", trustStore);
        System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");

//        System.setProperty("javax.net.ssl.keyStore", keyStore + File.separator +  "wso2carbon.jks");
//        System.setProperty("javax.net.ssl.keyStorePassword", "wso2carbon");

        ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(clientRepo, null);
        ServiceClient sc = new ServiceClient(ctx, null);
        sc.engageModule("rampart");
        sc.engageModule("addressing");

        Options opts = new Options();

            if(securityScenario==1){
                opts.setTo(new EndpointReference(endpointHttpS));
            }else{
                opts.setTo(new EndpointReference(endpointHttp));
            }

        opts.setAction(SoapAction);

            if(securityScenario!=0){
                try {
                    String securityPolicyPath=securityPolicy+File.separator +"scenario"+securityScenario+"-policy.xml";
                    opts.setProperty(RampartMessageData.KEY_RAMPART_POLICY, loadPolicy(securityPolicyPath,clientKey));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        sc.setOptions(opts);
        result = sc.sendReceive(AXIOMUtil.stringToOM(body));
        System.out.println(result.getFirstElement().getText());
        return result;
    }
   
    public Policy loadPolicy(String xmlPath , String clientKey) throws Exception {

        StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
        Policy policy = PolicyEngine.getPolicy(builder.getDocumentElement());

        RampartConfig rc = new RampartConfig();

        rc.setUser("admin");
        rc.setUserCertAlias("wso2carbon");
        rc.setEncryptionUser("wso2carbon");
        rc.setPwCbClass(SecurityClient.class.getName());

        CryptoConfig sigCryptoConfig = new CryptoConfig();
        sigCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin");

        Properties prop1 = new Properties();
        prop1.put("org.apache.ws.security.crypto.merlin.keystore.type", "JKS");
        prop1.put("org.apache.ws.security.crypto.merlin.file", clientKey);
        prop1.put("org.apache.ws.security.crypto.merlin.keystore.password", "wso2carbon");
        sigCryptoConfig.setProp(prop1);

        CryptoConfig encrCryptoConfig = new CryptoConfig();
        encrCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin");

        Properties prop2 = new Properties();
        prop2.put("org.apache.ws.security.crypto.merlin.keystore.type", "JKS");
        prop2.put("org.apache.ws.security.crypto.merlin.file", clientKey);
        prop2.put("org.apache.ws.security.crypto.merlin.keystore.password", "wso2carbon");
        encrCryptoConfig.setProp(prop2);

        rc.setSigCryptoConfig(sigCryptoConfig);
        rc.setEncrCryptoConfig(encrCryptoConfig);

        policy.addAssertion(rc);
        return policy;
    }



    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

        WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[0];
        String id = pwcb.getIdentifer();
        int usage = pwcb.getUsage();

        if (usage == WSPasswordCallback.USERNAME_TOKEN) {

           if ("admin".equals(id)) {
               pwcb.setPassword("admin");
           }

        } else if (usage == WSPasswordCallback.SIGNATURE || usage == WSPasswordCallback.DECRYPT) {

            if ("wso2carbon".equals(id)) {
                pwcb.setPassword("wso2carbon");
            }
        }
    }
}

10. Add relevant libraries to your class path 

How do we find those libraries.. there are many. It is easy Go to BPS_HOME/bin and run ant command. You will see created jar file in BPS_HOME/repository/lib  directory. Do not forget to add xalan jar that is in BPS_HOME/lib/endorsed directory.

11.Then run your secured client
Now you are able to secure your BPEL service using all 15 security scenarios..........!!!

Note1 :- if You want to invoke a secured BPEL service(not HelloWorld).You can  get the body part of soap message using soapui and SoapAction using WSDL
    1. Create a project in soapui using your service's WSDL
    2. Copy the body part from your soap request message.( make sure to copy the correct namespace)
    3. Find value of Action attribute from your service's WSDL


Note2 :- if you want to trace the secured soap messages , Open tcpmon( WSO2BPS/bin/tcpmon.sh) and configure it  and change http end point of your client.properties file
     Listen port   = Port that you configure in client.properties file
     Target port  = Actual port of your BPEL service