[#468] More OAuth scopes-specific tests.
authorIvan Tashkinov <ivantashkinov@gmail.com>
Wed, 20 Feb 2019 09:27:28 +0000 (12:27 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Wed, 20 Feb 2019 09:27:28 +0000 (12:27 +0300)
test/plugs/oauth_scopes_plug_test.exs [new file with mode: 0644]
test/web/twitter_api/twitter_api_controller_test.exs

diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/plugs/oauth_scopes_plug_test.exs
new file mode 100644 (file)
index 0000000..f328026
--- /dev/null
@@ -0,0 +1,122 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Plugs.OAuthScopesPlugTest do
+  use Pleroma.Web.ConnCase, async: true
+
+  alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.Repo
+
+  import Pleroma.Factory
+
+  test "proceeds with no op if `assigns[:token]` is nil", %{conn: conn} do
+    conn =
+      conn
+      |> assign(:user, insert(:user))
+      |> OAuthScopesPlug.call(%{scopes: ["read"]})
+
+    refute conn.halted
+    assert conn.assigns[:user]
+  end
+
+  test "proceeds with no op if `token.scopes` fulfill specified 'any of' conditions", %{
+    conn: conn
+  } do
+    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
+
+    conn =
+      conn
+      |> assign(:user, token.user)
+      |> assign(:token, token)
+      |> OAuthScopesPlug.call(%{scopes: ["read"]})
+
+    refute conn.halted
+    assert conn.assigns[:user]
+  end
+
+  test "proceeds with no op if `token.scopes` fulfill specified 'all of' conditions", %{
+    conn: conn
+  } do
+    token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user)
+
+    conn =
+      conn
+      |> assign(:user, token.user)
+      |> assign(:token, token)
+      |> OAuthScopesPlug.call(%{scopes: ["scope2", "scope3"], op: :&})
+
+    refute conn.halted
+    assert conn.assigns[:user]
+  end
+
+  test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'any of' conditions " <>
+         "and `fallback: :proceed_unauthenticated` option is specified",
+       %{conn: conn} do
+    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
+
+    conn =
+      conn
+      |> assign(:user, token.user)
+      |> assign(:token, token)
+      |> OAuthScopesPlug.call(%{scopes: ["follow"], fallback: :proceed_unauthenticated})
+
+    refute conn.halted
+    refute conn.assigns[:user]
+  end
+
+  test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'all of' conditions " <>
+         "and `fallback: :proceed_unauthenticated` option is specified",
+       %{conn: conn} do
+    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
+
+    conn =
+      conn
+      |> assign(:user, token.user)
+      |> assign(:token, token)
+      |> OAuthScopesPlug.call(%{
+        scopes: ["read", "follow"],
+        op: :&,
+        fallback: :proceed_unauthenticated
+      })
+
+    refute conn.halted
+    refute conn.assigns[:user]
+  end
+
+  test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'any of' conditions",
+       %{conn: conn} do
+    token = insert(:oauth_token, scopes: ["read", "write"])
+    any_of_scopes = ["follow"]
+
+    conn =
+      conn
+      |> assign(:token, token)
+      |> OAuthScopesPlug.call(%{scopes: any_of_scopes})
+
+    assert conn.halted
+    assert 403 == conn.status
+
+    expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, ", ")}."
+    assert Jason.encode!(%{error: expected_error}) == conn.resp_body
+  end
+
+  test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'all of' conditions",
+       %{conn: conn} do
+    token = insert(:oauth_token, scopes: ["read", "write"])
+    all_of_scopes = ["write", "follow"]
+
+    conn =
+      conn
+      |> assign(:token, token)
+      |> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&})
+
+    assert conn.halted
+    assert 403 == conn.status
+
+    expected_error =
+      "Insufficient permissions: #{Enum.join(all_of_scopes -- token.scopes, ", ")}."
+
+    assert Jason.encode!(%{error: expected_error}) == conn.resp_body
+  end
+end
index 27b1e878c3c99d8aedaf3e3fc92b1557cf87ced0..05a832967643438a7a5de21fde6e17540cab6aec 100644 (file)
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
   alias Pleroma.Notification
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.OAuth.Token
+  alias Pleroma.Web.TwitterAPI.Controller
   alias Pleroma.Web.TwitterAPI.UserView
   alias Pleroma.Web.TwitterAPI.NotificationView
   alias Pleroma.Web.CommonAPI
@@ -22,6 +23,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
   alias Ecto.Changeset
 
   import Pleroma.Factory
+  import Mock
 
   @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
 
@@ -187,6 +189,20 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
       |> get("/api/statuses/public_timeline.json")
       |> json_response(200)
     end
+
+    test_with_mock "treats user as unauthenticated if `assigns[:token]` is present but lacks `read` permission",
+                   Controller,
+                   [:passthrough],
+                   [] do
+      token = insert(:oauth_token, scopes: ["write"])
+
+      build_conn()
+      |> put_req_header("authorization", "Bearer #{token.token}")
+      |> get("/api/statuses/public_timeline.json")
+      |> json_response(200)
+
+      assert called(Controller.public_timeline(%{assigns: %{user: nil}}, :_))
+    end
   end
 
   describe "GET /statuses/public_and_external_timeline.json" do