Thanks, I will definitely keep tabs on your progress :)
2016-03-30 16:02 GMT+02:00 Eric Wittmann <eric.wittmann(a)redhat.com>:
Note, here are a couple of JIRA issues created for these features in
case
you're interested in tracking our progress on them:
https://issues.jboss.org/browse/APIMAN-1072
https://issues.jboss.org/browse/APIMAN-1077
-Eric
On 3/30/2016 4:26 AM, Benjamin Kastelic wrote:
> Just one more thing ...
> If a SOAP API is published on Apiman and you request the WSDL by using
> the gateway endpoint URL, you get the original WSDL - address is
> pointing to the real endpoint URL and not the gateway endpoint URL.
> I have solved this temporarily by adding URL rewrite policies to all
> SOAP APIs, which replace the real endpoint URL with the gateway endpoint
> URL.
> I guess it would be best if this policy was handled by the gateway
> internally so that you wouldn't have to worry by adding a correct policy
> to the API configuration.
>
> 2016-03-29 20:29 GMT+02:00 Benjamin Kastelic
> <kastelic.benjamin(a)gmail.com <mailto:kastelic.benjamin@gmail.com>>:
>
> OK, now I understand what you meant.
> I believe this would be a reasonable solution :)
>
> 2016-03-29 20:18 GMT+02:00 Eric Wittmann <eric.wittmann(a)redhat.com
> <mailto:eric.wittmann@redhat.com>>:
>
> My plan was unclear! Let's go with another example:
>
> Step 1 - the Gateway receives the following HTTP request:
>
> ----
> POST /apiman-gateway/MyOrg/soap-api/2.7 HTTP/1.1
> Host:
www.example.org <
http://www.example.org>
>
> Content-Type: application/soap+xml; charset=utf-8
> X-API-Key: API-KEY-FOR-ACTIVE-CLIENT
> SOAPAction: ExampleAction
>
> <?xml version="1.0"?>
> <soap:Envelope xmlns:soap="
>
http://www.w3.org/2003/05/soap-envelope">
> <soap:Header>
> <ns1:Header1
xmlns:ns1="uri:ns1">foo</ns1:Header1>
> <ns2:Header2
xmlns:ns2="uri:ns2">bar</ns2:Header2>
> </soap:Header>
> <soap:Body>
> <m:GetStockPrice
xmlns:m="http://www.example.org/stock/RHT">
> <m:StockName>Red Hat</m:StockName>
> </m:GetStockPrice>
> </soap:Body>
> </soap:Envelope>
> ----
>
> We'll parse the first part of the envelope so that we can read
> the headers and make them available to any policies. After
> that's done, we'll invoke the policy chain as per normal.
> However, because it's a SOAP api, there will exist a
> SOAPRequestInfo object in the policy context. So policies can
> read and/or modify the soap information. This class might look
> something like this:
>
> public class SOAPRequestInfo {
> private String action;
> private String encoding;
> private Map<QName, SOAPHeader> headers;
> }
>
> This allows interested policies (like your ws-security) policy
> to have easy access to all the soap related stuff. It also
> allows you to alter these things. Including
> adding/removing/modifying the SOAP headers.
>
> So let's assume that we have a policy which *adds* a SOAP header
> (ns3:AddedHeader) and another policy which *removes* one
> (ns2:Header2). The policy code might look like this:
>
> SOAPRequestInfo soapInfo = context.getAttribute(
> Constants.SOAP_INFO, (SOAPRequestInfo) null);
> soapInfo.getHeaders().remove(new QName("uri:ns2",
"Header2"));
> soapInfo.getHeaders().put(
> new QName("uri:ns3", "AddedHeader"),
> createSoapHeader()
> );
>
>
> In that case, this is the HTTP request that will be sent/proxied
> to the back-end API:
>
> ----
> POST / HTTP/1.1
> Host:
www.example.org <
http://www.example.org>
> Content-Type: application/soap+xml; charset=utf-8
> SOAPAction: ExampleAction
>
> <?xml version="1.0"?>
> <soap:Envelope xmlns:soap="
>
http://www.w3.org/2003/05/soap-envelope">
> <soap:Header>
> <ns1:Header1
xmlns:ns1="uri:ns1">foo</ns1:Header1>
> <ns3:AddedHeader
xmlns:ns3="uri:ns3">bar</ns3:AddedHeader>
> </soap:Header>
> <soap:Body>
> <m:GetStockPrice
xmlns:m="http://www.example.org/stock/RHT">
> <m:StockName>Red Hat</m:StockName>
> </m:GetStockPrice>
> </soap:Body>
> </soap:Envelope>
> ----
>
> Sound reasonable?
>
> -Eric
>
>
> On 3/29/2016 1:42 PM, Benjamin Kastelic wrote:
>
> 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(a)redhat.com
> <mailto:kbabo@redhat.com>
> <mailto:kbabo@redhat.com <mailto:kbabo@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(a)redhat.com
> <mailto:eric.wittmann@redhat.com>
> <mailto:eric.wittmann@redhat.com
> <mailto:eric.wittmann@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(a)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>
> <mailto:eric.wittmann@redhat.com
> <mailto: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(a)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>
> <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
> <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(a)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>
> <mailto:eric.wittmann@redhat.com
> <mailto:eric.wittmann@redhat.com>>><mailto:
> eric.wittmann(a)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>
> <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
> <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(a)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>
> <mailto:eric.wittmann@redhat.com
> <mailto:eric.wittmann@redhat.com>>><mailto:
> eric.wittmann(a)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>
> <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
> <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>>
> >>>> <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(a)lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>
> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>>
> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>
> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>>>
> >>>> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>
> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>>>
> >>>> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>
> <mailto:Apiman-dev@lists.jboss.org
> <mailto:Apiman-dev@lists.jboss.org>>
> >>>> <mailto: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
> >>
>
>
>
>
> --
> Lp, Benjamin
>
>
>
>
> --
> Lp, Benjamin
>
>
>
>
> --
> Lp, Benjamin
>