2017-04-07 37 views
0

.NET 4 (WCF가 아닌 Windows Forms)를 사용하여 ONVIF 드라이버를 개발 중입니다. Visual Studio에서 WSDL 파일을 서비스로 가져 오기 시작했습니다. 그래서 나는이 방법으로 장치에 명령을 보낼 수 있어요 :ONVIF wsdl 서비스 : 인증 할 수 없습니다.

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(); 

하지만 다이제스트 인증 HTTP를 관리 할 수 ​​없습니다입니다. 나는 구글 예제와 솔루션으로 검색하는 일을 보냈지 만, 유일한 방법은 XML 코드를 직접 작성하는 것 같다. 다음과 같은 깨끗한 해결책이 없습니다.

deviceClient.ChannelFactory.Credentials.HttpDigest.ClientCredential.UserName = USERNAME; 
deviceClient.ChannelFactory.Credentials.HttpDigest.ClientCredential.Password = digestPassword; 

(작동하지 않음)?

답변

0

는, 마지막으로 내가 WSE 3.0을 사용하지 않고 두 인증 유형을 수행 할 수 있었다. 이것은 IClientMessageInspector 인터페이스를 기반으로 (곤란에 대한) 부분적인 코드입니다 (이 인터페이스를 기반으로 다른 예제를 많이 찾을 수 있습니다) :

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; 
    } 
+0

예제에서 많은 것들이 누락되었습니다. 그리고 매우 중요한 몇 가지 사항 ... 다이제스트 헤더의 형식을 지정하는 데 사용되는 변수를 어떻게 얻습니까? (예 : nonce? 요청을해야합니까?) – cube45

+0

맞습니다. 인증없이 요청을 보내면 서버는 nonce, 영역 등을 포함하는 오류 메시지로 응답합니다. – ElmoDev001

+0

BeforeSendRequest 시작 부분에 HttpClient를 만들고 있습니까? 답을 편집하고보다 완벽한 예를 제공해 주시겠습니까? – cube45

1

먼저 Microsoft.Web.Services3 패키지를 설치해야합니다. (보기> 다른 창> 패키지 관리자 콘솔). 그런 다음 끝점에 다이제스트 동작을 추가해야합니다. 코드의 첫 번째 부분은 PasswordDigestBehavior 클래스이며, 이후에는 ONVIF 장치 서비스에 연결하는 데 사용됩니다.

public class PasswordDigestBehavior : IEndpointBehavior 
{ 
    public String Username { get; set; } 
    public String Password { get; set; } 

    public PasswordDigestBehavior(String username, String password) 
    { 
     this.Username = username; 
     this.Password = password; 
    } 


    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 
     // do nothing 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
    { 
     //clientRuntime.MessageInspectors.Add(new PasswordDigestMessageInspector(this.Username, this.Password)); 
     clientRuntime.MessageInspectors.Add(new PasswordDigestMessageInspector(this.Username, this.Password)); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
     // do nothing... 
    } 
} 


public class PasswordDigestMessageInspector : IClientMessageInspector 
{ 
    public String Username { get; set; } 
    public String Password { get; set; } 

    public PasswordDigestMessageInspector(String username, String password) 
    { 
     this.Username = username; 
     this.Password = password; 
    } 

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) 
    { 
     // do nothing 
    } 

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) 
    { 
     // Use the WSE 3.0 security token class 
     var option = PasswordOption.SendHashed; 
     if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password)) 
      option = PasswordOption.SendPlainText; 

     UsernameToken token = new UsernameToken(this.Username, this.Password, option); 

     // Serialize the token to XML 
     XmlDocument xmlDoc = new XmlDocument(); 
     XmlElement securityToken = token.GetXml(xmlDoc); 

     // find nonce and add EncodingType attribute for BSP compliance 
     XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); 
     nsMgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
     XmlNodeList nonces = securityToken.SelectNodes("//wsse:Nonce", nsMgr); 
     XmlAttribute encodingAttr = xmlDoc.CreateAttribute("EncodingType"); 
     encodingAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"; 
     if (nonces.Count > 0) 
     { 
      nonces[0].Attributes.Append(encodingAttr); 
      //nonces[0].Attributes[0].Value = "foo"; 
     } 


     // 
     MessageHeader securityHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityToken, false); 
     request.Headers.Add(securityHeader); 

     // complete 
     return Convert.DBNull; 
    } 
} 

그리고이 그것을 사용하는 방법입니다 : 미래의 독자

var endPointAddress = new EndpointAddress("http://DEVICE_IPADDRESS/onvif/device_service"); 
      var httpTransportBinding = new HttpTransportBindingElement { AuthenticationScheme = AuthenticationSchemes.Digest }; 
      var textMessageEncodingBinding = new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None) }; 
      var customBinding = new CustomBinding(textMessageEncodingBinding, httpTransportBinding); 
      var passwordDigestBehavior = new PasswordDigestBehavior(USERNAME, PASSWORD); 
      var deviceService = new DeviceClient(customBinding, endPointAddress); 
      deviceService.Endpoint.Behaviors.Add(passwordDigestBehavior); 
+0

귀하의 솔루션이 작동하지만, SOAP 인증을 수행하지 HTTP 다이제스트 인증한다 . 어쨌든 마침내 나는 WSE 3.0을 사용하지 않고 두 종류의 인증을 모두 수행 할 수있었습니다. – ElmoDev001