[英]PHP NTLM authentication + soap client
I came across the project where I need to implement web services protected by NTLM authentication.我遇到了需要实施受 NTLM 身份验证保护的 Web 服务的项目。
I gave it try via PHP SoapClient
:我通过 PHP SoapClient
尝试了一下:
$client = new \SoapClient("http://hostname.com/webservice",
array(
'cache_wsdl' => WSDL_CACHE_NONE,
'login' => "username",
'password' => "password"
));
This throws this error:这会引发此错误:
PHP Fatal error: SOAP-ERROR: Parsing WSDL: Couldn't load from ' http://hostname.com/webservice ' : failed to load external entity " http://hostname.com/webservice " PHP 致命错误:SOAP 错误:解析 WSDL:无法从“ http://hostname.com/webservice ”加载:无法加载外部实体“ http://hostname.com/webservice ”
I gave it try via CURL:我通过 CURL 尝试了一下:
curl --ntlm -u username:password "http://hostname.com/webservice" --verbose
It works as expected and returned the correct xml.它按预期工作并返回正确的 xml。
But again SoapClient
doesn't support NTLM authentication.但同样SoapClient
不支持 NTLM 身份验证。
Does anyone knows anything about PHP Soap+NTLM?有人知道 PHP Soap+NTLM 吗?
Thanks in advance提前致谢
I recently had this problem too.我最近也有这个问题。
Here's the solution I found:这是我找到的解决方案:
Create NTLMStream.php
with the following contents:使用以下内容创建NTLMStream.php
:
<?php
/*
* Original https://thomas.rabaix.net/blog/2008/03/using-soap-php-with-ntlm-authentication
* Modified by http://blogs.msdn.com/b/freddyk/archive/2010/01/19/connecting-to-nav-web-services-from-php.aspx:
*/
class NTLMStream
{
private $path;
private $mode;
private $options;
private $opened_path;
private $buffer;
private $pos;
public function stream_open($path, $mode, $options, $opened_path) {
$this->path = $path;
$this->mode = $mode;
$this->options = $options;
$this->opened_path = $opened_path;
$this->createBuffer($path);
return true;
}
public function stream_close() {
curl_close($this->ch);
}
public function stream_read($count) {
if(strlen($this->buffer) == 0) {
return false;
}
$read = substr($this->buffer,$this->pos, $count);
$this->pos += $count;
return $read;
}
public function stream_write($data) {
if(strlen($this->buffer) == 0) {
return false;
}
return true;
}
public function stream_eof() {
return ($this->pos > strlen($this->buffer));
}
public function stream_tell() {
return $this->pos;
}
public function stream_flush() {
$this->buffer = null;
$this->pos = null;
}
public function stream_stat() {
$this->createBuffer($this->path);
$stat = array(
'size' => strlen($this->buffer),
);
return $stat;
}
public function url_stat($path, $flags) {
$this->createBuffer($path);
$stat = array(
'size' => strlen($this->buffer),
);
return $stat;
}
private function createBuffer($path) {
if($this->buffer) {
return;
}
$this->ch = curl_init($path);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($this->ch, CURLOPT_USERPWD, USERPWD);
$this->buffer = curl_exec($this->ch);
$this->pos = 0;
}
}
class NTLMSoapClient extends \SoapClient
{
function __doRequest($request, $location, $action, $version, $one_way = 0) {
$headers = array(
'Method: POST',
'Connection: Keep-Alive',
'User-Agent: PHP-SOAP-CURL',
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: "'.$action.'"',
);
$this->__last_request_headers = $headers;
$ch = curl_init($location);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true );
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERPWD, USERPWD);
$response = curl_exec($ch);
return $response;
}
function __getLastRequestHeaders() {
return implode("\n", $this->__last_request_headers)."\n";
}
}
Then in your test.php
然后在你的test.php
<?php
define('USERPWD', 'domain\username:password');
require_once("NTLMStream.php");
stream_wrapper_unregister("https");
stream_wrapper_register("https", "NTLMStream");
$params = [
'stream_context' => stream_context_create([
'ssl' => [
'ciphers'=>'RC4-SHA',
'verify_peer'=>false,
'verify_peer_name'=>false,
'allow_self_signed'=>true,
]]),
'cache_wsdl' => WSDL_CACHE_NONE,
'soap_version' => SOAP_1_1,
'trace' => 1,
'connection_timeout' => 180,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
];
$client = new NTLMSoapClient("https://hostname.com/webservice", $params);
$retVal = $client->ReadMultiple(...
...
For http:// instead of https:// substitute:对于 http:// 而不是 https:// 替代:
stream_wrapper_register("http", "NTLMStream")
stream_wrapper_register("https", "NTLMStream")
This library helped me (I use composer): https://packagist.org/packages/matejsvajger/ntlm-soap-client这个库帮助了我(我使用作曲家): https : //packagist.org/packages/matejsvajger/ntlm-soap-client
$url = 'URL_TO_WEBSERVICE_WSDL';
$config = new matejsvajger\NTLMSoap\Common\NTLMConfig([
'domain' => 'domain',
'username' => 'username',
'password' => 'password'
]);
$client = new matejsvajger\NTLMSoap\Client($url, $config);
$response = $client->ReadMultiple(['filter'=>[], 'setSize'=>1]);
foreach ($response->ReadMultiple_Result->CRMContactlist as $entity) {
print_r($entity);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.