I need to connect to a web service that requires authentication credentials in the form of a plain text user name and password.
I have a basic understanding of SOAP and have managed to connect to other open web services that do not require a username or password using NuSOAP.
The following was sent to me:
<?php
// Set up security options
$security_options = array("useUsernameToken" => TRUE);
$policy = new WSPolicy(array("security" => $security_options));
$security_token = new WSSecurityToken(array(
"user" => "xxx",
"password" => "xxx",
"passwordType" => "basic"));
// Create client with options
$client = new WSClient(array("wsdl" => "https://xxx.asmx?wsdl",
"action" => "http://xxx",
"to" => "https://xxx",
"useWSA" => 'submission',
"CACert" => "cert.pem",
"useSOAP" => 1.1,
"policy" => $policy,
"securityToken" => $security_token));
// Send request and capture response
$proxy = $client->getProxy();
$input_array = array("From" => "2010-01-01 00:00:00",
"To" => "2010-01-31 00:00:00");
$resMessage = $proxy->xxx($input_array);
?>
After some research I understand that the above implementation uses wso2. I need to be able to do this without using wso2.
I have tried my best to look for resources (Google, forums, etc) about the above but haven't been able to find anything. I have read some tutorials on SOAP and have been able to set up a SOAP client using PHP but cannot get my head around all the authentication and "policies".
An explanation of how to achieve this and maybe some links to further reading about this would be very much appreciated as I am tearing my hair out! Ideally I would like some links to resources for an absolute beginner to the SOAP authentication.
Thanks. P.S some of the links/credentials in the above could have been xxx'd for privacy.
If you have the SOAP extension enabled in php (php version >= 5.0.1), you can use the SoapClient class to process your request. To authenticate, you can pass the username and password to the class with the target URL:
$soapURL = "https://www.example.com/soapapi.asmx?wsdl" ;
$soapParameters = Array('login' => "myusername", 'password' => "mypassword") ;
$soapFunction = "someFunction" ;
$soapFunctionParameters = Array('param1' => 42, 'param2' => "Search") ;
$soapClient = new SoapClient($soapURL, $soapParameters);
$soapResult = $soapClient->__soapCall($soapFunction, $soapFunctionParameters) ;
if(is_array($soapResult) && isset($soapResult['someFunctionResult'])) {
// Process result.
} else {
// Unexpected result
if(function_exists("debug_message")) {
debug_message("Unexpected soapResult for {$soapFunction}: ".print_r($soapResult, TRUE)) ;
}
}
If you're not sure about the functions you can call, you can view the target URL (e.g. ending in ".asmx?wsdl") in your browser. You should get an XML response that tells you the available SOAP functions you can call, and the expected parameters of those functions.
Check out the soap_wsse library
Related
I'm currently trying to implement a way to synchronize my PHP App calendar with the Outlook calendar of my clients, using Azure API.
I use OAuth2 and the custom Microsoft provider by Steven Maguire.
I currently run in an issue where I get an error in my response :
{"error":"unsupported_grant_type","error_description":"The provided value for the input parameter 'grant_type' is not valid. Expected values are the following: 'authorization_code', 'refresh_token'."}
I'm having trouble understanding why the grant_type password is not supported, even though it says on the documentation of Azure that it is.
The request looks like this :
client_id=44bef79b-**********************&client_secret=H****************&redirect_uri=https%3A%2F%2F192.168.1.123%2Fmapeyral%2Fcalendarsync.php&grant_type=password&username=******************&password=***********&scope=openid%20profile%20offline_access%20Calendars.ReadWrite
The Authorize url used is : https://login.live.com/oauth20_token.srf
as defined in the Steven Maguire provider.
The header contains the content-type application/x-www-form-urlencoded (I've seen a lot of post where this was what caused the error).
Some of my code :
$this->provider = new Microsoft([
'clientId' => MicrosoftGraphConstants::CLIENT_ID,
'clientSecret' => MicrosoftGraphConstants::CLIENT_SECRET,
'redirectUri' => MicrosoftGraphConstants::REDIRECT_URI,
'urlAuthorize' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::AUTHORIZE_ENDPOINT,
'urlAccessToken' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => MicrosoftGraphConstants::RESOURCE_ID,
'scope' => MicrosoftGraphConstants::SCOPES
]);
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_GET['code']))
{
// Try getting access token from Database
$workingAccount = $GLOBALS['AppUI']->getState('working_account');
if (isset($workingAccount))
{
// DB access
$DB = new DatabaseConnection();
$dbAccess = $DB->getConnection();
$contactData = DBUserUtils::getContactDataFromEmail($GLOBALS['AppUI']->getState('working_account'), $dbAccess);
// If at least one user contact found
if (!is_null($contactData))
{
// If has refresh token => fill session variables using refresh token
if (!is_null($contactData['contact_refreshToken']))
{
log_msg('debug.log', 'Has refresh token');
$GLOBALS['AppUI']->setState('preferred_username', $contactData['contact_email']);
$GLOBALS['AppUI']->setState('given_name', $contactData['contact_first_name']." ".$contactData['contact_last_name']);
// Get new tokens
$newAccessToken = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $contactData['contact_refreshToken']
]);
// Update tokens and DB
$GLOBALS['AppUI']->setState('refresh_token', $newAccessToken->getRefreshToken());
$GLOBALS['AppUI']->setState('access_token', $newAccessToken->getToken());
DBOAuthUtils::updateTokenForUser($contactData['contact_id'], $GLOBALS['AppUI']->getState('refresh_token'), $dbAccess);
$this->redirectTo($redirectURL);
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
function getAccessToken(){
$accessToken = $this->provider->getAccessToken('password', [
'username' => '*************',
'password' => '********',
'scope' => MicrosoftGraphConstants::SCOPES
]);
}
During the first try it doesn't pass the if (isset($workingAccount)) condition (as expected) and go straight to the last else.
Code is a bit ugly for now but I don't think it has an impact on my problem.
Any help would be appreciated !
Thanks
Edit : added code
That helped me, the problem was that I need to use Azure Active Directory and not Azure AD 2.0.
Problem solved !
I am trying to call a HTTPS ASMX service from my PHP blog
Here is my code
$param1="Web Submission";
$param2="Lead";
$param3="flase";
$param0=$comment_content;
if (!empty($comment_content)){
$client = new SoapClient("https://devop.setars.com/webservice/sellblog.asmx?wsdl");
$params->Notes=$param0;
$params->Type=$param1;
$params->PURPOSE=$param2;
$params->IsMail=$param3;
$result=$client->AddActivity($params);
}
When I tested this locally with HTTP it is working fine, but when hosting with HTTPS, it doesn't appear to be making the call correctly.
$param1="Web Submission";
$param2="Lead";
$param3="flase";
$param0=$comment_content;
if (!empty($param0)){
$client = new SoapClient("http://localhost:52078/WebService/SellBlog.asmx?wsdl");
$params->Notes=$param0;
$params->Type=$param1;
$params->PURPOSE=$param2;
$params->IsMail=$param3;
$result=$client->AddActivity($params);
}
I tried with this also but no solution
$soap_options = array(
'trace' => 1,
'exceptions' => 1 ,
);
$wsdl = "https://dev234.sentsis.com/webservice/sellblog.asmx?WSDL";
$param1="Web Submission";
$param2="Lead";
$param3="flase";
$param0=$comment_content;
if (!empty($comment_content)){
$client = new SoapClient( $wsdl, $soap_options);
$params->Notes=$param0;
$params->Type=$param1;
$params->PURPOSE=$param2;
$params->IsMail=$param3;
$result=$client->AddActivity($params)->AddActivityResult;
}
Is there any difference between making a service call from PHP to a HTTP service compared to a HTTPS one?
If you want to connect to a server that only supports SSLv2/3 and/or TLS 1.0 (no TLS 2 or 3), tell the SOAP client if you get a connection error by setting the appropriate stream context, example:
<?php
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
$client = new SoapClient(
'https://example.com/?wsdl',
array ( "encoding"=>"ISO-8859-1",
'stream_context' => stream_context_create($opts)
// your options
);
?>
You might need to disable the SOAP caching of WSDLs in order for the SOAP client to use the new context.
The Zend_Service_Twitter component is still for Twitters API v1.0 which will be deprecated at 5th March 2013. So I wanted to make my new website with Twitter API interaction v1.1 ready.
Everything works fine with v1.0 but if I change the URL from /1/ to /1.1/ it fails with the HTTP header code 400 and the JSON error message: Bad Authentication data (Code: 215)
To get the request and access token stayed the same and works already without any changes,
but if I want to verify the credentials like this I get the error I described above:
// Take a look for the code here: http://framework.zend.com/manual/1.12/en/zend.oauth.introduction.html
$accessToken = $twitterAuth->getAccessToken($_GET, unserialize($_SESSION['TWITTER_REQUEST_TOKEN']));
// I have a valid access token and now the problematic part
$twitter = new Zend_Service_Twitter(array(
'username' => $accessToken->getParam('screen_name'),
'accessToken' => $accessToken
));
print_r($twitter->account->verifyCredentials());
I changed the code of verifyCredentials in Zend/Service/Twitter.php from that to that:
public function accountVerifyCredentials()
{
$this->_init();
$response = $this->_get('/1/account/verify_credentials.xml');
return new Zend_Rest_Client_Result($response->getBody());
}
// to
public function accountVerifyCredentials()
{
$this->_init();
$response = $this->_get('/1.1/account/verify_credentials.json');
return Zend_Json::decode($response->getBody());
}
Now I added before the return Zend_Json[...] this line:
print_r($this->_localHttpClient->getLastRequest());
// And I get this output of it:
GET /1.1/account/verify_credentials.json HTTP/1.1
Host: api.twitter.com
Connection: close
Accept-encoding: gzip, deflate
User-Agent: Zend_Http_Client
Accept-Charset: ISO-8859-1,utf-8
Authorization: OAuth realm="",oauth_consumer_key="",oauth_nonce="91b6160db351060cdf4c774c78e2d0f2",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1349107209",oauth_version="1.0",oauth_token="hereismytoken",oauth_signature="hereisavalidsignature"
As you could see the oauth_consumer_key (and realm too) is empty. Could that be the error? How could I solve this error (because of the stricter new API version?)? Would it be fine to set somehow the oauth_consumer_key? If yes, how could I manage that?
Edit:
I also found already a bug report on the issue tracker of the Zend Framework:
http://framework.zend.com/issues/browse/ZF-12409 (maybe do an upvote?)
with ZF 1.12.3 the workaround is to pass consumerKey and consumerSecret in oauthOptions option, not directrly in the options.
$options = array(
'username' => /*...*/,
'accessToken' => /*...*/,
'oauthOptions' => array(
'consumerKey' => /*...*/,
'consumerSecret' => /*...*/,
)
);
While you wait to fix this issue in Zend_Twitter_Service component, you can do this workaround:
You need to send customerKey and customerSecret to Zend_Service_Twitter
$twitter = new Zend_Service_Twitter(array(
'consumerKey' => $this->consumer_key,
'consumerSecret' => $this->consumer_secret,
'username' => $user->screenName,
'accessToken' => unserialize($user->token)
));
Today I have the same problem - Zend Framework works with API 1.
I created new class like
class Zend_Service_Twitter11 extends Zend_Service_Twitter
And override functions, which I need.
statusUpdate
statusReplies
etc
$this->_session = new Zend_Session_Namespace('auth_twitter');
$config = Zend_Registry::get('config')->twitter->toArray();
$access_tokenSession = unserialize($this->_session->access_token);
$accessToken = new Zend_Oauth_Token_Access();
$accessToken->setToken($access_tokenSession->oauth_token);
$accessToken->setTokenSecret($access_tokenSession->oauth_token_secret);
$temp = array();
$temp['oauthOptions']['consumerKey'] = $config['consumerKey'];
$temp['oauthOptions']['consumerSecret'] = $config['consumerSecret'];
$temp['accessToken'] = $accessToken;
$temp['username'] = $access_tokenSession->screen_name;
$this->_twitter = new Zend_Service_Twitter($temp, null);
$this->_twitter->account->accountVerifyCredentials()->toValue()
i am new to SOAP . I am trying to integrate my application to SmartTurn webservice API(its a inventry management company). They are SOAP and wsdl for their API operations. i am new to soap so i have no idea that how i can do this in php. here is xml that i want to use.
<?xml version="1.0" encoding="UTF-8" ?><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:Body><saveSalesOrder
xmlns="http://www.smartturn.com/services/OccamService/sales-order">
<inCredential>
<ns1:UserId
xmlns:ns1="http://www.smartturn.com/services/occamtypes">webservice#fithoop.com.au</ns1:UserId>
<ns2:Password
xmlns:ns2="http://www.smartturn.com/services/occamtypes">secret</ns2:Password>
</inCredential>
<inSalesOrders>
<ns3:externalNumber xmlns:ns3="http://www.smartturn.com/services/sales-order-types">Ext-id-00502</ns3:externalNumber>
<ns4:type xmlns:ns4="http://www.smartturn.com/services/sales-order-types">EXTERNAL</ns4:type>
<ns5:date xmlns:ns5="http://www.smartturn.com/services/sales-order-types">2012-10-20T00:04:34.479Z</ns5:date>
<ns6:dateDue xmlns:ns6="http://www.smartturn.com/services/sales-order-types">2012-10-20T00:04:34.479Z</ns6:dateDue>
<ns7:customerName xmlns:ns7="http://www.smartturn.com/services/sales-order-types">customer name</ns7:customerName>
<ns8:customerContact
xmlns:ns8="http://www.smartturn.com/services/sales-order-types">customer contact</ns8:customerContact>
<ns9:customerContactPhone
xmlns:ns9="http://www.smartturn.com/services/sales-order-types">customer phone</ns9:customerContactPhone>
<ns10:customerAddress
xmlns:ns10="http://www.smartturn.com/services/sales-order-types">
<ns11:addressLine1
xmlns:ns11="http://www.smartturn.com/services/occamtypes">the main street</ns11:addressLine1>
<ns12:addressLine2
xmlns:ns12="http://www.smartturn.com/services/occamtypes">broadway</ns12:addressLine2>
<ns13:city
xmlns:ns13="http://www.smartturn.com/services/occamtypes">Oakland</ns13:city>
<ns14:state
xmlns:ns14="http://www.smartturn.com/services/occamtypes">California</ns14:state>
<ns15:country
xmlns:ns15="http://www.smartturn.com/services/occamtypes">USA</ns15:country>
<ns16:postalCode
xmlns:ns16="http://www.smartturn.com/services/occamtypes">94607</ns16:postalCode>
</ns10:customerAddress>
<ns17:salesRep xmlns:ns17="http://www.smartturn.com/services/sales-order-types">sales rep</ns17:salesRep>
<ns18:useShipToAsBillAddress
xmlns:ns18="http://www.smartturn.com/services/sales-order-types">false</ns18:useShipToAsBillAddress>
<ns19:shipToName xmlns:ns19="http://www.smartturn.com/services/sales-order-types">ship to name</ns19:shipToName>
<ns20:shipToContact
xmlns:ns20="http://www.smartturn.com/services/sales-order-types">ship to contact</ns20:shipToContact>
<ns21:shipToContactPhone
xmlns:ns21="http://www.smartturn.com/services/sales-order-types">ship to contact phone</ns21:shipToContactPhone>
<ns22:status xmlns:ns22="http://www.smartturn.com/services/sales-order-types">NEW</ns22:status>
<ns23:item xmlns:ns23="http://www.smartturn.com/services/sales-order-types">
<ns23:itemMasterId>BB-10</ns23:itemMasterId>
<ns23:description>this is a desc</ns23:description>
<ns23:details>these are details</ns23:details>
<ns23:orderedQuantity>
<ns26:value
xmlns:ns26="http://www.smartturn.com/services/occamtypes">10.0</ns26:value>
<ns27:unitAbbreviation
xmlns:ns27="http://www.smartturn.com/services/occamtypes">ea</ns27:unitAbbreviation>
</ns23:orderedQuantity>
<ns23:customerRequestDate>2007-03-
20T00:04:34.479Z</ns23:customerRequestDate>
<ns23:price>
<ns28:value
xmlns:ns28="http://www.smartturn.com/services/occamtypes">100.0</ns28:value>
<ns29:type
xmlns:ns29="http://www.smartturn.com/services/occamtypes">$10</ns29:type>
</ns23:price>
<ns23:vendorItemId>vendor item id</ns23:vendorItemId>
<ns23:manufacturerItemId>manf item id</ns23:manufacturerItemId>
<ns23:upcCode>UPC Code</ns23:upcCode>
<ns23:manufacturerId>manf id</ns23:manufacturerId>
</ns23:item>
<ns30:comments xmlns:ns30="http://www.smartturn.com/services/sales-order-types">This is a comment</ns30:comments>
</inSalesOrders>
</saveSalesOrder>
</soapenv:Body>
</soapenv:Envelope>
`
and the url is
$url = "https://services.smartturn.com/occam/services/OccamService?wsdl";
and the operation that i want to perform is 'saveSalesOrder'
how can i do that in php.
Thanks in advance .
First, you'll need PHP's SOAP extension installed and enabled. Then:
$url = "https://services.smartturn.com/occam/services/OccamService?wsdl";
$data = array(
"UserId" => "secret",
"Password" => "secret",
"type" => "EXTERNAL",
"date" => "2012-10-20T00:04:34.479Z",
"dateDue" => "2012-10-20T00:04:34.479Z",
"externalNumber" => "Ext-id-00502",
"customerName" => "test ",
"customerContact" => "customer Contact",
"customerContactPhone" => "123456789",
"salesRep" => "w salesRep",
);
try {
$soapClient = new SoapClient($url, array(
'trace' => true, // for debugging, disable in production
//"connection_timeout" => 1
));
// List types to get an idea how to call methods, since it looks like
// there are no help pages as in .asmx services
// var_dump($soapClient->__getTypes());
$soapClient->saveSalesOrder($data);
} catch (Exception $e) {
trigger_error("SOAP error: ".$e->getMessage(), E_USER_WARNING);
}
Links:
Overall SmartTurn service listing
PHP SoapClient documentation
Edit: updated example based on comment.
This is a great answer from Halil and really helped me to figure out what to do. You will need to add more arrays to create your request as the nested values of the XML request need to be put in arrays.
Also there is a minimum number of fields to fill out, so you're best to look at the API doc and see the sample request, then format your arrays to match the nested values.
For example:
$url = "https://stdemo.smartturn.com/occam/services/OccamService?wsdl"; //DEMO URL
// $url = "https://app.smartturn.com/occam/services/OccamService?wsdl"; //LIVE URL
$data = array(
"inCredential" => array("UserId" => "secret", "Password" => "secret"),
"inSalesOrders" => array("type" => "EXTERNAL",
"date" => "2012-10-20T00:04:34.479Z",
"dateDue" => "2012-10-20T00:04:34.479Z",
"externalNumber" => "Ext-id-00502",
"customerName" => "test ",
"customerContact" => "customer Contact",
"customerContactPhone" => "123456789",
"salesRep" => "w salesRep",
...
)
);
try {
$soapClient = new SoapClient($url, array(
'trace' => true, // for debugging, disable in production
//"connection_timeout" => 1
));
// List types to get an idea how to call methods, since it looks like
// there are no help pages as in .asmx services
// var_dump($soapClient->__getTypes());
$soapClient->saveSalesOrder($data);
} catch (Exception $e) {
trigger_error("SOAP error: ".$e->getMessage(), E_USER_WARNING);
}
The only issue with using this method for generating the SOAP envelopes is that as you are using an associative array, you can only sent 1 item object with each sales order request. As soon as you have multiple items in an order, this doesn't work. You could investigate SoapVar, I ended up forming the complete XML document and then sending it with CURL.
I'm trying to make my webservice in symfony with NuSOAP. I also made a client for test purpose.
I managed to make it work in my /web/ directory, but i can't access my symfony methods from there.
So i created a new module in my frontend app, and i copied the content of my nuSOAP server file into indexSuccess.php.
When i try to consume it, i get no error but also no results, and what's really strange is $proxy->response returning my homepage.
Here's my indexSuccess.php
require_once ("../lib/soap/nusoap.php");
$server = new soap_server();
$namespace = "Webservices";
$server->wsdl = new wsdl();
$server->wsdl->schemaTargetNamespace = $namespace;
$server->configureWSDL("Webservices", "Webservices");
function getDemandes($partnerCode)
{
$demandesArray = array();
$demandeArray[] = array( 'id' => 5, 'poid_id' => 25, 'demande_type' => "Male" );
$demandeArray[] = array( 'id' => 8,'poid_id' => 21, 'demande_type' => "Female");
return $demandeArray;
}
$server->register(
'getDemandes',
array('partnerCode' => 'xsd:string'),
array('getDemandesResponse'=>'tns:ArrayOfDemandesDatas'),
$namespace,
false,
'rpc',
'encoded',
'Return requests'
);
$POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
$server->service($POST_DATA);
exit();
After further research I get the error Response not of type text/xml: text/html; charset=utf-8 whitch is not surprising because i have my default layout in the $request -> response, even if i disable it with $this->layout(false);
Maybe you should choose an option that is better integrated in Symfony. There is the ckWebservicePlugin for example. This plugin is tightly integrated in Symfony and would be a far better choice than using NuSOAP.