👽

UMAサンプルアプリを作ってみた

2024/01/09に公開

記事の内容

UMAという認可フレームワークについて調べる機会がありました。しかし、UMAについて日本語の情報がとても少ないと感じました。
そのため公式の英語ベースの仕様書を読了するのが主なソースとなったのですが、RFCを読むような話なので理解するのに苦労しました。需要があるか謎ですが、せっかく読んだのでこの機会に記事にしてみようと思います。
また、Node.jsベースでサンプルコードを作成してみました。興味ある方はよかったら、どんな感じか雰囲気掴んでみてください。

https://github.com/r-3110/uma-sample

UMAとは

Wikipediaによると下記のようです。
未確認動物(みかくにんどうぶつ)または未確認生物(みかくにんせいぶつ)とは、目撃例や伝聞による情報はあるが、実在が確認されていない生物のことである
すいません。嘘です。いえ嘘ではないのですが、このUMAではありません。

UMAとは、User Managed Accessのイニシャルで、ユーザによるシステムへのアクセス管理を行う認可フレームワークです。
UMAはOAuthの拡張なので、OAuthと対比してみると違いがイメージできると思います。

OAuth

OAuthは、リソースオーナー=システム管理者となるイメージだと思います。
ユーザーはシステムを通して、システム管理者から権限を付与されています。例えば、あるECサイトにおいて会員登録することで買い物ができるとすると、この買い物の権限はそのECサイトの管理者によって与えられていると解釈できます。
これは一般的にもよくある構成で、権限の管理が中央集権的だと言って良いと思います。

UMA

一方、UMAはシステム利用者全てが各々リソースを所有しており、自身のリソースのオーナーとなるイメージだと思います。システム管理者が直接的に利用者個々の権限については管理をしておらず、権限以外のシステム運用を行っているとイメージすると良いと思います。
利用者は他オーナーのリソースについてアクセスするだけでなく、自らもオーナーとしてリソースの権限を管理しています。つまり、利用者相互の信頼でリソースへのアクセス権限が成り立っていると解釈していいでしょう。

登場人物

UMAには5つの登場人物がいます。うち4つはOAuthにも存在します。

  • resource owner
    保護されたリソースへのアクセスを許可できるリソースの管理者

  • client
    リソースオーナーの承認を得て、requesting party(後述)に代わって、保護されたリソースを要求できるアプリケーション

  • resource server
    リソースオーナーに代わってリソースをホストし、保護されたリソースに対する要求を受け入れて応答できるサーバー

  • authorization server
    リソースオーナーに代わって、リソース サーバーでホストされているリソースを保護するサーバー

  • requesting party
    これが上記と異なりOAuthには定義されていない登場人物です。
    保護されたリソースへのアクセスを求めるためにクライアントを使用する人(組織でも良い)。この人物はUMAとはで確認したように、本人からしてみればリソースオーナーにもなりえます。
    ややこしいですが、概念としては別の客体として考えることがポイントだと思います。

事例

このUMAの認可フレームワークの事例としてはHEARTというプロファイルが有名のようです。
HEARTはHealth Relationship Trustのイニシャルで、医療現場で患者が自らの臨床データをどのように、いつ、誰と共有するかを管理することができるよう定義しているプロファイルです。

  • 組織や個人がデータの要求できるかどうか (つまり、患者によって許可されているかどうか)を電子的に判断できるようにする

  • 最高レベルのセキュリティとプライバシーを遵守する、アクセス許可とデータの共有の両方を管理するためのプロトコルを作成する

  • 患者が臨床データを共有するための許可と承認を設定して、患者が選択した個人、機関、アプリとのみデータが共有されるようにするシステムをサポートおよび統合する

ちなみにこのHEARTですが、UMA(OAuth含む)だけでなく、OpenID Connectも前提にあります。
つまり、OAuth、OIDC、UMAにおいてMUSTとされていない点を、さらに細かく厳密に定義してある感じです。
なので深掘りすると膨大な内容になってしまうので、ここでは割愛します。
興味があれば下記をどうぞ。。。

https://openid.bitbucket.io/HEART/

サンプルコードの構成

下記が今回作成した認可フローのイメージです。少し冗長ですが、詳しめに作成してみました。

1 クライアントアプリがリソースサーバにリソースをリクエスト
2 リソースのアクセスにはトークンが必要。クライアントからのトークンを認可サーバに検証する
3 認可サーバはトークンの検証結果を返す。初回はまだ権限がないので否認される。
4 リソースサーバは認可サーバに、リソースアクセスに必要な権限を含むチケット(トークン)発行を依頼
5 認可サーバはチケットをリソースサーバに発行する
6 リソースサーバは、クライアントに401エラーとともに、チケットをクライアントにレスポンスする
7 クライアントは受け取ったチケットを認可サーバに送信して権限を申請する
8 リソースオーナーはKeycloak管理画面から申請を確認する。申請者と申請された権限を承認する。(もちろん否認もできる)

--時間経過--

9-15 再び、1で行ったリソースアクセスを再リクエスト。7の権限申請までは上記同様のフロー
16 今度は権限が承認されているのでここでトークンが貰える
17 再々、1で行ったリソースアクセスを再リクエスト
18 再々、トークンの検証。
19 有効なトークンがあるため検証に成功。トークンにはスコープが含まれているため、このスコープを認可サーバは確認する
20 要求されたリソースへアクセス。リソースサーバは結果をレスポンスする

補足しておくと、8~9間はリソースオーナーの承認が介入します。ですので、現実的には幾分かの時間経過が伴うでしょう。

感想

構成図ぱっと見の感じ実装が大変そうですね。。。所詮サンプルなのですが実際に大変でした。
特に大変なのが、リソースサーバの実装ですね。仕様書にもリソースサーバの要件は結構いろいろ記載されています。
トークンの検証と権限確認がやはりポイントなのですが、いかんせんUMAの認可フローに対応したライブラリが少ないこと。。。まあせっかくなので理解を深めるためにも結構自前で実装しました。
例外処理は最低限しかやっていないので、仕様に準拠していない点もあるかと思います。
後日、サンプルコード自体の解説は需要(未知数)があればやっていこうかと思います。

参考

https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html#UMAFedAuthz

https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-federated-authz-2.0.html

https://www.keycloak.org/docs/22.0.5/authorization_services/#_service_user_managed_access

NCDCエンジニアブログ

Discussion