X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Foauth%2Foauth_controller.ex;h=9874bac2319bdc706b9cd6cc348cb0f3243e9af0;hb=218d96a26bf551e0e08c54467975fdc07206084d;hp=4047288995d1b4122f236a5c4ea278eee31a729e;hpb=3e7f2bfc2f4769af3cedea3126fa0b3cab3f2b7b;p=akkoma diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 404728899..9874bac23 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2] - if Pleroma.Config.get([:auth, :oauth_consumer_enabled]), do: plug(Ueberauth) + if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth) plug(:fetch_session) plug(:fetch_flash) @@ -44,78 +44,95 @@ defmodule Pleroma.Web.OAuth.OAuthController do def authorize(conn, params), do: do_authorize(conn, params) - defp do_authorize(conn, params) do - app = Repo.get_by(App, client_id: params["client_id"]) + defp do_authorize(conn, %{"authorization" => auth_attrs}), do: do_authorize(conn, auth_attrs) + + defp do_authorize(conn, auth_attrs) do + app = Repo.get_by(App, client_id: auth_attrs["client_id"]) available_scopes = (app && app.scopes) || [] - scopes = oauth_scopes(params, nil) || available_scopes + scopes = oauth_scopes(auth_attrs, nil) || available_scopes render(conn, Authenticator.auth_template(), %{ - response_type: params["response_type"], - client_id: params["client_id"], + response_type: auth_attrs["response_type"], + client_id: auth_attrs["client_id"], available_scopes: available_scopes, scopes: scopes, - redirect_uri: params["redirect_uri"], - state: params["state"], - params: params + redirect_uri: auth_attrs["redirect_uri"], + state: auth_attrs["state"], + params: auth_attrs }) end def create_authorization( conn, - %{ - "authorization" => %{"redirect_uri" => redirect_uri} = auth_params - } = params, + %{"authorization" => _} = params, opts \\ [] ) do - with {:ok, auth} <- - (opts[:auth] && {:ok, opts[:auth]}) || - do_create_authorization(conn, params, opts[:user]) do - redirect_uri = redirect_uri(conn, redirect_uri) - - cond do - redirect_uri == "urn:ietf:wg:oauth:2.0:oob" -> - render(conn, "results.html", %{ - auth: auth - }) - - true -> - connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?" - url = "#{redirect_uri}#{connector}" - url_params = %{:code => auth.token} - - url_params = - if auth_params["state"] do - Map.put(url_params, :state, auth_params["state"]) - else - url_params - end + with {:ok, auth} <- do_create_authorization(conn, params, opts[:user]) do + after_create_authorization(conn, auth, params) + else + error -> + handle_create_authorization_error(conn, error, params) + end + end - url = "#{url}#{Plug.Conn.Query.encode(url_params)}" + def after_create_authorization(conn, auth, %{ + "authorization" => %{"redirect_uri" => redirect_uri} = auth_attrs + }) do + redirect_uri = redirect_uri(conn, redirect_uri) - redirect(conn, external: url) - end + if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do + render(conn, "results.html", %{ + auth: auth + }) else - {scopes_issue, _} when scopes_issue in [:unsupported_scopes, :missing_scopes] -> - # Per https://github.com/tootsuite/mastodon/blob/ - # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39 - conn - |> put_flash(:error, "This action is outside the authorized scopes") - |> put_status(:unauthorized) - |> authorize(auth_params) + connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?" + url = "#{redirect_uri}#{connector}" + url_params = %{:code => auth.token} - {:auth_active, false} -> - # Per https://github.com/tootsuite/mastodon/blob/ - # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 - conn - |> put_flash(:error, "Your login is missing a confirmed e-mail address") - |> put_status(:forbidden) - |> authorize(auth_params) + url_params = + if auth_attrs["state"] do + Map.put(url_params, :state, auth_attrs["state"]) + else + url_params + end - error -> - Authenticator.handle_error(conn, error) + url = "#{url}#{Plug.Conn.Query.encode(url_params)}" + + redirect(conn, external: url) end end + defp handle_create_authorization_error( + conn, + {scopes_issue, _}, + %{"authorization" => _} = params + ) + when scopes_issue in [:unsupported_scopes, :missing_scopes] do + # Per https://github.com/tootsuite/mastodon/blob/ + # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39 + conn + |> put_flash(:error, "This action is outside the authorized scopes") + |> put_status(:unauthorized) + |> authorize(params) + end + + defp handle_create_authorization_error( + conn, + {:auth_active, false}, + %{"authorization" => _} = params + ) do + # Per https://github.com/tootsuite/mastodon/blob/ + # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 + conn + |> put_flash(:error, "Your login is missing a confirmed e-mail address") + |> put_status(:forbidden) + |> authorize(params) + end + + defp handle_create_authorization_error(conn, error, %{"authorization" => _}) do + Authenticator.handle_error(conn, error) + end + def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do with %App{} = app <- get_app_from_request(conn, params), fixed_token = fix_padding(params["code"]), @@ -146,9 +163,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do conn, %{"grant_type" => "password"} = params ) do - with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn, params)}, + with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)}, %App{} = app <- get_app_from_request(conn, params), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, + {:user_active, true} <- {:user_active, !user.info.deactivated}, scopes <- oauth_scopes(params, app.scopes), [] <- scopes -- app.scopes, true <- Enum.any?(scopes), @@ -172,6 +190,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do |> put_status(:forbidden) |> json(%{error: "Your login is missing a confirmed e-mail address"}) + {:user_active, false} -> + conn + |> put_status(:forbidden) + |> json(%{error: "Your account is currently disabled"}) + _error -> put_status(conn, 400) |> json(%{error: "Invalid credentials"}) @@ -202,22 +225,24 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end - def prepare_request(conn, %{"provider" => provider} = params) do + @doc "Prepares OAuth request to provider for Ueberauth" + def prepare_request(conn, %{"provider" => provider, "authorization" => auth_attrs}) do scope = - oauth_scopes(params, []) + oauth_scopes(auth_attrs, []) |> Enum.join(" ") state = - params + auth_attrs |> Map.delete("scopes") |> Map.put("scope", scope) |> Poison.encode!() params = - params + auth_attrs |> Map.drop(~w(scope scopes client_id redirect_uri)) |> Map.put("state", state) + # Handing the request to Ueberauth redirect(conn, to: o_auth_path(conn, :request, provider, params)) end @@ -247,26 +272,26 @@ defmodule Pleroma.Web.OAuth.OAuthController do def callback(conn, params) do params = callback_params(params) - with {:ok, registration} <- Authenticator.get_registration(conn, params) do + with {:ok, registration} <- Authenticator.get_registration(conn) do user = Repo.preload(registration, :user).user - auth_params = Map.take(params, ~w(client_id redirect_uri scope scopes state)) + auth_attrs = Map.take(params, ~w(client_id redirect_uri scope scopes state)) if user do create_authorization( conn, - %{"authorization" => auth_params}, + %{"authorization" => auth_attrs}, user: user ) else registration_params = - Map.merge(auth_params, %{ + Map.merge(auth_attrs, %{ "nickname" => Registration.nickname(registration), "email" => Registration.email(registration) }) conn |> put_session(:registration_id, registration.id) - |> redirect(to: o_auth_path(conn, :registration_details, registration_params)) + |> registration_details(%{"authorization" => registration_params}) end else _ -> @@ -280,57 +305,44 @@ defmodule Pleroma.Web.OAuth.OAuthController do Map.merge(params, Poison.decode!(state)) end - def registration_details(conn, params) do + def registration_details(conn, %{"authorization" => auth_attrs}) do render(conn, "register.html", %{ - client_id: params["client_id"], - redirect_uri: params["redirect_uri"], - state: params["state"], - scopes: oauth_scopes(params, []), - nickname: params["nickname"], - email: params["email"] + client_id: auth_attrs["client_id"], + redirect_uri: auth_attrs["redirect_uri"], + state: auth_attrs["state"], + scopes: oauth_scopes(auth_attrs, []), + nickname: auth_attrs["nickname"], + email: auth_attrs["email"] }) end - def register(conn, %{"op" => "connect"} = params) do - create_authorization_params = %{ - "authorization" => Map.merge(params, %{"name" => params["auth_name"]}) - } - + def register(conn, %{"authorization" => _, "op" => "connect"} = params) do with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), %Registration{} = registration <- Repo.get(Registration, registration_id), - {:ok, auth} <- do_create_authorization(conn, create_authorization_params), + {_, {:ok, auth}} <- + {:create_authorization, do_create_authorization(conn, params)}, %User{} = user <- Repo.preload(auth, :user).user, {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do conn |> put_session_registration_id(nil) - |> create_authorization( - create_authorization_params, - auth: auth - ) + |> after_create_authorization(auth, params) else - _ -> - params = Map.delete(params, "password") + {:create_authorization, error} -> + {:register, handle_create_authorization_error(conn, error, params)} - conn - |> put_flash(:error, "Unknown error, please try again.") - |> redirect(to: o_auth_path(conn, :registration_details, params)) + _ -> + {:register, :generic_error} end end - def register(conn, params) do + def register(conn, %{"authorization" => _, "op" => "register"} = params) do with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), %Registration{} = registration <- Repo.get(Registration, registration_id), - {:ok, user} <- Authenticator.create_from_registration(conn, params, registration) do + {:ok, user} <- Authenticator.create_from_registration(conn, registration) do conn |> put_session_registration_id(nil) |> create_authorization( - %{ - "authorization" => %{ - "client_id" => params["client_id"], - "redirect_uri" => params["redirect_uri"], - "scopes" => oauth_scopes(params, nil) - } - }, + params, user: user ) else @@ -349,13 +361,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do ) conn + |> put_status(:forbidden) |> put_flash(:error, "Error: #{message}.") - |> redirect(to: o_auth_path(conn, :registration_details, params)) + |> registration_details(params) _ -> - conn - |> put_flash(:error, "Unknown error, please try again.") - |> redirect(to: o_auth_path(conn, :registration_details, params)) + {:register, :generic_error} end end @@ -366,15 +377,15 @@ defmodule Pleroma.Web.OAuth.OAuthController do %{ "client_id" => client_id, "redirect_uri" => redirect_uri - } = auth_params - } = params, + } = auth_attrs + }, user \\ nil ) do with {_, {:ok, %User{} = user}} <- - {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)}, + {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)}, %App{} = app <- Repo.get_by(App, client_id: client_id), true <- redirect_uri in String.split(app.redirect_uris), - scopes <- oauth_scopes(auth_params, []), + scopes <- oauth_scopes(auth_attrs, []), {:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes}, # Note: `scope` param is intentionally not optional in this context {:missing_scopes, false} <- {:missing_scopes, scopes == []},