You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Gareth Hughes <gv...@googlemail.com> on 2012/11/26 15:12:54 UTC

Help needed with namespace manipulation and DOM level XML hacking (post Jaxb) for WebClient

I am using WebClient to Post and Receive XML from a UK government service,
the Government Gateway. They provide the schemas. In java terms I send and
receive a GovTalkMessage which has a standard envelope and then it's Body
contains one of many possible classes depending on which service you use on
the Gateway. So I've set up a simple client in Spring 3 and it simply comes
down to

public GovTalkMessage liveClient(GovTalkMessage body) {
        return webClient.post(body, GovTalkMessage.class);
}

But here comes the nasty problem. The protocol requires you to take the
Body XML, format it in a certain way with a very specific set of namespace
definitions and create a type of Hash of the actual text. This hash is
embedded into the Body and used to prove that the message has not been
tampered with. We already have this code from our legacy implementation
that was built on raw DOM and URLConnection. The XML that the WebClient
sends has to look exactly the same so the hash can be compared at the other
end.
Of course the default XML generated by Jaxb does not look like this XML.

*What I need*
<GovTalkMessage xmlns:ps1="http://www.w3.org/2000/09/xmldsig#">
  <EnvelopeVersion>2.0</EnvelopeVersion>
  <Header>
    <MessageDetails>
..........
  </GovTalkDetails>
  <Body>
    <IRenvelope:IRenvelope xmlns:IRenvelope="
http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1">
      <IRheader>


*Default output*
<ns2:GovTalkMessage xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:ns2="
http://www.govtalk.gov.uk/CM/envelope">
  <ns2:EnvelopeVersion>2.0</ns2:EnvelopeVersion>
  <ns2:Header>
...
  <ns2:Body>
    <IRenvelope:IRenvelope xmlns:IRenvelope="
http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1" xmlns="
http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1">
      <IRheader>
        <Keys>

after a week of experiments and reading I have the following Spring for the
client:

    @Bean
    public WebClient testClient() {
        WebClient client = WebClient.create(TEST_URL);

        //Logging code hidden

        //Code to eat all the namespaces
        Map<String, String> outTransformMap = new HashMap<String, String>();
        outTransformMap.put("{http://www.w3.org/2000/09/xmldsig#}*", "*");
        outTransformMap.put("{
http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1}*", "*");
        outTransformMap.put("{http://www.govtalk.gov.uk/CM/envelope}*",
"*");
        org.apache.cxf.interceptor.transform.TransformOutInterceptor
transformOutInterceptor =
            new
org.apache.cxf.interceptor.transform.TransformOutInterceptor();
        transformOutInterceptor.setOutTransformElements(outTransformMap);
        config.getOutInterceptors().add(transformOutInterceptor);

        return client;
}

When run this will produce xml with all namespaces stripped out which is
good start.

<GovTalkMessage>
  <EnvelopeVersion>2.0</EnvelopeVersion>
  <Header>
......
  <Body>
    <IRenvelope/>


I have two requirements
*1 I need to add the namespace declations back with a very specific look as
shown by my sample.*
My XSL knowledge is very limited and I have tried a few things using
XSLTJaxbProvider with no success.

I have tried using JAXBElementProvider and it's namespacePrefixes methods
with no useful result.
There are also 7 types of data to put into the Body depending on what we
send to the Gateway. All of them have a top level class called IRenvelope
but obviously have different namespaces.


*2 Write Dom code to extract the Body section to send off to the hashing
algorithm and then use Dom methods to insert the generated hash into the
right place.*
I've written a skeleton Interceptor but am finding it very hard to know
where to go with this as the code is so vast and there are so many options.

In summary I'm just not sure how to do these things. There are so many
options but none of them quite does what I want and I find the code pretty
hard to get into. In some ways I'm a victim of the power of CXF (that's a
complement). Please can you help me with getting started on these nasty
tasks.


For reference this code is for a payroll company submitting data for
the RTI<http://www.hmrc.gov.uk/softwaredevelopers/rti/index.htm>project
to the UK HMRC on the Government
Gateway <http://www.hmrc.gov.uk/softwaredevelopers/govgateway/index.htm>.
The hashing code is called
IRmark<http://www.hmrc.gov.uk/softwaredevelopers/hmrcmark/index.htm>
.

Many thanks in advance

Gareth Hughes

Re: Help needed with namespace manipulation and DOM level XML hacking (post Jaxb) for WebClient

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi
On 27/11/12 13:08, Gareth Hughes wrote:
> Many thanks for the reply.
>
> I now have access to the Document.
> My next question is about which Phase to set and does my Interceptor
> have to be after any other. I have to dump the Document to a string to
> do what I need to do and when I do, my string looks like
>
> <ns2:GovTalkMessage xmlns:ns2="http://www.govtalk.gov.uk/CM/envelope"
> xmlns="http://www.w3.org/2000/09/xmldsig#"
> xmlns:ns3="http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1">
>
> So it looks like I'm too early in the chain as none of the
> TransformOutInterceptor rules have been applied.
>
> I've tried a number of Phases but with no changes so far.
>

TransformOutInterceptor interceptor can be configured to run at the 
specific phase, but in this particular case it is probably simpler to 
explicitly register JAXBElementProvider instead and set the transform 
properties directly on JAXBElementProvider, instead of using 
TransformOutInterceptor:

http://cxf.apache.org/docs/jax-rs-data-bindings.html#JAX-RSDataBindings-CustomizingJAXBXMLandJSONinputandoutput

HTH, Sergey

>
> On 26 November 2012 16:40, Sergey Beryozkin <sberyozkin@gmail.com
> <ma...@gmail.com>> wrote:
>
>     Hi
>
>
>     On 26/11/12 14:12, Gareth Hughes wrote:
>
>         I am using WebClient to Post and Receive XML from a UK
>         government service,
>         the Government Gateway. They provide the schemas. In java terms
>         I send and
>         receive a GovTalkMessage which has a standard envelope and then
>         it's Body
>         contains one of many possible classes depending on which service
>         you use on
>         the Gateway. So I've set up a simple client in Spring 3 and it
>         simply comes
>         down to
>
>         public GovTalkMessage liveClient(GovTalkMessage body) {
>                   return webClient.post(body, GovTalkMessage.class);
>         }
>
>         But here comes the nasty problem. The protocol requires you to
>         take the
>         Body XML, format it in a certain way with a very specific set of
>         namespace
>         definitions and create a type of Hash of the actual text. This
>         hash is
>         embedded into the Body and used to prove that the message has
>         not been
>         tampered with. We already have this code from our legacy
>         implementation
>         that was built on raw DOM and URLConnection. The XML that the
>         WebClient
>         sends has to look exactly the same so the hash can be compared
>         at the other
>         end.
>         Of course the default XML generated by Jaxb does not look like
>         this XML.
>
>         *What I need*
>
>         <GovTalkMessage xmlns:ps1="http://www.w3.org/__2000/09/xmldsig#
>         <http://www.w3.org/2000/09/xmldsig#>">
>         <EnvelopeVersion>2.0</__EnvelopeVersion>
>         <Header>
>         <MessageDetails>
>         ..........
>         </GovTalkDetails>
>         <Body>
>         <IRenvelope:IRenvelope xmlns:IRenvelope="
>         http://www.govtalk.gov.uk/__taxation/PAYE/MOV/09-10/1
>         <http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1>">
>         <IRheader>
>
>
>         *Default output*
>
>         <ns2:GovTalkMessage xmlns="http://www.w3.org/2000/__09/xmldsig#
>         <http://www.w3.org/2000/09/xmldsig#>" xmlns:ns2="
>         http://www.govtalk.gov.uk/CM/__envelope
>         <http://www.govtalk.gov.uk/CM/envelope>">
>         <ns2:EnvelopeVersion>2.0</ns2:__EnvelopeVersion>
>         <ns2:Header>
>         ...
>         <ns2:Body>
>         <IRenvelope:IRenvelope xmlns:IRenvelope="
>         http://www.govtalk.gov.uk/__taxation/PAYE/MOV/09-10/1
>         <http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1>" xmlns="
>         http://www.govtalk.gov.uk/__taxation/PAYE/MOV/09-10/1
>         <http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1>">
>         <IRheader>
>         <Keys>
>
>         after a week of experiments and reading I have the following
>         Spring for the
>         client:
>
>               @Bean
>               public WebClient testClient() {
>                   WebClient client = WebClient.create(TEST_URL);
>
>                   //Logging code hidden
>
>                   //Code to eat all the namespaces
>                   Map<String, String>  outTransformMap = new
>         HashMap<String, String>();
>
>           outTransformMap.put("{http://__www.w3.org/2000/09/xmldsig#}*
>         <http://www.w3.org/2000/09/xmldsig#%7D*>"__, "*");
>                   outTransformMap.put("{
>         http://www.govtalk.gov.uk/__taxation/PAYE/MOV/09-10/1}*
>         <http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1%7D*>", "*");
>
>           outTransformMap.put("{http://__www.govtalk.gov.uk/CM/__envelope}* <http://www.govtalk.gov.uk/CM/envelope%7D*>",
>         "*");
>
>           org.apache.cxf.interceptor.__transform.__TransformOutInterceptor
>         transformOutInterceptor =
>                       new
>         org.apache.cxf.interceptor.__transform.__TransformOutInterceptor();
>
>           transformOutInterceptor.__setOutTransformElements(__outTransformMap);
>
>           config.getOutInterceptors().__add(transformOutInterceptor);
>
>                   return client;
>         }
>
>         When run this will produce xml with all namespaces stripped out
>         which is
>         good start.
>
>         <GovTalkMessage>
>         <EnvelopeVersion>2.0</__EnvelopeVersion>
>         <Header>
>         ......
>         <Body>
>         <IRenvelope/>
>
>
>         I have two requirements
>         *1 I need to add the namespace declations back with a very
>         specific look as
>         shown by my sample.*
>
>         My XSL knowledge is very limited and I have tried a few things using
>         XSLTJaxbProvider with no success.
>
>         I have tried using JAXBElementProvider and it's
>         namespacePrefixes methods
>         with no useful result.
>         There are also 7 types of data to put into the Body depending on
>         what we
>         send to the Gateway. All of them have a top level class called
>         IRenvelope
>         but obviously have different namespaces.
>
>
>         *2 Write Dom code to extract the Body section to send off to the
>         hashing
>
>         algorithm and then use Dom methods to insert the generated hash
>         into the
>         right place.*
>
>         I've written a skeleton Interceptor but am finding it very hard
>         to know
>         where to go with this as the code is so vast and there are so
>         many options.
>
>         In summary I'm just not sure how to do these things. There are
>         so many
>         options but none of them quite does what I want and I find the
>         code pretty
>         hard to get into. In some ways I'm a victim of the power of CXF
>         (that's a
>         complement). Please can you help me with getting started on
>         these nasty
>         tasks.
>
>
>         For reference this code is for a payroll company submitting data for
>         the
>         RTI<http://www.hmrc.gov.uk/__softwaredevelopers/rti/index.__htm
>         <http://www.hmrc.gov.uk/softwaredevelopers/rti/index.htm>>project
>
>         to the UK HMRC on the Government
>         Gateway<http://www.hmrc.gov.__uk/softwaredevelopers/__govgateway/index.htm
>         <http://www.hmrc.gov.uk/softwaredevelopers/govgateway/index.htm>>.
>
>         The hashing code is called
>         IRmark<http://www.hmrc.gov.uk/__softwaredevelopers/hmrcmark/__index.htm
>         <http://www.hmrc.gov.uk/softwaredevelopers/hmrcmark/index.htm>>
>         .
>
>
>     I wonder if the code at [1] can help somehow, see getDomDocument(),
>     you can copy it in your own interceptor, extract it into DOM with
>     the help of JAXBElementProvider, then add few more elements as
>     needed and finally do:
>
>     message.setContent(List.class,
>     new MessageContentsList(new DOMSource(finalDoc)));
>
>     I wonder if the same if possible with JAX-RS 2.0 client out
>     interceptors/filters, haven't thought about it yet, but give it a
>     try with the CXF specific approach first and then we can think of
>     making it more portable
>
>     Cheers, Sergey
>
>
>     [1]
>     http://svn.apache.org/repos/__asf/cxf/trunk/rt/rs/security/__xml/src/main/java/org/apache/__cxf/rs/security/xml/__AbstractXmlSecOutInterceptor.__java
>     <http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/AbstractXmlSecOutInterceptor.java>
>
>
>         Many thanks in advance
>
>         Gareth Hughes
>
>
>



Re: Help needed with namespace manipulation and DOM level XML hacking (post Jaxb) for WebClient

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi

On 26/11/12 14:12, Gareth Hughes wrote:
> I am using WebClient to Post and Receive XML from a UK government service,
> the Government Gateway. They provide the schemas. In java terms I send and
> receive a GovTalkMessage which has a standard envelope and then it's Body
> contains one of many possible classes depending on which service you use on
> the Gateway. So I've set up a simple client in Spring 3 and it simply comes
> down to
>
> public GovTalkMessage liveClient(GovTalkMessage body) {
>          return webClient.post(body, GovTalkMessage.class);
> }
>
> But here comes the nasty problem. The protocol requires you to take the
> Body XML, format it in a certain way with a very specific set of namespace
> definitions and create a type of Hash of the actual text. This hash is
> embedded into the Body and used to prove that the message has not been
> tampered with. We already have this code from our legacy implementation
> that was built on raw DOM and URLConnection. The XML that the WebClient
> sends has to look exactly the same so the hash can be compared at the other
> end.
> Of course the default XML generated by Jaxb does not look like this XML.
>
> *What I need*
> <GovTalkMessage xmlns:ps1="http://www.w3.org/2000/09/xmldsig#">
>    <EnvelopeVersion>2.0</EnvelopeVersion>
>    <Header>
>      <MessageDetails>
> ..........
>    </GovTalkDetails>
>    <Body>
>      <IRenvelope:IRenvelope xmlns:IRenvelope="
> http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1">
>        <IRheader>
>
>
> *Default output*
> <ns2:GovTalkMessage xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:ns2="
> http://www.govtalk.gov.uk/CM/envelope">
>    <ns2:EnvelopeVersion>2.0</ns2:EnvelopeVersion>
>    <ns2:Header>
> ...
>    <ns2:Body>
>      <IRenvelope:IRenvelope xmlns:IRenvelope="
> http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1" xmlns="
> http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1">
>        <IRheader>
>          <Keys>
>
> after a week of experiments and reading I have the following Spring for the
> client:
>
>      @Bean
>      public WebClient testClient() {
>          WebClient client = WebClient.create(TEST_URL);
>
>          //Logging code hidden
>
>          //Code to eat all the namespaces
>          Map<String, String>  outTransformMap = new HashMap<String, String>();
>          outTransformMap.put("{http://www.w3.org/2000/09/xmldsig#}*", "*");
>          outTransformMap.put("{
> http://www.govtalk.gov.uk/taxation/PAYE/MOV/09-10/1}*", "*");
>          outTransformMap.put("{http://www.govtalk.gov.uk/CM/envelope}*",
> "*");
>          org.apache.cxf.interceptor.transform.TransformOutInterceptor
> transformOutInterceptor =
>              new
> org.apache.cxf.interceptor.transform.TransformOutInterceptor();
>          transformOutInterceptor.setOutTransformElements(outTransformMap);
>          config.getOutInterceptors().add(transformOutInterceptor);
>
>          return client;
> }
>
> When run this will produce xml with all namespaces stripped out which is
> good start.
>
> <GovTalkMessage>
>    <EnvelopeVersion>2.0</EnvelopeVersion>
>    <Header>
> ......
>    <Body>
>      <IRenvelope/>
>
>
> I have two requirements
> *1 I need to add the namespace declations back with a very specific look as
> shown by my sample.*
> My XSL knowledge is very limited and I have tried a few things using
> XSLTJaxbProvider with no success.
>
> I have tried using JAXBElementProvider and it's namespacePrefixes methods
> with no useful result.
> There are also 7 types of data to put into the Body depending on what we
> send to the Gateway. All of them have a top level class called IRenvelope
> but obviously have different namespaces.
>
>
> *2 Write Dom code to extract the Body section to send off to the hashing
> algorithm and then use Dom methods to insert the generated hash into the
> right place.*
> I've written a skeleton Interceptor but am finding it very hard to know
> where to go with this as the code is so vast and there are so many options.
>
> In summary I'm just not sure how to do these things. There are so many
> options but none of them quite does what I want and I find the code pretty
> hard to get into. In some ways I'm a victim of the power of CXF (that's a
> complement). Please can you help me with getting started on these nasty
> tasks.
>
>
> For reference this code is for a payroll company submitting data for
> the RTI<http://www.hmrc.gov.uk/softwaredevelopers/rti/index.htm>project
> to the UK HMRC on the Government
> Gateway<http://www.hmrc.gov.uk/softwaredevelopers/govgateway/index.htm>.
> The hashing code is called
> IRmark<http://www.hmrc.gov.uk/softwaredevelopers/hmrcmark/index.htm>
> .

I wonder if the code at [1] can help somehow, see getDomDocument(), you 
can copy it in your own interceptor, extract it into DOM with the help 
of JAXBElementProvider, then add few more elements as needed and finally do:

message.setContent(List.class,
new MessageContentsList(new DOMSource(finalDoc)));

I wonder if the same if possible with JAX-RS 2.0 client out 
interceptors/filters, haven't thought about it yet, but give it a try 
with the CXF specific approach first and then we can think of making it 
more portable

Cheers, Sergey


[1] 
http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/AbstractXmlSecOutInterceptor.java
>
> Many thanks in advance
>
> Gareth Hughes
>