I have a complex SOAP header which fails to pass security on the web service:
Here is the required XML:
<soapenv:Header>
<sec:Customer>
<sec:Name>Name</sec:Name>
</sec:Customer>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>User</Username>
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Password</Password>
</UsernameToken>
</Security>
</soapenv:Header>';
And here is the PHP I tried:
$client = new SoapClient($wsdl, array( 'trace' => 1,'exceptions' => 1));
$cust = array('Name' => "Name");
$token = array('UsernameToken' => array('Username' => "User",'Password' => "Password" ));
$headers = array();
$headers[] = new SoapHeader($ns1,'Customer',$cust);
$headers[] = new SoapHeader($ns2,'Security',$token);
$client->__setSoapHeaders($headers);
WsSecutiry headers are specials and can be tricky to set. They are not declared as the other common Soap Headers.
Your WsSecurity header is pretty basic whereas it can be more complexe when it includes password digest, nonce, and other timestamp information. WsSecurity header can easily be added using the WsSecurity project.
You have to be sure of what is sent (SoapClient::__getLastRequest()) and you mus tbe sure that it matches what is expected if you don't want an error in return. If you still have an error, you should first contact the web service provider.
Related
Im trying a SOAP Client with PHP. The connection works fine, but the response is always full of questionmarks and new lines (/n).
How i can set utf 8 to my SOAP Connection, or is it possible, so set the response to json?
This is my Code:
$c = new SoapClient('https://example.com/services/ShipmentService/V4_3?wsdl');
$token = [
'delisId' => $auth->delisId,
'authToken' => $auth->authToken,
'messageLanguage' => 'de_DE',
];
$header = new SOAPHeader('http://example.com/common/service/types/Authentication/2.0', 'authentication', $token);
$c->__setSoapHeaders($header);
$response = $c->storeOrders(...);
I have problem with send SOAP query. For some reason my code [numerNadania] isn't good. I guess it's some problem with structure.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:e=http://e-nadawca.poczta-polska.pl
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<e:addReklamacje>
<reklamowanaPrzesylka
dataNadania="2018-05-22"
urzadNadania="260578"
powodReklamacjiOpis="TEST TEST TEST"
odszkodowanie="0" oplata="0" oczekiwaneOdszkodowanie="0">
<przesylka
guid="262A34BA2C1111116237B659B312F5EB"
numerNadania="00159007738099827991"
opis="TEST"
planowanaDataNadania="2018-05-22"
xsi:type="e:przesylkaBiznesowaType"/>
<powodReklamacji
idPowodGlowny="4"
powodGlownyOpis="TEST TEST TEST">
<powodSzczegolowy
idPowodSzczegolowy="9" powodSzczegolowyOpis="TEST TEST TEST"/>
</powodReklamacji>
</reklamowanaPrzesylka>
</e:addReklamacje>
</soapenv:Body>
</soapev:Envelope>
$options["login"] = "***";
$options["password"] = "***";
$options["soap_version"] = SOAP_1_2;
$wsdl = 'en.wsdl';
try {
$client = new SoapClient($wsdl,$options);
}
catch(Throwable $e) {
echo 'Wystąpił problem z połączniem API';
}
$params = array(
'reklamowanaPrzesylka' => array (
'przesylka' => array (
'guid' => getGuid(),
'numerNadania' => $id,
),
'powodReklamacji' => "Czas dostawy",
)
);
$problem = $client->addReklamacje($params);
stdClass Object ( [errorNumber] => 13250 [errorDesc] => Numer nadania dla składanych reklamacji jest wymagany [guid] => F8CF816CDF4DD8151116C0EE340C4031 )
Numer nadania dla składanych reklamacji jest wymagany - Send number is required [TRANSLATE]
In the past i have been using wsdl2php converters to create client code that resolves most of this type of issues.
See this one for example: https://github.com/rquadling/wsdl2php
They all work pretty much the same, you need to provide ?wsdl endpoint, run script and it will produce client code and output it in to file. Than you can include file and use generated classes and methods.
Hope this helps.
This is my service header
<soapenv:Header xmlns:la="http://ccc.xxx.zzz.jjj">
<la:AID>Bach</la:AID>
<la:CID>TT2569</la:CID>
<la:CuID>ABC</la:CuID>
<la:CaID>12235</la:CaID>
</soapenv:Header>
I am setting the header in my php code like this:
$soapenv = array(
'AID' => 'Bach',
'CID'=>'TT2569',
'CuID'=>'ABC',
'CaID'=>'12235'
);
$header = new SoapHeader('http://ccc.xxx.zzz.jjj', 'la', $soapenv, false);
$temp=new SoapClient($url, array());
$temp->__setSoapHeaders(array($header));
On calling service, I am getting the soap fault as if I have not set the header
Can somebody rectify mistakes, I have been doing?
Here is the code which get me going. I am not aware of the possibility of better code, please enlighten me, if there exists one.
Replaced
$header = new SoapHeader('http://ccc.xxx.zzz.jjj', 'la', $soapenv, false);
with
$header = array(
new SoapHeader('http://ccc.xxx.zzz.jjj', 'CID', 'TT2569', false),
new SoapHeader('http://ccc.xxx.zzz.jjj', 'CaID', '12235', false),
new SoapHeader('http://ccc.xxx.zzz.jjj', 'AID', 'Bach', false),
new SoapHeader('http://ccc.xxx.zzz.jjj', 'CuID', 'ABC', false)
);
I have SOAP service with WSDL and php-client for it.
Php-client:
<?php
$client = new SoapClient('https://xx.xx.xx.xx/service/?wsdl');
$headers = array();
$headers[] = new SoapHeader('http://mfisoft.ru/auth','Login','admin');
$headers[] = new SoapHeader('http://mfisoft.ru/auth','Password','admin');
$client->__setSoapHeaders($headers);
$table_hi = $client->getTableByTitle('Blocked numbers');
$row_data = array(
array(
array(
'name' => 'prfx',
'value' => '55555555'
),
array(
'name' => 'blocking_time',
'value' => '20140306185014'
)
)
);
$rowset=$client->insertRowset($table_hi, $row_data);
?>
But I need to rewrite the python.
I tried to do using suds and pysimplesoap.
from suds.client import Client
url = 'http://localhost/service/?wsdl'
client = Client(url)
I don't understand how make similar program in particular these strings
$headers[] = new SoapHeader('http://mfisoft.ru/auth','Login','admin');
$headers[] = new SoapHeader('http://mfisoft.ru/auth','Password','admin');
$client->__setSoapHeaders($headers);
I have not found in suds doc.
I need your help.
Thanks in advance.
p.s.
Sorry for my bad English
P.S.S.
I need to rewrite the php client in the python client.
Forgive the formatting in advance.. the proper way to setup and connect using the suds client is as follows. In the case that you want the server part, I can't tell 100% from your question.. I might be able to help but it's not something I've ever done before in python.
client = suds.client.Client.(self,url=wsdl_url,
doctor=schema_doctor,
username=username)
try:
# This will throw an Exception if the wsdl_url is bad
# and will return False if the authentication fails
if not client.service.Connection_Authenticate(username,
password):
raise Exception("Failed to authenticate.")
I'm attempting to get a shipping quote from an SOAP service. I've been able to successfully create authentication headers and query the SOAP service with basic requests that require no body parameters.
I'm able to create the proper structure for the request but the namespace values are not showing up in the request output.
Example code:
$client = new SoapClient("http://demo.smc3.com/AdminManager/services/RateWareXL?wsdl",
array('trace' => TRUE));
$headerParams = array('ns1:licenseKey' => $key,
'ns1:password' => $pass,
'ns1:username' => $user);
$soapStruct = new SoapVar($headerParams, SOAP_ENC_OBJECT);
$header = new SoapHeader($ns, 'AuthenticationToken', $soapStruct, false);
$client->__setSoapHeaders($header);
// Check if shipping is ready - base call
$ready_to_ship = $client->isReady();
The above works just fine and returns true if the shipping service is available.
So I use the following code to build the request body (only filling required fields):
I've also tried putting everything into an array and converting that to a SoapVar, I've tried including ns1: and ns2: in the body request creation but that hasn't worked either. I believe something needs to be adjusted in the request creation... not sure of the best approach..
$rate_request = $client->LTLRateShipment;
$rate_request->LTLRateShipmentRequest->destinationCountry = $destination_country;
$rate_request->LTLRateShipmentRequest->destinationPostalCode = $destination_postal_code;
$rate_request->LTLRateShipmentRequest->destinationPostalCode = $destination_postal_code;
$rate_request->LTLRateShipmentRequest->details->LTLRequestDetail->nmfcClass = $ship_class;
$rate_request->LTLRateShipmentRequest->details->LTLRequestDetail->weight = $ship_weight;
$rate_request->LTLRateShipmentRequest->originCountry = $origin_country;
$rate_request->LTLRateShipmentRequest->originPostalCode = $origin_postal_code;
$rate_request->LTLRateShipmentRequest->shipmentDateCCYYMMDD = $ship_date;
$rate_request->LTLRateShipmentRequest->tariffName = $tariff;
And it produces the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://webservices.smc.com">
<SOAP-ENV:Header>
<ns1:AuthenticationToken>
<ns1:licenseKey>xxxxxxxx</ns1:licenseKey>
<ns1:password>xxxxxxxx</ns1:password>
<ns1:username>xxxxxxxxm</ns1:username>
</ns1:AuthenticationToken>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:LTLRateShipment>
<LTLRateShipmentRequest>
<destinationCountry>USA</destinationCountry>
<destinationPostalCode>10001</destinationPostalCode>
<details>
<LTLRequestDetail>
<nmfcClass>60</nmfcClass>
<weight>300</weight>
</LTLRequestDetail>
</details>
<originCountry>USA</originCountry>
<originPostalCode>90210</originPostalCode>
<shipmentDateCCYYMMDD>20110516</shipmentDateCCYYMMDD>
<tariffName>DEMOLTLA</tariffName>
</LTLRateShipmentRequest>
</ns1:LTLRateShipment>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
But the output should include the namespaces (web: and web1: where appropriate). The above request returns an error code of missing tariffName.
Here's an example of what the xml request should look like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://webservices.smc.com" xmlns:web1="http://web.ltl.smc.com">
<soapenv:Header>
<web:AuthenticationToken>
<web:licenseKey> string </web:licenseKey>
<web:password> string </web:password>
<web:username> string </web:username>
</web:AuthenticationToken>
</soapenv:Header>
<soapenv:Body>
<web:LTLRateShipment>
<web:LTLRateShipmentRequest>
<web1:LTL_Surcharge> string </web1:LTL_Surcharge>
<web1:TL_Surcharge> string </web1:TL_Surcharge>
<web1:destinationCity> string </web1:destinationCity>
<web1:destinationCountry> string </web1:destinationCountry>
<web1:destinationPostalCode> string </web1:destinationPostalCode>
<web1:destinationState> string </web1:destinationState>
<web1:details>
<!--Zero or more repetitions:-->
<web1:LTLRequestDetail>
<web1:nmfcClass> string </web1:nmfcClass>
<web1:weight> string </web1:weight>
</web1:LTLRequestDetail>
</web1:details>
<web1:discountApplication> string </web1:discountApplication>
<web1:mcDiscount> string </web1:mcDiscount>
<web1:orgDestToGateWayPointFlag> string </web1:orgDestToGateWayPointFlag>
<web1:originCity> string </web1:originCity>
<web1:originCountry> string </web1:originCountry>
<web1:originPostalCode> string </web1:originPostalCode>
<web1:originState> string </web1:originState>
<web1:rateAdjustmentFactor> string </web1:rateAdjustmentFactor>
<web1:shipmentDateCCYYMMDD> string </web1:shipmentDateCCYYMMDD>
<web1:shipmentID> string </web1:shipmentID>
<web1:stopAlternationWeight> string </web1:stopAlternationWeight>
<web1:surchargeApplication> string </web1:surchargeApplication>
<web1:tariffName> string </web1:tariffName>
<web1:weightBreak_Discount_1> string </web1:weightBreak_Discount_1>
</web:LTLRateShipmentRequest>
</web:LTLRateShipment>
</soapenv:Body>
</soapenv:Envelope>
Any suggestions / direction appreciated!
Ok... After too many hours of testing I finally have a solution..
I recreated the Authorization Token as a class and built the Soap Request without having to deal with any namespaces, SoapVars etc. it's surprisingly easy.
/* Object for holding authentication info
this could probably be accomplished using stdClass too */
class AuthHeader {
var $licenseKey;
var $password;
var $username;
function __construct($loginInfo) {
$this->licenseKey = $loginInfo['licenseKey'];
$this->password = $loginInfo['password'];
$this->username = $loginInfo['username'];
}
}
// set current soap header with login info
$client = new SoapClient("http://demo.smc3.com/AdminManager/services/RateWareXL?wsdl",
array('trace' => TRUE
));
// create header params array
$headerParams = array('licenseKey' => $key,
'password' => $pass,
'username' => $user);
// create AuthHeader object
$auth = new AuthHeader($headerParams);
// Turn auth header into a SOAP Header
$header = new SoapHeader($ns, 'AuthenticationToken', $auth, false);
// set the header
$client->__setSoapHeaders($header);
// Check if shipping is ready - base call
$ready_to_ship = $client->isReady();
// $last_request = $client->__getLastRequest();
$last_response = $client->__getLastResponse();
//print $last_request;
if ($last_response == true) {
print "Ready to ship\n";
// Create the shipping request
$d = new stdClass;
$d->nmfcClass = $ship_class;
$d->weight = $ship_weight;
$p = new stdClass;
$p->LTLRateShipmentRequest->destinationCountry = $destination_country;
$p->LTLRateShipmentRequest->destinationPostalCode = $destination_postal_code;
$p->LTLRateShipmentRequest->details = array($d);
$p->LTLRateShipmentRequest->originCountry = $origin_country;
$p->LTLRateShipmentRequest->originPostalCode = $origin_postal_code;
$p->LTLRateShipmentRequest->shipmentDateCCYYMMDD = $ship_date;
$p->LTLRateShipmentRequest->tariffName = $tariff;
$quote = $client->LTLRateShipment($p);
$last_request = $client->__getLastRequest();
$last_response = $client->__getLastResponse();
print "Request: " . $last_request;
print "\nResponse: " . $last_response;
}