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)