My task is to try to establish a communication with a ONVIF camera in the building to, eventually, upgrade the company's domotic solution to automatically recognize ONVIF cameras and to be able to set them up and to use their services.
I am already able to gather some basic informations like its model, its MAC address and its firmware version this way:
EndpointAddress endPointAddress = new EndpointAddress("<mycameraurl:<mycameraport>/onvif/device_service");
CustomBinding bind = new CustomBinding("DeviceBinding");
DeviceClient temp = new DeviceClient(bind, endPointAddress);
String[] arrayString = new String[4];
String res = temp.GetDeviceInformation(out arrayString[0], out arrayString[1], out arrayString[2], out arrayString[3]);
MessageBox.Show("Model " + arrayString[0] + ", FirmwareVersion " + arrayString[1] + ", SerialNumber " + arrayString[2] + ", HardwareId " + arrayString[3]);
I have this xml specification for the customBinding in my app.config file:
<customBinding>
<binding name="DeviceBinding">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="false" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
My problem is that it's impossible for me to go deeper into what I can ask the camera. I get "400 - Bad request" errors for anything I try, and according to what I have read it's because I need to handle authentication for the camera.
The problem is that, everything I find about WS-Security (which seems to be used by the ONVIF) is really, really confused, with a lot of different solutions, and nothing really working for me. For example, this post here make it sound very simple, but I've tried to create a UserNameSecurityToken and I still get 400 bad request errors. Since I don't know if that's because I've written my Token system wrong, if it's because the camera doesn't support what I try to do.
I've already tried WSHttpBinding and putting it in Username mode, but using WSHttpBinding break the basic information discovery I was able to create (with a MustUnderstand error)...
Any pointers for me? Simple WS-Security/.NET, C#/ONVIF tutorials, everything will be accepted.
All right:
EndpointAddress serviceAddress = new EndpointAddress("<mycameraurl:<mycameraport>/onvif/device_service");
HttpTransportBindingElement httpBinding = new HttpTransportBindingElement();
httpBinding.AuthenticationScheme = AuthenticationSchemes.Digest;
var messageElement = new TextMessageEncodingBindingElement();
messageElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);
CustomBinding bind = new CustomBinding(messageElement, httpBinding);
// Add our custom behavior - this require the Microsoft WSE 3.0 SDK
PasswordDigestBehavior behavior = new PasswordDigestBehavior(CameraASCIIStringLogin, CameraASCIIStringPassword);
DeviceClient client = new DeviceClient(bind, serviceAddress);
client.Endpoint.Behaviors.Add(behavior);
// We can now ask for information
client.GetSystemDateAndTime();
client.GetNetworkInterfaces();
client.GetScopes();
client.GetRelayOutputs();
client.GetWsdlUrl();
The problem was that the camera required authentication before giving any information beyond the simplest ones, and the trickiest part was to finally catch a working xml onvif message to recreate it in my own software.