PHP SoapClient with BasicAuth - php

I have a PHP script trying to connect to a WSDL.
I need to allow self signed AND give basic auth details.
Using SOAP UI, when I connect to the WSDL I am prompted for username / password.
I got this working.
I also found out that each request also requires basic auth (so on the request screen, I have to select Auth, then basic, enter same credentials as I used on the prompt).
How to I do this auth in PHP
As I said, I can connect, not a problem, I seem to kill the service or timeout if I try to make a request
<?php
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
$data = array(
'columnA' => 'dataA',
'columnB' => 'dataB',
'columnC' => 'dataC');
$url = 'https://111.111.111.111:1234/dir/file';
$login = 'username';
$pwd = 'password';
$client = new soapClient(null, array(
'location' => $url,
'uri' => '',
'login' => $login,
'password' => $pwd,
'stream_context' => $context
));
echo "\n\r---connected---\n\r";
$result = $client ->requestName($data);
print_r($result);
?>
My output is
---connected---
Then it seems to hang.
I have tried wrapping it round a try catch and I had the same result.
Any suggestions??

From the Manual soapclient support the http basic auth.
For HTTP authentication, the login and password options can be used to
supply credentials. For making an HTTP connection through a proxy
server, the options proxy_host, proxy_port, proxy_login and
proxy_password are also available. For HTTPS client certificate
authentication use local_cert and passphrase options. An
authentication may be supplied in the authentication option. The
authentication method may be either SOAP_AUTHENTICATION_BASIC
(default) or SOAP_AUTHENTICATION_DIGEST.
$wsdl = "http://example/services/Service?wsdl";
$option = array(
"trace"=>1,
"login"=>"admin",
"password"=>"admin",
);
$client = new SoapClient($wsdl,$option);
But when I initiate the soapclient, it will throw this error
Exception: Unauthorized
I also have tried to put the auth in the url, like
$wsdl = "http://admin:admin#example/services/Service?wsdl";
But it also doesn't works.
Finally I solved it by add authentication to the option. The manual says the authentication default value is the basic auth, but only when I explicitly set it, it can work.
$option = array(
"trace"=>1,
"login"=>"admin",
"password"=>"admin",
"authentication"=>SOAP_AUTHENTICATION_BASIC
);

Try url encoding your username and password inside the url that you are using:
$url = 'http://'.urlencode('yourLogin').':'.urlencode('yourPassword').'#111.111.111.111:1234/dir/file';
Also I don't see you make use of the wsdl in your code example. You can always download a copy of the wsdl locally and then reference that local copy. You can download the wsdl anyway you want (with php, curl, manually).

Related

Azure/Microsoft Identity Platform - Cannot Retrieve Access Token from Token Endpoint (PHP)

I'm trying to write a custom web app that utilizes the Microsoft Identity Platform to authenticate and authorize users. I'm able to successfully authenticate when calling the /authorize endpoint, and I have access to the "code" token that is returned.
I am now trying to retrieve my access token so that I can make calls to the APIs. Whenever I submit a POST request to the /token endpoint, the server returns a 400 Bad Request error. The header information that is provided contains no valuable information for troubleshooting and there is no JSON response returned so I have no idea where or what the issue is.
I'm making my call as follows:
$clientId = '00000000-0000-0000....'; // Omitted
$tenantId = '00000000-0000-0000....'; // Omitted
$grantType = 'authorization_code';
$scope = urlencode('User.Read');
$code = '......' // Obtained from authentication
$redirect_uri = 'http://localhost/smp/auth/handle';
$clientSecret = '...' // Omitted, set up in Azure App registrations under Certificates and secrets
$resource = 'api://00000000-0000-0000....'; // Omitted, set up in Azure App registrations under Overview -> App ID URI
$url = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token";
$parameters = [
'client_id' => $clientId,
'grant_type' => $grantType,
'scope' => $scope,
'code' => $code,
'redirect_uri' => $redirectUri,
'client_secret' => $clientSecret,
'resource' => $resource
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($parameters)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (!$result) {
exit('an error has occured');
}
PHP returns a warning that reads the following: (tenant id has been omitted):
Warning: file_get_contents(https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token): Failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in C:\xampp\htdocs\smp\application\models\user-model.php on line 261
I've verified everything I can possibly think of.
The client and tenant ids are working (based on the successful authentication request).
The "code" is correctly retrieved from the authentication request.
Redirect Uri is the same as the one used for the authentication request.
I've tried with and without the client_secret variable. It is my understanding that this is actually required in my case.
I've tried with and without the resource variable, which is setup using the default Azure naming convention of "api://".
Please assist! I know I must be missing something but cannot figure it out. Perhaps permissions or additional setup within Azure? I'm not really sure what's wrong with my code/approach but Microsoft Identity Platform/OAuth isn't returning anything for me to work with and/or troubleshoot.
I've figured this out.
Firstly, I modified by $options variable to include the following:
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($parameters),
'ignore_errors' => true
]
];
Adding ignore_errors allowed me to see the returned JSON.
Next, it became apparent that my parameters were not being accepted because I was url-encoding all of them. My client secret, redirect uri, and client ids were all url encoded (this detail was hidden in my original post because it was just a small snippet of a much larger system). By undoing this encoding, my parameters all ended up being accepted. I suppose it makes sense because these values weren't being appended to a url but rather passed as POST values.
Lastly, the "resource" variable was not accepted (indeed, it wasn't required). Not sure if any of this is going to help anyone else but just in case, this was my fix.

PHP SoapClient Doesn't Retrieve WSDL with Client Certificate

Other similar questions have not helped me resolve this.
I have to retrieve a WSDL file using a client certificate + private key combination from my webserver calling another external SOAP API.
$wsdl = 'https://www.example.com?wsdl';
$endpoint = 'https://www.example.com';
$sslContext = stream_context_create($contextOptions);
$options = [
'local_cert' => '/var/www/combo.pem',
'passphrase' => 'Pass1',
'cache_wsdl' => WSDL_CACHE_MEMORY,
'trace' => 1,
'stream_context' => stream_context_create([
'ssl' => [
'ciphers' => 'RC4-SHA',
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
]
])
];
try{
$soapClient = new SoapClient($wsdl, $options);
}
catch(Exception $e)
{
var_dump($e);
}
The error I'm getting is:
SOAP-ERROR: Parsing WSDL: Couldn't load from '..domain..' : failed to load external entity "..domain..?wsdl"
I tried numerous settings and none of them made any difference to this response. I tried no settings, empty array.
What has worked:
Establishing a raw connection via CURL, so the certificate file is fine
Retrieving WSDL information from SoapUI, so the WSDL destination is correct and the certificate file was okay
phpinfo() returns SoapClient is enabled, OpenSSL is enabled. What else could I try or check?
SOAP error could come from invalid character encoding or maybe some HTTP header missing like 'User-Agent' when you query the remote server.
Try to adding User-Agent to options like the sample below.
$options = array(
'http' => array(
'user_agent' => 'PHP_Embedded_Soap_Client'
)
);
PS: I would not recommend to strict ciphers to: RC4-SHA
I wanted to comment this but based on others' suggestions of using file_get_contents and your reply mentioning that it returned false, I'm now kind of sure it's more of a connection problem. Please check followings:
It's obvious that your actual $wsdl value is different than what is posted but please make sure that .com?wsdl is not happening in your code. it should be .com/?wsdl.
Check your DNS settings. A lookup through dnslookup can help identify problem.
Make sure date & time setting of server is correct. It can lead to SSL errors.
If none of above helped. You might consider downloading WSDL content with other tools (such as cURL) and on different machines to identify the cause of problem.

PHP SoapClient fails with - Failed to load external entity

I've been trying to use the European Union's website to validate TIN numbers (Europa TIN validation website - there is a WSDL available at the bottom of the page)
The problem I'm having is that when I try to make a new SoapClient the function fails immediately when building the client. At first I was having a "Failed to load external entity" and I assumed it was because the WSDL has a secure connection. After searching around I found some answers that said that the problem could have to do with the certificate being outdated and the most recent versions of PHP throw errors in that case, so I disabled certificate validation with:
// Stream context due to certificate problems
$streamContext = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
But now I'm getting another error: "failed to open stream: HTTP Request failed! HTTP/1.1 502 Bad Gateway". Any thoughts about how to solve this issue? If I remove "https://" from the link I get the same result as before with the "failed to load external entity" message.
Now here's the real brain picker. If I try to use chrome's extension "Boomerang" to test SOAP calls on the WSDL it works absolutely perfectly, so I have no idea what's wrong here... Anyone can easily try this by attempting to make a soap call in a PHP file.
Here's the full code:
public static function validateTIN($tin) {
// Stream context due to certificate problems
$streamContext = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
// Create our soap client
$client = new SoapClient('https://ec.europa.eu/taxation_customs/tin/checkTinService.wsdl', array(
'exceptions' => 0,
'trace' => 1,
'connection_timeout' => 1800,
'stream_context' => $streamContext
));
dd($client->__getFunctions());
return true;
}
After spending hours researching and trying to figure out the problem I found a 2 years old post that somehow served my purpose.
Unfortunately I can't mark this as duplicate so I'll just link it here: SOAP error parsing wsl couldn't load from but works on wamp
I couldn't find this question because Google didn't tag it as using the Europa services.
Either way, my problem was that I needed to specify my user agent explicitly because Europa web services are too outdated and can't resolve IPv6 requests, only IPv4. Like so:
$opts = array(
'http'=>array(
'user_agent' => 'PHPSoapClient'
)
);
$context = stream_context_create($opts);
$client = new SoapClient('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl',
array('stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE));
$result = $client->checkVat(array(
'countryCode' => 'DK',
'vatNumber' => '47458714'
));
The example uses the CheckVAT SOAP function but it works just as well for the CheckTIN function.

Writing library for Twitter, where am I going wrong?

I'm writing a library to connect to Twitter that uses Requests for PHP. I'm not sure, but I don't think that I'm building the OAuth correctly because I can't authenticate. I've double-checked it, and checked it against another existing library but still can't seem to get it right.
The code is here.
The idea is you instantiate the service, send it config parameters, and before it does the request, it generates the 'Authorization: OAuth xxx' header and adds it to said request.
$twitter = array(
'consumer_key' => '',
'consumer_secret' => '',
'access_token' => '',
'access_token_secret' => '',
'screen_name' => '_hassankhan',
'api_url' => 'https://api.twitter.com/1.1/'
);
$service = new OAuth1AService('Twitter', $twitter['api_url']);
$service->config($twitter);
$service->doGet(
'statuses/user_timeline.json',
array(
'screen_name' => '_hassankhan',
'include_entities' => 'true'
),
array(),
'raw'
);
print($service->getResult());
I would really recommend you to use one of the already made libraries like tmhOAuth which make it really easy to interact with the twitter api.
As for your problem, seems you don't sign your request correctly. At least I could not easily find out if you include all request parameters to create the signature.
The oauth_signature parameter contains a value which is generated by
running all of the other request parameters and two secret values
through a signing algorithm.
Creating the signature is described in this document: https://dev.twitter.com/docs/auth/creating-signature .

php SOAP not sending certificate.pem

I can load in the wsdl, pull out the functions and data types just fine but when I try to call a function on the server I get a connection error. When I look at the soap data passed in the $request it doesn't contain any of the security certificate and no errors are generated.
My code looks like this:
// setup the transaction array
$header = array('local_cert' => "certificate.pem",
'logonUser' => "user_name",
'style' => SOAP_DOCUMENT,
'use' => SOAP_LITERAL,
'exceptions' => true,
'trace' => true);
// create the soap client, this will log us in
$client = new SoapClient($wsdl, $header);
try
{
$response = $client->getMessage($parameters);
}
catch (Exception $e)
{
dumpVars($client->__getLastRequest());
echo 'Caught exception: ', $e->getMessage(), "\n";
}
?>
So my question is this, what do I have to do to get the security certificate to be passed?
Thanks,
Pete
The purpose of local_cert in $header is not sending it in the SOAP call itself. It's only being used as an SSL client certificate. Also, according to this comment on php.net you need to read the file contents of the certificate in order to use it.
2 (small) things :
'logonUser' does not seem to be a valid option for the SoapClient constructor. If it is a required header for this service, consider using soapClient::setSoapHeaders. If it is a standard HTTP login param, use the 'login' key.
try to use the full path of the pem certificate, and make sure it is readable by php

Categories