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  | 
