logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

oauth_scopes_plug_test.exs (6540B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Plugs.OAuthScopesPlugTest do
  5. use Pleroma.Web.ConnCase
  6. alias Pleroma.Plugs.OAuthScopesPlug
  7. alias Pleroma.Repo
  8. import Mock
  9. import Pleroma.Factory
  10. test "is not performed if marked as skipped", %{conn: conn} do
  11. with_mock OAuthScopesPlug, [:passthrough], perform: &passthrough([&1, &2]) do
  12. conn =
  13. conn
  14. |> OAuthScopesPlug.skip_plug()
  15. |> OAuthScopesPlug.call(%{scopes: ["random_scope"]})
  16. refute called(OAuthScopesPlug.perform(:_, :_))
  17. refute conn.halted
  18. end
  19. end
  20. test "if `token.scopes` fulfills specified 'any of' conditions, " <>
  21. "proceeds with no op",
  22. %{conn: conn} do
  23. token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
  24. conn =
  25. conn
  26. |> assign(:user, token.user)
  27. |> assign(:token, token)
  28. |> OAuthScopesPlug.call(%{scopes: ["read"]})
  29. refute conn.halted
  30. assert conn.assigns[:user]
  31. end
  32. test "if `token.scopes` fulfills specified 'all of' conditions, " <>
  33. "proceeds with no op",
  34. %{conn: conn} do
  35. token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user)
  36. conn =
  37. conn
  38. |> assign(:user, token.user)
  39. |> assign(:token, token)
  40. |> OAuthScopesPlug.call(%{scopes: ["scope2", "scope3"], op: :&})
  41. refute conn.halted
  42. assert conn.assigns[:user]
  43. end
  44. describe "with `fallback: :proceed_unauthenticated` option, " do
  45. test "if `token.scopes` doesn't fulfill specified conditions, " <>
  46. "clears :user and :token assigns",
  47. %{conn: conn} do
  48. user = insert(:user)
  49. token1 = insert(:oauth_token, scopes: ["read", "write"], user: user)
  50. for token <- [token1, nil], op <- [:|, :&] do
  51. ret_conn =
  52. conn
  53. |> assign(:user, user)
  54. |> assign(:token, token)
  55. |> OAuthScopesPlug.call(%{
  56. scopes: ["follow"],
  57. op: op,
  58. fallback: :proceed_unauthenticated
  59. })
  60. refute ret_conn.halted
  61. refute ret_conn.assigns[:user]
  62. refute ret_conn.assigns[:token]
  63. end
  64. end
  65. end
  66. describe "without :fallback option, " do
  67. test "if `token.scopes` does not fulfill specified 'any of' conditions, " <>
  68. "returns 403 and halts",
  69. %{conn: conn} do
  70. for token <- [insert(:oauth_token, scopes: ["read", "write"]), nil] do
  71. any_of_scopes = ["follow", "push"]
  72. ret_conn =
  73. conn
  74. |> assign(:token, token)
  75. |> OAuthScopesPlug.call(%{scopes: any_of_scopes})
  76. assert ret_conn.halted
  77. assert 403 == ret_conn.status
  78. expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, " | ")}."
  79. assert Jason.encode!(%{error: expected_error}) == ret_conn.resp_body
  80. end
  81. end
  82. test "if `token.scopes` does not fulfill specified 'all of' conditions, " <>
  83. "returns 403 and halts",
  84. %{conn: conn} do
  85. for token <- [insert(:oauth_token, scopes: ["read", "write"]), nil] do
  86. token_scopes = (token && token.scopes) || []
  87. all_of_scopes = ["write", "follow"]
  88. conn =
  89. conn
  90. |> assign(:token, token)
  91. |> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&})
  92. assert conn.halted
  93. assert 403 == conn.status
  94. expected_error =
  95. "Insufficient permissions: #{Enum.join(all_of_scopes -- token_scopes, " & ")}."
  96. assert Jason.encode!(%{error: expected_error}) == conn.resp_body
  97. end
  98. end
  99. end
  100. describe "with hierarchical scopes, " do
  101. test "if `token.scopes` fulfills specified 'any of' conditions, " <>
  102. "proceeds with no op",
  103. %{conn: conn} do
  104. token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
  105. conn =
  106. conn
  107. |> assign(:user, token.user)
  108. |> assign(:token, token)
  109. |> OAuthScopesPlug.call(%{scopes: ["read:something"]})
  110. refute conn.halted
  111. assert conn.assigns[:user]
  112. end
  113. test "if `token.scopes` fulfills specified 'all of' conditions, " <>
  114. "proceeds with no op",
  115. %{conn: conn} do
  116. token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user)
  117. conn =
  118. conn
  119. |> assign(:user, token.user)
  120. |> assign(:token, token)
  121. |> OAuthScopesPlug.call(%{scopes: ["scope1:subscope", "scope2:subscope"], op: :&})
  122. refute conn.halted
  123. assert conn.assigns[:user]
  124. end
  125. end
  126. describe "filter_descendants/2" do
  127. test "filters scopes which directly match or are ancestors of supported scopes" do
  128. f = fn scopes, supported_scopes ->
  129. OAuthScopesPlug.filter_descendants(scopes, supported_scopes)
  130. end
  131. assert f.(["read", "follow"], ["write", "read"]) == ["read"]
  132. assert f.(["read", "write:something", "follow"], ["write", "read"]) ==
  133. ["read", "write:something"]
  134. assert f.(["admin:read"], ["write", "read"]) == []
  135. assert f.(["admin:read"], ["write", "admin"]) == ["admin:read"]
  136. end
  137. end
  138. describe "transform_scopes/2" do
  139. setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage])
  140. setup do
  141. {:ok, %{f: &OAuthScopesPlug.transform_scopes/2}}
  142. end
  143. test "with :admin option, prefixes all requested scopes with `admin:` " <>
  144. "and [optionally] keeps only prefixed scopes, " <>
  145. "depending on `[:auth, :enforce_oauth_admin_scope_usage]` setting",
  146. %{f: f} do
  147. Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
  148. assert f.(["read"], %{admin: true}) == ["admin:read", "read"]
  149. assert f.(["read", "write"], %{admin: true}) == [
  150. "admin:read",
  151. "read",
  152. "admin:write",
  153. "write"
  154. ]
  155. Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true)
  156. assert f.(["read:accounts"], %{admin: true}) == ["admin:read:accounts"]
  157. assert f.(["read", "write:reports"], %{admin: true}) == [
  158. "admin:read",
  159. "admin:write:reports"
  160. ]
  161. end
  162. test "with no supported options, returns unmodified scopes", %{f: f} do
  163. assert f.(["read"], %{}) == ["read"]
  164. assert f.(["read", "write"], %{}) == ["read", "write"]
  165. end
  166. end
  167. end