XQuery/摘要认证
外观
< XQuery
您正在使用的API使用摘要认证,例如Talis平台 eXist httpclient模块没有直接支持此功能,但可以在XQuery中编写一个。
以下实现基于摘要认证中的描述和示例。
- eXist httpclient : 用于基本的POST操作
- eXist util : 用于UUID生成和MD5编码
module namespace http ="http://www.cems.uwe.ac.uk/xmlwiki/http";
declare namespace httpclient= "http://exist-db.org/xquery/httpclient";
两个函数在逗号分隔的name="value"对列表和XML表示之间进行转换
第一个函数采用以下格式的字符串:string="value",string1="value2",string3="value3"
请注意,replace函数从每个表达式的右侧删除所有双引号。
以下两个函数将这种形式的键值编码字符串
key1="value1",key2="value2",key3="value3"
转换为以下形式的XML结构
<field name="key1" value="value1"/> <field name="key2" value="value2"/> <field name="key3" value="value3"/>
以下是支持函数
declare function http:string-to-nvs($string) {
let $nameValues := tokenize($string,", ")
return
for $f in $nameValues
let $nv := tokenize($f,"=")
return <field name = "{$nv[1]}" value="{replace($nv[2],'"','')}"/>
};
declare function http:nvs-to-string($nvs) {
string-join(
for $field in $nvs
return
concat ($field/@name, '="',$field/@value,'" ')
, ", ")
};
主函数分两步处理POST操作。第一个POST将获得401响应(应该检查这一点)。摘要被构造并与第二个POST一起发送回去。
declare function http:post-with-digest($host, $path, $username, $password, $doc, $header ) {
let $uri := xs:anyURI(concat($host,$path))
(: send an HTTP Request to the server - called the challenge :)
let $request := httpclient:post( $uri, "dummy", false(), $header )
(: The server responds with the 401 response code. In this ressponse the server provide the authentication
realm and a randomly-generated, single-use value called a nonce.
We will get the realm and the nouce by finding the WWW-Authenticate value out of the response :)
let $first-response := substring-after($request//httpclient:header[@name="WWW-Authenticate"]/@value,"Digest ")
(: now we get the nounce, realm and the optional quality of protection out of the first response :)
let $fields := http:string-to-nvs($first-response)
let $nounce := $fields[@name="nonce"]/@value
let $realm := $fields[@name="realm"]/@value
let $qop := $fields[@name="qop"]/@value
(: Create a client nounce using a Universally Unique Identifier :)
let $cnonce := util:uuid()
(: this is the nounce count :)
let $nc := "00000001"
let $HA1:= util:md5(concat($username,":",$realm,":",$password))
(: TODO if the quality of protection (qos) is "auth-int" , then HA2 is
MD5(method : digestURU : MD5(entityBody))
But if qos "auth" or "auth-int" then it is the following :)
let $HA2 := util:md5(concat("POST:",$path))
let $response := util:md5(concat($HA1, ":", $nounce,":",$nc,":", $cnonce, ":", $qop, ":",$HA2))
(: note that if qop directive is unspecified, then the response should be md5(HA!:nounce:HA2) :)
(: here are the new headers :)
let $newfields := (
<field name="username" value="{$username}"/>,
<field name="uri" value="{$path}"/>,
<field name="cnonce" value="{$cnonce}"/>,
<field name="nc" value="{$nc}"/>,
<field name="response" value="{$response}"/>
)
let $authorization := concat("Digest ", http:nvs-to-string(($field,$newfields)))
let $header2 :=
<headers>
{$header/header}
<header name="Authorization"
value='{$authorization}'/>
</headers>
return httpclient:post( $uri, $doc, false(), $header2 )
};
请注意,在eXist 1.4下,util:md5($string)函数已被弃用。您现在应该使用util:hash($string, 'md5)函数,第二个参数现在是散列类型。
在此示例中,RDF文件被POST到Talis服务器。
declare namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; import module namespace http = "http://www.cems.uwe.ac.uk/xmlwiki/http" at "http.xqm"; let $rdf := doc("/db/RDF/dataset.rdf")/rdf:RDF let $path := "/store/mystore/meta" let $username := "myusername" let $password := "mypassword" let $host := "http://api.talis.com" let $header := <headers> <header name="Content-Type" value="application/rdf+xml"/> </headers> return http:put-with-digest($host, $path, $username, $password, $rdf , $header)