-->

Forbidden to Call method on Dynamics 365 AX via PH

2019-08-18 19:30发布

问题:

I am trying to call methods from dynamics SOAP through WSDL via PHP curl.

I get this error from both my webapp and SOAPUI. What could be the problem? It works fine when accessed from a .NET testing program with same credentials. Just facing problems from PHP side saying Forbidden with 1317 code. The specified account does not exist

I've been trying to call the method and faced different issues last issue I faced is this one. I thought maybe user agent I changed it I used SOAPUI. same thing. What I know is the user is registered in Azure AD and should have authorization for the app.

The POST is

POST /soap/services/servicemethodname?wsdl 
HTTP/1.1 
Host: domainname.sandbox.ax.dynamics.com 
Accept: text/xml 
Accept-Encoding: gzip,deflate 
Connection: Keep-Alive 
Content-type: text/xml 
User-Agent: Apache-HttpClient 
Authorization: Bearer longTokenString
Soapaction: "http://tempuri.org/webservice/method" 
Content-Length: 795 

The Response is

 HTTP/1.1 500 Internal Server Error Cache-Control: private 
 Content-Type: text/xml; charset=utf-8 
 Server: Microsoft-IIS/10.0 
 Strict-Transport-Security: max-age=31536000; includeSubDomains 
 Set-Cookie: ASP.NET_SessionId=hghtgkuhlihkjg; path=/; secure; 
 HttpOnly Set-Cookie: 
 ms-dyn-csrftoken= someTokenSTring; path=/; secure 
 ms-dyn-fqhn: 
 ms-dyn-namespace: namespace 
 ms-dyn-tenant: tenantidstring 
 ms-dyn-role: 
 ms-dyn-aid: aidString 
 X-Powered-By: ASP.NET 
 X-Content-Type-Options: nosniff 
 X-Frame-Options: SAMEORIGIN 
 p3p: CP="No P3P policy defined. Read the Microsoft privacy statement at https://go.microsoft.com/fwlink/?LinkId=271135" 
 Strict-Transport-Security: max-age=31536000; 
 includeSubDomains Date: Thu, 01 Aug 2019 19:24:52 GMT Content-Length: 1112 
 a:ForbiddenForbidden1317System.ComponentModel.Win32ExceptionThe specified account does not exist0-2147467259

I need to be able to call the method without errors and get the values it sends.

My php code

$requestBody = trim('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dat="http://schemas.microsoft.com/dynamics/2013/01/datacontracts" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tem="http://tempuri.org">
   <soapenv:Header>
      <dat:CallContext>
         <dat:Company>company</dat:Company>
         <dat:Language>en-us</dat:Language>
         <dat:MessageId>?</dat:MessageId>
         <dat:PartitionKey>12345667</dat:PartitionKey>
      </dat:CallContext>
   </soapenv:Header>
   <soapenv:Body>
      <m:getMethod xmlns:m="http://tempuri.org/webService/getMethod">
         <m:parameterName soap:mustUnderstand="1">12345</m:parameterName>
      </m:getMethod>
   </soapenv:Body>
</soapenv:Envelope>
            ');

    $soapAction = 'SOAPAction: http://tempuri.org/webService/getMethod';
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, 
            array(  'Accept:text/xml',
                    'Accept-Encoding: gzip,deflate',
                    'Connection: Keep-Alive',
                    'Content-type: text/xml; charset=utf-8',
                    'Cache-Control: no-cache',
                    'Pragma: no-cache',
                    'Authorization: Bearer longstringToken',
                    'SOAPAction: http://tempuri.org/webService/getMethod'
                ));
 if ($postData != '') {
            curl_setopt($ch, CURLOPT_POSTFIELDS,$postData);             
        }
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
// By default https does not work for CURL.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt ($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
// Set the option to recieve the response back as string.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
$odataURL = 'https://domainname.sandbox.ax.dynamics.com/soap/services/webService'; 
curl_setopt($ch, CURLOPT_URL, $odataURL);
// enable string response
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,false);

curl_setopt($ch, CURLOPT_POST, true);   

curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);
// Mark as Post request
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
// $output contains the output string
$output = curl_exec($ch);

回答1:

Ok so finally found a solution. It helps to read documentations on the classes you use and different systems used. In my case i was trying to integrate my app with microsoft dynamics 365 ax, so i had to read up on that too.

I read a lot of documents some were related to different dynamics service but this one helped most

And since the soap service needed Authorization Header, because they were using Windows authentication, we needed to get the token from oAuth link.

https://login.windows.net/$tenantDomainName/oauth2/token

PS: the oauth2 link i knew about it from github PHPConsoleApplication

I used PHP CURL to get my authorization Token and then created a client using PHP's SoapClient Class.

Make sure you add the authorization token in the header like so:

$arrayOpt = array(    
'stream_context'  => stream_context_create(
                            array('http' =>'Authorization: Bearer tokenString')
 ));

$client = new SoapClient($wsdl, $arrayOpt);

$response = $client->serviceMethod($parameters);

var_dump($response);

And you will get the values of the method.