How should I implement a SOAP client that consumes a service using ws-security.
I have this binding information
<wsHttpBinding>
<binding name="WSHttpBinding_Service" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
To my understanding this a .Net configuration and must be mapped to corresponding definitions in PHP.
The wsHttpBinding to my understanding means that SOAP1.1 must be used, and that seems to be working fine.
However, it the security settings are a big problem.
Is there any PHP library that supports WS Security?
I have tried to add a security header to PHP call:
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>username</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken></wsse:Security>
However, this does not help. Am I missing something?
There are many questions in Stackoverflow on PHP and WS-Security, but I have not found any of them helpful.
EDIT: It turned out that there were problems in the server side.
You can use the vanilla PHP SoapClient (and friends) by using SoapVar to set the SOAP headers. For example;
$objSoapClient = new \SoapClient([...]);
$strXML = <<<XML
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
XML;
$objAuthVar = new \SoapVar($strXML, XSD_ANYXML);
$objAuthHeader = new \SoapHeader("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", 'Security', $objAuthVar, false);
$objSoapClient->__setSoapHeaders(array($objAuthHeader));
Related
Using PHP 5.5.9, I'm trying to make a SOAP call and I cannot figure out how to add this header:
<SOAP-ENV:Header>
<wsa:Action>https://websvcs.adtrack.com/SmartLeadImport/Submit_Lead</wsa:Action>
<wsa:MessageID>urn:uuid:GUID</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To>http://stage.adtrack.com/SmartLeadImport/SmartLeadImport.asmx?wsdl</wsa:To>
<wsse:Security SOAP-ENV:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-GUID">
<wsu:Created>2017-10-19T14:02:37Z</wsu:Created>
<wsu:Expires>2017-10-19T14:07:37Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-GUID">
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">***************</wsse:Password>
<wsse:Nonce>SOMENONSENSE</wsse:Nonce>
<wsu:Created>2017-10-18T14:02:37Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
What I'm having a real problem with is the nested namespaces. I've tried a couple different approaches.
Adding the XML to a SoapVar, then making that a header, but I can't figure out how to specify namespaces.
Trying to create SoapHeaders, but those came out looking odd, and again, I don't know how to make sure all the namespaces get accounted for.
Any help with this would be amazing. Thanks.
Im having some problems consuming a wsHttpBinding WCF from PHP. I originally tried to use SOAP1.2 but couldnt get it to specify the WS Action.
I downloaded the nusoap library. I was originally getting an error saying that the webservice wouldnt accept the data due to a type mismatch (text/xml instead of the expected application/soap+xml). I managed to make changes to nusoap.php to send the data as application/soap+xml). Now that doesnt throw an error, i get 400 bad request error from the server.
I can consume the service from WCFTestClient and also from SOAPUI without any messing around, but just cannot get it to fly from PHP. I even copied the entire soap envelope from SOAPUI and set the $soapmsg in nusoap.php to be exactly that and it still fails.
So anyone want to offer some guidance.
EDIT
This is the code i was trying in SOAP 1.2
$params = array("soap_version"=> SOAP_1_2,
"trace"=>1,
"exceptions"=>0,
);
$client = #new SoapClient('https://localhost/wcftest/Service.svc?wsdl',$params);
$retval = $client->GetData(array('value'=>'stuff'));
if (is_soap_fault($retval)) {
trigger_error("SOAP Fault: (faultcode: {$retval->faultcode}, faultstring: {$retval->faultstring})", E_USER_ERROR);
}
EDIT #2
This is the code that works out of SOAPUI
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>http://tempuri.org/IService/GetData</wsa:Action></soap:Header>
<soap:Body>
<tem:GetData>
<!--Optional:-->
<tem:value>stuff</tem:value>
</tem:GetData>
</soap:Body>
</soap:Envelope>
After adding the SoapHeaders manually as mentioned by Gords link below i get this as the __last_request when debugging with netbeans and still the same error
"<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://tempuri.org/">
<env:Header>
<ns1:Action>http://tempuri.org/IService/GetData</ns1:Action>
</env:Header>
<env:Body><ns1:GetData><ns1:value>stuff</ns1:value></ns1:GetData></env:Body></env:Envelope>
any advice??
Thanks!
Andy
Ok so i got this to work. Thanks to Gord for making me double check stuff that i had overlooked earlier on.
I ended ditching nusoap and just sticking with with SOAP 1.2. Here is my php code
//Declare some paramaters for our soapclient. Need to make sure its set to soap 1.2
$params = array("soap_version"=> SOAP_1_2,
"trace"=>1,
"exceptions"=>0,
);
//Create the soap client
$client = new SoapClient('https://localhost/wcftest/Service.svc?wsdl',$params);
//add some WSAddressing Headers in. Ensure that you have the Namespace as the address if you are using wsHttpBinding on the endpoint
//This was the step that took me the longest to figure out!
$actionHeader = new SoapHeader('http://www.w3.org/2005/08/addressing','Action','http://tempuri.org/IService/GetData',true);
//Add the headers into the client
$client->__setSoapHeaders($actionHeader);
//Make the call and pass in the variables that we require to go to the server
$retval = $client->__soapCall('GetData',array('value'=>'stuff'));
//Some Error Catching
if (is_soap_fault($retval)) {
trigger_error("SOAP Fault: (faultcode: {$retval->faultcode}, faultstring: {$retval->faultstring})", E_USER_ERROR);
}
and the working envelope
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://tempuri.org/" xmlns:ns2="http://www.w3.org/2005/08/addressing">
<env:Header>
<ns2:Action env:mustUnderstand="true">http://tempuri.org/IService/GetData</ns2:Action>
</env:Header>
<env:Body>
<ns1:GetData/>
</env:Body>
</env:Envelope>
and the web.config file from the WCF Service
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
<connectionStrings>
<add name="Timeforce" connectionString="Data Source=apps.ziptrek.com;Initial Catalog=qqest;User ID=qqest; Password=qqest;"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Service" behaviorConfiguration="Service1">
<endpoint address="https://localhost/wcftest/Service.svc" binding="wsHttpBinding" bindingConfiguration="TransportSecurity" contract="IService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Service1">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="httpsService1">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
I need to create this xml:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext">
<wsse:UsernameToken>
<wsse:Username>user</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<vb:getAirportInfo xmlns:vb="http://www.example.com/schema/2005/02/booking.xsd">
<airport>BNE</airport>
<airport>PPP</airport>
<airport>MEL</airport>
</vb:getAirportInfo>
</soapenv:Body>
</soapenv:Envelope>
I am new to using SoapClients and need some help doing this. How would I do it?
To successfuly use SOAP from PHP, you need two things:
The first is SoapClient and/or SoapServer classes bundled with PHP. They work fine, see http://php.net/manual/en/book.soap.php for details.
The second is WsdlDocument library. It generates WSDL description of your services, so other clients can easily use it. See http://code.google.com/p/wsdldocument/
Using SoapClient is very simple, once you initialize it, you will get object on which you can call methods as usual and it will forward these calls to server.
SoapServer is only about creating instance of you service and calling handle method.
None of this includes manual handling of XML you posted. It magically works on it's own (quite literally).
I figured it out. I needed to do two things.
First I needed to create the header section which had the security in it.
$soap_client = new SoapClient("airportinfo.wsdl", array("trace" => 1,"exceptions"=>0));
$header_part = '
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username>'.$username.'</wsse:Username>
<wsse:Password>'.$password.'</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
';
$soap_var_header = new SoapVar( $header_part, XSD_ANYXML, null, null, null );
$soap_header = new SoapHeader( 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'wsse', $soap_var_header, true );
$soap_client->__setSoapHeaders($soap_header);
Second I needed to create an array and pass it to the function that was the WSDL had. I got a list of these by using __getFunctions(). I then used this code to generate the last of the xml
$airports = array("AirportInfoRQ" => array("AirportCode" => "PPP", "AirportCode" => "BNE"));
$responce = $soap_client->AxisTransaction($airports);
This gave me slightly different xml I stated above but it was the correct xml to get the SoapClient working correctly
I need a litte bit help.
I have the following two URLS:
WSDL: https://amsel.dpwn.net/abholportal/gw/lp/schema/1.0/var3ws.wsdl
Endpoint: https://amsel.dpwn.net/abholportal/gw/lp/SoapConnector
Now I want to send the server something like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:var="https://amsel.dpwn.net/abholportal/gw/lp/schema/1.0/var3bl">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity- secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>ws_online_retoure</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-tokenprofile1.0#
PasswordText">Anfang1!</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<var:BookLabelRequest
portalId="OnlineRetoure"
deliveryName="Spanien_Var3"
shipmentReference="ShipRef Nextt"
customerReference="1.Feld via Webservice"
labelFormat="PDF"
senderName1="Willi Webservice"
senderName2="via Webservice"
senderCareOfName="careOfName"
senderContactPhone="0800 123456"
senderStreet="Webservice Street"
senderStreetNumber="8080"
senderBoxNumber="12"
senderPostalCode="28010"
senderCity="Madrid"/>
</soapenv:Body>
</soapenv:Envelope>
How can I do this in PHP?
Thanks!
I had the similar problem as well due to sparse examples on how to use SOAP with PHP. Here are a couple of examples that may guide you to developing the SOAP interface.
http://bisqwit.iki.fi/story/howto/phpajaxsoap/#IsSoapTheBestWay
http://geekswithblogs.net/THines01/archive/2010/03/07/callws.aspx
http://jimmyzimmerman.com/2007/02/soap-server-with-php5-part-1.html
SOAP is clearly an overkill for many purposes in my opinion.
See NuSoap.
It simplifies the build of WebServices and clients.
Hi im having some trouble creating a schmea using PHP.
I need to generate something similar to :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:loc="http://some-url">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://some-url">
<wsse:UsernameToken wsu:Id="UsernameToken-837" xmlns:wsu="http://some-url">
<wsse:Username>account-username</wsse:Username>
<wsse:Password Type="http://some-url">account-password</wsse:Password>
<wsse:Nonce>NuehdiIAyh==</wsse:Nonce>
<wsu:Created>2009-05-07T21:41:49.765Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<loc:getLocation>
<loc:address>some-address</loc:address>
<loc:maximumAge>
<metric>Second</metric>
<units>100</units>
</loc:maximumAge>
<loc:responseTime>
<metric>Second</metric>
<units>100</units>
</loc:responseTime>
<loc:tolerance>LowDelay</loc:tolerance>
</loc:getLocation>
</soapenv:Body>
</soapenv:Envelope>
I've had 0 luck though. I tried some examples using Soapvar,Soapparam, anyone have an idea how I can go by doing this?
NuSOAP is an excellent toolkit for SOAP. It's quite easy to use, and the support is very good.
http://sourceforge.net/project/shownotes.php?release_id=552239
There is an excellent documentation available on how to create SOAP Scheme's.