diff --git a/changelog.d/oauth-tokens-scopes.security b/changelog.d/oauth-tokens-scopes.security new file mode 100644 index 000000000..653b7a059 --- /dev/null +++ b/changelog.d/oauth-tokens-scopes.security @@ -0,0 +1 @@ +Require the read:security and write:security scopes to list and revoke OAuth tokens (HTTP Basic auth no longer works for these endpoints) diff --git a/docs/development/API/pleroma_api.md b/docs/development/API/pleroma_api.md index b19523bce..5627252e8 100644 --- a/docs/development/API/pleroma_api.md +++ b/docs/development/API/pleroma_api.md @@ -780,6 +780,7 @@ Emoji reactions work a lot like favourites do. They make it possible to react to ### Retrieve a list of active sessions for the user * Method: `GET` * Authentication: required +* OAuth scope: `read:security` * Params: none * Response: JSON * Example response: @@ -808,8 +809,9 @@ Emoji reactions work a lot like favourites do. They make it possible to react to ### Revoke a user session by its ID * Method: `DELETE` * Authentication: required +* OAuth scope: `write:security` * Params: none -* Response: HTTP 200 on success, 500 on error +* Response: HTTP 201 on success, 500 on error ## `/api/v1/pleroma/settings/:app` ### Gets settings for some application diff --git a/lib/pleroma/web/o_auth/token_controller.ex b/lib/pleroma/web/o_auth/token_controller.ex index d2313a9cc..296b60510 100644 --- a/lib/pleroma/web/o_auth/token_controller.ex +++ b/lib/pleroma/web/o_auth/token_controller.ex @@ -13,7 +13,8 @@ defmodule Pleroma.Web.OAuth.TokenController do require Logger plug(:skip_auth when action == :confirm_email) - plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token]) + plug(OAuthScopesPlug, %{scopes: ["read:security"]} when action == :oauth_tokens) + plug(OAuthScopesPlug, %{scopes: ["write:security"]} when action == :revoke_token) action_fallback(:errors) diff --git a/test/pleroma/web/o_auth/token_controller_test.exs b/test/pleroma/web/o_auth/token_controller_test.exs index 5c64cb394..08acf27bf 100644 --- a/test/pleroma/web/o_auth/token_controller_test.exs +++ b/test/pleroma/web/o_auth/token_controller_test.exs @@ -52,36 +52,60 @@ defmodule Pleroma.Web.OAuth.TokenControllerTest do end describe "GET /api/oauth_tokens" do - setup do - token = insert(:oauth_token) |> Repo.preload(:user) - - %{token: token} - end - - test "renders list", %{token: token} do - response = - build_conn() - |> assign(:user, token.user) - |> get("/api/oauth_tokens") + test "renders list" do + %{conn: conn} = oauth_access(["read:security"]) keys = - json_response(response, 200) + conn + |> get("/api/oauth_tokens") + |> json_response(200) |> hd() |> Map.keys() assert Enum.sort(keys) == Enum.sort(["id", "app_name", "valid_until", "scopes"]) end - test "revoke token", %{token: token} do - response = - build_conn() - |> assign(:user, token.user) - |> delete("/api/oauth_tokens/#{token.id}") + test "is allowed with the read scope" do + %{conn: conn} = oauth_access(["read"]) - tokens = Token.get_user_tokens(token.user) + assert [_] = conn |> get("/api/oauth_tokens") |> json_response(200) + end - assert tokens == [] - assert response.status == 201 + test "is forbidden without read:security" do + %{conn: conn} = oauth_access(["profile", "read:accounts", "write:security"]) + + assert %{"error" => "Insufficient permissions: read:security."} = + conn |> get("/api/oauth_tokens") |> json_response(403) + end + end + + describe "DELETE /api/oauth_tokens/:id" do + test "revokes the token" do + %{conn: conn, user: user, token: token} = oauth_access(["write:security"]) + other = insert(:oauth_token, user: user) + + conn = delete(conn, "/api/oauth_tokens/#{other.id}") + + assert conn.status == 201 + assert [%Token{id: id}] = Token.get_user_tokens(user) + assert id == token.id + end + + test "is allowed with the write scope" do + %{conn: conn, user: user} = oauth_access(["write"]) + other = insert(:oauth_token, user: user) + + assert delete(conn, "/api/oauth_tokens/#{other.id}").status == 201 + end + + test "is forbidden without write:security" do + %{conn: conn, user: user} = oauth_access(["profile", "read", "write:accounts"]) + other = insert(:oauth_token, user: user) + + assert %{"error" => "Insufficient permissions: write:security."} = + conn |> delete("/api/oauth_tokens/#{other.id}") |> json_response(403) + + assert length(Token.get_user_tokens(user)) == 2 end end end