[Apiman-dev] Apiman - WS Security policy

Benjamin Kastelic kastelic.benjamin at gmail.com
Tue Mar 29 13:42:28 EDT 2016


If I understand you correctly Eric, only the soap:Body part will be
forwarded to the registered API?
What if the API still needs to receive the soap:Header part?

2016-03-29 15:34 GMT+02:00 Keith Babo <kbabo at redhat.com>:

> Sounds cool to me.  Header policy will need to be QName and DOM-aware, so
> that namespace-qualified headers can be added and appropriate namespace
> definitions can be added to the DOM if required.  Of course you already
> know all this, but pointing it out makes me feel useful.
>
> > On Mar 29, 2016, at 8:38 AM, Eric Wittmann <eric.wittmann at redhat.com>
> wrote:
> >
> > That's an interesting idea.  It'd be harder to inject the headers into
> the request than it is to inject HTTP request headers, obviously.  But not
> impossible.  We'd need to be aware of the change to any Content-Length that
> may be set.
> >
> > This makes the implementation slightly more complicated, because I think
> the HTTP connector will need to be made smarter (it will need to send the
> <soap:Envelope> and <soap:Header> sections first, then just stream the
> remaining request body as-is.
> >
> > So perhaps what we have is this:
> >
> > 1.  <?xml version="1.0"?>
> > 2.  <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
> > 3.    <soap:Header>
> > 4.      <ns1:Foo actor="..." xmlns:ns1="uri:ns1">BAR</ns1:Foo>
> > 5.    </soap:Header>
> > 6.    <soap:Body>
> > 7.      <m:GetStockPrice xmlns:m="http://www.example.org/stock/Surya">
> > 8.        <m:StockName>IBM</m:StockName>
> > 9.      </m:GetStockPrice>
> > 10.   </soap:Body>
> > 11. </soap:Envelope>
> >
> > Lines 1-5 will be read and consumed by apiman *before* any policies are
> executed.  We'll actually keep reading until we find <soap:Body> in the
> request body.  We'll throw out everything before line #6 from our in-memory
> buffer, resulting in a buffer with just line #6 (and any extra bytes after
> that based on our I/O chunk size).
> >
> > The policies will be executed, which may result in soap headers being
> added, modified, or removed.  If all policies pass, then we proxy the
> request to the back-end.  Normally the HTTP connection would simply send
> all bytes from the HTTP request as-is.  Instead, we'll need to *generate*
> new content for lines 1-5, with the newly modified soap headers.  Once the
> generated content is sent, then we send the contents of the in-memory
> buffer (which contains line #6+ any additional bytes).  After that, we
> proxy the remaining bytes from the HTTP request as-is.
> >
> > This may be starting to take shape.  :)
> >
> > Additional thoughts?
> >
> > -Eric
> >
> > PS:  @Keith - we'll likely have a separate Policy for manipulating SOAP
> headers, rather than re-use the existing HTTP headers policy.
> >
> > On 3/29/2016 8:13 AM, Keith Babo wrote:
> >> 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 at redhat.com
> >>> <mailto:eric.wittmann at 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 at redhat.com
> >>>> <mailto:eric.wittmann at redhat.com>
> >>>> <mailto:eric.wittmann at 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 at redhat.com
> >>>> <mailto:eric.wittmann at redhat.com><mailto:eric.wittmann at redhat.com>
> >>>>           <mailto:eric.wittmann at redhat.com
> >>>>           <mailto:eric.wittmann at 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 at redhat.com
> >>>> <mailto:eric.wittmann at redhat.com><mailto:eric.wittmann at redhat.com>
> >>>>               <mailto:eric.wittmann at redhat.com
> >>>>               <mailto:eric.wittmann at redhat.com>>
> >>>>               <mailto:eric.wittmann at redhat.com
> >>>>               <mailto:eric.wittmann at 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 at lists.jboss.org <mailto:Apiman-dev at lists.jboss.org>
> >>>>           <mailto:Apiman-dev at lists.jboss.org>
> >>>>           <mailto:Apiman-dev at lists.jboss.org
> >>>>           <mailto:Apiman-dev at lists.jboss.org>>
> >>>> https://lists.jboss.org/mailman/listinfo/apiman-dev
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>> --
> >>>> Lp, Benjamin
> >>
>
>


-- 
Lp, Benjamin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/apiman-dev/attachments/20160329/665e221c/attachment-0001.html 


More information about the Apiman-dev mailing list