0

Quick background, our company connects to an ERP system (Sage) via web services for some functions. We have both c# (.net) and java code that performs calls to the Web Service (WS). Recently Sage introduced Basic Authentication into their WS.

Please note: This is a JAVA question, but I'll show an example in C# first to explain.

In the c# program, I first would create an object that is for accessing the WS:

                var sageService = new CAdxWebServiceXmlCCServiceBasicAuth();

I then set up credential information:

                var sageServiceCallContext = SageFactory.Instance.GetCallContext();

            sageService.Credentials = new NetworkCredential(SageUser, SagePwd);      
            sageService.PreAuthenticate = true;

then finally the call to the specific web service method:

                    sageCustomerSvcResponse = sageService.run(sageServiceCallContext, "YTDPROF", sageCustomerRequestInXml);

When I set up the service object I use a custom class that looks like this:

    public class CAdxWebServiceXmlCCServiceBasicAuth : CAdxWebServiceXmlCCService
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
        HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);

        NetworkCredential credentials = Credentials as NetworkCredential;
        if (credentials != null)
        {
            string authInfo = "";
            if (credentials.Domain != null && credentials.Domain.Length > 0)
            {
                authInfo = string.Format(@"{0}\{1}:{2}", credentials.Domain, credentials.UserName, credentials.Password);
            }
            else
            {
                authInfo = string.Format(@"{0}:{1}", credentials.UserName, credentials.Password);
            };
            authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
            webRequest.Headers["Authorization"] = "Basic " + authInfo;
        }
        return webRequest;
    }

}

What happens is that now, when I perform any call to the web service methods, the GetWebRequest from the class is invoked every time. This is how we implemented basis authentication in c#.

How do I do this in Java?

In the java code currently, I create the service object (that which accesses the web services) this way:

WebServiceInvoker service = new WebServiceInvoker(SageWSURL,""); 

and the WebServiceInvoker looks like this (truncated for brevity):

    public WebServiceInvoker(String url, String dummy) throws ServiceException, IOException {
    serviceLocator = new CAdxWebServiceXmlCCServiceLocator();
    service = serviceLocator.getCAdxWebServiceXmlCC(url);  
    cc = new CAdxCallContext();
    cc.setCodeLang("ENG");
    cc.setCodeUser("USER");
    cc.setPassword("PAWWORD"); 
    cc.setPoolAlias("POOL"); 
    cc.setRequestConfig("adxwss.trace.on=on&adxwss.trace.size=16384&adonix.trace.on=on&adonix.trace.level=3&adonix.trace.size=8");
    log = new PrintWriter(new BufferedWriter(new FileWriter("C:/Kalio/service/orders/log.txt")));
}

the webservice locator looks like this:

public class CAdxWebServiceXmlCCServiceLocator extends org.apache.axis.client.Service implements com.adonix.www.WSS.CAdxWebServiceXmlCCService {

public CAdxWebServiceXmlCCServiceLocator() {
}

    public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC() throws javax.xml.rpc.ServiceException {
   java.net.URL endpoint;
   System.out.println("using local Sage Web Servivce URL:" + CAdxWebServiceXmlCC_address);

    try {
        endpoint = new java.net.URL(CAdxWebServiceXmlCC_address);
    }
    catch (java.net.MalformedURLException e) {
        throw new javax.xml.rpc.ServiceException(e);
    }
    return getCAdxWebServiceXmlCC(endpoint);
}

public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(java.net.URL portAddress) throws javax.xml.rpc.ServiceException {
    try {
        com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub _stub = new com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub(portAddress, this);
        _stub.setPortName(getCAdxWebServiceXmlCCWSDDServiceName());
        return _stub;
    }
    catch (org.apache.axis.AxisFault e) {
        return null;
    }
}

and the specific method within that class is this:

    public String getCustomer(String constructedXML) throws RemoteException {
    **CAdxResultXml result = service.run(cc, "XTDPROF", constructedXML);**
    CAdxMessage[] messages = result.getMessages();
    for (int i = 0; i<messages.length; i++) {
        CAdxMessage message = messages[i];
        log.println("X3 get customer message: " + message.getMessage());
        log.println("X3 get customer message type: " + message.getType());
    }
    return result.getResultXml();
}

So my questions is, how to I emulate that override that I see in the .net program in Java? It seems like it would be somewhere in either the service locator or invoker, but the program does not use standard http classes, but this adxwss stuff. I tried a straight c# to java conversion and that way didn't help. I have seen examples where basicAuth is implemented, but not against web service calls.

The c# is pretty clear cut, because once I create the service object using the basicAuth override, every web service calls goes through the orderride. How does that happen in Java?

I'll be happy to provide more info if needed and I'll continue to look/experiment, but at the moment I'm treading water.

Adding:

In tracing through the java code I found the specific web service call (run) where an apache "call" object is created. Is this where basicauth can be added?

    public com.adonix.www.WSS.CAdxResultXml run(com.adonix.www.WSS.CAdxCallContext callContext, java.lang.String publicName, java.lang.String inputXml) throws java.rmi.RemoteException {
    if (super.cachedEndpoint == null) {
        throw new org.apache.axis.NoEndPointException();
    }
    org.apache.axis.client.Call _call = createCall();
    _call.setOperation(_operations[0]);
    _call.setUseSOAPAction(true);
    _call.setSOAPActionURI("");
    _call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
    _call.setOperationName(new javax.xml.namespace.QName("http://www.adonix.com/WSS", "run"));

    setRequestHeaders(_call);
    setAttachments(_call);
 try {        java.lang.Object _resp = _call.invoke(new java.lang.Object[] {callContext, publicName, inputXml});

    if (_resp instanceof java.rmi.RemoteException) {
        throw (java.rmi.RemoteException)_resp;
    }
    else {
        extractAttachments(_call);
        try {
            return (com.adonix.www.WSS.CAdxResultXml) _resp;
        } catch (java.lang.Exception _exception) {
            return (com.adonix.www.WSS.CAdxResultXml) org.apache.axis.utils.JavaUtils.convert(_resp, com.adonix.www.WSS.CAdxResultXml.class);
        }
    }
  } catch (org.apache.axis.AxisFault axisFaultException) {
  throw axisFaultException;
}
}
JuanMoreno
  • 2,498
  • 1
  • 25
  • 34
j.hull
  • 321
  • 3
  • 15
  • You don't need to emulate overriding. Overriding existed in Java before the whole of C# language existed. But whether that's the correct way to implement basic authentication in this case is a whole different issue, so it would be a bad idea to just try to translate your C# code to Java. But yes, it seems like Axis basic authentication would be what you want (the code in the bottom is horrible btw). – Kayaman Feb 05 '20 at 15:58
  • I came up with a solution that did not use an override or extends which I'll post in the answer. However, the java code present was built when the WSDL was imported. No question it ain't pretty. Neither will the solution, because it just uses the existing auto-build code. – j.hull Feb 12 '20 at 14:40
  • I understand you're using Axis stack for the web service client. Look at this question for the configuration for HTTP Basic authentication https://stackoverflow.com/questions/1528089/how-to-do-basic-authentication-with-an-axis2-adb-client – JuanMoreno Feb 12 '20 at 15:48

1 Answers1

0

The solution I came up with is not elegant, but then I'm not a guru in Java, just know enough to be given these tasks.

Our company uses Sage as our ERP system and Sage has a WSDL to define the basic web services it provides.

Sage Web Servicew WSDL

In their latest version of Sage they went with basic authentication, but did not build it into the new WSDL. Since I could not seem to extend the class (CAdxWebServiceXmlCCService), I just copied/pasted a new class called CAdxWebServiceXmlCCServiceBasicAuth. The full code is shown below if anyone ever has need to deal with something like this in a web service.

The key point where BaiscAuth set set up is in the getCAdxWebServiceXmlCC method. I added setPassword and setUserName to the stub that is returned. What this accomplishes is that every time I perform a webservice method call, that stub is now part of the header.

package com.adonix.www.WSS;

import java.net.URL;
import java.util.Base64;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;

import javax.xml.rpc.ServiceException;

public class CAdxWebServiceXmlCCServiceBasicAuth extends org.apache.axis.client.Service implements com.adonix.www.WSS.CAdxWebServiceXmlCCService {

public CAdxWebServiceXmlCCServiceBasicAuth() {
}


public CAdxWebServiceXmlCCServiceBasicAuth(org.apache.axis.EngineConfiguration config) {
    super(config);
}

public CAdxWebServiceXmlCCServiceBasicAuth(java.lang.String wsdlLoc, javax.xml.namespace.QName sName) throws javax.xml.rpc.ServiceException {
    super(wsdlLoc, sName);
}

// Use to get a proxy class for CAdxWebServiceXmlCC
private java.lang.String CAdxWebServiceXmlCC_address = "http://10.28.0.7:8124/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC";

public java.lang.String getCAdxWebServiceXmlCCAddress() {
    return CAdxWebServiceXmlCC_address;
}

// The WSDD service name defaults to the port name.
private java.lang.String CAdxWebServiceXmlCCWSDDServiceName = "CAdxWebServiceXmlCC";

public java.lang.String getCAdxWebServiceXmlCCWSDDServiceName() {
    return CAdxWebServiceXmlCCWSDDServiceName;
}

public void setCAdxWebServiceXmlCCWSDDServiceName(java.lang.String name) {
    CAdxWebServiceXmlCCWSDDServiceName = name;
}

public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(String userName,String password) throws javax.xml.rpc.ServiceException {
   java.net.URL endpoint;
    try {
        endpoint = new java.net.URL(CAdxWebServiceXmlCC_address);
    }
    catch (java.net.MalformedURLException e) {
        throw new javax.xml.rpc.ServiceException(e);
    }
    return getCAdxWebServiceXmlCC(endpoint,userName,password);
}

public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(java.net.URL portAddress,String userName,String password) throws javax.xml.rpc.ServiceException {
    try {
        com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub _stub = new com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub(portAddress, this);
        _stub.setPortName(getCAdxWebServiceXmlCCWSDDServiceName());
        _stub.setPassword(password);
        _stub.setUsername(userName);
        return _stub;
    }
    catch (org.apache.axis.AxisFault e) {
        return null;
    }
}

public void setCAdxWebServiceXmlCCEndpointAddress(java.lang.String address) {
    CAdxWebServiceXmlCC_address = address;
}

/**
 * For the given interface, get the stub implementation.
 * If this service has no port for the given interface,
 * then ServiceException is thrown.
 */
public java.rmi.Remote getPort(Class serviceEndpointInterface) throws javax.xml.rpc.ServiceException {
    try {
        if (com.adonix.www.WSS.CAdxWebServiceXmlCC.class.isAssignableFrom(serviceEndpointInterface)) {
            com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub _stub = new com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub(new java.net.URL(CAdxWebServiceXmlCC_address), this);
            _stub.setPortName(getCAdxWebServiceXmlCCWSDDServiceName());
            return _stub;
        }
    }
    catch (java.lang.Throwable t) {
        throw new javax.xml.rpc.ServiceException(t);
    }
    throw new javax.xml.rpc.ServiceException("There is no stub implementation for the interface:  " + (serviceEndpointInterface == null ? "null" : serviceEndpointInterface.getName()));
}

/**
 * For the given interface, get the stub implementation.
 * If this service has no port for the given interface,
 * then ServiceException is thrown.
 */
public java.rmi.Remote getPort(javax.xml.namespace.QName portName, Class serviceEndpointInterface) throws javax.xml.rpc.ServiceException {
    if (portName == null) {
        return getPort(serviceEndpointInterface);
    }
    java.lang.String inputPortName = portName.getLocalPart();
    if ("CAdxWebServiceXmlCC".equals(inputPortName)) {
        return getCAdxWebServiceXmlCC();
    }
    else  {
        java.rmi.Remote _stub = getPort(serviceEndpointInterface);
        ((org.apache.axis.client.Stub) _stub).setPortName(portName);
        return _stub;
    }
}

public javax.xml.namespace.QName getServiceName() {
    return new javax.xml.namespace.QName("http://www.adonix.com/WSS", "CAdxWebServiceXmlCCService");
}

private java.util.HashSet ports = null;

public java.util.Iterator getPorts() {
    if (ports == null) {
        ports = new java.util.HashSet();
        ports.add(new javax.xml.namespace.QName("http://www.adonix.com/WSS", "CAdxWebServiceXmlCC"));
    }
    return ports.iterator();
}

/**
* Set the endpoint address for the specified port name.
*/
public void setEndpointAddress(java.lang.String portName, java.lang.String address) throws javax.xml.rpc.ServiceException {

if ("CAdxWebServiceXmlCC".equals(portName)) {
            setCAdxWebServiceXmlCCEndpointAddress(address);
        }
        else 
{ // Unknown Port Name
            throw new javax.xml.rpc.ServiceException(" Cannot set Endpoint Address for Unknown Port" + portName);
        }
    }

/**
* Set the endpoint address for the specified port name.
*/
public void setEndpointAddress(javax.xml.namespace.QName portName, java.lang.String address) throws javax.xml.rpc.ServiceException {
    setEndpointAddress(portName.getLocalPart(), address);
}


@Override
public CAdxWebServiceXmlCC getCAdxWebServiceXmlCC() throws ServiceException {
    // TODO Auto-generated method stub
    return null;
}


@Override
public CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(URL portAddress) throws ServiceException {
    // TODO Auto-generated method stub
    return null;
}

}

j.hull
  • 321
  • 3
  • 15