1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

情報銀行のプラットフォームとして利用できるかもしれないPersonium(PDS) を検証してみる 7 <APIでWebDavを触ってみる>

Last updated at Posted at 2019-03-19

##<APIでアクセスしてみる> のエントリーでAPIを叩きながら触ってみて、Personium の大きな構造は把握できたと思います。「Personium は PDS」って言うくらいなのですから、ファイルやDBへのアクセスができなくてはいけません… これからのいくつかのエントリーで、そんなキモの機能について理解を深めてみましょう。

Personium では、ユーザーのパーソナルな情報をBoxに溜め込む構造になっているのは、これまでのエントリーで説明しました。
そしてユーザーもしくはユーザー以外の事業者が提供するアプリケーションがこのBoxと紐づけられた状態で、アプリケーションがインストールされることとなり、アプリからはこのBox内にストアされたデータにしかアクセスできない構造です。
もし、この辺の理解が「ちょっと、あやふやなだなぁ…」というような場合は、<ざっくりとPersoniumとは> を、一度確認してみてください。


さて、Personium では、データをストアするためには、WebDavやODataの"箱"を作りそこにデータを収めるような仕組みとなっています。っがドキュメントを探ってもここを明確に記載しているものが… あまり記憶がなく、ドキュメント中には以下が当てはまるくらいでしょうか??
image.png

私が明確に「WebDavやODataの"箱"を作りそこにデータを収めるような仕組みとなっている」という認識ができたのは、ドキュメントではなく「ある異邦人」さんの「技術メモ」を認めた ブログ でした!!
そこに、以下のように記載されていました…

personiumは、アプリケーションが扱うデータというものは「木構造のディレクトリ構造をもったファイルシステム的なもの」か「リレーショナルデータ的なもの」の2種類でほぼ事足りるかなぁという仮説に立っています。それで、personiumのアプリケーション毎のデータ空間はWebDAVの空間なのですが、そこにODataの空間が切れるようにして2種類のデータを扱えるようにしています。

なにやら、この「ある異邦人」さんは"扱えるようにしています"とか、「私がそう決めたんです」的な表現で、ちょっと偉そうな書き方をしていますね… たぶんPersoniumに携わるそうとうエライ方なんだと想像されます。
まぁドキュメントのように事務的に「書いてあることに意義がある」記載方法と違い、このような経緯までが把握できると、理解もできますし記憶も深くキザまれます。

私は Personium に興味を持った早いタイミングで、この ブログ を読んでいたので把握できていたのですが、ドキュメントを読む限りでは、若干想像を膨らませる必要があるかもしれません。

※追記(2019/03/20)
 後日、『データの管理』 というドキュメントも見つけました…
image.png

#####またもや、ドキュメントのクォリティについて軽くdisったところで、そろそろ本題に進みましょう。


##1.環境の整理

まずはBoxを作らないといけないようですね。
<APIでアクセスしてみる> で利用したCellやAccount・Roleを流用し、環境を整えましょう。

しかしその前に、ここでまた一つ混乱するポイントを皆さんにインプットします。それは…
「セルを作成すると(自動的に)"隠しBOX"である"__"ボックスが作成されています」
<APIでアクセスしてみる> でも、以下の画像のように、"__ ボックスにひも付いている"とか、シレ〜と記載しています。
image.png

そしてこの"__"ボックスは、[main]ボックスと呼ばれる場合もあります。
「アプリセル」と呼ばれるアプリケーションのプログラムが配置される特殊なセルの場合、(パーソナル)データ以外の全てがこの"__"ボックス内に保持する用途として利用されます。
(この辺が本当に難しく… 私も全然理解が追いついていません。)

####既存の環境の整理

項目
ユニット https://personium.takky.org
セル admincell
アカウント user
ロール adminrole
コンテンツ(ACL) profile.json (read)

[ ユニット:https://personium.takky.org
  ∟ [ セル:admincell ]
    ∟ [ ボックス:__ ]
      ∟ [ ロール:adminrole ]
        ∟[ アカウント:user ]
      ∟[ コンテンツ:profile.json ]
        ∟[ ACL:adminrole - read ]

##2.WebDavを触るための環境の整備

以下の内容でWebDavコレクション(ディレクトリ)を作成しましょう。

項目 処理
ユニット https://personium.takky.org 無し
セル usercell 有り
ボックス userbox 有り
アカウント user 無し
ロール userrole 有り
コレクション(ACL) WebDavContents (read, write) 有り

セルの作成からACL付与までは、ユニット管理者で操作しましょう。
まずはトークンの取得

$ curl "https://personium.takky.org/unitadmin/__token" \
-X POST -i \
-d "grant_type=password&username={{unitAdminUser}}&password={{unitAdminPassword}}&p_target=https://personium.takky.org/" \
-H "Content-Type: application/x-www-form-urlencoded"

HTTP/1.1 200 
Date: Mon, 18 Mar 2019 10:46:29 GMT
Content-Type: application/json
Content-Length: 4378
Connection: keep-alive
Location: https://personium.takky.org/__token
X-Personium-Version: 1.7.4
Server: Personium

{
 "access_token":"{{unitAdminToken}}",
 "refresh_token_expires_in":86400,
 "refresh_token":"{{refreshToken}}",
 "p_target":"https:\/\/personium.takky.org\/",
 "token_type":"Bearer",
 "expires_in":3600
}

##3.セル(usercell)を作成します。

$ curl "https://personium.takky.org/__ctl/Cell" \
-X POST -i \
-d "{\"Name\":\"usercell\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Mon, 18 Mar 2019 10:49:14 GMT
Content-Type: application/json
Content-Length: 247
Connection: keep-alive
Location: https://personium.takky.org/__ctl/Cell('usercell')
DataServiceVersion: 2.0
ETag: W/"1-1552906154394"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{
        "uri":"https:\/\/personium.takky.org\/__ctl\/Cell('usercell')",
        "etag":"W\/\"1-1552906154394\"","type":"UnitCtl.Cell"
      },
      "Name":"usercell",
      "__published":"\/Date(1552906154394)\/",
      "__updated":"\/Date(1552906154394)\/"
    }
  }
}

##4.usercell セル内にボックス(userbox)を作成

$ curl "https://personium.takky.org/usercell/__ctl/Box" \
-X POST -i \
-d "{\"Name\":\"userbox\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Mon, 18 Mar 2019 10:56:49 GMT
Content-Type: application/json
Content-Length: 267
Connection: keep-alive
Location: https://personium.takky.org/usercell/__ctl/Box('userbox')
DataServiceVersion: 2.0
ETag: W/"1-1552906609545"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{
        "uri":"https:\/\/personium.takky.org\/usercell\/__ctl\/Box('userbox')",
        "etag":"W\/\"1-1552906609545\"",
        "type":"CellCtl.Box"
      },
      "Name":"userbox",
      "Schema":null,
      "__published":"\/Date(1552906609545)\/",
      "__updated":"\/Date(1552906609545)\/"
    }
  }
}

「HTTP/1.1 201 」 ここまで、順調ですね!!

##5.userboxボックス内にコレクション(WebDavContents)を作成

さて! ここからが本番の、WebDavコレクションの作成です。
とはいえ、これまでと何ら変わりません。

参考のドキュメントは、『WebDAV モデル』 で良いでしょうかね?

メソッドはこれまで利用したのとは少し違い「MKCOL」を利用するらしいです。
image.png

uriは、curl "https://personium.takky.org/{{cell}}/{{box}}/{{collection}}" のように
すれば良さそうです。
bodyには以下のようなXMLを記載する必要があるのですが、コレクションを作成する場合はこのままで良いようなので、そのまま利用します。
(リソースタイプは"collection"ですよ。ということが表現されているようです)
<?xml version=\"1.0\" encoding=\"utf-8\"?><D:mkcol xmlns:D=\"DAV:\" xmlns:p=\"urn:x-personium:xmlns\"><D:set><D:prop><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:set></D:mkcol>

$ curl "https://personium.takky.org/usercell/userbox/WebDavContents" \
-X MKCOL -i \
-d "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:mkcol xmlns:D=\"DAV:\" xmlns:p=\"urn:x-personium:xmlns\"><D:set><D:prop><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:set></D:mkcol>" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Mon, 18 Mar 2019 11:06:53 GMT
Content-Length: 0
Connection: keep-alive
ETag: "1-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium

エラーはありません!!

次に、作成したWebDavコレクションを確認しましょう。
usercell セルの userbox ボックス内にコレクションを作成したので、「userbox」を指定し確認してみましょう。

$ curl "https://personium.takky.org/usercell/userbox" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:1' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 207 
Date: Mon, 18 Mar 2019 11:23:18 GMT
Content-Type: application/xml
Content-Length: 1238
Connection: keep-alive
ETag: "1-1552907213232"
X-Personium-Version: 1.7.4
Server: Personium

<multistatus xmlns="DAV:">
    <response>
        <href>https://personium.takky.org/usercell/userbox</href>
        <propstat>
            <prop>
                <creationdate>2019-03-18T11:06:53.232+0000</creationdate>
                <getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
                <resourcetype>
                    <collection/>
                </resourcetype>
                <acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
    </response>
    <response>
        <href>https://personium.takky.org/usercell/userbox/WebDavContents</href>
        <propstat>
            <prop>
                <creationdate>2019-03-18T11:06:53.235+0000</creationdate>
                <getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
                <resourcetype>
                    <collection/>
                </resourcetype>
                <acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
    </response>
</multistatus>

「/userbox」と「/userbox/WebDavContents」の2つが出力されています。
userbx も WebDavContents も同等の扱いになっています。 ナンでやねん!!

#####実は、Personiumのオブジェクト全体が WebDav をベースに構成されているんです!
なので簡単に言うと、BoxもWebDavのディレクトリなんですね…

そして先ほど確認のために実行したコマンドには、"-H 'Depth:1'"とヘッダーにパラメータが与えられています。どんなコレクションが存在するかを取得する場合は、一つ上の階層を対象に'Depth:1'を指定し、ピンポイントでの存在の確認は、対象コレクションに対し'Depth:0'で取得するのが良いのかもしれません。

ヘッダ名 概要 有効値 必須
Depth 取得するリソースの階層 0:対象のリソース自身
1:対象のリソースとそれの直下のリソース

ピンポイントで確認

$ curl "https://personium.takky.org/usercell/userbox/WebDavContents" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:0' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 207 
Date: Mon, 18 Mar 2019 11:45:23 GMT
Content-Type: application/xml
Content-Length: 647
Connection: keep-alive
ETag: "1-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium

<multistatus xmlns="DAV:">
    <response>
        <href>https://personium.takky.org/usercell/userbox/WebDavContents</href>
        <propstat>
            <prop>
                <creationdate>2019-03-18T11:06:53.235+0000</creationdate>
                <getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
                <resourcetype>
                    <collection/>
                </resourcetype>
                <acl xml:base="https://personium.takky.org/usercell/__role/userbox/" xmlns:p="urn:x-personium:xmlns"/>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
    </response>

OKですね!!

では、存在しないコレクション(WebDavContents2)をピンポイントで確認すると…
404が返ってきます。 404なんですね…

$ curl "https://personium.takky.org/usercell/userbox/WebDavContents2" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:0' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 404 
Date: Mon, 18 Mar 2019 11:49:51 GMT
Content-Type: application/json
Content-Length: 142
Connection: keep-alive
X-Personium-Version: 1.7.4
Server: Personium

{
  "code":"PR404-DV-0001",
  "message":{
    "lang":"en",
    "value":"Resource not found. [https://personium.takky.org/usercell/userbox/WebDavContents2]."
  }
}

ついでに、ユニットマネージャでも確認してみましょう!
image.png

#####WebDavコレクションの作成は完了です!

※ お小言…
なにやら、ユニットマネージャにアクセスすると、以下のようにBasic認証のダイアログが出るようになったんですよねぇ… たぶん Ver1.7.5 から。
でもダイアログの[キャンセル]でそのまま利用できるので、今回はこれ以上追求しません。
image.png

##6.ロール(userrole)の作成とアカウントのひも付けとACL付与

では、次はアカウントを作ってロールに権限を付与しましょう。

設定内容の振り返り

項目 処理
ユニット https://personium.takky.org 無し
セル usercell 有り
ボックス userbox 有り
アカウント user 無し
ロール userrole 有り
コレクション(ACL) WebDavContents (read, write) 有り

ユーザー(user)を作成

$ curl "https://personium.takky.org/usercell/__ctl/Account" \
-X POST -i \
-d "{\"Name\":\"user\"}" \
-H "X-Personium-Credential:{{Password}}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Tue, 19 Mar 2019 04:54:48 GMT
Content-Type: application/json
Content-Length: 307
Connection: keep-alive
Location: https://personium.takky.org/usercell/__ctl/Account('user')
DataServiceVersion: 2.0
ETag: W/"1-1552971288710"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{
        "uri":"https:\/\/personium.takky.org\/usercell\/__ctl\/Account('user')",
        "etag":"W\/\"1-1552971288710\"","type":"CellCtl.Account"
      },
      "Name":"user",
      "LastAuthenticated":null,
      "Type":"basic",
      "Cell":null,
      "__published":"\/Date(1552971288710)\/",
      "__updated":"\/Date(1552971288710)\/"
    }
  }
}

##7.userbox にひも付いたロール(userrole)を作成

「userbox にひも付いた」の意味は、ボックスをExportしたりImportしたりすることがあり、この時にロールも含めてExportできるようにするための機能となります。
「userbox にひも付いた」状態にするためには、Bodyに"_Box.Name:userbox"と指定します。

 curl "https://personium.takky.org/usercell/__ctl/Role" \
-X POST -i \
-d "{\"Name\":\"userrole\",\"_Box.Name\":\"userbox\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 201 
Date: Tue, 19 Mar 2019 05:17:09 GMT
Content-Type: application/json
Content-Length: 304
Connection: keep-alive
Location: https://personium.takky.org/usercell/__ctl/Role(Name='userrole',_Box.Name='userbox')
DataServiceVersion: 2.0
ETag: W/"1-1552972629032"
X-Personium-Version: 1.7.4
Server: Personium

{
  "d":{
    "results":{
      "__metadata":{
        "uri":"https:\/\/personium.takky.org\/usercell\/__ctl\/Role(Name='userrole',_Box.Name='userbox')",
        "etag":"W\/\"1-1552972629032\"",
        "type":"CellCtl.Role"
      },
      "Name":"userrole",
      "_Box.Name":"userbox",
      "__published":"\/Date(1552972629032)\/",
      "__updated":"\/Date(1552972629032)\/"
    }
  }
}

##8.アカウント(user)にロール(userrole)をひも付ける

前の項で「userbox にひも付いた」状態にしているので、この時のロールの指定にも"_Box.Name:userbox"を指定する必要があることに注意しましょう。

$ curl "https://personium.takky.org/usercell/__ctl/Role(Name='userrole',_Box.Name='userbox')/\$links/_Account" \
> -X POST -i \
> -d "{\"uri\":\"https://personium.takky.org/usercell/__ctl/Account('user')\"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 204 
Date: Tue, 19 Mar 2019 05:31:07 GMT
Connection: keep-alive
DataServiceVersion: 2.0
X-Personium-Version: 1.7.4
Server: Personium

##9.コレクション(WebDavContents)に対してロール(userrole)にACL(read, write)を付与する

$ url 'https://personium.takky.org/usercell/userbox/WebDavContents'  \
-X ACL -i \
-d '<D:acl xmlns:D="DAV:" xmlns:p="urn:x-personium:xmlns" xml:base="https://personium.takky.org/usercell/__role/userbox/"><D:ace><D:principal><D:href>userrole</D:href></D:principal><D:grant><D:privilege><p:read/></D:privilege><D:privilege><p:write/></D:privilege></D:grant></D:ace></D:acl>' \
-H "Accept:application/json" -H "Authorization:Bearer {{unitAdminToken}}"

HTTP/1.1 200 
Date: Tue, 19 Mar 2019 08:47:48 GMT
Content-Length: 0
Connection: keep-alive
ETag: "5-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium

イケたみたいですね!!
read も write も付与したいので、以下のように指定するのがポイント。
「 <D:privilege><p:read/></D:privilege><D:privilege><p:write/></D:privilege> 」

##10.コレクション(WebDavContents)をピンポイントで参照(read)

まずはユーザー(user)のトークンの取得

$ curl "https://personium.takky.org/usercell/__token" \
-X POST -i \
-d "grant_type=password&username={{userName}}&password={{userPassword}}" \
-H "Content-Type: application/x-www-form-urlencoded"

HTTP/1.1 200 
Date: Tue, 19 Mar 2019 08:27:24 GMT
Content-Type: application/json
Content-Length: 331
Connection: keep-alive
X-Personium-Version: 1.7.4
Server: Personium

{
  "access_token":"{{user_token}}",
  "refresh_token_expires_in":86400,
  "refresh_token":"{{refresh_token}}",
  "token_type":"Bearer",
  "expires_in":3600
}

そして確認。

$ curl "https://personium.takky.org/usercell/userbox/WebDavContents" \
-X PROPFIND -i \
-d '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>' \
-H 'Depth:0' \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 207 
Date: Tue, 19 Mar 2019 08:56:30 GMT
Content-Type: application/xml
Content-Length: 528
Connection: keep-alive
ETag: "7-1552907213235"
X-Personium-Version: 1.7.4
Server: Personium

<multistatus xmlns="DAV:">
    <response>
        <href>https://personium.takky.org/usercell/userbox/WebDavContents</href>
        <propstat>
            <prop>
                <creationdate>2019-03-18T11:06:53.235+0000</creationdate>
                <getlastmodified>Mon, 18 Mar 2019 11:06:53 GMT</getlastmodified>
                <resourcetype>
                    <collection/>
                </resourcetype>
            </prop>
            <status>HTTP/1.1 200 OK</status>
        </propstat>
    </response>
</multistatus>

ユーザー(user)で、コレクション(ディレクトリ)をreadできました。

##11.オブジェクト(profilejson)の作成
コレクション(WebDavContents)配下に配置するファイルを作成します。
<APIでアクセスしてみる> のエントリーでも作成した、profile.json を作成しましょう。

$ curl "https://personium.takky.org/usercell/userbox/WebDavContents/profile.json" \
-X PUT -i \
-d "{\"DisplayName\":\"<APIでアクセスしてみる>\",\"Description\": \"<APIでアクセスしてみる>のサンプルで利用するファイル\",\"Image\": \"data:image/png;base64,{{Image}}"}" \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 100 Continue

HTTP/1.1 201 
Date: Tue, 19 Mar 2019 09:04:59 GMT
Content-Length: 0
Connection: keep-alive
ETag: "1-1552986299484"
X-Personium-Version: 1.7.4
Server: Personium

イケましたね…
##12.ファイル(profile.json)の確認

$ curl "https://personium.takky.org/usercell/userbox/WebDavContents/profile.json" \
-X GET -i \
-H "Accept:application/json" -H "Authorization:Bearer {{user_token}}"

HTTP/1.1 200 
Date: Tue, 19 Mar 2019 09:08:43 GMT
Content-Type: application/x-www-form-urlencoded
Content-Length: 32568
Connection: keep-alive
ETag: "1-1552986299484"
Accept-Ranges: bytes
X-Personium-Version: 1.7.4
Server: Personium

{
  "DisplayName":"<APIでアクセスしてみる>",
  "Description": "<APIでアクセスしてみる>のサンプルで利用するファイル",
  "Image": "data:image/png;base64,{{Image}}"
}

ファイルの内容である、"DisplayName" "Description" "Image" が取得できました。
想定通りです。

ついでに、ユニットマネージャでも確認してみましょう!
image.png

####WebDavコレクション(ディレクトリ)の作成と、ファイルの登録・参照が完了です!


###最後に

WebDavは… Personium の骨格とも言って良いベースの規格です。WebDavの空間上に Personium が乗っかっている感じです。なのでこのAPIを間違ってしまうと… とんでもない場所にファイルを作成してしまったり、アプリケーションに対して付与したACLが、Boxに影響してしまうような可能性も否定はできません。
そして、あるオブジェクトに付与したACLは、そのオブジェクトの配下のオブジェクトに、暗黙的に適用されてしまう仕様となっています。

上記のような仕様を把握した上で、適切なディレクトリ構造で適切なACL設定をするよう心がける必要があり、最悪の場合には公開してはいけないユーザー(ロール)に、パーソナル情報がダダ漏れする危険性もあります。

慎重な設計・コーディングを心がけてください。

本当は… このエントリでODataなどについても記載する想定だったのですが、思いの外 WebDav だけでそれなりの長編になってしまったので、OData・ExtRoleなどについては、この後のエントリで展開します。


####メニュー

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?