xmlsoaphttpwebrequest

ONVIF GetDeviceInformation SOAP Message


Im trying to make a web request to an onvif compliant camera but i am having trouble with the response.

I followed the ONVIF application programmer's guide and i came up with this soap message to get the device information:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope 
    xmlns:s="http://www.w3.org/2003/05/soap-envelope" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:tt="http://www.onvif.org/ver10/schema" 
    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:tds="http://www.onvif.org/ver10/device/wsdl">
    <s:Header>
        <wsse:Security>
            <wsse:Username>admin</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordDigest">
                WndlORLsIdMIyyvb99lzSgm0iGI=
            </wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
                Rjc0QUUzNDI2MTMyMTI4OTJCQjI1QzM2RUEzMDUzNEUxMTlFNEQ2Mg==
            </wsse:Nonce>
            <wsu:Created>2017-05-11T11:48:56.8823852ZZ</wsu:Created>
        </wsse:Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetDeviceInformation xmlns="http://www.onvif.org/ver10/device/wsdl" />
    </s:Body>
</s:Envelope>

And the response from the device is:

<SOAP-ENV:Envelope (...)>
    <SOAP-ENV:Header>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        <SOAP-ENV:Fault>
            <SOAP-ENV:Code>
                <SOAP-ENV:Value>SOAP-ENV:Sender</SOAP-ENV:Value>
            <SOAP-ENV:Subcode>
                <SOAP-ENV:Value>ter:NotAuthorized</SOAP-ENV:Value>
            </SOAP-ENV:Subcode>
            </SOAP-ENV:Code>
            <SOAP-ENV:Reason>
                <SOAP-ENV:Text xml:lang="en">Sender not Authorized</SOAP-ENV:Text>
            </SOAP-ENV:Reason>
        </SOAP-ENV:Fault>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Im calculating the Created time by subtracting the offset diference between my computer and the device so that the message is sent with a datetime compatible with the device.

Am i missing something in my request? Considering that the username and password is correct, what could be causing this issue?


Solution

  • So after some on and off research and trial and error I managed to resolve my issue. I used wireshark to check what the Onvif Device Manager application was sending to the camera and ended up with this message:

    <?xml version="1.0" encoding="utf-8"?>
    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
        <s:Header>
            <Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                <UsernameToken>
                    <Username>admin</Username>
                    <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">6KZX13jsvYLOE72Fb7Nc4tCFE60=</Password>
                    <Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">Xd0vNthkfp/VCmVtoHr3QA==</Nonce>
                    <Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-06-01T10:29:01.001Z</Created>
                </UsernameToken>
            </Security>
        </s:Header>
        <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <GetDeviceInformation xmlns="http://www.onvif.org/ver10/device/wsdl" />
        </s:Body>
    </s:Envelope>
    

    To calculate the nonce and password digest I also changed the methods I was using and ended up with this one:

    public static void GetPasswordDigest(string ONVIFPassword, TimeSpan CameraTimeOffset, out string nonceb64_out, out string created_out, out string passwordDigest_out)
            {
                //Get nonce
                Random rnd = new Random();
                Byte[] nonce_b = new Byte[16];
                rnd.NextBytes(nonce_b);
                string nonce64 = Convert.ToBase64String(nonce_b);
                nonceb64_out = nonce64;
    
                //Get timestamp
                DateTime created = DateTime.UtcNow - CameraTimeOffset;
                string creationtime = created.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
                Byte[] creationtime_b = Encoding.ASCII.GetBytes(creationtime);
                created_out = creationtime;
    
                //Convert the plain password to bytes
                Byte[] password_b = Encoding.ASCII.GetBytes(ONVIFPassword);
    
                //Concatenate nonce_b + creationtime_b + password_b
                Byte[] concatenation_b = new byte[nonce_b.Length + creationtime_b.Length + password_b.Length];
                System.Buffer.BlockCopy(nonce_b, 0, concatenation_b, 0, nonce_b.Length);
                System.Buffer.BlockCopy(creationtime_b, 0, concatenation_b, nonce_b.Length, creationtime_b.Length);
                System.Buffer.BlockCopy(password_b, 0, concatenation_b, nonce_b.Length + creationtime_b.Length, password_b.Length);
    
                //Apply SHA1 on the concatenation
                SHA1 sha = new SHA1CryptoServiceProvider();
                Byte[] pdresult = sha.ComputeHash(concatenation_b);
                string passworddigest = Convert.ToBase64String(pdresult);
                passwordDigest_out = passworddigest;
    
            } 
    

    This method is heavily based on someone else's answer to a different question here in StackOverflow, unfortunately I forgot to save the link or the person's name. I hope this helps people that are in the same roadblock I was.