2012-05-14 10 views
10

Tôi đã kết thúc mạng lưới này. Tôi vừa mới có một ác quỷ của một thời gian làm điều đó, và các nhà cung cấp có dịch vụ web tôi đang cố gắng để tiêu thụ từ chối chính thức hỗ trợ WCF như một phương pháp tiêu thụ.(Đang cố gắng) di chuyển từ WSE 3.0 sang WCF cho mã máy khách

Tôi không có chuyên gia dịch vụ web, vì vậy tôi sẽ cố gắng hết sức để viết và giải thích bằng bài đăng đầu tiên này, nhưng bằng mọi cách, hãy yêu cầu thêm thông tin nếu bạn cần và hy vọng tôi có thể cung cấp bất cứ điều gì là cần thiết.

Dịch vụ

Tại công ty của tôi, chúng tôi sử dụng một ứng dụng cung cấp cho thấy rằng một dịch vụ. Ứng dụng này được viết bằng java và có vẻ như wsdl đã được tạo bằng Apache Axis 1.2.

mã di sản của tôi sử dụng WSE 3.0. Đặc biệt, nó sử dụng các lớp proxy có "WSE" tự động tacked ở cuối. Điều này cho phép tôi sử dụng một lược đồ xác thực đơn giản hơn nhiều (cách duy nhất tôi có thể làm cho nó hoạt động). Tôi không cần phải sử dụng chứng chỉ. Tôi sử dụng một đạo hàm của SecurityPolicyAssertion và bọc nó trong một đối tượng Policy được chuyển đến phương thức SetPolicy của lớp ứng dụng khách. Dưới đây là tất cả những gì tôi cần làm để tạo một ví dụ hoạt động của khách hàng:

MyWebServiceWse api = new MyWebServiceWse(); 
api.Url = myUrl; 
api.SetPolicy(new Policy(new MyDerivedSecurityAssertion(user, pass))); 

Mã mặc định, mã ngoài của WCF (được tạo với tham chiếu dịch vụ) không chấp nhận bằng chứng xác thực, vì vậy tôi biết có vấn đề ngay lập tức. Tôi đã đọc những thứ khác nhau trực tuyến về việc sử dụng các cài đặt security hoặc ràng buộc khác nhau trong số app.config của mình, nhưng không có gì hoàn toàn hoạt động. Lỗi phổ biến nhất của tôi sau khi mày mò phong phú là WSDoAllReceiver: Request does not contain required Security header.

Đây là app.config. Có lẽ chúng ta có thể bắt đầu bằng cách cho tôi biết những gì nên thay đổi ở đây để tạo thuận lợi cho việc vượt qua các thông tin - một lần nữa, tôi đã thấy các ý kiến ​​khác nhau trực tuyến.

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
     <bindings> 
      <basicHttpBinding> 
       <binding name="MySoapBinding" closeTimeout="00:01:00" 
        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
        allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
        maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 
        messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
        useDefaultWebProxy="true"> 
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
         maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
        <security mode="None"> 
         <transport clientCredentialType="None" proxyCredentialType="None" 
          realm="" /> 
         <message clientCredentialType="UserName" algorithmSuite="Default" /> 
        </security> 
       </binding> 
      </basicHttpBinding> 
     </bindings> 
     <client> 
      <endpoint address="http://xyz:12345/services/MyService" 
       binding="basicHttpBinding" bindingConfiguration="MySoapBinding" 
       contract="MyNS.MyService" name="MyService" /> 
     </client> 
    </system.serviceModel> 
</configuration> 

Tôi đã thay đổi một số thuộc tính để làm mờ dịch vụ cụ thể mà chúng tôi đang sử dụng (chính sách công ty và tất cả điều đó).

Và đây là đoạn code mẫu C# cho đến nay (thử nghiệm trong một ứng dụng giao diện điều khiển):

MyClient client = new MyClient(); 
client.listMethod(); 

CẬP NHẬT

đọc này SO bài: wcf security . . ..

Tôi đã cập nhật ứng dụng của mình.config cho phù hợp và hiện đang chuyển tên người dùng và mã pwd vào mã. Tôi vẫn nhận được lỗi tương tự:

WSDoAllReceiver: Request does not contain required Security header 

20120517 CẬP NHẬT

Một yêu cầu thành công (từ WSE3):

<soap:Header> 
    <wsa:Action> 
    </wsa:Action> 
    <wsa:MessageID>urn:uuid:cb739422-c077-4eec-8cb2-686837b76878</wsa:MessageID> 
    <wsa:ReplyTo> 
     <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address> 
    </wsa:ReplyTo> 
    <wsa:To>http://removed-for-security</wsa:To> 
    <wsse:Security soap:mustUnderstand="1"> 
     <wsu:Timestamp wsu:Id="Timestamp-e13feaf9-33d9-47bf-ab5b-60b4611eb81a"> 
     <wsu:Created>2012-05-17T11:25:41Z</wsu:Created> 
     <wsu:Expires>2012-05-17T11:30:41Z</wsu:Expires> 
     </wsu:Timestamp> 
     <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-00c26e1a-3b3b-400f-a99a-3aa54cf8c8ff"> 
     <wsse:Username>change-to-protect-the-innocent</wsse:Username> 
     <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">nice-try</wsse:Password> 
     <wsse:Nonce>KJMvUuWF2eO2uIJCuxJC4A==</wsse:Nonce> 
     <wsu:Created>2012-05-17T11:25:41Z</wsu:Created> 
     </wsse:UsernameToken> 
    </wsse:Security> 
    </soap:Header> 
    <soap:Body> 
    <listChannels xmlns="http://removed-for-security"> 
     <rowfrom>0</rowfrom> 
     <rowto>10</rowto> 
    </listChannels> 
    </soap:Body> 
</soap:Envelope> 

Làm việc trên nhận được trace- WCF - sẽ sớm thêm.

20120517 UPDATE 2

Và đây là phong bì từ WCF:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
    <s:Header> 
     <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"></Action> 
    </s:Header> 
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
     <listChannels xmlns="http://removed-for-security"> 
     <rowfrom>1</rowfrom> 
     <rowto>2147483647</rowto> 
     </listChannels> 
    </s:Body> 
    </s:Envelope> 

20120518 CẬP NHẬT Tôi đã cố gắng thực hiện các giải pháp trong bài viết rằng Mike Miller liên kết đến trong các ý kiến. Bây giờ tôi nhận được lỗi sau (không có thông báo kết thúc lên nhận gửi vì barfing một cái gì đó về chương trình này):

The provided URI scheme 'http' is invalid; expected 'https'. 

Và trong trường hợp bất cứ ai muốn hỏi, vâng, tôi cần phải gửi qua http, và vâng, tôi m nhận thức rằng thông tin đăng nhập được gửi dưới dạng chuỗi không được mã hóa :-)

+0

Điều đầu tiên tôi sẽ so sánh là yêu cầu xà phòng được tạo từ cả khách hàng WSE và WCF. Vì trình khách WCF được cấu hình cho 'security mode =" None "', nó không có tiêu đề bảo mật xà phòng nào được tạo ra nhưng các yêu cầu đã capture sẽ hiển thị điều đó. Tôi tin rằng basicHttpBinding không thể được cấu hình để hỗ trợ bảo mật mức tin nhắn. Bạn có thể sẽ cần đến wsHttpBinding cho cấu hình đó. Cuối cùng, hãy xem những gì Microsoft đã làm trong dự án [WCF Express Interop] (http://wcf.codeplex.com/wikipage?title=WCF%20Express%20Interop%20Bindings), các trình thủ thuật của nó cũng có thể áp dụng cho các máy khách WCF. –

+0

Cảm ơn, Sixto - cách tốt nhất để nắm bắt yêu cầu mà WCF đang gửi là gì? –

+0

WCF có tích hợp tính năng [truy tìm thư] (http://msdn.microsoft.com/en-us/library/ms730064.aspx) nhưng bạn cũng có thể sử dụng [Fiddler] (http: //www.fiddler2. com/fiddler2 /) để chụp lưu lượng truy cập từ cả khách hàng WSE và WCF. Để mở rộng trên bình luận trước của tôi, bạn nên tiếp cận việc tạo máy khách WCF mới của mình từ quan điểm của giao tiếp với một dịch vụ Apache Axis thay vì chuyển từ một máy khách WSE kế thừa. Bất chấp lời hứa "interop" của các tiêu chuẩn WS- *, đó là một nỗi đau thực sự khiến WCF làm việc với bất kỳ dịch vụ hoặc máy khách không dựa trên WCF nào. –

Trả lời

10

Điều bạn cần là gửi mã thông báo tên người dùng qua phương tiện http không được hỗ trợ trong wot. ngoài ra mã thông báo của bạn sử dụng nonce/created cũng không phải là ootb. bạn có 2 tùy chọn:

  1. oss project thêm nonce/được tạo vào mã thông báo tên người dùng này. điều này oss project thêm khả năng gửi tên người dùng qua http. bạn sẽ cần phải kết hợp cả hai dự án với nhau.

  2. bảo mật ws thường được coi là phức tạp, nhưng bạn sử dụng nó ở dạng đơn giản nhất (tên người dùng). cách đơn giản nhất là loại bỏ mọi cài đặt bảo mật wcf cùng nhau và tạo toàn bộ tiêu đề bảo mật của chính bạn trong một message inspector! Như bạn có thể thấy hầu hết các tiêu đề chỉ là các nút xml tĩnh và hầu hết các giá trị đều khá rõ ràng (bạn biết tên người dùng). hai khó khăn duy nhất là nonce và timestamps mà bạn có thể tìm cách thực hiện trong oss project (mỗi dòng một). Có một biến thể của tùy chọn này có thể dễ dàng hơn - sử dụng CUB sau khi tất cả và triển khai custom encoder để đẩy timestmpa/nonce. Tôi sẽ đi cho sau này nhưng tôi thiên vị kể từ khi tôi phát triển CUB ...

Ngoài ra còn có các tiêu đề WS-Addressing mà bạn có thể cấu hình trên mã hóa tùy chỉnh của bạn "messageVersion" bất động sản. Tôi không thể cho biết giá trị chính xác vì bạn đã bỏ qua tiêu đề phong bì với định nghĩa tiền tố wsa.

Nếu bạn muốn được trợ giúp riêng tư (vì bạn dường như có các hạn chế về bảo mật), hãy gửi email cho tôi theo số my blog.

EDIT: Tôi đã triển khai nó cho bạn. làm theo các bước sau:

  1. tải cub và làm cho mình quen thuộc với nó (không phải là internals, chỉ cần làm thế nào để sử dụng nó theo bài viết trên blog)

  2. thêm tài liệu tham khảo để System.Runtime.Serialization.dll cho dự án ClearUsernameBinding

  3. thêm tệp mới vào dự án đó: UsernameExEncoder.cs. Dán nội dung này:

    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.ServiceModel.Channels; 
    using System.IO; 
    using System.Xml; 
    using System.Security.Cryptography; 
    
    namespace Webservices20.BindingExtensions 
        { 
        class UsernameExEncoderBindingElement : MessageEncodingBindingElement 
        { 
        MessageEncodingBindingElement inner;   
    
        public UsernameExEncoderBindingElement(MessageEncodingBindingElement inner) 
        { 
         this.inner = inner;    
        } 
    
        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) 
        { 
         context.BindingParameters.Add(this); 
         var res = base.BuildChannelFactory<TChannel>(context); 
         return res; 
        } 
    
        public override bool CanBuildChannelFactory<TChannel>(BindingContext context) 
        { 
         var res = base.CanBuildChannelFactory<TChannel>(context); 
         return res; 
        } 
    
        public override MessageEncoderFactory CreateMessageEncoderFactory() 
        { 
         return new UsernameExEncoderFactory(this.inner.CreateMessageEncoderFactory()); 
        }  
    
        public override MessageVersion MessageVersion 
        { 
         get 
         { 
          return this.inner.MessageVersion; 
         } 
         set 
         { 
          this.inner.MessageVersion = value; 
         } 
        } 
    
        public override BindingElement Clone() 
        { 
         var c = (MessageEncodingBindingElement)this.inner.Clone(); 
         var res = new UsernameExEncoderBindingElement(c); 
         return res; 
        } 
    
        public override T GetProperty<T>(BindingContext context) 
        { 
         var res = this.inner.GetProperty<T>(context); 
         return res; 
        } 
    } 
    
    class UsernameExEncoderFactory : MessageEncoderFactory 
    { 
        MessageEncoderFactory inner;   
    
        public UsernameExEncoderFactory(MessageEncoderFactory inner) 
        { 
         this.inner = inner;    
        } 
    
        public override MessageEncoder Encoder 
        { 
         get { return new UsernameExEncoder(inner.Encoder); } 
        } 
    
        public override MessageVersion MessageVersion 
        { 
         get { return this.inner.MessageVersion; } 
        } 
    
    } 
    
    class UsernameExEncoder : MessageEncoder 
    { 
        MessageEncoder inner; 
    
        public override T GetProperty<T>() 
        { 
         return inner.GetProperty<T>(); 
        } 
    
        public UsernameExEncoder(MessageEncoder inner) 
        { 
         this.inner = inner; 
        } 
    
        public override string ContentType 
        { 
         get { return this.inner.ContentType; } 
        } 
    
        public override string MediaType 
        { 
         get { return this.inner.MediaType; } 
        } 
    
        public override MessageVersion MessageVersion 
        { 
         get { return this.inner.MessageVersion; } 
        } 
    
        public override bool IsContentTypeSupported(string contentType) 
        { 
         return this.inner.IsContentTypeSupported(contentType); 
        } 
    
        public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) 
        { 
         return this.inner.ReadMessage(buffer, bufferManager, contentType); 
        } 
    
        public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType) 
        { 
         return this.inner.ReadMessage(stream, maxSizeOfHeaders, contentType); 
        } 
    
        public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) 
        { 
         //load the message to dom 
         var mem = new MemoryStream(); 
         var x = XmlWriter.Create(mem); 
         message.WriteMessage(x); 
         x.Flush(); 
         mem.Flush(); 
         mem.Position = 0; 
         XmlDocument doc = new XmlDocument(); 
         doc.Load(mem); 
    
         //add the missing elements 
         var token = doc.SelectSingleNode("//*[local-name(.)='UsernameToken']"); 
         var created = doc.CreateElement("Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
         var nonce = doc.CreateElement("Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
         token.AppendChild(created); 
         token.AppendChild(nonce); 
    
         //set nonce value 
         byte[] nonce_bytes = new byte[16]; 
         RandomNumberGenerator rndGenerator = new RNGCryptoServiceProvider(); 
         rndGenerator.GetBytes(nonce_bytes); 
         nonce.InnerText = Convert.ToBase64String(nonce_bytes); 
    
         //set create value 
         created.InnerText = XmlConvert.ToString(DateTime.Now.ToUniversalTime(), "yyyy-MM-ddTHH:mm:ssZ"); 
    
         //create a new message 
         var r = XmlReader.Create(new StringReader(doc.OuterXml)); 
         var newMsg = Message.CreateMessage(message.Version, message.Headers.Action, r); 
    
         return this.inner.WriteMessage(newMsg, maxMessageSize, bufferManager, messageOffset); 
        } 
    
    
    
    
        public override void WriteMessage(Message message, System.IO.Stream stream) 
        { 
         this.inner.WriteMessage(message, stream); 
        } 
    } 
    } 
    
  4. Trong ClearUsernameBinding.cs tập tin thay thế này:

    res.Add (TextMessageEncodingBindingElement mới() {MessageVersion = này.messageVersion});

    với điều này:

    var textEncoder = new TextMessageEncodingBindingElement() {MessageVersion = this.messageVersion}; res.Thêm (new UsernameExEncoderBindingElement (textEncoder));

  5. Trong dự án TestClient trong app.config có thuộc tính messageVersion trên phần tử liên kết. Bạn đã không được xuất bản gốc của phong bì của bạn vì vậy tôi không thể biết chắc chắn, nhưng có lẽ bạn cần phải đặt nó để Soap11WSAddressingAugust2004 hoặc Soap11WSAddressing10 (hoặc một trong những với Soap12 để thay thế).

Chúc may mắn!

+0

Yaron - Tôi nhận được sự vi phạm proxy ở đây trên mạng công việc đang cố gắng lấy mã CUB (vì đó là @ blogspot). Bạn có bất kỳ vị trí nào khác có mã không? –

+0

mã nằm trong mã google http://code.google.com/p/wcf-clear-username-binding/ blog chỉ chứa lời giải thích –