Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-8077

WSS4JInInterceptor is not thread safe

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 3.3.2
    • 3.1.18, 3.2.10, 3.3.3
    • WS-* Components
    • None
    • Unknown

    Description

      org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor uses a cached property WSSecurityEngine secEngineOverride.  In the situation that the same instance of secEngineOverride is used for 2 or more threads,  Following code in handleMessageInternal() will cause WSS4J to lookup wrong XML document.

      if (soapBody != null)

      { engine.setCallbackLookup(new CXFCallbackLookup(soapBody.getOwnerDocument(), soapBody)); }

      In my case, interceptor is used to do X.509 authentication with Signature for signing. When 2 or more requests comes at the almost the same time, it produces following error for victim thread(s).

      org.apache.cxf.binding.soap.SoapFault: A security error was encountered when verifying the message
      at org.apache.cxf.ws.security.wss4j.WSS4JUtils.createSoapFault(WSS4JUtils.java:234)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessageInternal(WSS4JInInterceptor.java:376)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:212)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:92)
      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
      at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
      at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:267)
      at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
      at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
      at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
      at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:216)
      at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:301)
      at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:220)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
      at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:276)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:209)
      at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
      at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
      at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114)
      at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
      at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
      at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
      at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
      at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
      at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:748)
      Caused by: org.apache.wss4j.common.ext.WSSecurityException: javax.xml.crypto.URIReferenceException: org.apache.xml.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID id-e41ca583-c6f1-40d5-8acc-f3968287b0cb
      at org.apache.wss4j.dom.processor.SignatureProcessor.verifyXMLSignature(SignatureProcessor.java:399)
      at org.apache.wss4j.dom.processor.SignatureProcessor.handleToken(SignatureProcessor.java:232)
      at org.apache.wss4j.dom.engine.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:340)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessageInternal(WSS4JInInterceptor.java:320)
      ... 65 common frames omitted
      Caused by: javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: org.apache.xml.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID id-e41ca583-c6f1-40d5-8acc-f3968287b0cb
      at org.apache.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:418)
      at org.apache.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java:382)
      at org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignature.validate(DOMXMLSignature.java:277)
      at org.apache.wss4j.dom.processor.SignatureProcessor.verifyXMLSignature(SignatureProcessor.java:372)
      ... 68 common frames omitted
      Caused by: javax.xml.crypto.URIReferenceException: org.apache.xml.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID id-e41ca583-c6f1-40d5-8acc-f3968287b0cb
      at org.apache.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:117)
      at org.apache.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:414)
      ... 71 common frames omitted
      Caused by: org.apache.xml.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID id-e41ca583-c6f1-40d5-8acc-f3968287b0cb
      at org.apache.xml.security.utils.resolver.implementations.ResolverFragment.engineResolveURI(ResolverFragment.java:78)
      at org.apache.xml.security.utils.resolver.ResourceResolver.resolve(ResourceResolver.java:278)
      at org.apache.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:110)
      ... 72 common frames omitted

       

      I ended up to override protected WSSecurityEngine getSecurityEngine(boolean utWithCallbacks)  to create WSSecurityEngine everything to avoid the issue.

       

      It can be fixed using antonymous inner class to replace previous code as following as a concept.  Please note that calling new CXFCallbackLookup(soapBody.getOwnerDocument(), soapBody) in each interface method might not be most efficient.

       

      final Element soapBody = SAAJUtils.getBody(doc);
      if (soapBody != null) {
      engine.setCallbackLookup(new CallbackLookup() {
      @Override
      public Element getElement(String s, String s1, boolean b) throws WSSecurityException

      { return new CXFCallbackLookup(soapBody.getOwnerDocument(), soapBody).getElement(s, s1, b); }

      @Override
      public Element getAndRegisterElement(String s, String s1, boolean b, DOMCryptoContext domCryptoContext) throws WSSecurityException

      { return new CXFCallbackLookup(soapBody.getOwnerDocument(), soapBody).getAndRegisterElement(s, s1, b, domCryptoContext); }

      @Override
      public List<Element> getElements(String s, String s1) throws WSSecurityException

      { return new CXFCallbackLookup(soapBody.getOwnerDocument(), soapBody).getElements(s, s1); }

      @Override
      public Element getSOAPBody()

      { return new CXFCallbackLookup(soapBody.getOwnerDocument(), soapBody).getSOAPBody(); }

      });
      }

      Attachments

        Activity

          People

            coheigea Colm O hEigeartaigh
            shuminli Shumin Li
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: