XML in HTTP request body
Monday, 3 June 2019 · 3 messages
JC
Jerome Chauveau3 Jun 2019 12:17 #
Hi,
I am trying to check XML content (HTTP posted) with an hmac function in a RESTXQ webapp.
My Java client sends an HTTP post request where XML data looks like :
<data><user>doe</user><content><TEI
xsi:schemaLocation="http://www.tei-c.org/ns/1.0"
xml:id="idtest"Quoted text · 6 lines
><teiHeader ><fileDesc ><titleStmt ><title >Test</title ><author
xml:id="authortest"
Quoted text · 7 lines
>XXX</author ></titleStmt ></teiHeader ><text ><front ></front ><body
xml:space="preserve"
Quoted text · 2 lines
><listPlace ><place
type="lieu"
Quoted text · 1 line
><placeName
xml:lang="la"
Quoted text · 7 lines
>Burgunvilla</placeName ></place ></listPlace ></body ></text ></TEI ></content></data>
This content is HMAC encrypted and the signature is added to the HTTP header :
[...]
String secret = "1234";
StringEntity entity = new StringEntity(xml, ContentType.create("text/xml", Consts.UTF_8));
String signature = HTTPUtils.hmacSHA1(xml, secret);
httppost.setHeader("Authorization", signature);
httppost.setEntity(entity);
[...]Here is my RESTXQ function :
declare
%rest:POST("{$body}")
%rest:consumes("application/xml", "text/xml")
%rest:header-param("Authorization", "{$signature}", "none")
%rest:path("/sf/testpost")
function sf.test:testPost($signature,$body){
let $secret := 1234
crypto:hmac($body,$secret,'sha1','base64') = $signature
}Equality check always fails with such an XML sequence but works fine when XML does not contain any carriage return : <data><user>doe</user><content><TEI><front></front><text><body>This is a test</body></text></TEI>
It seems to come when "The body of a POST or PUT request is converted to an XQuery item".
I tried to set serializer's options without any success !
How could I retrieve xml (in $body) exactly serialized as sent by the client ?
Tests are running on BaseX922.
Thank you for your time.
Jérôme
MS
Michael Seiferle3 Jun 2019 16:39 #
Hi Jerome,
If I understand correctly, you want to create a hash value for the string serialization of the document you sent to restxq right?
Currently inside RESTXQ your document is treated as an XML Document, hence:
$body will be of type document-node():Quoted text · Jerome Chauveau · 6 lines
> > <data> > <foo>Hello</foo> > <bar>World</bar> > </data> >
where as
crypto:hmac requires a string-type $message:Quoted text · Jerome Chauveau · 1 line
> crypto:hmac($message as xs:string,
Hence your $body will be converted like so:
Quoted text · Jerome Chauveau · 6 lines
> string( > <data> > <foo>Hello</foo> > <bar>World</bar> > </data> > )
Turning it into:
Quoted text · Jerome Chauveau · 1 line
> „HelloWorld“
In order to actually compute a hash on the bytes your document contains, do as follows:
Working example here: https://git.basex.io/snippets/63
Treat your document as binary:
Quoted text · Jerome Chauveau · 1 line
> %rest:consumes("application/octet-stream“)
And then decode that binary to a string and then compute the hash for the string, using:
bin:decode-string#2:Quoted text · Jerome Chauveau · 2 lines
> let $str-doc := bin:decode-string($body,'utf-8') (: xs:string :) > let $sig-cand := crypto:hmac($str-doc,$secret,'sha1','base64')
Hope this helps :-)
Michael
Quoted text · Jerome Chauveau · 75 lines
> Am 03.06.2019 um 12:17 schrieb Jerome Chauveau <jerome.chauveau at unicaen.fr>: > > Hi, > > I am trying to check XML content (HTTP posted) with an hmac function in a RESTXQ webapp. > > My Java client sends an HTTP post request where XML data looks like : > > <data><user>doe</user><content><TEI > xsi:schemaLocation="http://www.tei-c.org/ns/1.0" > xml:id="idtest" > ><teiHeader > ><fileDesc > ><titleStmt > ><title > >Test</title > ><author > xml:id="authortest" > >XXX</author > ></titleStmt > ></teiHeader > ><text > ><front > ></front > ><body > xml:space="preserve" > ><listPlace > ><place > type="lieu" > ><placeName > xml:lang="la" > >Burgunvilla</placeName > ></place > ></listPlace > ></body > ></text > ></TEI > ></content></data> > > This content is HMAC encrypted and the signature is added to the HTTP header : > > [...] > String secret = "1234"; > StringEntity entity = new StringEntity(xml, ContentType.create("text/xml", Consts.UTF_8)); > String signature = HTTPUtils.hmacSHA1(xml, secret); > httppost.setHeader("Authorization", signature); > httppost.setEntity(entity); > [...] > > > Here is my RESTXQ function : > > declare > %rest:POST("{$body}") > %rest:consumes("application/xml", "text/xml") > %rest:header-param("Authorization", "{$signature}", "none") > %rest:path("/sf/testpost") > function sf.test:testPost($signature,$body){ > let $secret := 1234 > crypto:hmac($body,$secret,'sha1','base64') = $signature > } > > Equality check always fails with such an XML sequence but works fine when XML does not contain any carriage return : > <data><user>doe</user><content><TEI><front></front><text><body>This is a test</body></text></TEI> > > It seems to come when "The body of a POST or PUT request is converted to an XQuery item". > > I tried to set serializer's options without any success ! > > How could I retrieve xml (in $body) exactly serialized as sent by the client ? > > Tests are running on BaseX922. > Thank you for your time. > > Jérôme
JC
Jerome Chauveau3 Jun 2019 18:02 #
Hi Michael,
It seems to work ... perfectly !
Thank you so much for that clear and quick answer :-)
Jérôme
Quoted text · Michael Seiferle · 105 lines
De: "Michael Seiferle" <ms at basex.org> À: "jerome chauveau" <jerome.chauveau at unicaen.fr> Cc: "basex-talk" <basex-talk at mailman.uni-konstanz.de> Envoyé: Lundi 3 Juin 2019 16:39:07 Objet: Re: [basex-talk] XML in HTTP request body Hi Jerome, If I understand correctly, you want to create a hash value for the string serialization of the document you sent to restxq right? Currently inside RESTXQ your document is treated as an XML Document, hence: $body will be of type document-node(): <data> <foo>Hello</foo> <bar>World</bar> </data> where as crypto:hmac requires a string-type $message: BQ_BEGIN crypto:hmac ($message as xs:string, BQ_END Hence your $body will be converted like so: BQ_BEGIN string( <data> <foo>Hello</foo> <bar>World</bar> </data> ) BQ_END Turning it into: BQ_BEGIN „HelloWorld“ BQ_END In order to actually compute a hash on the bytes your document contains, do as follows: Working example here: [ https://git.basex.io/snippets/63 | https://git.basex.io/snippets/63 ] Treat your document as binary: BQ_BEGIN %rest:consumes("application/octet-stream“) BQ_END And then decode that binary to a string and then compute the hash for the string, using: bin:decode-string#2: BQ_BEGIN let $str-doc := bin:decode-string($body,'utf-8') (: xs:string :) let $sig-cand := crypto:hmac($str-doc,$secret,'sha1','base64') BQ_END Hope this helps :-) Michael BQ_BEGIN Am 03.06.2019 um 12:17 schrieb Jerome Chauveau < [ mailto:jerome.chauveau at unicaen.fr | jerome.chauveau at unicaen.fr ] >: Hi, I am trying to check XML content (HTTP posted) with an hmac function in a RESTXQ webapp. My Java client sends an HTTP post request where XML data looks like : <data><user>doe</user><content><TEI xsi:schemaLocation=" [ http://www.tei-c.org/ns/1.0 | http://www.tei-c.org/ns/1.0 ] " xml:id="idtest" ><teiHeader ><fileDesc ><titleStmt ><title >Test</title ><author xml:id="authortest" >XXX</author ></titleStmt ></teiHeader ><text ><front ></front ><body xml:space="preserve" ><listPlace ><place type="lieu" ><placeName xml:lang="la" >Burgunvilla</placeName ></place ></listPlace ></body ></text ></TEI ></content></data> This content is HMAC encrypted and the signature is added to the HTTP header : [...] String secret = "1234"; StringEntity entity = new StringEntity(xml, ContentType.create("text/xml", Consts.UTF_8)); String signature = HTTPUtils.hmacSHA1(xml, secret); httppost.setHeader("Authorization", signature); httppost.setEntity(entity); [...] Here is my RESTXQ function : declare %rest:POST("{$body}") %rest:consumes("application/xml", "text/xml") %rest:header-param("Authorization", "{$signature}", "none") %rest:path("/sf/testpost") function sf.test:testPost($signature,$body){ let $secret := 1234 crypto:hmac($body,$secret,'sha1','base64') = $signature } Equality check always fails with such an XML sequence but works fine when XML does not contain any carriage return : <data><user>doe</user><content><TEI><front></front><text><body>This is a test</body></text></TEI> It seems to come when "The body of a POST or PUT request is converted to an XQuery item". I tried to set serializer's options without any success ! How could I retrieve xml (in $body) exactly serialized as sent by the client ? Tests are running on BaseX922. Thank you for your time. Jérôme BQ_END
Written for BaseX 9.2. BaseX may have changed since: please check the current documentation.
⚡Generated with XQuery