group_names パラメータ付きの API 招待で、グループ所有者が管理者でない場合 403 が返る

概要

Discourse グループの所有者である非管理者ユーザーは、Web UI の招待ダイアログを通じて、そのグループが割り当てられた新しいメンバーを正常に招待できます。REST API(/invites.json、グローバルスコープの API キー、正しい Api-Username)で同じアクションを実行すると、ペイロードに group_names/group_ids が含まれている場合のみ 403 invalid_access が返されます。これは、group_names がプレーンな文字列(例:"group_names": "my-group")として渡される場合でも、配列(例:"group_names": ["my-group"])として渡される場合でも発生します。どちらの形式でも同じ 403 が返されます。

重要な点として、ユーザーにモデレーター権限を付与しても API 呼び出しは修正されません。完全に成功するのは、完全な管理者権限を付与した場合のみです。モデレーター権限は、テストされた他のすべてのシナリオ(Web UI、グループ未指定の API 招待)では十分であるにもかかわらずです。

環境

  • Discourse バージョン: [記入 — Admin → Upgrade ページ]
  • API キーの種類: グローバルスコープ、Api-Username = テストユーザーの正確なユーザー名

再現手順

  1. 非管理者かつ非モデレーターのユーザー(<userid>)を作成し、グループ <group_name>所有者にします。
  2. Web UI で <userid> として操作:グループなしで招待 → 成功。<group_name> を割り当てて招待 → 成功。
  3. API で <userid> として操作(グローバルスコープのキー、Api-Username=<userid>):
    • group_names なしの POST /invites.json → 成功。
    • group_names="<group_name>"(文字列形式)の POST /invites.json403 invalid_access
    • group_names=["<group_name>"](配列形式)の POST /invites.json403 invalid_access(両方の形式をテストし、同じ失敗)。
  4. <userid>モデレーターに昇格。ステップ 3 のグループ付き API 呼び出し(両方の形式)を繰り返す → 依然として 403 invalid_access
  5. <userid>管理者に昇格。ステップ 3 のグループ付き API 呼び出しを、同じキー、同じペイロードで繰り返す → 成功

期待される動作

グループの所有権のみで、非スタッフユーザーが Web UI 経由で招待時にそのグループを割り当てるのに十分な権限があるため、Api-Username によって同じユーザーとして認証された API も、同じ権限を尊重すべきです。少なくとも、モデレーター(これはスタッフです)は、ここでは権限のないユーザーと同じように動作すべきではありません。モデレーターがロールなしの場合と同一に失敗し、管理者のみが成功するという事実は、API のコードパスがグループの所有権や一般的なスタッフステータス(モデレーターでは真となる user.staff?)ではなく、特に user.admin? をチェックしていることを示唆しています。

実際の動作

API は、実行しているユーザーが完全な管理者でない限り、グループ付き招待(文字列または配列のパラメータ形式)に対して 403 を返します。グループの所有権(Web UI 経由で動作確認済み)とモデレーター/スタッフステータス(直接昇格テストで確認済み)は、いずれも Web UI またはグループ未指定の API ケースでは十分であるにもかかわらず、API パスでは不十分です。

Discourse チームへの質問

API 認証によるグループ付き招待のコードパスは、Web UI / セッション認証パスがグループの所有権や user.staff? をチェックするように、明示的に user.admin? を要求しているのでしょうか?もしそうであれば、これは意図的なもの(文書化されていない API 固有の制限)ですか、それともこのアクションにおいて API のガーディアンチェックが Web のガーディアンチェックと乖離しているバグですか?

必要に応じて、完全なリクエスト/レスポンスログ(キーはマスク済み)を提供できます。