diff options
Diffstat (limited to 'test/web/auth')
-rw-r--r-- | test/web/auth/auth_test_controller_test.exs | 242 | ||||
-rw-r--r-- | test/web/auth/oauth_test_controller_test.exs | 49 | ||||
-rw-r--r-- | test/web/auth/pleroma_authenticator_test.exs | 43 | ||||
-rw-r--r-- | test/web/auth/totp_authenticator_test.exs | 51 |
4 files changed, 336 insertions, 49 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/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..7125c5081 --- /dev/null +++ b/test/web/auth/pleroma_authenticator_test.exs @@ -0,0 +1,43 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 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: Comeonin.Pbkdf2.hashpwsalt(password)) + {:ok, [user: user, name: name, password: password]} + end + + test "get_user/authorization", %{user: user, name: name, password: password} do + params = %{"authorization" => %{"name" => name, "password" => password}} + res = PleromaAuthenticator.get_user(%Plug.Conn{params: params}) + + assert {:ok, user} == res + 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..e08069490 --- /dev/null +++ b/test/web/auth/totp_authenticator_test.exs @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 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(&Comeonin.Pbkdf2.hashpwsalt(&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 |