Subscribe
Accepted Solution

Setting Credentials in CXF (or other java) clients

I am trying to invoke WFA Webservices from java using CXF. After generating JAX-WS stubs, the call is straight-forward.

public class WFAServiceTestClient {

    private static final QName SERVICE_NAME = new QName("http://ws.wfa.netapp.com/","WorkflowService");

    public static void main(String[] args) {

        URL wsdlURL=null;

        try {

             wsdlURL = new URL( "http://10.72.64.247/wfa-ws/WorkflowService_doc?wsdl");

        } catch (MalformedURLException e) {

            e.printStackTrace();

        }       

        WorkflowService ss = new WorkflowService(wsdlURL, SERVICE_NAME);

        WorkflowServiceDoc port = ss.getWorkflowServiceDocPort();

        // Set request context property.

        java.util.Map<String, Object> requestContext = ((javax.xml.ws.BindingProvider)port).getRequestContext();

        requestContext.put("ws-security.username", "admin");

        requestContext.put("ws-security.password", "admin");

        List returnList = port.getAllWorkflows();        

    }

}

But this code does not set the correct credentials and the call fails with :

com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 401: Unauthorized

What should be the correct method of setting the credentials ? I tried setting up a callback handler as per WS-Security UsernameToken spec 1.0, but it seems that WFA is not using it.

My request (from wireshark sniff) -

<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getAllWorkflows xmlns:ns2="http://ws.wfa.netapp.com/"/></S:Body></S:Envelope>

Re: Setting Credentials in CXF (or other java) clients

You should be using the AuthorizationPolicy capability as illustrated below:

private JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();

.

.

.

client = dcf.createClient(wsdlUrl);


AuthorizationPolicy authorization = ((HTTPConduit) client.getConduit()).getAuthorization();

authorization.setUserName(userName);

authorization.setPassword(password);

client.getRequestContext().put("javax.xml.ws.client.receiveTimeout", TIMEOUT_MS);// 120 seconds

client.getRequestContext().put("javax.xml.ws.client.connectionTimeout", TIMEOUT_MS);// 120 seconds

.

.

.

client.invoke(operationName, params)

Setting Credentials in CXF (or other java) clients

Thanks, is there some sample code that I can take a look at ?

Re: Setting Credentials in CXF (or other java) clients

Following is the class we use internally for testing:

/**

* Note that in order for this wrapper to run from TeamCity, the agent must have in its environment:<ul>

* <li> path=%path%;c:\work\tools\jdk\bin

* <li> JAVA_HOME=c:\work\tools\JDK

* </ul>

* Also, the "maven runner" should be configured to use JAVA_HOME.

* See http://garygregory.wordpress.com/2010/03/25/fixing-cxf-java-lang-illegalstateexception-unable-to-create-jaxbcontext-for-generated-packages/

*/

public class WebServiceWrapper {

    private static final String TIMEOUT_MS = "120000";

    private JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();

    private String hostIp;

    private String userName;

    private String password;

    private Map<String, CachedClient> clientCache = new HashMap<String, CachedClient>();

    public WebServiceWrapper(String hostIp, String userName, String password) {

        this.hostIp = hostIp;

        this.userName = userName;

        this.password = password;

    }

    public Object[] invokeWebService(String serviceName, String operationName, Object... params) {

        ClassLoader prevClassLoader = Thread.currentThread().getContextClassLoader();

        CachedClient cachedClient = getClient("http://" + hostIp + "/wfa-ws/" + serviceName + "?wsdl");

        try {

            return cachedClient.client.invoke(operationName, params);

        } catch (Exception e) {

            throw new EndToEndException("Web-service invocation failed invoking " + serviceName + "." + operationName, e);

        } finally {

            // Restore the original class loader

            Thread.currentThread().setContextClassLoader(prevClassLoader);

        }

    }

    @Override

    public String toString() {

        return "WebServiceWrapper{" +

                "hostIp='" + hostIp + '\'' +

                ", userName='" + userName + '\'' +

                ", password='" + password + '\'' +

                '}';

    }

    public String getHostIp() {

        return hostIp;

    }

    Map<String, CachedClient> getClientCache() {

        return Collections.unmodifiableMap(clientCache);

    }

    private CachedClient getClient(String wsdlUrl) {

        CachedClient cachedClient = clientCache.get(wsdlUrl);

        if (cachedClient == null) {

            cachedClient = new CachedClient(dcf.createClient(wsdlUrl));

            cachedClient.classLoader = Thread.currentThread().getContextClassLoader();

            AuthorizationPolicy authorization = ((HTTPConduit) cachedClient.client.getConduit()).getAuthorization();

            authorization.setUserName(userName);

            authorization.setPassword(password);

            cachedClient.client.getRequestContext().put("javax.xml.ws.client.receiveTimeout", TIMEOUT_MS);// 120 seconds

            cachedClient.client.getRequestContext().put("javax.xml.ws.client.connectionTimeout", TIMEOUT_MS);// 120 seconds

            clientCache.put(wsdlUrl, cachedClient);

        }

        else {

            // for existing client, restore's the client's class loader

            Thread.currentThread().setContextClassLoader(cachedClient.classLoader);

        }

        return cachedClient;

    }

    public class CachedClient {

        Client client;

        ClassLoader classLoader;

        public CachedClient(Client client) {

            this.client = client;

        }

        public Client getClient() {

            return client;

        }

    }

}

Example for using this utility:

webServiceWrapper = new WebServiceWrapper("10.68.66.170", "admin", "<some password>");

webServiceWrapper.invokeWebService("ValidationService", "validateConfiguration");