summaryrefslogtreecommitdiff
path: root/test/web/auth
diff options
context:
space:
mode:
Diffstat (limited to 'test/web/auth')
-rw-r--r--test/web/auth/auth_test_controller_test.exs242
-rw-r--r--test/web/auth/basic_auth_test.exs2
-rw-r--r--test/web/auth/oauth_test_controller_test.exs49
-rw-r--r--test/web/auth/pleroma_authenticator_test.exs48
-rw-r--r--test/web/auth/totp_authenticator_test.exs51
5 files changed, 342 insertions, 50 deletions
diff --git a/test/web/auth/auth_test_controller_test.exs b/test/web/auth/auth_test_controller_test.exs
new file mode 100644
index 000000000..fed52b7f3
--- /dev/null
+++ b/test/web/auth/auth_test_controller_test.exs
@@ -0,0 +1,242 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Tests.AuthTestControllerTest do
+ use Pleroma.Web.ConnCase
+
+ import Pleroma.Factory
+
+ describe "do_oauth_check" do
+ test "serves with proper OAuth token (fulfilling requested scopes)" do
+ %{conn: good_token_conn, user: user} = oauth_access(["read"])
+
+ assert %{"user_id" => user.id} ==
+ good_token_conn
+ |> get("/test/authenticated_api/do_oauth_check")
+ |> json_response(200)
+
+ # Unintended usage (:api) — use with :authenticated_api instead
+ assert %{"user_id" => user.id} ==
+ good_token_conn
+ |> get("/test/api/do_oauth_check")
+ |> json_response(200)
+ end
+
+ test "fails on no token / missing scope(s)" do
+ %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"])
+
+ bad_token_conn
+ |> get("/test/authenticated_api/do_oauth_check")
+ |> json_response(403)
+
+ bad_token_conn
+ |> assign(:token, nil)
+ |> get("/test/api/do_oauth_check")
+ |> json_response(403)
+ end
+ end
+
+ describe "fallback_oauth_check" do
+ test "serves with proper OAuth token (fulfilling requested scopes)" do
+ %{conn: good_token_conn, user: user} = oauth_access(["read"])
+
+ assert %{"user_id" => user.id} ==
+ good_token_conn
+ |> get("/test/api/fallback_oauth_check")
+ |> json_response(200)
+
+ # Unintended usage (:authenticated_api) — use with :api instead
+ assert %{"user_id" => user.id} ==
+ good_token_conn
+ |> get("/test/authenticated_api/fallback_oauth_check")
+ |> json_response(200)
+ end
+
+ test "for :api on public instance, drops :user and renders on no token / missing scope(s)" do
+ clear_config([:instance, :public], true)
+
+ %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"])
+
+ assert %{"user_id" => nil} ==
+ bad_token_conn
+ |> get("/test/api/fallback_oauth_check")
+ |> json_response(200)
+
+ assert %{"user_id" => nil} ==
+ bad_token_conn
+ |> assign(:token, nil)
+ |> get("/test/api/fallback_oauth_check")
+ |> json_response(200)
+ end
+
+ test "for :api on private instance, fails on no token / missing scope(s)" do
+ clear_config([:instance, :public], false)
+
+ %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"])
+
+ bad_token_conn
+ |> get("/test/api/fallback_oauth_check")
+ |> json_response(403)
+
+ bad_token_conn
+ |> assign(:token, nil)
+ |> get("/test/api/fallback_oauth_check")
+ |> json_response(403)
+ end
+ end
+
+ describe "skip_oauth_check" do
+ test "for :authenticated_api, serves if :user is set (regardless of token / token scopes)" do
+ user = insert(:user)
+
+ assert %{"user_id" => user.id} ==
+ build_conn()
+ |> assign(:user, user)
+ |> get("/test/authenticated_api/skip_oauth_check")
+ |> json_response(200)
+
+ %{conn: bad_token_conn, user: user} = oauth_access(["irrelevant_scope"])
+
+ assert %{"user_id" => user.id} ==
+ bad_token_conn
+ |> get("/test/authenticated_api/skip_oauth_check")
+ |> json_response(200)
+ end
+
+ test "serves via :api on public instance if :user is not set" do
+ clear_config([:instance, :public], true)
+
+ assert %{"user_id" => nil} ==
+ build_conn()
+ |> get("/test/api/skip_oauth_check")
+ |> json_response(200)
+
+ build_conn()
+ |> get("/test/authenticated_api/skip_oauth_check")
+ |> json_response(403)
+ end
+
+ test "fails on private instance if :user is not set" do
+ clear_config([:instance, :public], false)
+
+ build_conn()
+ |> get("/test/api/skip_oauth_check")
+ |> json_response(403)
+
+ build_conn()
+ |> get("/test/authenticated_api/skip_oauth_check")
+ |> json_response(403)
+ end
+ end
+
+ describe "fallback_oauth_skip_publicity_check" do
+ test "serves with proper OAuth token (fulfilling requested scopes)" do
+ %{conn: good_token_conn, user: user} = oauth_access(["read"])
+
+ assert %{"user_id" => user.id} ==
+ good_token_conn
+ |> get("/test/api/fallback_oauth_skip_publicity_check")
+ |> json_response(200)
+
+ # Unintended usage (:authenticated_api)
+ assert %{"user_id" => user.id} ==
+ good_token_conn
+ |> get("/test/authenticated_api/fallback_oauth_skip_publicity_check")
+ |> json_response(200)
+ end
+
+ test "for :api on private / public instance, drops :user and renders on token issue" do
+ %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"])
+
+ for is_public <- [true, false] do
+ clear_config([:instance, :public], is_public)
+
+ assert %{"user_id" => nil} ==
+ bad_token_conn
+ |> get("/test/api/fallback_oauth_skip_publicity_check")
+ |> json_response(200)
+
+ assert %{"user_id" => nil} ==
+ bad_token_conn
+ |> assign(:token, nil)
+ |> get("/test/api/fallback_oauth_skip_publicity_check")
+ |> json_response(200)
+ end
+ end
+ end
+
+ describe "skip_oauth_skip_publicity_check" do
+ test "for :authenticated_api, serves if :user is set (regardless of token / token scopes)" do
+ user = insert(:user)
+
+ assert %{"user_id" => user.id} ==
+ build_conn()
+ |> assign(:user, user)
+ |> get("/test/authenticated_api/skip_oauth_skip_publicity_check")
+ |> json_response(200)
+
+ %{conn: bad_token_conn, user: user} = oauth_access(["irrelevant_scope"])
+
+ assert %{"user_id" => user.id} ==
+ bad_token_conn
+ |> get("/test/authenticated_api/skip_oauth_skip_publicity_check")
+ |> json_response(200)
+ end
+
+ test "for :api, serves on private and public instances regardless of whether :user is set" do
+ user = insert(:user)
+
+ for is_public <- [true, false] do
+ clear_config([:instance, :public], is_public)
+
+ assert %{"user_id" => nil} ==
+ build_conn()
+ |> get("/test/api/skip_oauth_skip_publicity_check")
+ |> json_response(200)
+
+ assert %{"user_id" => user.id} ==
+ build_conn()
+ |> assign(:user, user)
+ |> get("/test/api/skip_oauth_skip_publicity_check")
+ |> json_response(200)
+ end
+ end
+ end
+
+ describe "missing_oauth_check_definition" do
+ def test_missing_oauth_check_definition_failure(endpoint, expected_error) do
+ %{conn: conn} = oauth_access(["read", "write", "follow", "push", "admin"])
+
+ assert %{"error" => expected_error} ==
+ conn
+ |> get(endpoint)
+ |> json_response(403)
+ end
+
+ test "fails if served via :authenticated_api" do
+ test_missing_oauth_check_definition_failure(
+ "/test/authenticated_api/missing_oauth_check_definition",
+ "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
+ )
+ end
+
+ test "fails if served via :api and the instance is private" do
+ clear_config([:instance, :public], false)
+
+ test_missing_oauth_check_definition_failure(
+ "/test/api/missing_oauth_check_definition",
+ "This resource requires authentication."
+ )
+ end
+
+ test "succeeds with dropped :user if served via :api on public instance" do
+ %{conn: conn} = oauth_access(["read", "write", "follow", "push", "admin"])
+
+ assert %{"user_id" => nil} ==
+ conn
+ |> get("/test/api/missing_oauth_check_definition")
+ |> json_response(200)
+ end
+ end
+end
diff --git a/test/web/auth/basic_auth_test.exs b/test/web/auth/basic_auth_test.exs
index 64f8a6863..bf6e3d2fc 100644
--- a/test/web/auth/basic_auth_test.exs
+++ b/test/web/auth/basic_auth_test.exs
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.Auth.BasicAuthTest do
conn: conn
} do
user = insert(:user)
- assert Comeonin.Pbkdf2.checkpw("test", user.password_hash)
+ assert Pbkdf2.verify_pass("test", user.password_hash)
basic_auth_contents =
(URI.encode_www_form(user.nickname) <> ":" <> URI.encode_www_form("test"))
diff --git a/test/web/auth/oauth_test_controller_test.exs b/test/web/auth/oauth_test_controller_test.exs
deleted file mode 100644
index a2f6009ac..000000000
--- a/test/web/auth/oauth_test_controller_test.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Tests.OAuthTestControllerTest do
- use Pleroma.Web.ConnCase
-
- import Pleroma.Factory
-
- setup %{conn: conn} do
- user = insert(:user)
- conn = assign(conn, :user, user)
- %{conn: conn, user: user}
- end
-
- test "missed_oauth", %{conn: conn} do
- res =
- conn
- |> get("/test/authenticated_api/missed_oauth")
- |> json_response(403)
-
- assert res ==
- %{
- "error" =>
- "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
- }
- end
-
- test "skipped_oauth", %{conn: conn} do
- conn
- |> assign(:token, nil)
- |> get("/test/authenticated_api/skipped_oauth")
- |> json_response(200)
- end
-
- test "performed_oauth", %{user: user} do
- %{conn: good_token_conn} = oauth_access(["read"], user: user)
-
- good_token_conn
- |> get("/test/authenticated_api/performed_oauth")
- |> json_response(200)
-
- %{conn: bad_token_conn} = oauth_access(["follow"], user: user)
-
- bad_token_conn
- |> get("/test/authenticated_api/performed_oauth")
- |> json_response(403)
- end
-end
diff --git a/test/web/auth/pleroma_authenticator_test.exs b/test/web/auth/pleroma_authenticator_test.exs
new file mode 100644
index 000000000..1ba0dfecc
--- /dev/null
+++ b/test/web/auth/pleroma_authenticator_test.exs
@@ -0,0 +1,48 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.Web.Auth.PleromaAuthenticator
+ import Pleroma.Factory
+
+ setup do
+ password = "testpassword"
+ name = "AgentSmith"
+ user = insert(:user, nickname: name, password_hash: Pbkdf2.hash_pwd_salt(password))
+ {:ok, [user: user, name: name, password: password]}
+ end
+
+ test "get_user/authorization", %{name: name, password: password} do
+ name = name <> "1"
+ user = insert(:user, nickname: name, password_hash: Bcrypt.hash_pwd_salt(password))
+
+ params = %{"authorization" => %{"name" => name, "password" => password}}
+ res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
+
+ assert {:ok, returned_user} = res
+ assert returned_user.id == user.id
+ assert "$pbkdf2" <> _ = returned_user.password_hash
+ end
+
+ test "get_user/authorization with invalid password", %{name: name} do
+ params = %{"authorization" => %{"name" => name, "password" => "password"}}
+ res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
+
+ assert {:error, {:checkpw, false}} == res
+ end
+
+ test "get_user/grant_type_password", %{user: user, name: name, password: password} do
+ params = %{"grant_type" => "password", "username" => name, "password" => password}
+ res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
+
+ assert {:ok, user} == res
+ end
+
+ test "error credintails" do
+ res = PleromaAuthenticator.get_user(%Plug.Conn{params: %{}})
+ assert {:error, :invalid_credentials} == res
+ end
+end
diff --git a/test/web/auth/totp_authenticator_test.exs b/test/web/auth/totp_authenticator_test.exs
new file mode 100644
index 000000000..84d4cd840
--- /dev/null
+++ b/test/web/auth/totp_authenticator_test.exs
@@ -0,0 +1,51 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.MFA
+ alias Pleroma.MFA.BackupCodes
+ alias Pleroma.MFA.TOTP
+ alias Pleroma.Web.Auth.TOTPAuthenticator
+
+ import Pleroma.Factory
+
+ test "verify token" do
+ otp_secret = TOTP.generate_secret()
+ otp_token = TOTP.generate_token(otp_secret)
+
+ user =
+ insert(:user,
+ multi_factor_authentication_settings: %MFA.Settings{
+ enabled: true,
+ totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
+ }
+ )
+
+ assert TOTPAuthenticator.verify(otp_token, user) == {:ok, :pass}
+ assert TOTPAuthenticator.verify(nil, user) == {:error, :invalid_token}
+ assert TOTPAuthenticator.verify("", user) == {:error, :invalid_token}
+ end
+
+ test "checks backup codes" do
+ [code | _] = backup_codes = BackupCodes.generate()
+
+ hashed_codes =
+ backup_codes
+ |> Enum.map(&Pbkdf2.hash_pwd_salt(&1))
+
+ user =
+ insert(:user,
+ multi_factor_authentication_settings: %MFA.Settings{
+ enabled: true,
+ backup_codes: hashed_codes,
+ totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
+ }
+ )
+
+ assert TOTPAuthenticator.verify_recovery_code(user, code) == {:ok, :pass}
+ refute TOTPAuthenticator.verify_recovery_code(code, refresh_record(user)) == {:ok, :pass}
+ end
+end