Sounds like a reasonable first step to me.  Just to make life slightly more complicated, will the headers policy be updated to allow add/remove of SOAP:Headers? :-)

~ keith

On Mar 29, 2016, at 7:52 AM, Eric Wittmann <eric.wittmann@redhat.com> wrote:

OK so here's what I propose (feedback welcome):

*If* an API's 'type' is set to SOAP, then we will *always* look for a soap envelope in the body.  If no body is found or no soap envelope is found in the body, then a standard apiman error will be thrown.

If an envelope *is* found, then we will read the body of the HTTP request until we find "<soap:Body>".  We'll extract the <soap:Header> and parse its children.  While parsing, we'll obviously keep the data we read in a memory buffer.  Once parsing is done, we'll include the soap headers, soap action, and the global encoding type in some sort of soapinfo object and include that in the policy context.

Finally, after all that is done, we'll process the request as normal, executing the policy chain, then processing the request body, etc. The entire request payload will still be processed (remember that we saved the bytes we read in a memory buffer).

So from the perspective of a policy, everything will look identical except that a SOAPInfo object will be available in the policy context.

Thoughts?

-Eric

On 3/28/2016 1:48 PM, Benjamin Kastelic wrote:
Yup, I agree. That would probably be best, since several validators
(wss4j for example) require DOM Elements (javax.xml.soap.SOAPHeader) to
function.

Best regards,
Benjamin

2016-03-28 19:14 GMT+02:00 Eric Wittmann <eric.wittmann@redhat.com
<mailto:eric.wittmann@redhat.com>>:

   Thanks!  In that case, making the headers available as DOM Element
   objects (perhaps with a simple QName based lookup) would be best.

   -Eric

   On 3/28/2016 12:39 PM, Keith Babo wrote:

       SOAP:Headers can be complex types.  WS-Security is a good example of
       this in practice.

       ~ keith

           On Mar 28, 2016, at 11:37 AM, Eric Wittmann
           <eric.wittmann@redhat.com <mailto:eric.wittmann@redhat.com>
           <mailto:eric.wittmann@redhat.com
           <mailto:eric.wittmann@redhat.com>>> wrote:

           That's a bit hacky, but also sort of a genius approach as
           well.  I'm
           actually a little bummed I didn't think of it.  :)

           As for extending SOAP support - I was thinking that I could
           make the
           relevant changes to apiman if you would be willing to provide
           feedback/guidance/testing.  My SOAP expertise is quite stale
           at this
           point, so having some eyeballs on these changes would be
           very useful.

           To start off with, what pieces of the SOAP envelope should
           be extracted
           prior to calling the policy chain?  Some candidates are:

           * The encoding style
           * All SOAP headers
           * SOAPAction (already available as an HTTP header)
           * ???

           For the soap headers, all of the examples I've seen take the
           following
           form:

           <HeaderName xmlns="elementNS">Header-Value</HeaderName>

           It can also have the optional "actor" or "mustUnderstand"
           attributes.
           The SOAP envelope schema is pretty lax though, so I'm not
           sure if the
           above is a convention or a rule.  Can headers be more
           complex than the
           above?

           -Eric

           On 3/26/2016 7:06 AM, Benjamin Kastelic wrote:

               Hi,

               I temporarily solved the problem by storing the request
               body, which is
               contained in ApiRequest.rawRequest object, in a
               temporary buffer. I then
               process the data (authentication) and based on the
               results proceed with
               the policy chain or report a failure. Then in the end()
               method of the
               requestDataHandler method I write the contents of my
               temporary buffer
               using super.write(IApimanBuffer). That way I can forward
               the request to
               then ext policy in the chain. But this is still a hacky
               way of doing
               this.

               I would be glad to help with extending SOAP support. But
               I would need a
               few pointers where to start. The way of storing SOAP
               headers in the
               ApiRequest object seems like a good idea.

               2016-03-24 18:40 GMT+01:00 Eric Wittmann
               <eric.wittmann@redhat.com <mailto:eric.wittmann@redhat.com>
               <mailto:eric.wittmann@redhat.com
               <mailto:eric.wittmann@redhat.com>>
               <mailto:eric.wittmann@redhat.com
               <mailto:eric.wittmann@redhat.com>>>:

                   Hi Benjamin - thanks for the excellent question.  I
               will do my best
                   to answer and note that I am CC'ing the apiman-dev
               mailing list so
                   others can chime in.

                   First let me say that a WS-Security policy sounds
               great - we haven't
                   focused much on the WS-* protocols because we get
               much more demand
                   for managing REST APIs than SOAP APIs.  That said,
               better SOAP
                   support is certainly on the radar.  When that
               happens, my hope is
                   that processing the envelope might be a core part of
               the gateway and
                   so implementing policies that use information in
               there will be
                   easier.  Perhaps your implementation can be the
               genesis of some of
                   that work!

                   To your question - without core changes to apiman,
               the approach you
                   *need* to take is to have your policy implement
               IDataPolicy.  I
                   believe you may have already tried that, and
               observed that you
                   cannot send proper policy failures from that
               method.  You are right
                   - that's something we will need to fix!  I think you
               should be able
                   to throw a runtime exception from the
               write(IApimanBuffer chunk)
                   method if you detect an error.  However, this is a
               little bit hacky!

                   Instead, I suggest (if you're up for it) that we
               perhaps work
                   together to bake SOAP support directly into the core
               of apiman, such
                   that the SOAP envelope is read/parsed *before* the
               policy chain is
                   executed.  We could expose, for example, the SOAP
               headers as a
                   proper Map<> stored either in the context or on the
               ApiRequest.
                   This would allow you to properly implement most
               (all?) WS-*
                   protocols as proper apiman policies in the
               apply(ApiRequest request)
                   method.

                   Thoughts?

                   -Eric


                   On 3/24/2016 7:58 AM, Benjamin Kastelic wrote:

                       Greetings,

                       I first thought to write this question as an
               issue on Github,
               but it
                       seemed better to write you a direct email.

                       I am making a custom WS Security policy, that
               reads the body and
                       check
                       the UsernameToken security header. This works
               OK, but now I've
                       hit a wall.

                       In the doApply method I get the rawRequest
               object and read the
                       body from
                       the ServletInputStream of the request. The
               problem I'm facing
               now is
                       that the input stream was read and it can't be
               reset back to it's
                       initial state.

                       I was also trying to implement the same logic in the
                       requestDataHandler
                       method, but I don't know if it is even possible
               to send a failure
                       message to the request chain from there.

                       Any suggesstions ?

                       Best regards,
                       Benjamin




               --
               Lp, Benjamin

           _______________________________________________
           Apiman-dev mailing list
           Apiman-dev@lists.jboss.org
           <mailto:Apiman-dev@lists.jboss.org>
           <mailto:Apiman-dev@lists.jboss.org
           <mailto:Apiman-dev@lists.jboss.org>>
           https://lists.jboss.org/mailman/listinfo/apiman-dev





--
Lp, Benjamin