跳轉到內容

XQuery/摘要認證

來自Wikibooks,開放世界中的開放書籍

您正在使用的API使用摘要認證,例如Talis平臺 eXist httpclient模組沒有直接支援此功能,但可以在XQuery中編寫一個。

以下實現基於摘要認證中的描述和示例。

模組和概念

[編輯 | 編輯原始碼]
  • eXist httpclient : 用於基本的POST操作
  • eXist util : 用於UUID生成和MD5編碼


XQuery模組

[編輯 | 編輯原始碼]
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操作。第一個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)

參考文獻

[編輯 | 編輯原始碼]
華夏公益教科書