(试图)从WSE 3.0迁移到WCF为客户机代码((Attempting to) migrate f

2019-06-24 10:34发布

我一直都在网为这一点。 我刚刚一直有一个时间的魔鬼做,并且其网络服务我想占用拒绝正式支持WCF作为消费的一个方法的供应商。

我没有Web服务专家,所以我会尽我所能来记录以及与此初始后解释,但通过各种手段,如果你需要它获得更多信息,并希望我能提供一切必要。

服务

在我的公司,我们使用的是公开服务供应商的应用程序。 该应用程序是用Java编写的,它看起来像WSDL与Apache Axis的1.2创建的。

代码

我的遗留代码使用WSE 3.0。 特别是,它使用了“WSE”末自动上涨的代理类。 这让我用一个更简单的身份验证方案(我能得到它的工作的唯一途径)。 我并不需要使用证书。 我用的衍生物SecurityPolicyAssertion ,并在其包装Policy获取传递给对象SetPolicy客户端类的方法。 这里的一切,我需要做创建客户端的工作实例:

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

我默认情况下,外的现成的WCF代码(有服务引用生成)不接受凭据,所以我知道有一个问题马上蝙蝠。 我读过关于网络使用不同的各种事情security或在我的绑定设置app.config ,但没有曾经完全奏效。 我丰富的修修补补之后最常见的错误是WSDoAllReceiver: Request does not contain required Security header

下面是在app.config。 网上再次,我已经看到了不同的看法 - 或许我们可以告诉我应该是什么改变这里,以方便传递凭据开始。

<?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>

我已经改变了一些属性掩盖,我们所使用的特定服务(公司政策和所有)。

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

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

UPDATE

阅读SO帖子: WCF安全。 。 。 。

我已经相应地更新我的app.config,和我现在通过用户名和PWD代码。 我仍然收到了同样的错误:

WSDoAllReceiver: Request does not contain required Security header

20120517 UPDATE

一个成功的请求(来自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>

在得到WCF跟踪工作 - 将在短期内增加。

20120517更新2

下面是从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 UPDATE我试图实现在麦克-米勒链接到的意见后的解决方案。 现在,我收到以下错误(没有消息最终得到发送,因为东西是barfing的方案):

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

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

Answer 1:

你需要的是超过未在WCF开箱即用支持HTTP传输发送用户名令牌。 除了你的令牌使用现时/创建这也是没有开箱即用的。 你有2种选择:

  1. 这个开放源码软件项目增加现时/创建用户名令牌。 这个开放源码软件项目增加了通过HTTP发送用户名的能力。 你将需要两个项目结合在一起。

  2. WS-Security是通常被认为是复杂的,但你在最简单​​的形式(用户名)使用它。 最简单的将开除任何WCF安全设置都在一起,并通过自己在创建整个安全头消息检查 ! 正如你所看到的最头都只是静态的XML节点,最值是很清楚的(你知道用户名)。 唯一棘手的两个是随机数,哪些是你可以看看如何在这做的时间戳OSS项目 (每一条线)。 有这个选项,可能会更容易的一个变种-使用CUB毕竟和实施定制的编码器 ,其推动timestmpa /随机数。 我会去为后者,但我因为我开发CUB偏见...

另外还有的WS-Addressing,您可以在您的自定义编码“messageVersion”属性配置的标头。 因为你与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<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. 在文件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一个代替)。

祝好运!



文章来源: (Attempting to) migrate from WSE 3.0 to WCF for client code