(尝试)从WSE 3.0迁移到WCF以获取客户端代码

为此我一直都在网上。 我刚刚做了一段时间的恶魔,我试图消费的网络服务供应商拒绝正式支持WCF作为消费方法。

我不是网络服务专家,所以我会尽力记录和解释这篇文章,但无论如何,如果你需要的话,请求更多的信息,希望我能够提供任何必要的东西。

服务

在我的公司,我们使用公开服务的供应商应用程序。 应用程序是用java编写的,看起来wsdl是用Apache Axis 1.2创建的。

代码

我的遗留代码使用WSE 3.0。 特别是,它使用最后自动添加“WSE”的代理类。 这允许我使用更简单的身份validation方案(我可以使它工作的唯一方法)。 我不需要使用证书。 我使用SecurityPolicyAssertion的衍生物,并将其包装在一个Policy对象中,该对象被传递给客户端类的SetPolicy方法。 以下是创建客户端工作实例所需的全部内容:

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

我的默认,开箱即用的WCF代码(使用服务引用生成)不接受凭据,所以我知道现在有一个问题。 我在网上阅读了有关在app.config使用不同security或绑定设置的各种内容,但没有任何内容完全奏效。 在大量修补之后我最常见的错误是WSDoAllReceiver: Request does not contain required Security header

这是app.config。 也许我们可以先告诉我这里应该改变什么来促进传递证书 – 再次,我在网上看到了不同的意见。

                    

我已经改变了一些属性来模糊我们正在使用的特定服务(公司政策和所有这些)。

这是目前为止的示例C#代码(在控制台应用程序中测试):

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

UPDATE

阅读此SOpost: wcf security。 。 。 。

我已相应更新了我的app.config,现在正在代码中传递用户名和密码。 我仍然收到同样的错误:

 WSDoAllReceiver: Request does not contain required Security header 

20120517更新

一个成功的请求(来自WSE3):

     urn:uuid:cb739422-c077-4eec-8cb2-686837b76878  http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous  http://removed-for-security   2012-05-17T11:25:41Z 2012-05-17T11:30:41Z   change-to-protect-the-innocent nice-try KJMvUuWF2eO2uIJCuxJC4A== 2012-05-17T11:25:41Z      0 10    

致力于获取WCF跟踪 – 将很快添加。

20120517更新2

这是WCF的信封:

        1 2147483647    

20120518更新我尝试在Mike Miller在评论中链接的post中实现解决方案。 现在我收到以下错误(没有消息最终被发送,因为某些东西正在计划中):

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

如果有人想问,是的,我需要通过http发送,是的,我知道凭据是作为未加密的字符串发送的:-)

您需要的是通过http传输发送用户名令牌,这在wcf ootb中是不受支持的。 此外,您的令牌使用nonce / created,这也不是ootb。 你有2个选择:

  1. 这个oss项目将nonce / created添加到用户名令牌中。 这个oss项目增加了通过http发送用户名的function。 你需要将两个项目结合在一起。

  2. ws-security通常被认为是复杂的,但您以最简单的forms(用户名)使用它。 最简单的方法是将所有wcf安全设置一起解除,并在消息检查器中自己创建整个安全标头! 正如您所看到的,大多数标头只是静态xml节点,而且大多数值非常清晰(您知道用户名)。 唯一棘手的两个是nonce和时间戳,你可以看看在这个oss项目中如何做(每行一行)。 这个选项的变体可能更容易 – 毕竟使用CUB并实现一个推送timestmpa / nonce的自定义编码器 。 我会选择后者但是因为我开发了CUB而我有偏见…

您还可以在自定义编码“messageVersion”属性上配置ws-addressing标头。 由于您省略了带有wsa前缀定义的信封标头,因此无法确切地说出确切的值。

如果您私下想要帮助(因为您似乎有安全限制),请通过我的博客向我发送电子邮件。

编辑:我已经为你实现了它。 跟着这些步骤:

  1. 下载幼崽并熟悉它(不是内部,根据博客文章如何使用它)

  2. 将System.Runtime.Serialization.dll的引用添加到项目ClearUsernameBinding

  3. 向该项目添加一个新文件:UsernameExEncoder.cs。 粘贴此内容:

     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 BuildChannelFactory(BindingContext context) { context.BindingParameters.Add(this); var res = base.BuildChannelFactory(context); return res; } public override bool CanBuildChannelFactory(BindingContext context) { var res = base.CanBuildChannelFactory(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(BindingContext context) { var res = this.inner.GetProperty(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() { return inner.GetProperty(); } 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 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 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. 在ClearUsernameBinding.cs文件中替换为:

    res.Add(new TextMessageEncodingBindingElement(){MessageVersion = this.messageVersion});

    有了这个:

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

  5. 在app.config中的项目TestClient中,绑定元素上有一个messageVersion属性。 您尚未发布信封的根目录,因此我无法确切知道,但您可能需要将其设置为Soap11WSAddressingAugust2004或Soap11WSAddressing10(或其中一个使用Soap12)。

祝好运!