2014-01-16 3 views
0

Этот вопрос обсуждался здесь по нескольким темам, но я не смог найти ответ для меня.Запрос Onvif SOAP с аутентификацией уровня SOAP и аутентификацией HTTP

Что я пытаюсь сделать, это использовать IP-камеру через интерфейс Onvif. Я создал веб-службы из файлов WSDL, доступных на главной странице Onvif, и добавил пользовательский код аутентификации SOAP, как предлагалось here, и я могу получить возможности устройства и т. Д.

Но для некоторых служб, например, управление PTZ, также требуется HTTP-аутентификация. Мой код удаляет ClientCredentials behaivor (так что да, я думаю, установка их не имеет никакого смысла, но я все равно оставил эти строки в надежде, что, может быть, 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; 

Тем не менее, когда я посмотрите на wirehark, я вижу, что аутентификация SOAP сгенерирована, но не установлен заголовок HTTP-аутентификации (ну, я уже ожидал, что, поскольку у меня есть пользовательский поведение). Поэтому вопрос в том, что если я создаю привязку таким образом, каковы мои лучшие варианты добавления заголовков HTTP-аутентификации? Могу ли я просто добавить инспектор сообщений, и если да, то какие-нибудь примеры? Должен ли я создать другую транспортную привязку? Я видел, как люди советовали другим использовать BasicHttpBinding, а затем установили на нем свойство Security, но где в этом случае будут выполняться учетные данные и как применить экземпляр BasicHttpBinding к моему привязке? Есть ли какие-либо обратные вызовы в WCF, которые запускаются с помощью кода HTTP 401, который я могу подключить, а затем предоставить заголовок? Это на самом деле мой первый опыт работы с WCF, и до сих пор я делал все из примеров, найденных в Интернете, но что касается этой конкретной проблемы, я ничего не смог найти.

ответ

1

Если кому-то интересно, вот как я получил его работу. Я объединил 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) уровень проверки подлинности.

0

Я подробно описал, как HTTP дайджест работает в другом answer.

Помните, что функции аутентификации должны выполняться только в функции класса PRE_AUTH, в соответствии с §5.12.1 от Core spec.

Вы должны вызывать функцию любого класса, но PRE_AUTH без проверки подлинности в форме. Если вы получаете HTTP 401, тогда вам нужно использовать HTTP digset, иначе вам придется получить WS-UsernameToken.

Вы не можете напрямую использовать HTTP-дайджест, потому что вам понадобится хотя бы устройство, чтобы отправить вам вызов для HTTP-дайджест.

+0

Я согласен, но проблема в том, что с приведенным примером кода, даже когда HTTP-заголовок аутентификации возвращается с сервера, соединение не повторяет ответ, а просто терпит неудачу. –

Смежные вопросы