ユーザーAPIキークライアントが有効なauth_redirectを登録できるかどうかの可能性

ユーザーAPIキークライアントが、キー作成の目的で有効な auth_redirect を登録できるようにするかどうかを検討しています。

現在の機能

現在、ユーザーAPIキーのリダイレクトは、ホストサイトがサイト設定 allowed_user_api_auth_redirects で登録する必要があります。キー作成リクエストで送信された auth_redirect は、そのサイト設定リストに対してチェックされます(こちらを参照)。これは、オープンリダイレクト(さまざまなセキュリティリスクにつながる)を回避するための賢明な保護策です。

効率的な原因

この検討の効率的な原因は、ActivityPub プラグインのユーザー認証機能です。これにより、ユーザーは ActivityPub アクターの所有権を証明でき、そのアクターのアクティビティを特定のインスタンスのアカウントに関連付けることができます。これがその様子です。

これは現在 Mastodon で機能しています。なぜなら、すべての Mastodon サーバーは OAuth プロバイダーであり、OAuth クライアントのプログラムによる作成を許可しているからです。フローは次のようになります。

  1. ユーザーは、自分のアカウントが存在する Mastodon ドメインを特定します。
  2. そのドメインで初めて承認される場合、プラグインは Mastodon サーバー上に OAuth アプリを作成し、リダイレクトを登録して、OAuth フローのクライアント認証情報を取得します。
  3. プラグインは、2. で作成した(または以前に作成した)OAuth アプリを使用して、ユーザーと OAuth フローを実行します。

目標は、ユーザーAPIキーを使用して Discourse で実質的に同じ機能を持つことです。これはすでにこの PR で実装されています。

このフローでは、ホストサイトがクライアントのドメインまたはリダイレクトを allowed_user_api_auth_redirects に既に登録している必要があります。

可能な変更

現在考えているのは、discourse/discourse に PR を作成して、次のことを行うことです。

user_api_key_client テーブルの作成

列:

  • client_idapplication_nameuser_api_key から移行されます。
  • redirect_uri(オプション)
  • public_key(オプション)

client_idapplication_name を使用する既存のすべての機能は、user_api_key_client を介して以前と同様に機能します。

クライアント登録ルートの追加

post "/user-api-key/register" => "user_api_keys#register"

必須パラメータ:

  • application_name
  • client_id
  • public_key
  • auth_redirect

アクション:

  • パラメータを検証して user_api_key_client に保存します。
  • 成功した場合は成功コードを返します。

作成アクションでの登録済みクライアントの使用を許可する

UserApiKeyController の create アクションを次のように変更します。

  • client_iduser_api_key_client に存在し、auth_redirectpublic_key の両方がある場合:
    • 保存されている auth_redirect を使用した auth_redirect の使用を検証します。
    • 保存されている public_key を使用して戻りペイロードを暗号化します。
  • それ以外の場合は、既存の機能に従います。

cc @pmusaraj

「いいね!」 2

全体として、これはActivityPubプラグイン以降のユーザー認証ワークフローを管理者にほとんど手間をかけずに有効にできるため、賛成です。

ただし、いくつか質問があります。

私はここでの移行にはあまり賛成ではありません。個々のユーザーキーのIDと名前は、登録済みクライアントのIDと名前とは独立しているため、既存のユーザーAPIキーはそのままにしておきたいです。代わりに、user_api_keyuser_api_key_client_idの列を追加できるのではないでしょうか。クライアントに関連付けられたキーは、クライアントによって設定されたリダイレクトを使用できます(もちろん、既存のキーも現在の動作を維持します)。

さらに、管理者は登録済みクライアントのリストをどこかで確認できるべきでしょうか?

「いいね!」 1

だからこそ、client_idを移行すべきだと考えています :slight_smile:

現在、user_api_keysテーブルは、おそらく2つの別々のデータモデルであるべきものを混在させています。ユーザーAPIキーとユーザーAPIキークライアントです。現在の方法の制限は、キー作成メソッド(こちら)で見ることができます。

# 既存の古いキーをすべて削除
UserApiKey.where(user_id: current_user.id, client_id: params[:client_id]).destroy_all

key =
  UserApiKey.create!(
    application_name: @application_name,
    client_id: params[:client_id],
    user_id: current_user.id,
    push_url: params[:push_url],
    scopes: scopes.map { |name| UserApiKeyScope.new(name: name) },
  )

新しいキーを作成するには、client_idが同じすべてのキーを削除する必要があります。これにより、client_idが一意に保たれます。言い換えれば、現在のデータモデルはクライアントとキーの間に1対1の関係を必要とします。その1対1の関係は、ユースケースの一部には役立ちますが、他のユースケースを制限します。

確かに、この1対1の制限が、あなたが提案しているアプローチが機能しない理由でしょう。

クライアントが複数のキーに対してリダイレクトを登録できるようにするには、client_idの一意性がキー自体から独立している必要があります。そうでなければ、登録アクションで使用されるclient_idがリダイレクトを識別するために使用されるため、複数のキーに対する登録は機能しません。

client_idapplication_nameを専用のuser_api_key_clientsテーブルに移動すると、1対1のケースを維持しながら、1対多のケースと、ActivityPubの目的でのredirect_uri登録などの機能も可能になります。

「いいね!」 1

遅れてすみません、アンガス。

おっしゃることは理解できますが、既存の client_id を移行すると、移行されたID/名前が1対1のクライアントであるキーのものであるため、新しいテーブルにもこの混同の一部が残ることになります。特に管理者の観点からすると、登録済みの多対一クライアントのリストがあるのは良いことです。

しかし、現時点ではそれに対処するのは適切ではないかもしれません。

ご提案の計画を進めましょう。PRを楽しみにしています。ありがとうございます!

「いいね!」 1

これを実装したドラフトPRを公開しました。

注意点:

  • 既存の機能はすべて以前と同様に動作します。
  • マイグレーションは元に戻すことができます。

対応予定:

  • 失敗したテストを修正する。
  • 現在、どのユーザーでもクライアントを登録できます。これを何らかの方法で制限すべきかどうかをクエリします(?)
「いいね!」 1

ActivityPub に戻って注力することにしたため、この PR をリベースしました。これは、OP で議論されたように、ActivityPub の機能の 1 つの潜在的なフレームワークとなります。

リベース中に、この PR が行っているようにキーをクライアントから分離することで、@nat が最近対処したような問題も解決できることに気づきました。

具体的には、ユーザーに関係なく、クライアントに関連付けられた古いキーをすべて破棄する必要があるという変更は、キーとクライアントが同じテーブルにあることが原因です。それらを分離することで、クライアントの代替ユーザーに対して新しいキーを登録するだけで済みます。

「いいね!」 1

これでついにマージされました。@angusさん、本当にありがとうございます。これでアンブロックされることを願っています。

「いいね!」 1

ありがとうございます! (これでブロックが解除されました) :slight_smile: 近いうちに、ActivityPub Discourse間認証のPRで実装される予定です。

「いいね!」 1