Windows Azure Authentication for Bing Search in PHP - php

I am trying to perform a Bing Search by using the Windows Azure Marketplace API, I have downloaded their guide and sample code. The code prepares a HTTPS request with basic authentication, however I am constantly getting the following error:
Warning: file_get_contents(https://api.datamarket.azure.com/Data.ashx/Bing/SearchWeb/Web?Query=%27washburn%27&Adult=%27Off%27&$top=50&$format=Atom): failed to open stream: Connection refused
The php code (from Microsoft's document):
$context = stream_context_create(array(
'http' => array(
'proxy' => 'tcp://127.0.0.1:8888',
'request_fulluri' => true,
'header' => "Authorization: Basic " . base64_encode($accountKey.":".$accountKey)
)
));
Does anyone know what is causing the error please? I have correctly set the $accountKey and I tested it in a browser. What puzzles me a little is 127.0.0.1:8888 and also base64_encode($accountKey.":".$accountKey) , how come you need the $accountKey both before and after the : while when using a browser you are supposed to leave the username blank and just input the account key into the password field?

I have solved it and here is what I have found for future people that would be doing the same thing:
I commented out the line where it says:
'proxy' => 'tcp://127.0.0.1:8888',
'request_fulluri' => true,
and also set base64_encode("ignored:".$accountKey) instead
Base on what I read on MSDN, the username part is said to be ignored, so it shouldn't matter what value it is. I was thinking perhaps the length or the special characters in the key screwed things up so I replaces it with ignored (or anything really).
That did the trick and I can parse the returned JSON data. Good luck!

Related

PHP SOAP-ERROR: Parsing Schema: element already defined When Connecting to D365 WSDL

I am connecting to dynamics 365. It used to work perfectly, i curl to get the token then i use it as an authorization header along with php soapclient and it works, i connect i create a client and i can call my methods.
All of a sudden it decided not to work, and where it used to connect as SOAP 1.1 now it enforced SOAP 1.2
After changing from SOAP 1.1 to SOAP 1.2 ( because I got the error of binding mismatch where it said expecting application/soap+xml and text/xml was found ) So I changed versions and that error disappeared and got replaced with ERROR Fetching HTTP Headers.
That error got stuck for the longest time, people suggested to increase timeout but i put it as high as 500 800 5000 all the same.
Then all of a sudden, it started giving me SOAP ERROR Parsing schema element already defined. I did not change my code, i played for awhile with the headers but to no avail, I even removed the authorization header just to see what is going on and that did nothing i kept getting the same error.
SOAP-ERROR: Parsing Schema: element 'http://schemas.datacontract.org/2004/07/Microsoft.Dynamics.Ax.Xpp:XppObjectBase' already defined [string:Exception:private]
everytime I try to connect I get different kind of parsing schema error even though i am not changing anything in my code:
SOAP-ERROR: Parsing Schema: element 'http://schemas.microsoft.com/2003/10/Serialization/:anyType' already defined [string:Exception:private]
and another
SOAP-ERROR: Parsing Schema: element 'http://schemas.datacontract.org/2004/07/Microsoft.Dynamics.AX.KernelInterop:ProxyBase' already defined [string:Exception:private]
and then sometimes it does get through for a second but with fetching http header error again..
so i can not create a client instance anymore now..
where before i was able to create a client instance but i get an error when I call the method of "Error Fetching HTTP Headers"
something is definitely not stable because my errors are not one.
now some stated the wsdl could be faulty, but this is microsoft and the person i am in contact keeps saying he can not doing anything about it.
Help is this a PHP problem or a dynamics problem or wsdl custom made problem .
And how to solve this.
Thank you.
UPDATE
I'm sorry I mentioned earlier it is Dynamics AX , it turns out it is Dynamics 365 D365. I will keep dynamics ax tag in case it helps someone who needs the solutions provided.
UPDATE
Following is the connection code I am using:
function getAuthenticationHeader()
{
//Each variable has the values for our server
//resource
$appResource = urlencode($appADResource);
//clientID
$appClientID = urlencode($appADClientId);
//appSecret
$appSecret = urlencode($appADSecret);
//username
$appUserID = urlencode($appUserID);
// Password
$appUserPassword = urlencode($password);
// Construct the body for the STS request
$authenticationRequestBody = 'resource='.$appResource.'&client_id='.$appClientID.'&client_secret='.$appSecret.'&grant_type=password&username='.$appUserID.'&password='.$appUserPassword.'&scope=openid';
//Using curl to post the information to STS and get back the authentication response
$ch = curl_init();
// set url
$stsUrl = 'https://login.microsoftonline.com/'.$appTenantId.'/oauth2/token';
curl_setopt($ch, CURLOPT_URL, $stsUrl);
// Get the response back as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// Set the parameters for the request
curl_setopt($ch, CURLOPT_POSTFIELDS, $authenticationRequestBody);
// By default, HTTPS does not work with curl.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// read the output from the post request
$output = curl_exec($ch);
// close curl resource to free up system resources
curl_close($ch);
// decode the response from sts using json decoder
$tokenOutput = json_decode($output);
return $tokenOutput->{'token_type'}.' '.$tokenOutput->{'access_token'};
}
try
{
//WSDL Link
$url = "https://urlToOurServer/services/webservice?wsdl";
$authorizationToken = getAuthenticationHeader();
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
),
'https' => array(
'curl_verify_ssl_peer' => false,
'curl_verify_ssl_host' => false
),
'http' => array(
'header' =>'Authorization: '.$authorizationToken
)
));
//Create array of Soap Options
$arrOpt = array(
"soap_version" => SOAP_1_2,
"cache_wsdl" => WSDL_CACHE_NONE,
"exceptions" => true,
'trace' => true,
'encoding' => 'UTF-8',
'stream_context' => $context
);
}catch(Exception $e)
{
print_r($e);
}
I also found this in my wsdl
<sp:IssuedToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<sp:RequestSecurityTokenTemplate>
<trust:TokenType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0
</trust:TokenType>
<trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer
</trust:KeyType>
</sp:RequestSecurityTokenTemplate>
<wsp:Policy>
<sp:RequireInternalReference/>
How can I connect to SAML for Token ?
If everything is pretty much the same, but it's not working, the first thing to do is rule out the most basic AX issues. These may not solve your issue but will be a good first step.
now some stated the wsdl could be faulty, but this is microsoft and the person i am in contact keeps saying he can not doing anything about it.
Whomever that person is, you need to confirm they've done the following:
Confirm the environment and specifically the CIL is fully compiled. Do a full AXBuild and a full CIL to be sure during non-business hours and ensure the output is good. It's basically saying "recompile everything".
Refresh the WCF configuration in the client configuration you are using to connect to AX. This client configuration may be a *.axc file or it may just be the active one. Also refresh the business connector WCF. This is separate and may be what you are using to connect to AX. This is what most people are talking about.
Here's a little article that talks about creating a configuration, but I'll discuss below.
An AX client configuration ultimately is a bunch of text. It's either stored in an .axc file or stored in the registry in a few locations. The Business Connector client config may be the one that is getting missed in your scenario.
If you follow the link above and create a new .axc configuration file and ensure you've clicked "Refresh Configuration" before exporting, when you open the file up in Notepad, you'll see wcfconfig and a bunch of XML following it. That XML is what you're trying to get updated. Creating a new AXC here is just an exercise to help you understand what it is. You can delete the file after you're done looking.
Now, you've basically created a specific configuration file, but that doesn't mean anything is using it. If you call AX32.exe it will default to the one that is loaded in that config screen. Using a file is a way to very specifically choose one. Your code is probably using a specific AXC somewhere that needs either replaced or refreshed OR it's using one that's saved in this window:
It is very likely it is using one of the two that are saved in that configuration window. When you refresh in that window, it ultimately saves the WCF XML in the windows registry on the machine that is hosting the client and/or the AOS in subfolders in HKLM\SOFTWARE\Microsoft\Dynamics\6.0\Configuration. The key(s) is wcfconfig paired with wcfconfigversionid, which just stores a GUID to see if it's up-to-date.
When I say two, I mean most people don't even bother to look at the Business Connector AXC. It's what is highlighted in yellow in my image, and you need to specifically choose and refresh it. This could be important for you. In my image, I do not have it chosen. You need to drop the menu down and choose it.
On a dev machine, you can just clear both of those keys and refresh and you should see whatever configuration you're working on update.
This is a long post, but it's important to rule this part out first. If you have someone who's reasonably experienced administering AX they should know how to ensure these are refreshed.
Since you're saying this is not Dynamics AX, but one of the Dynamics 365 versions. The AX version used to be called Dynamics 365 for Finance and Operations Enterprise Edition but they've changed the licensing/naming again, so I don't even know what it's technically called. Most people call it Dynamics 365 for Operations or some variant.
Either way, you should test the service following the below method. We would need to see more information about the service details and call, so following the below is most likely best.
https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/third-party-service-test

API token authentication issues in php

First of all I want to say that I'm not a native english (french) so that's why this could bring some mistakes sometimes.
So my problem is that I'm trying to use the API of a website, which documentation can be found at documentation
The problem is for requests which need authentication, every thing is fine for public requests.
So I tried the first request which is according to the website 'retrieve account balances' which is a signed get method (using a hmac256 payload).
Thing are getting harder since the documentation is saying that the payload has to be either recvWindow=5000×tamp=1540203005798 (with the weird cross before tamp) even if I think this is more a display problem or has we can find in the documentation at another line : recvWindow=5000&timestamp=my timestamp.
So this is the first problem because I don't know the which one to use in the payload. (but I've tried with both and it didn't work so ...).
Then I wrote a quick php script to retrieve my informations :
<?php
include('pwd.php');
$time = time()*1000;
$sign = hash_hmac('sha256', 'recvWindow=5000&timestamp='.$time, $private);
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=> array("Authorization" => $public,
"Signature" => $sign
)
));
$context = stream_context_create($opts);
$fp = file_get_contents('https://trade.coss.io/c/api/v1/account/balances?
recvWindow=5000&timestamp='.$time, false, $context);
echo $fp;
?>
The first include juste includes my public key and my private key.
I run out of idea to find what is the problem with this script, because I tried with every payload with the cross without the cross with my timestamp with fixed timestamp but nothing work, I just get 500 error.
Any kind of help would be great.
I found the answer to my problem it came from the header which had a syntax mistake, instead of what I wrote the proper way is :
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=> array("Authorization: ".$public,
"Signature: ".$sign
)
));

PHPCrawl fails to create SSL socket

I'm trying to use PHPCrawl (http://sourceforge.net/projects/phpcrawl/) to trawl a website delivered over HTTPS.
I can see that there is support for SSL in the PHPCrawlerHTTPRequest class (openSocket method):
// If ssl -> perform Server name indication
if ($this->url_parts["protocol"] == "https://")
{
$context = stream_context_create(array('ssl' => array('SNI_server_name' => $this->url_parts["host"])));
$this->socket = #stream_socket_client($protocol_prefix.$ip_address.":".$this->url_parts["port"], $error_code, $error_str,
$this->socketConnectTimeout, STREAM_CLIENT_CONNECT, $context);
}
The problem lies in the call to stream_socket_client - although it returns a zero error_code, and no error_str, this->socket is still false.
The documentation for the method states the following:
If the value returned in errno is 0 and the function returned FALSE, it is an indication that the error occurred before the connect() call.
(See http://php.net/manual/en/function.stream-socket-client.php)
So I've tried to use an example provided in the comments section to modify the stream context using 'stream_context_set_option' to set verify_host and verify_peer to false - neither of which seems to have any effect.
I'm not very proficient in PHP or the intricacies of web - does anyone know either:
What condition (specifically) can cause this call to fail?
OR
A workaround for the issue?
I should note - I am using Facebook (HTTPS) as the test server.
I've found the issue -
PHP versions 5.6.x turn peer verification on by default, and apparently the necesarry cert isn't found sometimes (see this bug report)
The workaround is to drop back to a PHP version prior to 5.6
Old topic, but I had the same problem using the PHPCrawler. What worked for me, is what an user wrote on sourceforge (Source: https://sourceforge.net/p/phpcrawl/bugs/86/#5993).
What you have to do, is to rewrite the stream_context_create call on line 547 in PHPCrawlerHTTPReqeust.class.php into the following:
$context = stream_context_create(array(
'ssl' => array(
'SNI_server_name' => $this->url_parts["host"],
'verify_peer' => false,
'verify_peer_name' => false,
)
));
Hope this helps someone in the future.

Can't connect to SSRS in PHP

I'm using SSRS SDK for PHP
PHP Version 5.4
webserver: Centos 6.4
MSSQL Server 2008 R2
define("UID", "*****\*****");
define("PASWD", "*****");
define("SERVICE_URL", "http://192.168.0.1/ReportServerURL/");
try {
$ssrs_report = new SSRSReport(new Credentials(UID, PASWD), SERVICE_URL);
} catch (SSRSReportException $serviceException) {
echo $serviceException->GetErrorMessage() . "<br>";
}
When I try to connect SSRS report, it is throughing the following error:
Failed to connect to Reporting Service
Make sure that the url (http://192.168.0.1/ReportServerURL/) and credentials are correct!
The same credentials & link are accessible through browser without problem. But, through SSRS SDK it is not working.
I was looking for a solution in the net and I find that using the file TestSSRSConnection.php I could get more details but I dont know how to use it, and I cant find any documentation about it.
$testSSRSConnection = new TestSSRSConnection("/192.168.0.1/TESTREPORT/ReportServerURL/*****\*****/*****");
$testSSRSConnection->Parse();
$testSSRSConnection->TestConnection();
Testing it I get the following error:
Usage:TestSSRSConnection.php /server: /report: /uid: /pwd: [/datasource: /uid: /pwd:]
Some idea how to go forward in this topic?
Update
Doing a var_export($http_response_header))
I got
array (
0 => 'HTTP/1.1 401 Unauthorized',
1 => 'Content-Length: 0',
2 => 'WWW-Authenticate: Negotiate',
3 => 'WWW-Authenticate: NTLM',
4 => 'Date: Tue, 04 Mar 2014 22:13:58 GMT',
5 => 'Connection: close',
)
The problem was with the Authentication Type.
By default, Reporting Services accepts requests that specify Negotiate and NTLM authentication. If your deployment includes client applications or browsers that use Basic authentication, you must add Basic authentication to the list of supported types.
To get the header response I added in the SSRSReport.php in the line 193
if ($content === FALSE) {
throw new SSRSReportException("", "<br>Failed to connect to Reporting Service <br/> Make sure " .
"that the url ($this->_BaseUrl) and credentials are correct!<br>" .
var_export($http_response_header));//Line added by me to get the http header response
}
Output:
array (
0 => 'HTTP/1.1 401 Unauthorized',
1 => 'Content-Length: 0',
2 => 'WWW-Authenticate: Negotiate',
3 => 'WWW-Authenticate: NTLM',
4 => 'Date: Tue, 04 Mar 2014 22:13:58 GMT',
5 => 'Connection: close',
)
Failed to connect to Reporting Service
Make sure that the url (http://192.168.0.1/ReportServerURL/) and credentials are correct!
Adding Basic authentication to the SSRS solve the problem.
To configure a report server to use Basic authentication
1- Open RSReportServer.config in a text editor.
2- Find Authentication.
3- Copy one of the following XML structures that best fits your needs. The first XML structure provides placeholders for specifying all of the elements, which are described in the next section:
<Authentication>
<AuthenticationTypes>
<RSWindowsBasic>
<LogonMethod>3</LogonMethod>
<Realm></Realm>
<DefaultDomain></DefaultDomain>
</RSWindowsBasic>
</AuthenticationTypes>
<EnableAuthPersistence>true</EnableAuthPersistence>
</Authentication>
If you are using default values, you can copy the minimum element structure:
<AuthenticationTypes>
<RSWindowsBasic/>
</AuthenticationTypes>
4- Paste it over the existing entries for .
If you are using multiple authentication types, add just the RSWindowsBasic element but do not delete the entries for RSWindowsNegotiate, RSWindowsNTLM, or RSWindowsKerberos.
To support the Safari browser, you cannot configure the report server to use multiple authentication types. You must specify only RSWindowsBasic and delete the other entries.
Note that you cannot use Custom with other authentication types.
5- Replace empty values for or with values that are valid for your environment.
6- Save the file.
7- If you configured a scale-out deployment, repeat these steps for other report servers in the deployment.
8- Restart the report server to clear any sessions that are currently open.
Assuming there's no actual bug in the SDK, I would venture a guess at saying the problem lies with the constants you have defined:
define("UID", "*****\*****");
The backslash separates domain from user name in Windows, but it has a special meaning in a string value, e.g.:
define("UID", "domain\nick");
echo UID;
Output
domain
nick
The \n was transformed into a newline; so what you want is escape the backslash:
define("UID", "domain\\nick"); // backslash is escaped
echo UID; // output: domain\nick
Update
Inside SSRSReport.php (line 168) there's this:
$stream_conext_params = array('http' => array(
'header' => array($credentials->getBase64Auth())
));
However, the header context option takes a string, not an array:
$stream_conext_params = array('http' => array(
'header' => $credentials->getBase64Auth(),
));

PHP stream_context_create with proxy

I'm currently developing an web application which uses an XML Interface located on a different server, that I have to access via a proxy.
So I tried to set the proxy in a stream_context_create array, but it doesn't seem to work.
$set = array(
'http' => array(
'method' => 'GET',
'header' => sprintf(
'Proxy-Authorization: Basic %s',
base64_encode(Constants::XML_AUTH)
),
'protocol_version' => '1.1',
'proxy' => '89.122.180.178:46565'
)
);
$stream = stream_context_create($set);
I'm not quite sure what I'm doing wrong.
If I comment out the proxy key i get a 403 Forbidden Response as it should be.
If I comment in the proxy key I receive a 400 Bad Request Response.
I'm not quite sure what I'm doing wrong. Can you help me out? I never did a communication through a proxy before with PHP.
My guess is that the proxy declaration is missing the protocol. An URI has to be specified (according to the doc), that contains the protocol (scheme).
So this could work: 'proxy' => 'tcp://89.122.180.178:46565'. It might be necessary to remove 'protocol_version' since this may not be required for tcp.
Does that work for you? (or have you already solved it? ... ;-)

Categories