401 SoapClient尝试获取架构文件时发生身份验证错误


401 Authentication Error when SoapClient tries to fetch schema file

我的应用程序定期连接到第三方服务器,通过SOAP/WSDL:获取数据

$this->soap_client = new SoapClient("https://[the-domain]:443/[path]?wsdl", array(
    'trace'=>1,
    'login'=>$this->username,
    'password'=>$this->password,
    'exceptions' => true,
    'cache_wsdl' => WSDL_CACHE_NONE
)

去年一切都很好,但他们最近更新了WSDL文件,现在当应用程序尝试连接时,我收到了以下两个错误:

SoapClient::SoapClient(http://[the-domain]:80/[path]?xsd=1): failed to open stream: HTTP request failed! HTTP/1.1 401 Unauthorized

SoapClient::SoapClient(): I/O warning : failed to load external entity "http://[the-domain]:80/[path]?xsd=1"

当我查看WSDL XML文件时,似乎有问题的不可加载文件是它试图导入的文档模式文件(schemaLocation(:(来自WSDL:(

<types>
<xsd:schema>
<xsd:import namespace="[irrelevant]" schemaLocation="http://[the-domain]:80/[path]?xsd=1"/>
</xsd:schema>
</types>

我已经为此头疼了一段时间,据我所知,问题是两件事之一:

  1. 当我在浏览器中加载该模式URL时(在浏览器身份验证之后(,它将302 redirects转换为https URL(并删除端口声明(。在尝试导入模式时,SOAP调用是否可能不遵循重定向
  2. 假设错误消息是401错误,那么SOAP调用在尝试导入模式时是否可能没有传递凭据?模式文件需要与WSDL文件相同的身份验证,但服务器在尝试导入时可能没有将身份验证扩展到模式

假设这是第二个问题,有没有任何方法可以强制系统使用不同的模式URL,而无需下载WSDL文件、编辑它并在本地存储/引用它?如果是这样,我可以尝试在URL中传递凭据(http://username:password@domain....(?

如果我唯一的尝试是创建WSDL和XSD模式文件的修改副本,那就顺其自然吧,但我很想听听是否有人有任何想法可以让我避免这种情况(因为模式确实会不时更改(。

看起来PHP SoapClient坚持相同的域策略(包括方案(,用于在WSDL请求中发送基本身份验证用户名和密码,该请求用于在WDSL模式中导入xsd文件。

因此,如果WSDL url具有https方案,而导入具有http方案,则PHP不会发送基本的身份验证信息,因为在请求http导入url时,连接不再加密(这将损害身份验证信息的机密性(。

然而,似乎至少对于某些PHP版本(可能在较新版本中得到修复(,即使http url重定向到https url(在同一域上(,身份验证问题仍然存在重定向到具有相同域的安全URL后,PHP可能会再次包含给定的基本身份验证信息

解决方案

最后,我发现解决这个问题的唯一巧妙方法是让另一方更改他们的WSDL内容,以导入一个安全的URL(https(,该URL与WDSL URL本身具有相同的方案、域和端口。

变通办法

如果这对您来说不是一个选项,您可以随时选择变通方法,即将WSDL和导入保存为本地文件,并引用WDSL文件,而不是URL。当然,这也意味着您必须更改WSDL以导入正确的本地文件(而不是httpURL(,并且可能还需要其他导入。不幸的是,这是我所知道的在这种情况下唯一的解决方法。


PHP Bug

我还发现了这个PHP错误报告,它可能是相关的。

我会试试cURL,它有一个用于以下重定向的选项

如何从PHP 发布SOAP请求