概要
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= テストユーザーの正確なユーザー名
再現手順
- 非管理者かつ非モデレーターのユーザー(
<userid>)を作成し、グループ<group_name>の所有者にします。 - Web UI で
<userid>として操作:グループなしで招待 → 成功。<group_name>を割り当てて招待 → 成功。 - API で
<userid>として操作(グローバルスコープのキー、Api-Username=<userid>):group_namesなしのPOST /invites.json→ 成功。group_names="<group_name>"(文字列形式)のPOST /invites.json→ 403invalid_access。group_names=["<group_name>"](配列形式)のPOST /invites.json→ 403invalid_access(両方の形式をテストし、同じ失敗)。
<userid>をモデレーターに昇格。ステップ 3 のグループ付き API 呼び出し(両方の形式)を繰り返す → 依然として 403invalid_access。<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 のガーディアンチェックと乖離しているバグですか?
必要に応じて、完全なリクエスト/レスポンスログ(キーはマスク済み)を提供できます。