跳转到内容

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)

参考文献

[编辑 | 编辑源代码]
华夏公益教科书