savon
savon copied to clipboard
HTTPClient::KeepAliveDisconnected on ONVIF unsubscribe request
Bug report
I am generating SOAP requests to IP cameras to use ONVIF API. When generating a request through Savon it doesn't work. However, when generating via the official tool request passes OK.
Current behavior: Here is the request generated through Savon and I am getting HTTPClient::KeepAliveDisconnected
[2022-04-26 21:29:16 +0000] SOAP request: http://192.168.0.89/onvif/Subscription?Idx=77
[2022-04-26 21:29:16 +0000] Content-Type: application/soap+xml; charset=utf-8, SOAPAction: "http://docs.oasis-open.org/wsn/bw-2/PausableSubscriptionManager/UnsubscribeRequest", Content-Length: 1709
[2022-04-26 21:29:16 +0000] <?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://www.onvif.org/ver10/events/wsdl" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>http://docs.oasis-open.org/wsn/bw-2/PausableSubscriptionManager/UnsubscribeRequest</wsa:Action>
<wsa:To>http://192.168.0.89/onvif/Subscription?Idx=77</wsa:To>
<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:b4742513-fd62-44b5-a9d9-3db005e1a330</wsa:MessageID>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1">
<wsse:Username>admin</wsse:Username>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">M2M0NGJhMGI1Y2ZjMWYxYTRjMTkyYTg1NmFjNzg4ZDliOGIzNjkyOA==</wsse:Nonce>
<wsu:Created>2022-04-26T21:29:16Z</wsu:Created>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">h+WeEanGY2sFUhBbhcd5Oi1ZHhw=</wsse:Password>
</wsse:UsernameToken>
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2">
<wsu:Created>2022-04-26T21:29:16Z</wsu:Created>
<wsu:Expires>2022-04-26T21:30:16Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<wsdl:Unsubscribe/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
[2022-04-26 21:29:16 +0000] HTTPI /none POST request to 192.168.0.89 (httpclient)
/data/deployer/onvif/vendor/bundle/ruby/3.1.0/gems/httpclient-2.8.3/lib/httpclient/session.rb:808:in `block in parse_header': HTTPClient::KeepAliveDisconnected: (HTTPClient::KeepAliveDisconnected)
/data/deployer/onvif/vendor/bundle/ruby/3.1.0/gems/httpclient-2.8.3/lib/httpclient/session.rb:808:in `block in parse_header': HTTPClient::KeepAliveDisconnected: `(HTTPClient::KeepAliveDisconnected)
Request generated via the official tool:
POST /onvif/Subscription?Idx=87 HTTP/1.1
Host: 192.168.0.89
Content-Type: application/soap+xml; charset=utf-8
Authorization: Digest username="admin",realm="Login to 2L05ABCPAA00246",qop="auth",algorithm=MD5,uri="/onvif/Subscription?Idx=87",nonce="b252aWYtZGlnZXN0OjQyOTc3MDM4Njcw",nc=00000001,cnonce="AA1E66694E8FDFD77C29FC359DAA0C15",opaque="",response="9a6aa57108955142ddb522698d20c274"
Content-Length: 713
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/UnsubscribeRequest</a:Action>
<a:MessageID>urn:uuid:bf921174-c408-48f7-97c8-f5f64ee3462e</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://192.168.0.89/onvif/Subscription?Idx=87</a:To>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Unsubscribe xmlns="http://docs.oasis-open.org/wsn/b-2" />
</s:Body>
</s:Envelope>
Steps to reproduce current behavior:
require 'savon'
@ip. = 'ip'
@user = 'user'
@pass. = 'pass'
@wsdl = 'http://www.onvif.org/ver10/events/wsdl/event.wsdl'
@endpoint = 'http://192.168.0.89/onvif/event_service'
@soap_client = Savon.client do |c|
c.wsdl wsdl
c.endpoint @endpoint
c.wsse_auth(user, pass, :digest)
c.use_wsa_headers true
c.wsse_timestamp true
c.convert_request_keys_to :none
c.env_namespace 'SOAP-ENV'
c.open_timeout 60
c.read_timeout 60
c.soap_version 2
c.headers 'Content-Type' => 'application/soap+xml; charset=utf-8'
c.pretty_print_xml true
end
@soap_client.call(:create_pull_point_subscription)
...
@soap_client.call(:unsubscribe)
Expected behavior:
Generated request passes OK
System information:
- ruby version: 3.1
- savon version: 2.12.1
To me, by just looking at the thing, the top one seems to use the wsse type of authentication, which is a Web Service description of authentication. The lower one seems to have a Digest header only.
Could it be that the service authenticates requests in some other way than the wsse thing?
@olleolleolle Hi thanks for the suggestion. I tried different types of auth but ONVIF cameras support both wsse and digest so it should not be auth issue. The next thing that I tried is changing namespaces and that made a request to work. HTTPClient::KeepAliveDisconnected doesn't look like a correct error in this case.
The Official tool adds xmlns="http://docs.oasis-open.org/wsn/b-2" straight to the Unsubscribe tag.
<Unsubscribe xmlns="http://docs.oasis-open.org/wsn/b-2" />
Savon builds requests in a different way and adds a namespace wsdl:Unsubscribe with namespace declaration with wrong namespace xmlns:wsdl="http://www.onvif.org/ver10/events/wsdl"
<wsdl:Unsubscribe/>
I did not manage to add xmlns="http://docs.oasis-open.org/wsn/b-2" or remove wsdl namespace from Unsubscribe tag but managed to override it namespaces: { 'xmlns:wsdl' => "http://docs.oasis-open.org/wsn/b-2" }
Is there a way I can build the same request with savon as the official tools offer?