具有SOAP级别身份验证和HTTP身份验证的Onvif SOAP请求

时间:2014-01-16 18:57:44

标签: c# wcf soap onvif

这个问题已经在几个主题中进行了讨论,但我无法找到答案。

我要做的是通过Onvif界面使用IP摄像头。我已经从Onvif主页上提供的WSDL文件生成了Web服务,并按照建议here添加了自定义SOAP身份验证代码,并且我能够检索设备功能等等。

但对于某些服务,例如PTZ控制,还需要HTTP身份验证。我的代码删除了ClientCredentials行为(所以是的,我想设置它们没有任何意义,但我仍然希望这些行可能会使HTTP传输尝试使用它们):

HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
httpBindingElement.AuthenticationScheme = AuthenticationSchemes.Basic;
...
PTZClient ptzClient = new PTZClient(customBinding, endPointAddress);
ptzClient.Endpoint.Behaviors.Remove(typeof(System.ServiceModel.Description.ClientCredentials));
UsernameClientCredentials onvifCredentials = new UsernameClientCredentials(new UsernameInfo(_username, _password));
ptzClient.Endpoint.Behaviors.Add(onvifCredentials);
ptzClient.ClientCredentials.UserName.UserName = _username;
ptzClient.ClientCredentials.UserName.Password = _password;

当我查看wireshark时,我发现生成了SOAP身份验证,但没有设置HTTP身份验证标头(好吧,我已经预料到了,因为我这里有自定义行为)。所以问题是,如果我以这种方式创建绑定,那么添加HTTP身份验证标头的最佳选择是什么?我可以添加一个消息检查器吗?如果有,可以添加任何示例吗?我必须创建不同的传输绑定吗?我见过有人建议其他人使用BasicHttpBinding,然后在其上设置Security属性,但在这种情况下凭据的位置如何,以及如何将BasicHttpBinding实例应用于我的捆绑? WCF中是否有任何由HTTP 401代码触发的回调,我可以连接并提供标题?这实际上是我第一次使用WCF,到目前为止,我已经完成了互联网上的所有示例,但至于这个特殊问题我还没有找到任何东西。

2 个答案:

答案 0 :(得分:2)

如果有人有兴趣,我就是这样做的。我以下列方式将BasicHttpBinding与客户端凭据合并:

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];
    }
}

这适用于我们不知道身份验证模式的设备,并且同时适用于(HTTP / SOAP)身份验证级别。

答案 1 :(得分:0)

我详细介绍了HTTP摘要在另一个answer中的工作原理。

请记住,根据Core spec的§5.12.1,只有类PRE_AUTH的函数需要进行身份验证。

您应该调用任何类的函数,但不需要任何表单身份验证的PRE_AUTH。如果你得到HTTP 401那么你必须使用HTTP digset,否则你必须使用WS-UsernameToken。

您不能直接使用HTTP摘要,因为您至少需要设备向您发送HTTP摘要的挑战。