Fix formatter warnings
[akkoma] / test / web / oauth / oauth_controller_test.exs
index cb68369838979a66504054b78683d596b94a2e75..0b0972b17979f9aaad3521633201660854ff11db 100644 (file)
@@ -1,34 +1,26 @@
 # Pleroma: A lightweight social networking server
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.OAuth.OAuthControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.OAuth.OAuthControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
-  import Mock
 
 
-  alias Pleroma.Registration
   alias Pleroma.Repo
   alias Pleroma.Repo
+  alias Pleroma.User
   alias Pleroma.Web.OAuth.Authorization
   alias Pleroma.Web.OAuth.Authorization
+  alias Pleroma.Web.OAuth.OAuthController
   alias Pleroma.Web.OAuth.Token
 
   alias Pleroma.Web.OAuth.Token
 
-  @oauth_config_path [:oauth2, :issue_new_refresh_token]
   @session_opts [
     store: :cookie,
     key: "_test",
     signing_salt: "cooldude"
   ]
   @session_opts [
     store: :cookie,
     key: "_test",
     signing_salt: "cooldude"
   ]
+  setup do: clear_config([:instance, :account_activation_required])
 
   describe "in OAuth consumer mode, " do
     setup do
 
   describe "in OAuth consumer mode, " do
     setup do
-      oauth_consumer_strategies_path = [:auth, :oauth_consumer_strategies]
-      oauth_consumer_strategies = Pleroma.Config.get(oauth_consumer_strategies_path)
-      Pleroma.Config.put(oauth_consumer_strategies_path, ~w(twitter facebook))
-
-      on_exit(fn ->
-        Pleroma.Config.put(oauth_consumer_strategies_path, oauth_consumer_strategies)
-      end)
-
       [
         app: insert(:oauth_app),
         conn:
       [
         app: insert(:oauth_app),
         conn:
@@ -38,6 +30,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
       ]
     end
 
       ]
     end
 
+    setup do: clear_config([:auth, :oauth_consumer_strategies], ~w(twitter facebook))
+
     test "GET /oauth/authorize renders auth forms, including OAuth consumer form", %{
       app: app,
       conn: conn
     test "GET /oauth/authorize renders auth forms, including OAuth consumer form", %{
       app: app,
       conn: conn
@@ -49,7 +43,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => OAuthController.default_redirect_uri(app),
             "scope" => "read"
           }
         )
             "scope" => "read"
           }
         )
@@ -72,7 +66,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "authorization" => %{
               "scope" => "read follow",
               "client_id" => app.client_id,
             "authorization" => %{
               "scope" => "read follow",
               "client_id" => app.client_id,
-              "redirect_uri" => app.redirect_uris,
+              "redirect_uri" => OAuthController.default_redirect_uri(app),
               "state" => "a_state"
             }
           }
               "state" => "a_state"
             }
           }
@@ -98,64 +92,65 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
     test "with user-bound registration, GET /oauth/<provider>/callback redirects to `redirect_uri` with `code`",
          %{app: app, conn: conn} do
       registration = insert(:registration)
     test "with user-bound registration, GET /oauth/<provider>/callback redirects to `redirect_uri` with `code`",
          %{app: app, conn: conn} do
       registration = insert(:registration)
+      redirect_uri = OAuthController.default_redirect_uri(app)
 
       state_params = %{
         "scope" => Enum.join(app.scopes, " "),
         "client_id" => app.client_id,
 
       state_params = %{
         "scope" => Enum.join(app.scopes, " "),
         "client_id" => app.client_id,
-        "redirect_uri" => app.redirect_uris,
+        "redirect_uri" => redirect_uri,
         "state" => ""
       }
 
         "state" => ""
       }
 
-      with_mock Pleroma.Web.Auth.Authenticator,
-        get_registration: fn _ -> {:ok, registration} end do
-        conn =
-          get(
-            conn,
-            "/oauth/twitter/callback",
-            %{
-              "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
-              "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
-              "provider" => "twitter",
-              "state" => Poison.encode!(state_params)
-            }
-          )
+      conn =
+        conn
+        |> assign(:ueberauth_auth, %{provider: registration.provider, uid: registration.uid})
+        |> get(
+          "/oauth/twitter/callback",
+          %{
+            "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
+            "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
+            "provider" => "twitter",
+            "state" => Poison.encode!(state_params)
+          }
+        )
 
 
-        assert response = html_response(conn, 302)
-        assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
-      end
+      assert response = html_response(conn, 302)
+      assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
     end
 
     test "with user-unbound registration, GET /oauth/<provider>/callback renders registration_details page",
          %{app: app, conn: conn} do
     end
 
     test "with user-unbound registration, GET /oauth/<provider>/callback renders registration_details page",
          %{app: app, conn: conn} do
-      registration = insert(:registration, user: nil)
+      user = insert(:user)
 
       state_params = %{
         "scope" => "read write",
         "client_id" => app.client_id,
 
       state_params = %{
         "scope" => "read write",
         "client_id" => app.client_id,
-        "redirect_uri" => app.redirect_uris,
+        "redirect_uri" => OAuthController.default_redirect_uri(app),
         "state" => "a_state"
       }
 
         "state" => "a_state"
       }
 
-      with_mock Pleroma.Web.Auth.Authenticator,
-        get_registration: fn _ -> {:ok, registration} end do
-        conn =
-          get(
-            conn,
-            "/oauth/twitter/callback",
-            %{
-              "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
-              "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
-              "provider" => "twitter",
-              "state" => Poison.encode!(state_params)
-            }
-          )
+      conn =
+        conn
+        |> assign(:ueberauth_auth, %{
+          provider: "twitter",
+          uid: "171799000",
+          info: %{nickname: user.nickname, email: user.email, name: user.name, description: nil}
+        })
+        |> get(
+          "/oauth/twitter/callback",
+          %{
+            "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
+            "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
+            "provider" => "twitter",
+            "state" => Poison.encode!(state_params)
+          }
+        )
 
 
-        assert response = html_response(conn, 200)
-        assert response =~ ~r/name="op" type="submit" value="register"/
-        assert response =~ ~r/name="op" type="submit" value="connect"/
-        assert response =~ Registration.email(registration)
-        assert response =~ Registration.nickname(registration)
-      end
+      assert response = html_response(conn, 200)
+      assert response =~ ~r/name="op" type="submit" value="register"/
+      assert response =~ ~r/name="op" type="submit" value="connect"/
+      assert response =~ user.email
+      assert response =~ user.nickname
     end
 
     test "on authentication error, GET /oauth/<provider>/callback redirects to `redirect_uri`", %{
     end
 
     test "on authentication error, GET /oauth/<provider>/callback redirects to `redirect_uri`", %{
@@ -165,7 +160,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
       state_params = %{
         "scope" => Enum.join(app.scopes, " "),
         "client_id" => app.client_id,
       state_params = %{
         "scope" => Enum.join(app.scopes, " "),
         "client_id" => app.client_id,
-        "redirect_uri" => app.redirect_uris,
+        "redirect_uri" => OAuthController.default_redirect_uri(app),
         "state" => ""
       }
 
         "state" => ""
       }
 
@@ -199,7 +194,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "authorization" => %{
               "scopes" => app.scopes,
               "client_id" => app.client_id,
             "authorization" => %{
               "scopes" => app.scopes,
               "client_id" => app.client_id,
-              "redirect_uri" => app.redirect_uris,
+              "redirect_uri" => OAuthController.default_redirect_uri(app),
               "state" => "a_state",
               "nickname" => nil,
               "email" => "john@doe.com"
               "state" => "a_state",
               "nickname" => nil,
               "email" => "john@doe.com"
@@ -218,6 +213,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
            conn: conn
          } do
       registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
            conn: conn
          } do
       registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
+      redirect_uri = OAuthController.default_redirect_uri(app)
 
       conn =
         conn
 
       conn =
         conn
@@ -229,7 +225,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "authorization" => %{
               "scopes" => app.scopes,
               "client_id" => app.client_id,
             "authorization" => %{
               "scopes" => app.scopes,
               "client_id" => app.client_id,
-              "redirect_uri" => app.redirect_uris,
+              "redirect_uri" => redirect_uri,
               "state" => "a_state",
               "nickname" => "availablenick",
               "email" => "available@email.com"
               "state" => "a_state",
               "nickname" => "availablenick",
               "email" => "available@email.com"
@@ -238,7 +234,36 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         )
 
       assert response = html_response(conn, 302)
         )
 
       assert response = html_response(conn, 302)
-      assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+      assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
+    end
+
+    test "with unlisted `redirect_uri`, POST /oauth/register?op=register results in HTTP 401",
+         %{
+           app: app,
+           conn: conn
+         } do
+      registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
+      unlisted_redirect_uri = "http://cross-site-request.com"
+
+      conn =
+        conn
+        |> put_session(:registration_id, registration.id)
+        |> post(
+          "/oauth/register",
+          %{
+            "op" => "register",
+            "authorization" => %{
+              "scopes" => app.scopes,
+              "client_id" => app.client_id,
+              "redirect_uri" => unlisted_redirect_uri,
+              "state" => "a_state",
+              "nickname" => "availablenick",
+              "email" => "available@email.com"
+            }
+          }
+        )
+
+      assert response = html_response(conn, 401)
     end
 
     test "with invalid params, POST /oauth/register?op=register renders registration_details page",
     end
 
     test "with invalid params, POST /oauth/register?op=register renders registration_details page",
@@ -254,7 +279,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         "authorization" => %{
           "scopes" => app.scopes,
           "client_id" => app.client_id,
         "authorization" => %{
           "scopes" => app.scopes,
           "client_id" => app.client_id,
-          "redirect_uri" => app.redirect_uris,
+          "redirect_uri" => OAuthController.default_redirect_uri(app),
           "state" => "a_state",
           "nickname" => "availablenickname",
           "email" => "available@email.com"
           "state" => "a_state",
           "nickname" => "availablenickname",
           "email" => "available@email.com"
@@ -286,6 +311,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
          } do
       user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
       registration = insert(:registration, user: nil)
          } do
       user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
       registration = insert(:registration, user: nil)
+      redirect_uri = OAuthController.default_redirect_uri(app)
 
       conn =
         conn
 
       conn =
         conn
@@ -297,7 +323,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "authorization" => %{
               "scopes" => app.scopes,
               "client_id" => app.client_id,
             "authorization" => %{
               "scopes" => app.scopes,
               "client_id" => app.client_id,
-              "redirect_uri" => app.redirect_uris,
+              "redirect_uri" => redirect_uri,
               "state" => "a_state",
               "name" => user.nickname,
               "password" => "testpassword"
               "state" => "a_state",
               "name" => user.nickname,
               "password" => "testpassword"
@@ -306,7 +332,37 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         )
 
       assert response = html_response(conn, 302)
         )
 
       assert response = html_response(conn, 302)
-      assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+      assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
+    end
+
+    test "with unlisted `redirect_uri`, POST /oauth/register?op=connect results in HTTP 401`",
+         %{
+           app: app,
+           conn: conn
+         } do
+      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
+      registration = insert(:registration, user: nil)
+      unlisted_redirect_uri = "http://cross-site-request.com"
+
+      conn =
+        conn
+        |> put_session(:registration_id, registration.id)
+        |> post(
+          "/oauth/register",
+          %{
+            "op" => "connect",
+            "authorization" => %{
+              "scopes" => app.scopes,
+              "client_id" => app.client_id,
+              "redirect_uri" => unlisted_redirect_uri,
+              "state" => "a_state",
+              "name" => user.nickname,
+              "password" => "testpassword"
+            }
+          }
+        )
+
+      assert response = html_response(conn, 401)
     end
 
     test "with invalid params, POST /oauth/register?op=connect renders registration_details page",
     end
 
     test "with invalid params, POST /oauth/register?op=connect renders registration_details page",
@@ -322,7 +378,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         "authorization" => %{
           "scopes" => app.scopes,
           "client_id" => app.client_id,
         "authorization" => %{
           "scopes" => app.scopes,
           "client_id" => app.client_id,
-          "redirect_uri" => app.redirect_uris,
+          "redirect_uri" => OAuthController.default_redirect_uri(app),
           "state" => "a_state",
           "name" => user.nickname,
           "password" => "wrong password"
           "state" => "a_state",
           "name" => user.nickname,
           "password" => "wrong password"
@@ -358,7 +414,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => OAuthController.default_redirect_uri(app),
             "scope" => "read"
           }
         )
             "scope" => "read"
           }
         )
@@ -378,7 +434,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "authorization" => %{
               "response_type" => "code",
               "client_id" => app.client_id,
             "authorization" => %{
               "response_type" => "code",
               "client_id" => app.client_id,
-              "redirect_uri" => app.redirect_uris,
+              "redirect_uri" => OAuthController.default_redirect_uri(app),
               "scope" => "read"
             }
           }
               "scope" => "read"
             }
           }
@@ -389,7 +445,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
     test "renders authentication page if user is already authenticated but `force_login` is tru-ish",
          %{app: app, conn: conn} do
 
     test "renders authentication page if user is already authenticated but `force_login` is tru-ish",
          %{app: app, conn: conn} do
-      token = insert(:oauth_token, app_id: app.id)
+      token = insert(:oauth_token, app: app)
 
       conn =
         conn
 
       conn =
         conn
@@ -399,7 +455,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => OAuthController.default_redirect_uri(app),
             "scope" => "read",
             "force_login" => "true"
           }
             "scope" => "read",
             "force_login" => "true"
           }
@@ -408,8 +464,35 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
       assert html_response(conn, 200) =~ ~s(type="submit")
     end
 
       assert html_response(conn, 200) =~ ~s(type="submit")
     end
 
-    test "redirects to app if user is already authenticated", %{app: app, conn: conn} do
-      token = insert(:oauth_token, app_id: app.id)
+    test "renders authentication page if user is already authenticated but user request with another client",
+         %{
+           app: app,
+           conn: conn
+         } do
+      token = insert(:oauth_token, app: app)
+
+      conn =
+        conn
+        |> put_session(:oauth_token, token.token)
+        |> get(
+          "/oauth/authorize",
+          %{
+            "response_type" => "code",
+            "client_id" => "another_client_id",
+            "redirect_uri" => OAuthController.default_redirect_uri(app),
+            "scope" => "read"
+          }
+        )
+
+      assert html_response(conn, 200) =~ ~s(type="submit")
+    end
+
+    test "with existing authentication and non-OOB `redirect_uri`, redirects to app with `token` and `state` params",
+         %{
+           app: app,
+           conn: conn
+         } do
+      token = insert(:oauth_token, app: app)
 
       conn =
         conn
 
       conn =
         conn
@@ -419,47 +502,112 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
           %{
             "response_type" => "code",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => OAuthController.default_redirect_uri(app),
+            "state" => "specific_client_state",
             "scope" => "read"
           }
         )
 
             "scope" => "read"
           }
         )
 
-      assert redirected_to(conn) == "https://redirect.url"
+      assert URI.decode(redirected_to(conn)) ==
+               "https://redirect.url?access_token=#{token.token}&state=specific_client_state"
     end
     end
-  end
 
 
-  describe "POST /oauth/authorize" do
-    test "redirects with oauth authorization" do
-      user = insert(:user)
-      app = insert(:oauth_app, scopes: ["read", "write", "follow"])
+    test "with existing authentication and unlisted non-OOB `redirect_uri`, redirects without credentials",
+         %{
+           app: app,
+           conn: conn
+         } do
+      unlisted_redirect_uri = "http://cross-site-request.com"
+      token = insert(:oauth_token, app: app)
 
       conn =
 
       conn =
-        build_conn()
-        |> post("/oauth/authorize", %{
-          "authorization" => %{
-            "name" => user.nickname,
-            "password" => "test",
+        conn
+        |> put_session(:oauth_token, token.token)
+        |> get(
+          "/oauth/authorize",
+          %{
+            "response_type" => "code",
             "client_id" => app.client_id,
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
-            "scope" => "read write",
-            "state" => "statepassed"
+            "redirect_uri" => unlisted_redirect_uri,
+            "state" => "specific_client_state",
+            "scope" => "read"
           }
           }
-        })
+        )
 
 
-      target = redirected_to(conn)
-      assert target =~ app.redirect_uris
+      assert redirected_to(conn) == unlisted_redirect_uri
+    end
 
 
-      query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+    test "with existing authentication and OOB `redirect_uri`, redirects to app with `token` and `state` params",
+         %{
+           app: app,
+           conn: conn
+         } do
+      token = insert(:oauth_token, app: app)
 
 
-      assert %{"state" => "statepassed", "code" => code} = query
-      auth = Repo.get_by(Authorization, token: code)
-      assert auth
-      assert auth.scopes == ["read", "write"]
+      conn =
+        conn
+        |> put_session(:oauth_token, token.token)
+        |> get(
+          "/oauth/authorize",
+          %{
+            "response_type" => "code",
+            "client_id" => app.client_id,
+            "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
+            "scope" => "read"
+          }
+        )
+
+      assert html_response(conn, 200) =~ "Authorization exists"
+    end
+  end
+
+  describe "POST /oauth/authorize" do
+    test "redirects with oauth authorization, " <>
+           "granting requested app-supported scopes to both admin- and non-admin users" do
+      app_scopes = ["read", "write", "admin", "secret_scope"]
+      app = insert(:oauth_app, scopes: app_scopes)
+      redirect_uri = OAuthController.default_redirect_uri(app)
+
+      non_admin = insert(:user, is_admin: false)
+      admin = insert(:user, is_admin: true)
+      scopes_subset = ["read:subscope", "write", "admin"]
+
+      # In case scope param is missing, expecting _all_ app-supported scopes to be granted
+      for user <- [non_admin, admin],
+          {requested_scopes, expected_scopes} <-
+            %{scopes_subset => scopes_subset, nil => app_scopes} do
+        conn =
+          post(
+            build_conn(),
+            "/oauth/authorize",
+            %{
+              "authorization" => %{
+                "name" => user.nickname,
+                "password" => "test",
+                "client_id" => app.client_id,
+                "redirect_uri" => redirect_uri,
+                "scope" => requested_scopes,
+                "state" => "statepassed"
+              }
+            }
+          )
+
+        target = redirected_to(conn)
+        assert target =~ redirect_uri
+
+        query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+
+        assert %{"state" => "statepassed", "code" => code} = query
+        auth = Repo.get_by(Authorization, token: code)
+        assert auth
+        assert auth.scopes == expected_scopes
+      end
     end
 
     test "returns 401 for wrong credentials", %{conn: conn} do
       user = insert(:user)
       app = insert(:oauth_app)
     end
 
     test "returns 401 for wrong credentials", %{conn: conn} do
       user = insert(:user)
       app = insert(:oauth_app)
+      redirect_uri = OAuthController.default_redirect_uri(app)
 
       result =
         conn
 
       result =
         conn
@@ -468,7 +616,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "name" => user.nickname,
             "password" => "wrong",
             "client_id" => app.client_id,
             "name" => user.nickname,
             "password" => "wrong",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => redirect_uri,
             "state" => "statepassed",
             "scope" => Enum.join(app.scopes, " ")
           }
             "state" => "statepassed",
             "scope" => Enum.join(app.scopes, " ")
           }
@@ -477,24 +625,25 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
       # Keep the details
       assert result =~ app.client_id
 
       # Keep the details
       assert result =~ app.client_id
-      assert result =~ app.redirect_uris
+      assert result =~ redirect_uri
 
       # Error message
       assert result =~ "Invalid Username/Password"
     end
 
 
       # Error message
       assert result =~ "Invalid Username/Password"
     end
 
-    test "returns 401 for missing scopes", %{conn: conn} do
-      user = insert(:user)
-      app = insert(:oauth_app)
+    test "returns 401 for missing scopes" do
+      user = insert(:user, is_admin: false)
+      app = insert(:oauth_app, scopes: ["read", "write", "admin"])
+      redirect_uri = OAuthController.default_redirect_uri(app)
 
       result =
 
       result =
-        conn
+        build_conn()
         |> post("/oauth/authorize", %{
           "authorization" => %{
             "name" => user.nickname,
             "password" => "test",
             "client_id" => app.client_id,
         |> post("/oauth/authorize", %{
           "authorization" => %{
             "name" => user.nickname,
             "password" => "test",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => redirect_uri,
             "state" => "statepassed",
             "scope" => ""
           }
             "state" => "statepassed",
             "scope" => ""
           }
@@ -503,15 +652,16 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
       # Keep the details
       assert result =~ app.client_id
 
       # Keep the details
       assert result =~ app.client_id
-      assert result =~ app.redirect_uris
+      assert result =~ redirect_uri
 
       # Error message
       assert result =~ "This action is outside the authorized scopes"
     end
 
 
       # Error message
       assert result =~ "This action is outside the authorized scopes"
     end
 
-    test "returns 401 for scopes beyond app scopes", %{conn: conn} do
+    test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do
       user = insert(:user)
       app = insert(:oauth_app, scopes: ["read", "write"])
       user = insert(:user)
       app = insert(:oauth_app, scopes: ["read", "write"])
+      redirect_uri = OAuthController.default_redirect_uri(app)
 
       result =
         conn
 
       result =
         conn
@@ -520,7 +670,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
             "name" => user.nickname,
             "password" => "test",
             "client_id" => app.client_id,
             "name" => user.nickname,
             "password" => "test",
             "client_id" => app.client_id,
-            "redirect_uri" => app.redirect_uris,
+            "redirect_uri" => redirect_uri,
             "state" => "statepassed",
             "scope" => "read write follow"
           }
             "state" => "statepassed",
             "scope" => "read write follow"
           }
@@ -529,7 +679,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
       # Keep the details
       assert result =~ app.client_id
 
       # Keep the details
       assert result =~ app.client_id
-      assert result =~ app.redirect_uris
+      assert result =~ redirect_uri
 
       # Error message
       assert result =~ "This action is outside the authorized scopes"
 
       # Error message
       assert result =~ "This action is outside the authorized scopes"
@@ -548,7 +698,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => auth.token,
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => auth.token,
-          "redirect_uri" => app.redirect_uris,
+          "redirect_uri" => OAuthController.default_redirect_uri(app),
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
@@ -602,7 +752,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => auth.token,
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => auth.token,
-          "redirect_uri" => app.redirect_uris
+          "redirect_uri" => OAuthController.default_redirect_uri(app)
         })
 
       assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
         })
 
       assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
@@ -614,6 +764,27 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
       assert token.scopes == ["scope1", "scope2"]
     end
 
       assert token.scopes == ["scope1", "scope2"]
     end
 
+    test "issue a token for client_credentials grant type" do
+      app = insert(:oauth_app, scopes: ["read", "write"])
+
+      conn =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "client_credentials",
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
+
+      assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
+               json_response(conn, 200)
+
+      assert token
+      token_from_db = Repo.get_by(Token, token: token)
+      assert token_from_db
+      assert refresh
+      assert scope == "read write"
+    end
+
     test "rejects token exchange with invalid client credentials" do
       user = insert(:user)
       app = insert(:oauth_app)
     test "rejects token exchange with invalid client credentials" do
       user = insert(:user)
       app = insert(:oauth_app)
@@ -626,7 +797,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => auth.token,
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => auth.token,
-          "redirect_uri" => app.redirect_uris
+          "redirect_uri" => OAuthController.default_redirect_uri(app)
         })
 
       assert resp = json_response(conn, 400)
         })
 
       assert resp = json_response(conn, 400)
@@ -635,24 +806,15 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
     end
 
     test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
     end
 
     test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
-      setting = Pleroma.Config.get([:instance, :account_activation_required])
-
-      unless setting do
-        Pleroma.Config.put([:instance, :account_activation_required], true)
-        on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
-      end
-
+      Pleroma.Config.put([:instance, :account_activation_required], true)
       password = "testpassword"
       password = "testpassword"
-      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
-      info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
 
       {:ok, user} =
 
       {:ok, user} =
-        user
-        |> Ecto.Changeset.change()
-        |> Ecto.Changeset.put_embed(:info, info_change)
-        |> Repo.update()
+        insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+        |> User.confirmation_changeset(need_confirmation: true)
+        |> User.update_and_set_cache()
 
 
-      refute Pleroma.User.auth_active?(user)
+      refute Pleroma.User.account_status(user) == :active
 
       app = insert(:oauth_app)
 
 
       app = insert(:oauth_app)
 
@@ -677,12 +839,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
       user =
         insert(:user,
           password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
       user =
         insert(:user,
           password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
-          info: %{deactivated: true}
+          deactivated: true
         )
 
       app = insert(:oauth_app)
 
         )
 
       app = insert(:oauth_app)
 
-      conn =
+      resp =
         build_conn()
         |> post("/oauth/token", %{
           "grant_type" => "password",
         build_conn()
         |> post("/oauth/token", %{
           "grant_type" => "password",
@@ -691,10 +853,69 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
+        |> json_response(403)
 
 
-      assert resp = json_response(conn, 403)
-      assert %{"error" => _} = resp
-      refute Map.has_key?(resp, "access_token")
+      assert resp == %{
+               "error" => "Your account is currently disabled",
+               "identifier" => "account_is_disabled"
+             }
+    end
+
+    test "rejects token exchange for user with password_reset_pending set to true" do
+      password = "testpassword"
+
+      user =
+        insert(:user,
+          password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
+          password_reset_pending: true
+        )
+
+      app = insert(:oauth_app, scopes: ["read", "write"])
+
+      resp =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "password",
+          "username" => user.nickname,
+          "password" => password,
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
+        |> json_response(403)
+
+      assert resp == %{
+               "error" => "Password reset is required",
+               "identifier" => "password_reset_required"
+             }
+    end
+
+    test "rejects token exchange for user with confirmation_pending set to true" do
+      Pleroma.Config.put([:instance, :account_activation_required], true)
+      password = "testpassword"
+
+      user =
+        insert(:user,
+          password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
+          confirmation_pending: true
+        )
+
+      app = insert(:oauth_app, scopes: ["read", "write"])
+
+      resp =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "password",
+          "username" => user.nickname,
+          "password" => password,
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
+        |> json_response(403)
+
+      assert resp == %{
+               "error" => "Your login is missing a confirmed e-mail address",
+               "identifier" => "missing_confirmed_email"
+             }
     end
 
     test "rejects an invalid authorization code" do
     end
 
     test "rejects an invalid authorization code" do
@@ -705,7 +926,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => "Imobviouslyinvalid",
         |> post("/oauth/token", %{
           "grant_type" => "authorization_code",
           "code" => "Imobviouslyinvalid",
-          "redirect_uri" => app.redirect_uris,
+          "redirect_uri" => OAuthController.default_redirect_uri(app),
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
@@ -717,16 +938,10 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
   end
 
   describe "POST /oauth/token - refresh token" do
   end
 
   describe "POST /oauth/token - refresh token" do
-    setup do
-      oauth_token_config = Pleroma.Config.get(@oauth_config_path)
-
-      on_exit(fn ->
-        Pleroma.Config.get(@oauth_config_path, oauth_token_config)
-      end)
-    end
+    setup do: clear_config([:oauth2, :issue_new_refresh_token])
 
     test "issues a new access token with keep fresh token" do
 
     test "issues a new access token with keep fresh token" do
-      Pleroma.Config.put(@oauth_config_path, true)
+      Pleroma.Config.put([:oauth2, :issue_new_refresh_token], true)
       user = insert(:user)
       app = insert(:oauth_app, scopes: ["read", "write"])
 
       user = insert(:user)
       app = insert(:oauth_app, scopes: ["read", "write"])
 
@@ -766,7 +981,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
     end
 
     test "issues a new access token with new fresh token" do
     end
 
     test "issues a new access token with new fresh token" do
-      Pleroma.Config.put(@oauth_config_path, false)
+      Pleroma.Config.put([:oauth2, :issue_new_refresh_token], false)
       user = insert(:user)
       app = insert(:oauth_app, scopes: ["read", "write"])
 
       user = insert(:user)
       app = insert(:oauth_app, scopes: ["read", "write"])