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(); } } } |
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
Post a Comment