Java Web 服务客户端使用需要 header 和 body 签名的 WCF 服务

Java web service client to consume a WCF service that needs header and body to be signed

我们正在开发的系统包括以下应用程序: - 可以颁发 WSTrust 访问令牌的 .Net WCF 安全令牌服务。 - 公开简单 Ping 操作的 Java 服务。 - Java servlet,调用 STS 获取令牌,然后使用它访问服务。

.Net WCF STS 的要求: - 请求和响应的消息体都必须签名。 - 没有加密。 - 必须有时间戳并且必须签名。 - 必须使用 https。

为了满足这些要求,我们创建了一个自定义 WCF Web 服务,其自定义绑定是:

        var bindings = new BindingElementCollection();
        var transportBinding = new HttpsTransportBindingElement { RequireClientCertificate = false };
        var encodingBinding = new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap12WSAddressing10 };
        MessageSecurityVersion version =
            MessageSecurityVersion
                .WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;

        var sec = SecurityBindingElement.CreateMutualCertificateBindingElement(version) as AsymmetricSecurityBindingElement;
        sec.MessageProtectionOrder = MessageProtectionOrder.EncryptBeforeSign;

        bindings.Add(sec);
        bindings.Add(encodingBinding);
        bindings.Add(transportBinding);

服务主机初始化如下:

        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IWSTrust13SyncContract),
              new MyCustomBinding(), "/myendpoint");
        endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;

到目前为止一切顺利。我们使用 .Net 客户端对其进行了测试,它运行良好。对于 Java 部分,结果不是很好。 到目前为止我们完成的所有步骤是:

  1. 在 Java 服务中:编辑网络服务属性:

    • 使用“STS Issued Endorsing token”机制设置安全服务
    • 设置密钥库和信任库
  2. 在 servlet 应用程序中

    • 使用 Java 服务的 wsdl 添加网络服务客户端 -> 编辑网络服务属性
    • 设置安全性:密钥库和信任库
    • 设置安全令牌服务:端点、wsdl 位置、服务名称、端口名称、命名空间和 ws 信任版本

    • 使用 STS 的 wsdl 添加 Web 服务客户端 -> 编辑 Web 服务属性

    • 在“服务质量”选项卡中,只有“传输”部分。 "Security" 部分不存在。 (1)
  3. 设置以上所有选项后,检查文件夹“Src/java/META - INF”有wsit-client.xml和2个服务参考xml 文件如预期

    • 我检查了 xml 个文件生成的策略,对我来说一切正常,它与我们的 STS 的 wsdl 具有相同的策略。详细来说,它有:
    • 非对称绑定
    • SignedParts
    • 传输绑定
  4. 最后一步是启动服务端口并调用如下操作 Service_Service 服务 = 新 Service_Service(); 服务存根 = service.getServicePort(); return stub.ping();

我希望在发送到 STS 之前对消息进行签名(header 和 body)。然而实际上,发送给STS的消息是没有签名的。 STS 报错: “必须对 ID 为‘_1’的安全 header 元素 'Timestamp' 进行签名” (2)

如果我们更改为使用 http 而不是 https 进行传输绑定,则对 STS 的请求消息已正确签名。但是要求是使用https。

我们的问题是:

事实证明,服务和Java客户端都没有问题。正是暴露的 WSDL 导致了所有的麻烦。简而言之,WSDL 同时具有 AsymmetricBinding 和 TransportBinding 元素,这使得客户端在尝试使用 WSDL 时感到困惑。在我从 WSDL 中删除 TransportBinding 元素后,Java 客户端可以使用 WSDL 并生成带有签名的正确请求。