WS Dynamic Client with https and user and password. SOAPUI util

Let's create a client that should be authenticated with https protocol.


1. The URL of the WSDL


It is https://192.XXX.XXX.XXX:8443/gexflow/ws/RegistroV3?wsdl


2. Creating the classes with Apache cxf

It is interesting creating the classes with wsdl2java shell as it can be seen in an elder post. So you can use these classes for several purposes and analyzing cxf interpretation of the WSDL.


3. Bypassing server authentication. NOT WORKING!!! skip this step!

If your server has a problematic certificate, (expired, not valid...) you can use a static method in the service class... but you cannot fool the cxf security (in new versions) as cxf redirects to a new DefaultHostServerVerifier. In older versions, this trick can work.

1
2
3
4
5
6
7
8
static {
  javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
    @Override
    public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
      return true;
    }
  });
}


4.Create properties for authentication


Let's create a map for storing the values for the authentication XXXXX

1
2
3
4
5
6
7
8
public static Map<String, Object> getPasswordInterceptorProperties(String user, CallbackHandler PwdProvider) {
  Map<String, Object> outProps = new HashMap<String, Object>();
  outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
  outProps.put(WSHandlerConstants.USER, user); //// Specify our username 
  outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST); // Password converted to MD5Hex
  outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, PwdProvider.getClass().getName()); //CallBackClass that stores passwords
  return outProps;
}


Line 4 the name of the user is given
Line 5, the password will be digested to MD5
Line 6, we need a class for assigning the password PwdProvider  hat implements CallbackHandler


5. Class for assigning the password

Here is a simple class


 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
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.wss4j.common.ext.WSPasswordCallback;
 
public class APwdProvider implements CallbackHandler {
 
    public void handle(Callback[] callbacks) throws IOException, 
        UnsupportedCallbackException {
 
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
 
        if (pc.getIdentifier().equals("myuser")) {
            // set the password on the callback. This will be compared to the
            // password which was sent from the client.
            
            pc.setPassword(DigestUtils.md5Hex("mypassword"));
            return;
        }
    }
 
}


6. The whole code with dynamic WS client

Here is the class

  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
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package mypackage;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import javax.security.auth.callback.CallbackHandler;

import org.apache.commons.lang3.reflect.FieldUtils;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.ext.logging.LoggingInInterceptor;
import org.apache.cxf.ext.logging.LoggingOutInterceptor;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;

import openadmin.wsteralco.ClientePasswordCallback;



public class WSUtils {
	
	/**
	 * Returns an endpoint client for WS
	 * @param WSDL_URL
	 * @return
	 */
	public static Client getWSClient(String WSDL_URL) {
		Client client=null;
		try {
			JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
			client = dcf.createClient(WSDL_URL);
		} catch (Exception e) {e.printStackTrace(); }	
		return client;
	}
	
	/**
	 * If the process is executed from a thread, the classloader is lost
	 *   and cannot create a class dynamically 
	 * @param WSDL_URL
	 * @return
	 */
	public static List<Object> getWSClientAndClassLoader(String WSDL_URL) {
		List<Object> lObs=new ArrayList<Object>();
		Client client=null;
		try {
			System.out.println("getting Client ....");
			JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
			client = dcf.createClient(WSDL_URL);
			System.out.println("Client got OK!");
			System.out.println("Getting class loader...");
			ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
			lObs.add(client);
			lObs.add(classLoader);
			System.out.println("got class loader...");
		} catch (Exception e) {e.printStackTrace(); }	
		return lObs;
	}
	
	public static List<Object> getWSClientAndClassLoader(String WSDL_URL, String user,  CallbackHandler PwdProvider, boolean showXMLMessage) {
		List<Object> lObs=new ArrayList<Object>();
		Client client=null;
		try {
			System.out.println("getting Client ....");
			JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
			client = dcf.createClient(WSDL_URL);
			System.out.println("Client got OK!");
			System.out.println("Getting class loader...");
			ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
			lObs.add(client);
			lObs.add(classLoader);
			System.out.println("Adding user and password...");
			
			Map<String, Object> outProps = getPasswordInterceptorProperties(user,PwdProvider);
			WSS4JOutInterceptor wsOut =new WSS4JOutInterceptor(outProps);
	        client.getOutInterceptors().add(wsOut);
	        
	        if (showXMLMessage) {
	        	client.getInInterceptors().add(new LoggingInInterceptor());
		        client.getOutInterceptors().add(new LoggingOutInterceptor());
		    }
			
		} catch (Exception e) {e.printStackTrace(); }	
		return lObs;
	}
	
	public static Map<String, Object> getPasswordInterceptorProperties(String user, CallbackHandler PwdProvider) {
	  Map<String, Object> outProps = new HashMap<String, Object>();
          outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
          outProps.put(WSHandlerConstants.USER, user); //// Specify our username 
          outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST); // Password converted to MD5Hex
          outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, PwdProvider.getClass().getName()); //CallBackClass that stores passwords
          return outProps;
	}
	
	public static void main (String[] args) throws Exception {
		try {
			List<Object> lObjs=WSUtils.getWSClientAndClassLoader(
				"https://myserver:8443/gexflow/ws/ExpedienteV3?wsdl", 
				"myuser", new APwdProvider(), true);
			
			Client GexflowClient          =(Client)      lObjs.get(0);
			ClassLoader gexflowClassLoader=(ClassLoader) lObjs.get(1);
			
			
			var mp   =new HashMap<String, Object>(); 
			mp.put("idEntidad"               , 2);
			mp.put("idExpediente"            , 11111);
			mp.put("codigo"                  , "2019_EXP_G000_01194");
			Object obtExp= ObjUtils.getObject("gexflow.expediente.ObtenerExpediente", gexflowClassLoader);
			ObjUtils.assignFieldsWithImplicitConversion(obtExp, mp);
			
			Object[] res =null;
			res = GexflowClient.invokeWrapped("obtenerExpediente",obtExp);
			Object resultado=res[0];
			System.out.println(res[0].toString());

	      } catch (Exception e) {
	         e.printStackTrace();
	      }
	   }
	
	
}

6. SoapUI utility



Here is a saple request


where the "auser" represents a user with WS privileges and the password is not the clean password, the digested in MD5 must be provided.

And the result





Comments

Popular posts from this blog

ORVE WS (Dynamic) (4) Jackson XML mapper

ENI (1) ENI Document OR the Spanish Electronic Administration Mafia

ORVE WS (Dynamic) (12) Defiining the control tables