I am developing a ONVIF driver using .NET 4 (Windows Forms, not WCF). I started importing WSDL files as a service in visual studio. So I am able to send command to a device in this way:
HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
[...]
TextMessageEncodingBindingElement messegeElement = new TextMessageEncodingBindingElement();
[...]
CustomBinding binding = new CustomBinding(messegeElement, httpTransportBindingElement);
[...]
EndpointAddress serviceAddress = new EndpointAddress(url);
DeviceClient deviceClient = new DeviceClient(binding, serviceAddress);
Device channel = deviceClient.ChannelFactory.CreateChannel();
DeviceServiceCapabilities dsc = channel.GetServiceCapabilities();
But I am not able to manage HTTP digest authentication. I spent days searching on google examples and solutions, but the only ways seems to be hand write XML code. There is not any clean solution like:
deviceClient.ChannelFactory.Credentials.HttpDigest.ClientCredential.UserName = USERNAME;
deviceClient.ChannelFactory.Credentials.HttpDigest.ClientCredential.Password = digestPassword;
(that doesn't work)?
For future readers, finally I was able to perform both type of authentication without using WSE 3.0. This is partial code (for shortness), based on the IClientMessageInspector interface (you can find lot of other examples based on this interface):
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
if (HTTPDigestAuthentication)
{
string digestHeader = string.Format("Digest username=\"{0}\",realm=\"{1}\",nonce=\"{2}\",uri=\"{3}\"," +
"cnonce=\"{4}\",nc={5:00000000},qop={6},response=\"{7}\",opaque=\"{8}\"",
_username, realm, nonce, new Uri(this.URI).AbsolutePath, cnonce, counter, qop, digestResponse, opaque);
HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
httpRequest.Headers.Add("Authorization", digestHeader);
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequest);
return Convert.DBNull;
}
else if (UsernametokenAuthorization)
{
string headerText = "<wsse:UsernameToken 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\">" +
"<wsse:Username>" + _username + "</wsse:Username>" +
"<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + digestPassword + "</wsse:Password>" +
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + Convert.ToBase64String(nonce) + "</wsse:Nonce>" +
"<wsu:Created xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + created + "</wsu:Created>" +
"</wsse:UsernameToken>";
XmlDocument MyDoc = new XmlDocument();
MyDoc.LoadXml(headerText);
MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", MyDoc.DocumentElement, false);
request.Headers.Add(myHeader);
return Convert.DBNull;
}
return request;
}