SOAP XML Request with Basic Authentication in PHP - php

I am trying to setup a SOAP request in PHP using HTTP basic Authentication. For some reason I keep getting, HTTP/1.1 401 Unauthorized error.
This is an example of the request I'm trying to create:
POST https://url/someurl/soap HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "SomeSoapAction"
User-Agent: SomeUser Client-HttpClient/3.1
Content-Length: 1503
Authorization: Basic dGsomebasicreyteryheyp0ZXN0ZXI=
Host: somehost.com
This is a snippet of my code:
ini_set('display_errors',1);
ini_set("soap.wsdl_cache_enabled", "0");
error_reporting(E_ALL);
$wsdl = "urltosomewsdlfile.wsdl";
$url = "somerl";
$username = "username";
$password = "password";
$encodedstuff = base64_encode("{$username}:{$password}");
$client = new SoapClient($wsdl, array('exceptions' => true,'trace' => true,'login' => 'somelogin', 'password' => 'somepw'));
$header = new SoapHeader($url, 'Authorization: Basic', $encodedstuff);
$client->__setSoapHeaders($header);
try {
$result = $client->SomeSoapAction();
} catch (SoapFault $soapFault) {
var_dump($soapFault);
echo "<br />Request :<br />", htmlentities($client->__getLastRequest()), "<br />";
echo "<br />Response :<br />", htmlentities($client->__getLastResponse()), "<br />";
}
If I take the username and password out of the new SoapClient section it throws up Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from...
If I put in the base64 encoded variable to the new SoapClient section instead of the username/pw it throws the same Parsing error as above:
$client = new SoapClient($wsdl, array( 'authentication' => "Basic $encodedstuff", 'exceptions' => true,'trace' => true,));
The username and password work when loading the URL directly.
Can anyone point me in the right direction? Thanks for any help.
Update 12/18/18: I've been trying this as a new method suggested, but still receive the same 401 error message:
$opts = array( 'http'=>array( 'method'=>"POST", 'header' => "Authorization: Basic " . base64_encode("{$user}:{$pw}") ) );
$context = stream_context_create($opts);
$client = new SoapClient($wsdl, array('stream_context' => $context,'exceptions' => true,'trace' => true,));
$header = new SoapHeader($url, 'Authorization: Basic', $encodedstuff);
$client->__setSoapHeaders($header);
Update 15/01/19:
I'm still having issues with this.
Using SOAPUI I can make a successful request and gain authentication. I can't see what the difference is between the SOAPUI request and my own PHP request.
I've noticed that the request header created by my PHP code alters the POST and Host endpoint URLs. The first part of the POST URL has the domain removed and the Host also has the first section of the URL removed.
SOAPUI request header (correct returns 200):
POST https://test-example.com/file/SOAP HTTP/1.1
Host: test-example.com
PHP request header (returns a 401):
POST /file/SOAP HTTP/1.1
Host: example.com
This seems to be causing the problem as it looks as if I'm pointing to the wrong endpoint. Does anyone have any advice on what might be wrong with my PHP code to break this request? Thanks.

Related

How to set content type to 'application/soap+xml; charset=utf-8' in PHP while SOAP request

When I try to send a request to the WSDL I got this error Cannot process the message because the content type text/xml; charset=utf-8 was not the expected type application/soap+xml; charset=utf-8
Here is my code
$client = new SoapClient("http://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc?singleWsdl");
$parameter = array(
'User ID' => '0123',
'Password' => 'mf#abc',
'Pass Key' => 'abcdef1234',
);
$result = $client->getPassword($parameter);
I tried passing content type like this
$client = new SoapClient("http://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc?wsdl",array('content type'=>'application/soap+xml'));
but didnot work.
Here is the WSDL Link :WSDL Source Link
Please share some solutions. Thanks in advance.
Just change the SOAP version in your request to 1.2
$client = new SoapClient("http://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc?wsdl",array('soap_version' => SOAP_1_2));

Soap Header with Authorization Basic in native PHP

i need to connect to TeraData SOAP API which now demands a Authorization Basic Header to be sent with the login credentials. I do not know how to adress the problem. I got the access working in SoapUI when adding Basic Authorization Header - please can anyone help me to get the code straight:
Here's the Header SoapUI sends and the response is good:
POST http://example.com/api/soap/v6 HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
Content-Length: 302
Host: example.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Authorization: Basic [user&pass-base64-encoded]
Here's how i am trying to set up my SoapClient:
$namespace = "http://ecircle.com/developer/ecmapi";
$wsdl = "https://sslh.teradatadmc.com/teradata/api/soap/v6?wsdl";
$client = new SoapClient($wsdl, array("trace" => 1, "exceptions" => 0));
$login = 'xxx';
$password = 'yyy';
$header = new SoapHeader($namespace, 'Authorization: Basic',
base64_encode("$login:$password"));
$client->__setSoapHeaders($header);
it's not accepted and i just get an HTTP/1.1 401 Unauthorized Error
The stacktrace shows me the header that i sent - the Authorization part is missing there.
public '__last_request_headers' => string 'POST /api/soap/v6 HTTP/1.1
Host: example.com
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.5.12
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Content-Length: 584
man i was so stupid:
$client = new SoapClient($wsdl, array("trace" => 1, "exceptions" => 0,
"login" => $login, "password" => $password) );
For HTTP authentication, the login and password options can be used to supply credentials.
That's because you should encode your login credentials this way:
base64_encode("$login:$password")
instead of:
base64_encode($login) . ':' . base64_encode($password)

SOAP Authentication issue

I'm having authentication issues with the SOAP server I'm trying to connect to.
I need to use this address for retreiving the wsdl info
https://profitweb.afasonline.nl/profitservices/updateconnector.asmx?wsdl
When I enter this address in the browser, a username and password is asked. Filling in my username and password, the WSLD XML is shown.
So, I'm using this peace of PHP code
$wsdl = "https://profitweb.afasonline.nl/profitservices/updateconnector.asmx?wsdl";
$url = "https://profitweb.afasonline.nl/profitservices/updateconnector.asmx";
$login = 'username';
$password = 'password';
$client = new SoapClient( $wsdl, array('login' => $login, 'password' => $password));
But then I get the following error:
Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://profitweb.afasonline.nl/profitservices/updateconnector.asmx?wsdl' : failed to load external entity "https://profitweb.afasonline.nl/profitservices/updateconnector.asmx?wsdl" in C:\xampp\htdocs\test.nl\soap.php:8 Stack trace: #0 C:\xampp\htdocs\test.nl\soap.php(8): SoapClient->SoapClient('https://profitw...', Array) #1 {main} thrown in C:\xampp\htdocs\test.nl\soap.php on line 8
This doesn't look like a authentication error. However if I download the wsdl file manually, save it local and then use that file for creating a new SoapClient, I'm not getting any errors when initializing the SoapClient.
But if I then do a request
$client->__doRequest($request, $url, 'Execute', '1');
I'm getting this __getLastResponseHeaders
HTTP/1.1 401 Unauthorized ( The server requires authorization to fulfill the request. Access to the Web server is denied. Contact the server administrator. ) WWW-Authenticate: Negotiate WWW-Authenticate: Kerberos WWW-Authenticate: NTLM Connection: Keep-Alive Pragma: no-cache Cache-Control: no-cache Content-Type: text/html Content-Length: 3184
So that's giving me the idea that I'm running into authentication issues! Read a lot of posts already about this issue, but couldn't find the right answer jet!
EDIT
Adding this to the options
'trace' => 1, 'exceptions' => 0
Give's me indeed an authentication error.
Warning: SoapClient::SoapClient(https://profitweb.afasonline.nl/profitservices/updateconnector.asmx?wsdl): failed to open stream: HTTP request failed! HTTP/1.1 401 Unauthorized ( The server requires authorization to fulfill the request. Access to the Web server is denied. Cont in C:\xampp\htdocs\test.nl\soap.php on line 9
AFAS still uses NuSOAP (4.x) instead of SOAP (5.x). I'm using the noiselabs/nusoap-bundle which can be found on Github to access AFAS myself.
Basically you get these kind of errors when you connect with Afasonline Soap API in PHP
Below is an example how to connect and request
NOTE: First you need to know some concept about Afasonline API before connecting as you know Afasonline uses Nusoap with Windows NTLM Authentication so in order connect you need domain name for NTLM which is “AOL” in case Afasonline. You can read more about NTLM by searching over the internet. Further you need the following parameter also in order to connect
environmentId (it always starts with OXXXXXXX), userId, Password, connectorID.
I am going show an example for Getconnector with connectorID (SSS_werkgever_vacatures) to get all the jobs but method of authentication is same for all the connectors.
Click here to see Tutorial in Detail
<?php
require_once('lib/nusoap.php');
$wsdl = 'https://profitweb.afasonline.nl/profitservices/getconnector.asmx?wsdl';
$client = new nusoap_client($wsdl, true);
$client->setCredentials("AOL" . '\\' . "53175.Webbio", "Password!", 'ntlm');
$client->setUseCurl(true);
$client->useHTTPPersistentConnection();
$client->setCurlOption(CURLOPT_USERPWD, '53175.webbio:Password!');
$xml_array['environmentId'] = 'O12343AA';
$xml_array['userId'] = "41258.Webbio";
$xml_array['password'] = "Password";
$xml_array['logonAs'] = "";
$xml_array['connectorId'] = "SSS_werkgever_vacatures";
$xml_array['filtersXml'] = "";
$err = $client->getError();
if ($err) {
echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
echo '<h2>Debug</h2><pre>' . htmlspecialchars($client->getDebug(), ENT_QUOTES) . '</pre>';
exit();
}
$result = $client->call('GetData', array('parameters' => $xml_array), '', '', false, true);
// var_dump($result);
header('Content-Type: application/xml');
print_r($result["GetDataResult"]);
?>

How do I use Yelp's API in ZF2?

I'm trying to connect to Yelp's API, currently using ZF2 and ZendOAuth. I don't know why I'm getting a 404. Here is the raw request and response headers.
POST /v2/search?term=tacos&location=sf HTTP/1.1
Host: api.yelp.com
Connection: close
Accept-Encoding: gzip, deflate
User-Agent: Zend\Http\Client
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth realm="",oauth_consumer_key="<key>",oauth_nonce="<nonce>",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1387401249",oauth_version="1.0",oauth_token="<token>",oauth_signature="<signature>"
HTTP/1.1 404 Not Found
Date: Wed, 18 Dec 2013 21:14:09 GMT
Server: Apache
X-Node: web41, api_com
Content-Length: 8308
Vary: User-Agent
Connection: close
Content-Type: text/html; charset=UTF-8
X-Mode: rw
X-Proxied: lb1
Does that request look like it should connect somewhere?
Here's some code.
$accessToken = new \ZendOAuth\Token\Access();
$accessToken->setToken('<token>');
$accessToken->setTokenSecret('<secret>');
$host = 'http://' . $_SERVER['HTTP_HOST'];
$config = array(
'consumerKey'=>'<key>',
'consumerSecret'=>'<secret>',
);
$client = $accessToken->getHttpClient($config);
$client->setUri('http://api.yelp.com/v2/search?term=tacos&location=sf');
$client->setMethod('POST');
$adapter = new \Zend\Http\Client\Adapter\Socket();
$client->setAdapter($adapter);
$response = $client->send();
$result = $response->getBody();
All the examples of OAuth I've seen get the access token with a request token, but Yelp already gave me the token and secret, so I'm trying to construct it manually.
Update:
Changing
$client->setMethod('POST');
to
$client->setMethod('GET');
is the first step, but the parameters can't be added manually to the URL, they have to be added with setParameterGet();. So here's my updated working code.
$accessToken = new \ZendOAuth\Token\Access();
$accessToken->setToken('<token>');
$accessToken->setTokenSecret('<secret>');
$host = 'http://' . $_SERVER['HTTP_HOST'];
$config = array(
'consumerKey'=>'<key>',
'consumerSecret'=>'<secret>',
);
$client = $accessToken->getHttpClient($config);
$client->setUri('http://api.yelp.com/v2/search');
$client->setMethod('GET');
$params = array('term'=>'tacos', 'location'=>'sf');
$client->setParameterGet($params);
$adapter = new \Zend\Http\Client\Adapter\Socket();
$client->setAdapter($adapter);
$response = $client->send();
$result = $response->getBody();
That api requires GET method. So change:
$client->setMethod('POST');
To:
$client->setMethod('GET');
And try again )

NuSOAP 0.7.2 sending empty SOAP requests

OK, so before I get flooded with answers like "Use PHP's built-in SOAP extension" or "upgrade to nuSOAP 0.9.5" I just want to make it clear that these are not an option in my situation. I'm working in a hosted environment and I'm lucky they even had this legacy version of nuSOAP installed on the server.
That said, I need some help with my SOAP requests.
Here's what I have so far:
require_once('nusoap_0.7.2/nusoap.php');
ini_set("soap.wsdl_cache_enabled", "0");
date_default_timezone_set('America/Los_Angeles');
$wsdl = "https://api.bronto.com/v4?wsdl";
$ns = "https://api.bronto.com/v4";
$client = new soapclient($wsdl, array('trace'=>1, 'encoding'=>'UTF-8'));
// Login
$token = "API-TOKEN";
$sessionId = $client->call('login', array('apiToken' => $token), $ns, $ns);
if (!$sessionId) {
print "Login failed.\n";
exit;
}
print_r($sessionId);
$client->setHeaders(array($ns, 'sessionHeader', array('sessionId' => $sessionId)));
echo htmlspecialchars($client->request, ENT_QUOTES); // debug request
This is what the login call to the API returns:
Array ( [faultcode] => soap:Client [faultstring] => 107: There was an error in your soap request. Please examine the request and try again. [detail] => There was an error in your soap request. Please examine the request and try again. )
This is what the SOAP request ends up looking like:
POST /v4 HTTP/1.0 Host: api.bronto.com User-Agent: NuSOAP/0.7.2 (1.94)
Content-Type: text/xml; charset=UTF-8
SOAPAction: ""
Content-Length: 379
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns7166="https://api.bronto.com/v4">
<SOAP-ENV:Body>
<parameters/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The SOAP request appears to be sending fine but the envelope is empty. I suspect I may need to replace the arrays in the request with SoapVal objects, but the documentation on this object is difficult to get my head around.
For reference, this is the PHP SOAP code I am trying to translate to nusoap 0.7.2
ini_set("soap.wsdl_cache_enabled", "0");
date_default_timezone_set('America/New_York');
$wsdl = "https://api.bronto.com/v4?wsdl";
$url = "https://api.bronto.com/v4";
$client = new SoapClient($wsdl, array('trace' => 1, 'encoding' => 'UTF-8'));
$client->__setLocation($url);
// Login
$token = "ADD YOUR API TOKEN HERE";
$sessionId = $client->login(array("apiToken" => $token))->return;
if (!$sessionId) {
print "Login failed.\n";
exit;
}
$client->__setSoapHeaders(array(new SoapHeader("http://api.bronto.com/v4", 'sessionHeader', array('sessionId' => $sessionId))));
print "Login was successful.\n";
I had had same problem even on NuSOAP/0.9.11 and later. ;-) SOAPAction: ""
NuSOAP has several issues. E.g. it supports only wsdl-mode for me, and your NuSOAP api usage is wrong (new nusoap_client second parameter).
For using wsdl-mode you must smth like this:
$wsdlurl = 'https://api-sandbox.direct.yandex.com/v5/campaigns?wsdl'; // your wsdl url
$token = '<your token if needed>';
$locale = 'en';
// Construct NuSOAP-client
$client = new nusoap_client($wsdlurl, 'wsdl'); // second parameter must be boolean true or 'wsdl'
# Auth of NuSOAP-client
$client->authtype = 'basic'; /// but Yandex Direct needs 'bearer'
$client->decode_utf8 = 0;
$client->soap_defencoding = 'UTF-8';
// ..... $client->setCredentials and $client->setHeaders if needed
// Call soap/wsdl api method
$result = $client->call(
'get',
array('SelectionCriteria' => (object) array(), 'FieldNames' => array('Id', 'Name'))
); // string $operation (required), mixed $params (required), string $namespace (optional method namespace for non-WSDL), string $soapAction (optional SOAPAction value for non-WSDL)
// Output
echo "Request:<pre>".htmlspecialchars($client->request, ENT_QUOTES)."</pre>";
echo "Response:<p>".nl2br(htmlspecialchars($client->response, ENT_QUOTES))."</p>";
// Debug
echo '<hr><pre>'.htmlspecialchars($client->debug_str, ENT_QUOTES).'</pre>';
P.S.: If you need Yandex, fixed lib is here and samples client4yandex.

Categories