[Apiman-dev] Apiman - WS Security policy
Benjamin Kastelic
kastelic.benjamin at gmail.com
Wed Mar 30 13:25:53 EDT 2016
Thanks, I will definitely keep tabs on your progress :)
2016-03-30 16:02 GMT+02:00 Eric Wittmann <eric.wittmann at 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 at gmail.com <mailto:kastelic.benjamin at 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 at redhat.com
>> <mailto:eric.wittmann at 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 at redhat.com
>> <mailto:kbabo at redhat.com>
>> <mailto:kbabo at redhat.com <mailto: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
>> <mailto:eric.wittmann at redhat.com>
>> <mailto:eric.wittmann at redhat.com
>> <mailto: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>
>> <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>>>> 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
>> <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
>> <mailto: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
>> <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
>> <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
>> <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
>> <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
>> <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
>> <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
>> <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
>> <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
>> <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
>> <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
>> <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
>>
>>
>>
>>
>> --
>> Lp, Benjamin
>>
>>
>>
>>
>> --
>> Lp, Benjamin
>>
>
--
Lp, Benjamin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/apiman-dev/attachments/20160330/8b614c15/attachment-0001.html
More information about the Apiman-dev
mailing list