【问题标题】:Sign JAX-WS SOAP request签署 JAX-WS SOAP 请求
【发布时间】:2011-11-27 17:45:32
【问题描述】:

我想编写一个 JAX-WS Web 服务,使用 http://www.w3.org/TR/xmldsig-core/ 建议对我的 SOAP 消息进行签名。

根据我在 Internet 上找到的内容,我编写了一个 JAX-WS 处理程序 (SOAPHandler<SOAPMessageContext>),它设法更改 SOAP 请求的副本:

@Override
public boolean handleMessage(SOAPMessageContext smc) {
    Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    SOAPMessage message = smc.getMessage();

    if (outboundProperty) {
        try {
            SOAPPart soapPart = message.getSOAPPart();
            SOAPEnvelope soapEnvelope = soapPart.getEnvelope();

            Source source = soapPart.getContent();

            Node root = null;
            Document doc22 = null;
            if (source instanceof DOMSource) {
                root = ((DOMSource) source).getNode();
            } else if (source instanceof SAXSource) {
                InputSource inSource = ((SAXSource) source).getInputSource();
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true);
                DocumentBuilder db = null;

                db = dbf.newDocumentBuilder();

                doc22 = db.parse(inSource);
                root = (Node) doc22.getDocumentElement();
            }

            XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

            Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null),
                    Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
                    null, null);

            SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
                    (C14NMethodParameterSpec) null),
                    fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                    Collections.singletonList(ref));

            // Load the KeyStore and get the signing key and certificate.
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream("client_keystore.jks"), "changeit".toCharArray());
            KeyStore.PrivateKeyEntry keyEntry =
                    (KeyStore.PrivateKeyEntry) ks.getEntry("client", new KeyStore.PasswordProtection("changeit".toCharArray()));
            X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
            // Create the KeyInfo containing the X509Data.
            KeyInfoFactory kif2 = fac.getKeyInfoFactory();
            List x509Content = new ArrayList();
            x509Content.add(cert.getSubjectX500Principal().getName());
            x509Content.add(cert);
            X509Data xd = kif2.newX509Data(x509Content);
            KeyInfo ki = kif2.newKeyInfo(Collections.singletonList(xd));

            Element header = getFirstChildElement(root/*.getDocumentElement()*/);
            DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), header /*doc.getDocumentElement()*/);

            XMLSignature signature = fac.newXMLSignature(si, ki);

            signature.sign(dsc);

            //TODO: change this to update the SOAP message, not write it to disks
            OutputStream os = new FileOutputStream("out.xml");
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer trans = tf.newTransformer();
            trans.transform(new DOMSource(root), new StreamResult(os));

        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

    return true;
}

但我不知道如何更新 SOAP 请求?

【问题讨论】:

  • soapPart.setContent(new DOMSource(root)) 不起作用吗?我只是猜测,我自己没有做过。
  • 不幸的是,这会清空 bode 和 header 元素。不过,感谢您的关注!
  • 您找到解决此问题的方法了吗?我很好奇,因为我要做类似的事情
  • 我放弃了这个想法,但如果有人有解决方案,我仍然对解决方案感兴趣!
  • 我的测试告诉我你不需要做任何事情,因为签名已经更新了 SOAP 消息。

标签: java soap jax-ws x509


【解决方案1】:

代码行之后:

signature.sign(dsc);

插入此语句:

soapMsg.saveChanges();

它将保存您的更改。

【讨论】:

    【解决方案2】:

    你可以试试soapPart.saveChanges();

    【讨论】:

      【解决方案3】:

      我为 Soap 请求的 Xml 数字签名开发了一个 SOAPHandler。

      public class SOAPSecurityHandler implements
              LogicalHandler<LogicalMessageContext> {
      
          static final String KEYSTORE_FILE = "keystore_name.jks";
          static final String KEYSTORE_INSTANCE = "JKS";
          static final String KEYSTORE_PWD = "123456";
          static final String KEYSTORE_ALIAS = "keystore";
      
          public Set<QName> getHeaders() {
              return Collections.emptySet();
          }
      
          @Override
          public boolean handleMessage(LogicalMessageContext smc) {
              Boolean outboundProperty = (Boolean) smc
                      .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
      
              try {
      
                  if (outboundProperty) {
      
                      Source source = smc.getMessage().getPayload();
      
                      Node root = null;
      
                      root = ((DOMSource) source).getNode();
      
                      XMLSignatureFactory fac = XMLSignatureFactory
                              .getInstance("DOM");
      
                      Reference ref = fac.newReference("", fac.newDigestMethod(
                              DigestMethod.SHA1, null), Collections.singletonList(fac
                              .newTransform(Transform.ENVELOPED,
                                      (TransformParameterSpec) null)), null, null);
      
                      SignedInfo si = fac.newSignedInfo(fac
                              .newCanonicalizationMethod(
                                      CanonicalizationMethod.INCLUSIVE,
                                      (C14NMethodParameterSpec) null), fac
                              .newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                              Collections.singletonList(ref));
      
                      // Load the KeyStore and get the signing key and certificate.
                      KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE);
                      ks.load(new FileInputStream(KEYSTORE_FILE),
                              KEYSTORE_PWD.toCharArray());
                      KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks
                              .getEntry(
                                      KEYSTORE_ALIAS,
                                      new KeyStore.PasswordProtection(KEYSTORE_PWD
                                              .toCharArray()));
                      X509Certificate cert = (X509Certificate) keyEntry
                              .getCertificate();
                      // Create the KeyInfo containing the X509Data.
                      KeyInfoFactory kif2 = fac.getKeyInfoFactory();
                      List x509Content = new ArrayList();
                      x509Content.add(cert.getSubjectX500Principal().getName());
                      x509Content.add(cert);
                      X509Data xd = kif2.newX509Data(x509Content);
                      KeyInfo ki = kif2.newKeyInfo(Collections.singletonList(xd));
      
                      Element header = DOMUtils.getFirstChildElement(root);
                      DOMSignContext dsc = new DOMSignContext(
                              keyEntry.getPrivateKey(), header);
      
                      XMLSignature signature = fac.newXMLSignature(si, ki);
      
                      signature.sign(dsc);
      
                  }
      
              } catch (Exception e) {
                  e.printStackTrace();
              }
      
              return true;
      
          }
      
          public boolean handleFault(SOAPMessageContext smc) {
              // addDigitalSignature(smc);
              return true;
          }
      
          // nothing to clean up
          public void close(MessageContext messageContext) {
          }
      
          @Override
          public boolean handleFault(LogicalMessageContext arg0) {
              // TODO Auto-generated method stub
              return false;
          }
      
      }
      

      我认为@AndrewBourgeois 代码中的问题是获取源代码的方式。

      问候,

      【讨论】:

      • DomUtils 的逻辑在哪里?
      【解决方案4】:

      最简单的方法是使用集成在应用服务器中的功能。例如:Securing JAX-WS Web services using message-level security with WebSphere App Server

      如何在WAS上配置签名你可以找到here

      这里是WebLogic documentation about Configuring Message-Level Security

      【讨论】:

      • 这是关于签名,而不是一般的保护,这是众所周知的。也许您可以提供更详细的链接和/或示例?
      • @LukasEder:消息级安全性也指签名。在此页面上,您也可以找到指向签名配置的链接。我现在将其添加到响应中。
      • 我没有时间检查这个答案的内容,但它解决了 Lukas 的问题吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      相关资源
      最近更新 更多