alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Web.Auth.Authenticator
- alias Pleroma.Web.ControllerHelper
+ alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.MFAController
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
alias Pleroma.Web.Plugs.RateLimiter
+ alias Pleroma.Web.Utils.Params
require Logger
plug(:fetch_session)
plug(:fetch_flash)
- plug(:skip_plug, [
- Pleroma.Web.Plugs.OAuthScopesPlug,
- Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
- ])
+ plug(:skip_auth)
plug(RateLimiter, [name: :authentication] when action == :create_authorization)
end
def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, %{"force_login" => _} = params) do
- if ControllerHelper.truthy_param?(params["force_login"]) do
+ if Params.truthy_param?(params["force_login"]) do
do_authorize(conn, params)
else
handle_existing_authorization(conn, params)
# after user already authorized to MastodonFE.
# So we have to check client and token.
def authorize(
- %Plug.Conn{assigns: %{token: %Token{} = token}} = conn,
+ %Plug.Conn{assigns: %{token: %Token{} = token, user: %User{} = user}} = conn,
%{"client_id" => client_id} = params
) do
with %Token{} = t <- Repo.get_by(Token, token: token.token) |> Repo.preload(:app),
^client_id <- t.app.client_id do
handle_existing_authorization(conn, params)
+ else
+ _ ->
+ maybe_reuse_token(conn, params, user.id)
+ end
+ end
+
+ def authorize(%Plug.Conn{} = conn, params) do
+ # if we have a user in the session, attempt to authenticate as them
+ # otherwise show the login form
+ maybe_reuse_token(conn, params, AuthHelper.get_session_user(conn))
+ end
+
+ defp maybe_reuse_token(conn, params, user_id) when is_binary(user_id) do
+ with %User{} = user <- User.get_cached_by_id(user_id),
+ %App{} = app <- Repo.get_by(App, client_id: params["client_id"]),
+ {:ok, %Token{} = token} <- Token.get_preeexisting_by_app_and_user(app, user),
+ {:ok, %Authorization{} = auth} <-
+ Authorization.get_preeexisting_by_app_and_user(app, user) do
+ conn
+ |> assign(:token, token)
+ |> after_create_authorization(auth, %{"authorization" => params})
else
_ -> do_authorize(conn, params)
end
end
- def authorize(%Plug.Conn{} = conn, params), do: do_authorize(conn, params)
+ defp maybe_reuse_token(conn, params, _user), do: do_authorize(conn, params)
defp do_authorize(%Plug.Conn{} = conn, params) do
app = Repo.get_by(App, client_id: params["client_id"])
scopes: scopes,
redirect_uri: params["redirect_uri"],
state: params["state"],
- params: params
+ params: params,
+ view_module: OAuthView
})
end
def create_authorization(%Plug.Conn{} = conn, %{"authorization" => _} = params, opts) do
with {:ok, auth, user} <- do_create_authorization(conn, params, opts[:user]),
{:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)} do
- after_create_authorization(conn, auth, params)
+ conn
+ |> AuthHelper.put_session_user(user.id)
+ |> after_create_authorization(auth, params)
else
error ->
handle_create_authorization_error(conn, error, params)
# Enforcing the view to reuse the template when calling from other controllers
conn
|> put_view(OAuthView)
- |> render("oob_authorization_created.html", %{auth: auth})
+ |> render("oob_authorization_created.html", %{auth: auth, view_module: OAuthView})
end
def after_create_authorization(%Plug.Conn{} = conn, %Authorization{} = auth, %{
fixed_token = Token.Utils.fix_padding(params["code"]),
{:ok, auth} <- Authorization.get_by_token(app, fixed_token),
%User{} = user <- User.get_cached_by_id(auth.user_id),
- {:ok, token} <- Token.exchange_token(app, auth) do
+ {:ok, token} <- Token.get_or_exchange_token(auth, app, user) do
after_token_exchange(conn, %{user: user, token: token})
else
error ->
def after_token_exchange(%Plug.Conn{} = conn, %{token: token} = view_params) do
conn
|> AuthHelper.put_session_token(token.token)
+ |> AuthHelper.put_session_user(token.user_id)
|> json(OAuthView.render("token.json", view_params))
end
|> Map.put("state", state)
# Handing the request to Ueberauth
- redirect(conn, to: o_auth_path(conn, :request, provider, params))
+ redirect(conn, to: Routes.o_auth_path(conn, :request, provider, params))
end
def request(%Plug.Conn{} = conn, params) do
end
# Special case: Local MastodonFE
- defp redirect_uri(%Plug.Conn{} = conn, "."), do: auth_url(conn, :login)
+ defp redirect_uri(%Plug.Conn{} = conn, "."), do: Routes.auth_url(conn, :login)
defp redirect_uri(%Plug.Conn{}, redirect_uri), do: redirect_uri