【发布时间】:2016-09-01 03:56:19
【问题描述】:
经常阅读,第一次提问。
我正在努力将 Perl 与我们的供应商之一 (LogRhythm) 提供的 SOAP API 连接起来,但似乎遇到了一些障碍。
我已经能够与 API 交互,并且克服了我最初遇到的身份验证挑战。现在,当我需要为 SOAP 调用提供参数时,我遇到了 SOAP 信封正文中的名称空间标记问题。
供应商提供的 API 是围绕 .NET 和 WCF 构建的。
我的原型代码目前如下所示:
use strict;
no strict "refs";
use Data::Dumper;
use IO::Socket::SSL qw (SSL_VERIFY_NONE) ;
use SOAP::Lite;
use Tie::IxHash;
# Username and Password
my $sUID = "<API UserID>";
my $sPWD = "<API Password>";
# WSDL definition URI. Using a cached local copy using file:/... also works
my $LookupService_wsdl = 'https://melcapi01.soc.ipsec.net.au/LogRhythm.API/Services/LookupServiceBasicAuth.svc?singleWsdl';
my $lrns = 'http://www.logrhythm.com/webservices';
# Ensure that a consistent xmlns:soap value is used, without this we get inconsistent results.
$SOAP::Constants::PREFIX_ENV = 'SOAP-ENV';
# Don't validate SSL Certificate while testing
IO::Socket::SSL::set_defaults(SSL_verify_mode => "SSL_VERIFY_NONE");
# Construct the security header
my %authHash;
tie %authHash, "Tie::IxHash";
%authHash = (
Username => SOAP::Data->type( '' => $sUID )->prefix('wsse'),
Password => SOAP::Data->type( '' => $sPWD )->prefix('wsse'),
);
my $wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
my $securityHeader = SOAP::Header->new(
name => 'Security',
uri => $wsse,
prefix => 'wsse',
value => \SOAP::Data->new(
name => 'UsernameToken',
prefix => 'wsse',
value => \%authHash,
)
);
# Error handling
on_fault => sub { my($soap, $res) = @_;
die ref $res ? $res->faultstring : $soap->transport->status;
};
# Define the SOAP Instance
my $lrapi = SOAP::Lite
-> readable (1)
-> service($LookupService_wsdl)
-> on_action( sub {return $action});
# Set the default Namespace
$lrapi->default_ns($lrns);
# Actually get data from the LookupService
my $result;
# Build up the parameters
my @classificationType = ( SOAP::Data->new(name =>'classificationType', value => 2000));
$result = $lrapi->GetClassificationsByType($securityHeader);
print Dumper $result;
这会产生以下 SOAP 请求:
SOAPAction: "http://www.logrhythm.com/webservices/LookupService/GetClassificationsByType"
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://www.logrhythm.com/webservices"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsa10="http://www.w3.org/2005/08/addressing"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>reporting</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tns:GetClassificationsByType>
<classificationType xsi:type="xsd:int">2000</classificationType>
<classificationTypeSpecified xsi:type="xsd:boolean">true</classificationTypeSpecified>
</tns:GetClassificationsByType>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
不返回任何结果。我已经使用 .NET WebService Studio 进行了一些挖掘和请求修正,并确定问题是由于 SOAP 主体中的元素缺少 xmlns 标识符引起的。
SOAP 请求应如下所示:
SOAPAction: "http://www.logrhythm.com/webservices/LookupService/GetClassificationsByType"
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://www.logrhythm.com/webservices"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsa10="http://www.w3.org/2005/08/addressing"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>reporting</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tns:GetClassificationsByType xmlns="http://www.logrhythm.com/webservices">
<classificationType xsi:type="xsd:int">2000</classificationType>
<classificationTypeSpecified xsi:type="xsd:boolean">true</classificationTypeSpecified>
</tns:GetClassificationsByType>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
各种支持请求表明应该通过在 SOAP::Lite 对象上手动设置 default_ns 来解决此问题,但是,这对我不起作用。
我已经挖掘了SOAP::Lite (1.20) 的源代码以查看发生了什么,并且似乎在进行 SOAP 方法调用之前设置为 1 的 {'_use_default_ns'} 属性似乎得到了在处理呼叫期间重置为0。
我还尝试手动构建 SOAP::Lite 对象,目的是使用 call() 方法来获得所需的结果,但是,我认为我遇到了自动命名空间数量的问题- 由于我目前使用的service() 机制而添加。如果我想使用call() 方法,我似乎无法使用service() 设置对象。
有没有人有任何其他建议我可以尝试,因为我现在不知所措?
任何帮助将不胜感激。
免责声明:我不是程序员/开发人员,我是具有一定编程能力的高级安全工程师/顾问/架构师,所以如果我的代码结构不正确,我提前道歉。这也是我第一次尝试摆弄 SOAP。
【问题讨论】:
-
这是给客户的吗?你会接受多肮脏的解决方案?你的代码没有
use warnings,但我的评估是它不是很乱。它只是 SOAP::Lite 和所有与之相关的东西,看起来并不像现代 Perl。 -
LogRhythm API 文档不仅糟糕,而且完全具有误导性。期望某些函数以与记录的顺序完全不同的顺序接受参数。
标签: perl soap namespaces