Personiumを使ってパーソナルデータの使用許諾要求・同意・アクセス制御を行う

## はじめに

パーソナルデータを他のシステムやサービスが利用するとき、データの持ち主への同意を取ることが基本必要になります。例えば、Webサービスを利用開始するときにプライバシーポリシーへの同意を求められたり、海外のWebページを見ているとcookieの使用許諾を求められたりすることは誰でもよく体験すると思います。

オープンソースPersonal Data Store(PDS)であるPersoniumでは、こういったパーソナルデータを持ち主以外の人や組織が使用するときを想定して使用許諾の要求・同意・アクセス制御を行う機能があり、これらを行いたいスマホアプリやWebアプリなどに組み込むことができます。

しかし、現状の公式ドキュメントではそれがどのAPIでどのようにやったらよいか若干わかりづらいところがあります。それなので、本記事ではそれらPersoniumの機能を使って使用許諾の要求・同意・アクセス制御を行うための方法について紹介したいと思います。

本来なら公式ドキュメントにあって良い内容なので、いずれ整理できたらOSSコミュニティにコントリビュートしたいと思います。

## Personiumとは

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_103339_7239cc0b-c7d8-3496-1c05-869446bd464e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103339/27aa2adb-a650-9af2-c473-877b5b9b9ec0.png)

PersoniumはオープンソースのPersonal Data Store (PDS)です。PDSとは、これまでサービスやシステム単位でバラバラに格納・扱われていたパーソナルデータを個人単位で集約して格納するデータストアのことです。このようなデータの格納を行い、個人の管理下に置くことで個人に還元できるデータの流通・活用を目指すものです。

![Personium.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103339/6d2e6a01-c7eb-afbd-8e43-02cea65019b2.png)
*上記は[公式サイト](https://personium.io/docs/ja/introduction/001_Introduction/)の画像を引用*

Personium上のデータ操作含む全ての機能はREST APIを通じて行います。
詳しくは以下の公式サイトや既存発表資料もご参照ください。

- [Personium 公式サイト](https://personium.io/)
- [2020年2月Open Source Conference発表資料](https://www2.slideshare.net/yasufumitochiori/pdspersonium-228809198)

## 使用許諾の要求・同意・アクセス制御の実現

### 本記事での想定

まず、PersoniumのAPIの使い方を説明するにあたって、イメージしやすい簡単な例を考えます。本当に現実的かはさておき、以下の例を考えます。

1. 医者のAliceが患者のBobに対して、診療のためにBobのPDS上にある過去の医療データの利用を要求する
2. Bobが同意する
3. AliceがBobのPDS上の医療データを参照する

正確な図ではありませんが、以下のようなイメージです。

![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103339/47ac7a8f-6990-6a52-9951-f5df9bc3a65d.png)

ここで

* AliceとBobはスマホアプリもしくはWebアプリを使って操作を行う
* Bobが使用許諾要求に対して同意をするまで、AliceはBobのデータにアクセスできない
* Bobが同意をした時点でAliceはBobのデータにアクセスできる

とします。次項からは上記の想定の時のアプリからのPersonium APIの呼び出し方について述べていきます。

なお、ここではAliceを個人にしましたが、Aliceを病院といった組織に置き換えることもできます。

### 自身のデータへのアクセス

他者へのデータアクセスに入る前にPersoniumの基本として、自身のデータへのアクセスを考えます。

Personiumでは個人のデータ含む領域をCellと呼んでいて、一意のURLが割り当てられます。例えば、AliceとBobのCellは次のようなURLで表されます。

- `https://alice.pds.example/`
- `https://bob.pds.example/`

Aliceが自身のデータにアクセスする場合、自身の[トークンエンドポイントAPI](https://personium.io/docs/ja/apiref/293_OAuth2_Token_Endpoint/)、すなわち`https://alice.pds.example/__token`でアクセストークンを取得し、自身のデータ`https://alice.pds.example/mybox/mydata`にアクセストークンを与えてアクセスします。

```shell
USERNAME=me
PASSWORD=****

# アクセストークンの取得
ACCESS_TOKEN=$(curl -X POST \
    -d "grant_type=password&username=${USERNAME}&password=${PASSWORD}" \
    https://alice.pds.example/__token | jq -r .access_token)

# Alice自身のデータへのアクセス
curl -X GET \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    https://alice.pds.example/mybox/mydata.file
```

### 他者データにアクセスする場合のアクセス制御設定

使用許諾要求より先に同意後のアクセス制御設定を考えます。

AliceがBobにアクセスするときは[他者Cellへのデータアクセス](https://personium.io/docs/ja/app-developer/003_Auth/#%E4%BB%96%E8%80%85cell%E3%81%B8%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9)に書かれているような以下の設定がBob Cell上で事前に行われている必要があります。

1. 'Doctor' Roleの作成
2. ExtCell作成でAlice Cellを指定
3. 上記ExtCellと'Doctor' Roleのリンクの作成

```shell
USERNAME=me
PASSWORD=****

# アクセストークンの取得
ACCESS_TOKEN=$(curl -X POST \
    -d "grant_type=password&username=${USERNAME}&password=${PASSWORD}" \
    https://bob.pds.example/__token | jq -r .access_token)

# 'Doctor' Roleの作成
curl -X POST \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H 'Content-Type: application/json' \
    -d '{"Name":"Doctor"}' \
    https://bob.pds.example/__ctl/Role

# ExtCell作成でAlice Cellを指定
curl -X POST \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H 'Content-Type: application/json' \
    -d '{"Url":"https://alice.pds.example/"}' \
    https://bob.pds.example/__ctl/ExtCell

# 上記ExtCellと'Doctor' Roleのリンクの作成
BODY=$(cat << EOS
{
    "uri": "https://bob.pds.example/__ctl/Role(Name='Doctor')"
}
EOS
)
curl -X POST \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H 'Content-Type: application/json' \
    -d "${BODY}" \
    "https://bob.pds.example/__ctl/ExtCell('https%3A%2F%2Falice.pds.example%2F')/\$links/_Role"
```

上記設定を行うことで、Bob Cell上のデータをAliceがアクセスしたときに'Doctor' Roleとしてアクセスされます。この設定が同意前は行われておらず、同意後に行われるようにすることで想定通りのアクセス制御が行えます。

### データの使用許諾要求

Aliceが行うデータ使用許諾要求は[メッセージ送信API](https://personium.io/docs/ja/apiref/271_Send_Message/)を使用して行います。

ただし、このAPIが呼ばれる前に'Doctor' Roleが定義されたアプリの[barファイル](https://personium.io/docs/ja/apiref/301_Bar_File/)を使ってBobのCellに[Boxインストール](https://personium.io/docs/ja/apiref/007_Box_install/)されている必要があります。Barファイル/Boxインストールに関してはリンク先のドキュメントをご参照ください。

メッセージ送信APIは2種類のTypeがあり、Type="request"を指定した場合、同意きっかけに相手に与えるRoleを指定することができます。

```shell
# Bob Cellで事前に'Doctor' Roleが定義されたアプリのbarファイルをBoxインストールしておく
# アクセストークンはアプリのスキーマ認証したものを使用する (OAuth 2.0 認可コードフローを使って取得する)

# データの使用許諾リクエストの作成
BODY=$(cat << EOS
{
  "BoxBound": true,
  "To": "https://bob.pds.example/",
  "Type": "request",
  "Title": "医療データの使用許諾",
  "Body": "診療のため、医療データを参照しますがよろしいでしょうか。",
  "RequestObjects": [
    {
      "RequestType": "role.add",
      "Name": "Doctor",
      "TargetUrl": "https://alice.pds.example/"
    }
  ]
}
EOS
)

curl -X POST \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H 'Content-Type: application/json' \
    -d "${BODY}" \
    https://alice.pds.example/__message/send | jq .
```

### データ使用の同意

Bobが行うデータ使用の同意は[メッセージ状態変更API](https://personium.io/docs/ja/apiref/267_Received_Message_Approval/)を使用して行います。


```shell
# データ使用許諾の同意
MESSAGE_ID='4ee33143dffc4f49a3fe39096fa476f8'
curl -X POST \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H 'Content-Type: application/json' \
    -d '{"Command": "approved"}' \
    https://bob.pds.example/__message/received/${MESSAGE_ID}
```

これが実行された後、Bob Cell上ではExtCellにAlice Cellが作成され、'Doctor' Roleとリンクされます。

### 同意後の他者データアクセス

同意後にAliceがBobのデータにアクセスするときは[他者Cellへのデータアクセス](https://personium.io/docs/ja/app-developer/003_Auth/#%E4%BB%96%E8%80%85cell%E3%81%B8%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9)の通り、次のように行います。

```shell
# トランスセルトークンの取得 (p_targetパラメータを追加)
ACCESS_TOKEN=$(curl -X POST \
    -d "grant_type=password&username=${USERNAME}&password=${PASSWORD}&p_target=https://bob.pds.example/" \
    https://alice.pds.example/__token | jq -r .access_token)

# Bobのデータへのアクセス
curl -X GET \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    https://bob.pds.example/demo/helth-data.file
```

ここでBobのデータ`https://bob.pds.example/demo/helth-data.file`はAliceから'Doctor' Roleとしてアクセスされます。このデータが'Doctor' Roleに対してACL設定で許可されていればアクセスできます。使用許諾の要求に同意するまではAliceに'Doctor' Roleが付与されてないのでこのデータにアクセスできないようになっています。

## おわりに

本記事で紹介したようなPersoniumのAPIを使うことで、アプリにパーソナルデータの使用許諾要求・同意・アクセス制御を組み込むことができます。

もしかするとPersoniumのAPIの作りを独特と思われたかもしれません。このような作りになっているのは非中央集権で相互運用できる仕組みだったり、PDSを目指しているが故の作りだったりします。そのあたりもいずれ書いていきたいところです。