Java SpringWS验证签名并提取端点中的SOAP头

Java SpringWS验证签名并提取端点中的SOAP头,java,web-services,soap,spring-ws,Java,Web Services,Soap,Spring Ws,我们有一个获取下一条SOAP消息的Web服务。我只发布了标题,它是我们问题的重要部分 <SOAP-ENV:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wss

我们有一个获取下一条SOAP消息的Web服务。我只发布了标题,它是我们问题的重要部分

<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" SOAP-ENV:mustUnderstand="1">
  <wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509-65E18DC0CA7D9A38B214168992655731">THE_CERTIFICATE</wsse:BinarySecurityToken>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-65E18DC0CA7D9A38B214168992656685">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
        <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="SOAP-ENV"/>
      </ds:CanonicalizationMethod>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      <ds:Reference URI="#id-65E18DC0CA7D9A38B214168992656044">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
            <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList=""/>
          </ds:Transform>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <ds:DigestValue>DIGEST_VALUE</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>THE_SIGNATURE</ds:SignatureValue>
    <ds:KeyInfo Id="KI-65E18DC0CA7D9A38B214168992655892">
      <wsse:SecurityTokenReference wsu:Id="STR-65E18DC0CA7D9A38B214168992655893">
        <wsse:Reference URI="#X509-65E18DC0CA7D9A38B214168992655731" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
      </wsse:SecurityTokenReference>
    </ds:KeyInfo>
  </ds:Signature>
</wsse:Security>
当Spring验证请求的签名时,似乎删除了头,因此我们无法访问头元素的第一个子元素。如果我们在应用程序上下文中对验证部分进行注释,那么前面的代码就像一个符咒,我们得到了证书

我们如何避免这种行为?为什么验证后会删除请求的标头


谢谢

经过一个漫长的夜晚的研究和阅读Spring文档,我找到了一个解决方法。我不明白为什么Spring正在使用这些头,或者为什么我的端点没有收到这些头,但是我们可以在下一个代码中提取证书(激活签名验证):

@PayloadRoot(localPart=“ValidateUserRequest”,namespace=GET\u TARGET\u namespace)
public@ResponsePayload ValidateUserResponse validateUser(@RequestPayload ValidateUserRequest,MessageContext MessageContext)抛出WSSecurityException,CertificateException{
List handlerResults=(List)messageContext.getProperty(WSHandlerConstants.RECV_RESULTS);
WSHandlerResult rResult=handlerResults.get(0);
List results=rResult.getResults();
WSSecurityEngineResult actionResult=WSSecurityUtil.fetchActionResult(结果,WSConstants.SIGN);
X509CertificateReturnCert=null;
if(actionResult!=null){
returnCert=(X509Certificate)actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
}
//对证书和返回值进行处理
}

经过一些研究,我发现Spring正在MessageContext中保存验证中处理的结果,其中包含证书(请参见
Wss4jSecurityInterceptor#updateContextWithResults
)。

使用AOP对
MessageContext
参数进行验证不是更好吗?
<sws:interceptors>
    <bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
        <property name="validationActions" value="Signature" />
        <property name="validationSignatureCrypto">
            <bean
                class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
                <property name="keyStorePassword" value="passtrustore" />
                <property name="keyStoreLocation" value="classpath:/ts-webservice.jks" />
            </bean>
        </property>
        <property name="securementActions" value="Signature" />
        <property name="securementUsername" value="user" />
        <property name="securementPassword" value="pass" />
        <property name="securementSignatureKeyIdentifier" value="DirectReference" />
        <property name="securementSignatureCrypto">
            <bean
                class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean">
                <property name="keyStorePassword" value="passkeystore" />
                <property name="keyStoreLocation" value="classpath:/ks-webservice.jks" />
            </bean>
        </property>
    </bean>
</sws:interceptors>
@PayloadRoot(localPart = "ValidateUserRequest", namespace = GET_TARGET_NAMESPACE)
public @ResponsePayload
ValidateUserResponse validateUser(@RequestPayload ValidateUserRequest request, MessageContext messageContext) throws WSSecurityException,
        CertificateException {
    // read SOAP Header
    SoapMessage mc = (SoapMessage) messageContext.getRequest();
    String soapNamespace = WSSecurityUtil.getSOAPNamespace(mc.getDocument().getDocumentElement());
    Element elem = WSSecurityUtil.getDirectChildElement(mc.getDocument().getDocumentElement(), WSConstants.ELEM_HEADER, soapNamespace);

    // get the BinarySignature tag
    // FIRST getFirstChild() is NULL if we have validated the request
    Node binarySignatureTag = elem.getFirstChild().getFirstChild();
    BinarySecurity token = new X509Security((Element) binarySignatureTag);

    InputStream in = new ByteArrayInputStream(token.getToken());
    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
    X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);

    // do stuff with the certificate and return values
}
@PayloadRoot(localPart = "ValidateUserRequest", namespace = GET_TARGET_NAMESPACE)
public @ResponsePayload ValidateUserResponse validateUser(@RequestPayload ValidateUserRequest request, MessageContext messageContext) throws WSSecurityException, CertificateException {
    List<WSHandlerResult> handlerResults = (List<WSHandlerResult>) messageContext.getProperty(WSHandlerConstants.RECV_RESULTS);
    WSHandlerResult rResult = handlerResults.get(0);
    List<WSSecurityEngineResult> results = rResult.getResults();

    WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);

    X509Certificate returnCert = null;
    if (actionResult != null) {
        returnCert = (X509Certificate) actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
    }
// do stuff with the certificate and return values
}