Invoking SAP ABAP Web Service

Sometimes we need to call function modules in SAP using Web Service techniques instead of plain RFC. For example, using PHP platform, we might want to avoid installing saprfc extension, and in .NET platform, we might want to avoid NetCo (SAP .NET Connector). It seems that calling SAP Web Services have several pitfalls. This post would inform you, the reader, so you would not make the same mistake as I did.

Ensure the Web Service is configured with authentication

At minimum, the web service must be invoked with SAP user id  and password. This means in two sides : the SAP web service must be prepared to receive SAP user id & password, and the calling client (.NET framework, for example) must send appropriate authentication headers (in my case, Basic authentication). For the first part, set the Authentication Method/ Transport Channel Authentication in transaction SOAMANAGER to require username/password. See http://scn.sap.com/docs/DOC-38805 for a screenshot. Failing to do so might make the Web Service provider asks for no authentication headers, so the calling client would not send any headers. This would result in 'SRT Authorization Denied' errors.

Ensure the calling client doesn't do Keep Alives

The problem is, SAP Netweaver's Web Service providers doesn't like keep alives. The symptoms is these error message : 'The request was aborted' or 'The request was cancelled'.  When I am watching network packets, the symptoms are FIN-marked packet from the server just after the client sends the POST request with the proper authentication headers.
What actually happens is :
  • client sends POST request without authentication headers, with Keep Alive on.
  • server replies with Not Authorized Http header.
  • client repeats POST request,  now with authentication headers
  • server sends FIN, because server doesn't feel like communicating anymore after sending Not Authorized reply. (I am not a server/network expert, but why on earth the server didn't send FIN after sending Not Authorized?)
For clients such as .NET Web Service client, this is would stop your client from calling SAP Web Service, so the workaround is to disable keep alive.  You might need to copy Markus Reich's solution from here.
public partial class xyzService : System.Web.Services.Protocols.SoapHttpClientProtocol {

...

    protected override System.Net.WebRequest GetWebRequest(Uri uri)
    {
        System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
        request.KeepAlive = false;
        request.ProtocolVersion = System.Net.HttpVersion.Version10;
        return request;
    }

...

}

Alternative: Force client to send authentication headers at first request

This is not standards-oriented, but this solution might be useful too : Force the web service client to send authentication headers at first request. So there is no need for a second client request.

protected override System.Net.WebRequest
GetWebRequest(Uri uri)
        {
            System.Net.HttpWebRequest request =
            (System.Net.HttpWebRequest)base.GetWebRequest(uri);
            if (this.PreAuthenticate)
            {
                System.Net.NetworkCredential nc =
                this.Credentials.GetCredential(uri, "Basic");
                if (nc != null)
                {
                    byte[] credBuf =
                    new System.Text.UTF8Encoding().
                    GetBytes(nc.UserName + ":" + nc.Password);
                    request.Headers["Authorization"] =
                    "Basic " + Convert.ToBase64String(credBuf);
                }
            }
            return request;
        }

Ensure your SAP web service user has S_SERVICE and/or SAP_BC_WEBSERVICE_CONSUMER

From what I read, we need SAP_BC_WEBSERVICE_CONSUMER role in the SAP userid used during authentication above. SRT Authorization denied errors might occurred because of missing authorization role/objects. The reference states that we only need S_SERVICE with correct fields. Please try either solutions. 

Try different WSDL options when having SOAP errors

I only vaguely remember that in the past using certain WSDL options resulted in problems such as SOAP errors. I can't remember whether document/literal or rpc/encoded is the correct one, in my latest experience the service works with document/literals WSDL.

ABAP protocol stack requires full domain in the URL

It is not that fully qualified domain name required because virtual host issues, but the ABAP web protocol stack short dumps when we call a URL using hostname only. It seems that the ABAP web protocol stack specifically looks for dots (.) in the host portion of the URL, and when finding none it would stop further processing. So please give your server a Fully Qualified Domain Name and calls it using the FQDN. Or just create an /etc/hosts entry with fake FQDN in the client, and call the web service using the fake FQDN. The tricky part is that your WSDL would contain service URL, but you need to override that if the URL contains no dots (.), replacing it with fake FQDN service URL.
References:

Comments

Popular posts from this blog

Long running process in Linux using PHP

Reverse Engineering Reptile Kernel module to Extract Authentication code

SAP System Copy Lessons Learned