Onvif SOAP request with SOAP level authentication and HTTP authentication

旧城冷巷雨未停 提交于 2019-12-04 19:24:00

If anyone is interested this is how I got it working. I combined the BasicHttpBinding with the client credentials in a following way:

TransportSecurityBindingElement transportSecurity = new TransportSecurityBindingElement();
// UsernameCredentials is a class implementing WS-UsernameToken authentication
transportSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UsernameTokenParameters());
transportSecurity.AllowInsecureTransport = true;
transportSecurity.IncludeTimestamp = false;
TextMessageEncodingBindingElement messageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8);
HttpClientCredentialType[] credentialTypes = new HttpClientCredentialType[3] { HttpClientCredentialType.None, HttpClientCredentialType.Basic, HttpClientCredentialType.Digest };
...
foreach (HttpClientCredentialType credentialType in credentialTypes)
{
    BasicHttpBinding httpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
    httpBinding.Security.Transport.ClientCredentialType = credentialType;
    BindingElementCollection elements = new BindingElementCollection(new BindingElement[1]{messageEncoding});
    foreach(BindingElement element in httpBinding.CreateBindingElements())
    {
        if (element is TextMessageEncodingBindingElement)
            continue;
        elements.Add(element);
    }
    CustomBinding customBinding = new CustomBinding(elements);
    DeviceClient deviceClient = new DeviceClient(customBinding, endPointAddress);
    if (credentialType == HttpClientCredentialType.Basic)
    {
         // Set all credentials, not sure from which one WCF actually takes the value
         deviceClient.ClientCredentials.UserName.UserName = pair[0];
         deviceClient.ClientCredentials.UserName.Password = pair[1];
    }
    else if (credentialType == HttpClientCredentialType.Digest)
    {
        deviceClient.ClientCredentials.HttpDigest.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
        deviceClient.ClientCredentials.HttpDigest.ClientCredential.UserName = pair[0];
        deviceClient.ClientCredentials.HttpDigest.ClientCredential.Password = pair[1];
    }
}

This works efficiently with a device for which we do not know the authentication mode and works on both (HTTP/SOAP) authentication level.

Ottavio Campana

I detailed how HTTP digest works in another answer.

Remember that only functions of class PRE_AUTH, according to §5.12.1 of the Core spec, require authentication.

You should invoke a function of any class but PRE_AUTH without any form authentication. If you get a HTTP 401 then you have to use HTTP digset, otherwise you'll have to got with WS-UsernameToken.

You can't directly use HTTP digest because you'll need at least the device to send you the challange for HTTP digest.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!