Interoperability : WCF Secured Service, .NET Client, SoapUI, Java Client

Author: Shahim Sadakath


Hi Guys,


I had a requirement to make a secured WCF service to be hosted in HTTPS and the credentials must be passed with the soap header within the username token tags. So this post is about that.


1) WCF Service
 

public class MyService : IMyService

    {

   

        public ReturnMsg SaveTransaction(Transaction objTransaction, Patient objPatient)

         {

             System.Data.OracleClient.OracleConnection con = new System.Data.OracleClient.OracleConnection();

             System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand();

             ReturnMsg objReturnMsg = new ReturnMsg() { QaidNo = -1 };

            


            //The Logics have been removed 

             try

             {

                 //Validate for Mandatory Fields

                 if (Validate(objTransaction, objPatient, objReturnMsg))

                 {

                     


                     objReturnMsg.QaidNo = 10000;


                     objReturnMsg.Status = Status.Success;

                 }

                 



             }

             catch (Exception ex)

             {

                 objReturnMsg.Status = Status.Failed;

                 objReturnMsg.Message = ex.Message;

             }

             finally

             {

                 if (con.State == ConnectionState.Open)

                     con.Close();



                 con.Dispose();

             }

             return objReturnMsg;







         }

}


2) WCF Configurations (Web.config)



    

      

        

          

          

          

            

            

              

            

          

        

       

      

    

    

      

        

          

            

          

        

      

     

    

    

      

        

        

      

    

    



  


3) Custom Credential Validator 
 

public class UsernameValidator : UserNamePasswordValidator

    {

        public override void Validate(string userName, string password)

        {

            // validate arguments

            if (string.IsNullOrEmpty(userName))

                throw new ArgumentNullException("userName");

            if (string.IsNullOrEmpty(password))

                throw new ArgumentNullException("password");


            // check if the user is not test

            if (userName.Trim().ToLower() != WcfService.Properties.Settings.Default.WSSE_USER.Trim().ToLower()

                || password.Trim().ToLower() != WcfService.Properties.Settings.Default.WSSE_PWD.Trim().ToLower())

                throw new SecurityTokenException("Unknown username or password");

        }



    }


4) I created a Self signed certificate in IIS and hosted my Service in HTTPS 

 How to Create a Self Signed Certificate


.NET Client (Console Application)

 

1) Add Service Reference to MyService


2) Paste the following code in Program.cs

static void Main(string[] args)

        {


            


            //Creating an instance for the client   

            

            ServiceReference.MyServiceClient client = new ServiceReference.MyServiceClient();

            //Setting the Credentials

            client.ClientCredentials.UserName.UserName = "username";

            client.ClientCredentials.UserName.Password = "password";


            try

            {


                //Creating and Filling the Objects which will be passed to method

                ClientApplication.ServiceReference.Transaction objTransaction = new ClientApplication.ServiceReference.Transaction();

                ClientApplication.ServiceReference.Patient objPatient = new ClientApplication.ServiceReference.Patient();


               

                ClientApplication.ServiceReference.ReturnMsg objReturnMsg = client.SaveTransaction(objTransaction, null);


                //If Status is Success

                if (objReturnMsg != null && objReturnMsg.Status == ServiceReference.Status.Success)

                    Console.WriteLine(objReturnMsg.QaidNo);

                else

                    Console.WriteLine(objReturnMsg.Message);

            }

            catch (Exception ex)

            {

                Console.WriteLine(ex.Message);

            }

            finally { 

                 Console.ReadLine();

            }            



        }


3) Output

 



Soap UI 


1) Create a New Soap Project with Soap UI for the hosted WCF service (WSDL)


2) Double click on the created the Request and PasswordText for WSS-Password Type, specify the correct username and password in Request Properties


3) Output 

 

 

Java Client

 

1) Create a Java Application using Net Beans

 

2) Add a Web Service Client for the Java Application 

How to consume Web Services Net Beans

 

3) Add a SecurityHandler.java class for the project and paste the following code. Here you will specify the username and password.

/*

 * To change this license header, choose License Headers in Project Properties.

 * To change this template file, choose Tools | Templates

 * and open the template in the editor.

 */

package serviceclient;

import javax.xml.ws.handler.soap.SOAPHandler;

import javax.xml.ws.handler.soap.SOAPMessageContext;

import javax.xml.ws.handler.MessageContext;

import javax.xml.soap.*;

import java.util.*;

import javax.xml.namespace.QName;



/**

 *

 * @author Sshahim

 */

public final class SecurityHandler implements SOAPHandler {



    @Override public Set getHeaders()

    {

         QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", 

                "Security"); 

        HashSet headers = new HashSet(); 

        headers.add(securityHeader);         

        return headers; 

    }

    

    @Override public void close(MessageContext context)

    {

        

    }

    

    @Override public boolean handleFault(SOAPMessageContext context)

    {

        return true;

    }



    @Override  public boolean handleMessage(final SOAPMessageContext msgCtx) {



        // Indicator telling us which direction this message is going in

        final Boolean outInd = (Boolean) msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);



        // Handler must only add security headers to outbound messages

        if (outInd.booleanValue()) {

            try {

                // Get the SOAP Envelope

                final SOAPEnvelope envelope = msgCtx.getMessage().getSOAPPart().getEnvelope();



                // Header may or may not exist yet

                SOAPHeader header = envelope.getHeader();

                if (header == null)

                    header = envelope.addHeader();



                // Add WSS Usertoken Element Tree 

                final SOAPElement security = header.addChildElement("Security", "wsse",

                        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

                final SOAPElement userToken = security.addChildElement("UsernameToken", "wsse");

                userToken.addChildElement("Username", "wsse").addTextNode("username");

                userToken.addChildElement("Password", "wsse").addTextNode("password");



            } catch (final Exception e) {

                

                return false;

            }

        }

        return true;

    }



    

    // Other required methods on interface need no guts



}

 

4) Open the main java file and paste the following code. This code will bind the created handler before calling the service.

/*

 * To change this license header, choose License Headers in Project Properties.

 * To change this template file, choose Tools | Templates

 * and open the template in the editor.

 */

package serviceclient;



import javax.xml.bind.JAXBElement;

import javax.xml.namespace.QName;

import org.datacontract.schemas._2004._07.wcfservice.ReturnMsg;

import javax.xml.ws.BindingProvider;

import com.sun.xml.wss.XWSSConstants;

import javax.xml.ws.Binding;

import javax.xml.soap.SOAPException;

import java.util.*;

import javax.xml.ws.handler.Handler;

import org.datacontract.schemas._2004._07.wcfservice.Status;



/**

 *

 * @author Sshahim

 */

public class ServiceClient {



    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) {

        // TODO code application logic here

        

        org.datacontract.schemas._2004._07.wcfservice.Transaction objTransaction =

                new org.datacontract.schemas._2004._07.wcfservice.Transaction();

        

        org.datacontract.schemas._2004._07.wcfservice.Patient objPatient = 

                new org.datacontract.schemas._2004._07.wcfservice.Patient();

        

       ReturnMsg objReturn = saveTransaction(objTransaction, objPatient);

       if (objReturn.getStatus() == Status.SUCCESS)

           System.out.println(objReturn.getQaidNo()); 

       else

           System.out.println(objReturn.getMessage().getValue());  

        

                 

        

    }



    



    private static ReturnMsg saveTransaction(org.datacontract.schemas._2004._07.wcfservice.Transaction objTransaction, org.datacontract.schemas._2004._07.wcfservice.Patient objPatient) {

          

       



        org.tempuri.MyService service = new org.tempuri.MyService();

        org.tempuri.IMyService port = service.getWsSecureService();

        





        final Binding binding = ((BindingProvider)port).getBinding();

        List handlerList = binding.getHandlerChain();

        if (handlerList == null)

            handlerList = new ArrayList();



        handlerList.add(new SecurityHandler());

        binding.setHandlerChain(handlerList); // <- important!

     

        

        return port.saveTransaction(objTransaction, objPatient);

    }

    

    

    

}

 

5) Output

 

 

 

 

 



Tags: Java WCF C#
Views: 1023
Register for more exciting articles

Comments

Please login or register to post a comment.


There are currently no comments.