forked from AkkomaGang/akkoma
[#923] OAuth consumer params handling refactoring.
Registration and authorization-related params are wrapped in "authorization" in order to reduce edge cases number and simplify handling logic.
This commit is contained in:
parent
e5d553aa45
commit
c3f12cf3c3
10 changed files with 153 additions and 138 deletions
|
@ -13,21 +13,21 @@ def implementation do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()}
|
@callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
|
||||||
def get_user(plug, params), do: implementation().get_user(plug, params)
|
def get_user(plug), do: implementation().get_user(plug)
|
||||||
|
|
||||||
@callback create_from_registration(Plug.Conn.t(), Map.t(), Registration.t()) ::
|
@callback create_from_registration(Plug.Conn.t(), Registration.t()) ::
|
||||||
{:ok, User.t()} | {:error, any()}
|
{:ok, User.t()} | {:error, any()}
|
||||||
def create_from_registration(plug, params, registration),
|
def create_from_registration(plug, registration),
|
||||||
do: implementation().create_from_registration(plug, params, registration)
|
do: implementation().create_from_registration(plug, registration)
|
||||||
|
|
||||||
@callback get_registration(Plug.Conn.t(), Map.t()) ::
|
@callback get_registration(Plug.Conn.t()) ::
|
||||||
{:ok, Registration.t()} | {:error, any()}
|
{:ok, Registration.t()} | {:error, any()}
|
||||||
def get_registration(plug, params),
|
def get_registration(plug), do: implementation().get_registration(plug)
|
||||||
do: implementation().get_registration(plug, params)
|
|
||||||
|
|
||||||
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
||||||
def handle_error(plug, error), do: implementation().handle_error(plug, error)
|
def handle_error(plug, error),
|
||||||
|
do: implementation().handle_error(plug, error)
|
||||||
|
|
||||||
@callback auth_template() :: String.t() | nil
|
@callback auth_template() :: String.t() | nil
|
||||||
def auth_template do
|
def auth_template do
|
||||||
|
|
|
@ -13,14 +13,16 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
|
||||||
@connection_timeout 10_000
|
@connection_timeout 10_000
|
||||||
@search_timeout 10_000
|
@search_timeout 10_000
|
||||||
|
|
||||||
defdelegate get_registration(conn, params), to: @base
|
defdelegate get_registration(conn), to: @base
|
||||||
|
defdelegate create_from_registration(conn, registration), to: @base
|
||||||
|
defdelegate handle_error(conn, error), to: @base
|
||||||
|
defdelegate auth_template, to: @base
|
||||||
|
defdelegate oauth_consumer_template, to: @base
|
||||||
|
|
||||||
defdelegate create_from_registration(conn, params, registration), to: @base
|
def get_user(%Plug.Conn{} = conn) do
|
||||||
|
|
||||||
def get_user(%Plug.Conn{} = conn, params) do
|
|
||||||
if Pleroma.Config.get([:ldap, :enabled]) do
|
if Pleroma.Config.get([:ldap, :enabled]) do
|
||||||
{name, password} =
|
{name, password} =
|
||||||
case params do
|
case conn.params do
|
||||||
%{"authorization" => %{"name" => name, "password" => password}} ->
|
%{"authorization" => %{"name" => name, "password" => password}} ->
|
||||||
{name, password}
|
{name, password}
|
||||||
|
|
||||||
|
@ -34,25 +36,17 @@ def get_user(%Plug.Conn{} = conn, params) do
|
||||||
|
|
||||||
{:error, {:ldap_connection_error, _}} ->
|
{:error, {:ldap_connection_error, _}} ->
|
||||||
# When LDAP is unavailable, try default authenticator
|
# When LDAP is unavailable, try default authenticator
|
||||||
@base.get_user(conn, params)
|
@base.get_user(conn)
|
||||||
|
|
||||||
error ->
|
error ->
|
||||||
error
|
error
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# Fall back to default authenticator
|
# Fall back to default authenticator
|
||||||
@base.get_user(conn, params)
|
@base.get_user(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_error(%Plug.Conn{} = _conn, error) do
|
|
||||||
error
|
|
||||||
end
|
|
||||||
|
|
||||||
def auth_template, do: nil
|
|
||||||
|
|
||||||
def oauth_consumer_template, do: nil
|
|
||||||
|
|
||||||
defp ldap_user(name, password) do
|
defp ldap_user(name, password) do
|
||||||
ldap = Pleroma.Config.get(:ldap, [])
|
ldap = Pleroma.Config.get(:ldap, [])
|
||||||
host = Keyword.get(ldap, :host, "localhost")
|
host = Keyword.get(ldap, :host, "localhost")
|
||||||
|
|
|
@ -10,9 +10,9 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
||||||
|
|
||||||
@behaviour Pleroma.Web.Auth.Authenticator
|
@behaviour Pleroma.Web.Auth.Authenticator
|
||||||
|
|
||||||
def get_user(%Plug.Conn{} = _conn, params) do
|
def get_user(%Plug.Conn{} = conn) do
|
||||||
{name, password} =
|
{name, password} =
|
||||||
case params do
|
case conn.params do
|
||||||
%{"authorization" => %{"name" => name, "password" => password}} ->
|
%{"authorization" => %{"name" => name, "password" => password}} ->
|
||||||
{name, password}
|
{name, password}
|
||||||
|
|
||||||
|
@ -29,10 +29,9 @@ def get_user(%Plug.Conn{} = _conn, params) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_registration(
|
def get_registration(%Plug.Conn{
|
||||||
%Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}},
|
assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}
|
||||||
_params
|
}) do
|
||||||
) do
|
|
||||||
registration = Registration.get_by_provider_uid(provider, uid)
|
registration = Registration.get_by_provider_uid(provider, uid)
|
||||||
|
|
||||||
if registration do
|
if registration do
|
||||||
|
@ -40,7 +39,8 @@ def get_registration(
|
||||||
else
|
else
|
||||||
info = auth.info
|
info = auth.info
|
||||||
|
|
||||||
Registration.changeset(%Registration{}, %{
|
%Registration{}
|
||||||
|
|> Registration.changeset(%{
|
||||||
provider: to_string(provider),
|
provider: to_string(provider),
|
||||||
uid: to_string(uid),
|
uid: to_string(uid),
|
||||||
info: %{
|
info: %{
|
||||||
|
@ -54,13 +54,16 @@ def get_registration(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_registration(%Plug.Conn{} = _conn, _params), do: {:error, :missing_credentials}
|
def get_registration(%Plug.Conn{} = _conn), do: {:error, :missing_credentials}
|
||||||
|
|
||||||
def create_from_registration(_conn, params, registration) do
|
def create_from_registration(
|
||||||
nickname = value([params["nickname"], Registration.nickname(registration)])
|
%Plug.Conn{params: %{"authorization" => registration_attrs}},
|
||||||
email = value([params["email"], Registration.email(registration)])
|
registration
|
||||||
name = value([params["name"], Registration.name(registration)]) || nickname
|
) do
|
||||||
bio = value([params["bio"], Registration.description(registration)])
|
nickname = value([registration_attrs["nickname"], Registration.nickname(registration)])
|
||||||
|
email = value([registration_attrs["email"], Registration.email(registration)])
|
||||||
|
name = value([registration_attrs["name"], Registration.name(registration)]) || nickname
|
||||||
|
bio = value([registration_attrs["bio"], Registration.description(registration)])
|
||||||
|
|
||||||
random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
|
random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,6 @@ def call(conn, _error) do
|
||||||
conn
|
conn
|
||||||
|> put_status(:unauthorized)
|
|> put_status(:unauthorized)
|
||||||
|> put_flash(:error, "Invalid Username/Password")
|
|> put_flash(:error, "Invalid Username/Password")
|
||||||
|> OAuthController.authorize(conn.params["authorization"])
|
|> OAuthController.authorize(conn.params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,36 +44,40 @@ def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do
|
||||||
|
|
||||||
def authorize(conn, params), do: do_authorize(conn, params)
|
def authorize(conn, params), do: do_authorize(conn, params)
|
||||||
|
|
||||||
defp do_authorize(conn, params) do
|
defp do_authorize(conn, %{"authorization" => auth_attrs}) do
|
||||||
app = Repo.get_by(App, client_id: params["client_id"])
|
app = Repo.get_by(App, client_id: auth_attrs["client_id"])
|
||||||
available_scopes = (app && app.scopes) || []
|
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(), %{
|
render(conn, Authenticator.auth_template(), %{
|
||||||
response_type: params["response_type"],
|
response_type: auth_attrs["response_type"],
|
||||||
client_id: params["client_id"],
|
client_id: auth_attrs["client_id"],
|
||||||
available_scopes: available_scopes,
|
available_scopes: available_scopes,
|
||||||
scopes: scopes,
|
scopes: scopes,
|
||||||
redirect_uri: params["redirect_uri"],
|
redirect_uri: auth_attrs["redirect_uri"],
|
||||||
state: params["state"],
|
state: auth_attrs["state"],
|
||||||
params: params
|
params: auth_attrs
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp do_authorize(conn, auth_attrs), do: do_authorize(conn, %{"authorization" => auth_attrs})
|
||||||
|
|
||||||
def create_authorization(
|
def create_authorization(
|
||||||
conn,
|
conn,
|
||||||
%{"authorization" => auth_params} = params,
|
%{"authorization" => _} = params,
|
||||||
opts \\ []
|
opts \\ []
|
||||||
) do
|
) do
|
||||||
with {:ok, auth} <- do_create_authorization(conn, params, opts[:user]) do
|
with {:ok, auth} <- do_create_authorization(conn, params, opts[:user]) do
|
||||||
after_create_authorization(conn, auth, auth_params)
|
after_create_authorization(conn, auth, params)
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
handle_create_authorization_error(conn, error, auth_params)
|
handle_create_authorization_error(conn, error, params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_create_authorization(conn, auth, %{"redirect_uri" => redirect_uri} = auth_params) do
|
def after_create_authorization(conn, auth, %{
|
||||||
|
"authorization" => %{"redirect_uri" => redirect_uri} = auth_attrs
|
||||||
|
}) do
|
||||||
redirect_uri = redirect_uri(conn, redirect_uri)
|
redirect_uri = redirect_uri(conn, redirect_uri)
|
||||||
|
|
||||||
if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do
|
if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do
|
||||||
|
@ -86,8 +90,8 @@ def after_create_authorization(conn, auth, %{"redirect_uri" => redirect_uri} = a
|
||||||
url_params = %{:code => auth.token}
|
url_params = %{:code => auth.token}
|
||||||
|
|
||||||
url_params =
|
url_params =
|
||||||
if auth_params["state"] do
|
if auth_attrs["state"] do
|
||||||
Map.put(url_params, :state, auth_params["state"])
|
Map.put(url_params, :state, auth_attrs["state"])
|
||||||
else
|
else
|
||||||
url_params
|
url_params
|
||||||
end
|
end
|
||||||
|
@ -98,26 +102,34 @@ def after_create_authorization(conn, auth, %{"redirect_uri" => redirect_uri} = a
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_create_authorization_error(conn, {scopes_issue, _}, auth_params)
|
defp handle_create_authorization_error(
|
||||||
|
conn,
|
||||||
|
{scopes_issue, _},
|
||||||
|
%{"authorization" => _} = params
|
||||||
|
)
|
||||||
when scopes_issue in [:unsupported_scopes, :missing_scopes] do
|
when scopes_issue in [:unsupported_scopes, :missing_scopes] do
|
||||||
# Per https://github.com/tootsuite/mastodon/blob/
|
# Per https://github.com/tootsuite/mastodon/blob/
|
||||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39
|
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39
|
||||||
conn
|
conn
|
||||||
|> put_flash(:error, "This action is outside the authorized scopes")
|
|> put_flash(:error, "This action is outside the authorized scopes")
|
||||||
|> put_status(:unauthorized)
|
|> put_status(:unauthorized)
|
||||||
|> authorize(auth_params)
|
|> authorize(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_create_authorization_error(conn, {:auth_active, false}, auth_params) do
|
defp handle_create_authorization_error(
|
||||||
|
conn,
|
||||||
|
{:auth_active, false},
|
||||||
|
%{"authorization" => _} = params
|
||||||
|
) do
|
||||||
# Per https://github.com/tootsuite/mastodon/blob/
|
# Per https://github.com/tootsuite/mastodon/blob/
|
||||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
|
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
|
||||||
conn
|
conn
|
||||||
|> put_flash(:error, "Your login is missing a confirmed e-mail address")
|
|> put_flash(:error, "Your login is missing a confirmed e-mail address")
|
||||||
|> put_status(:forbidden)
|
|> put_status(:forbidden)
|
||||||
|> authorize(auth_params)
|
|> authorize(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_create_authorization_error(conn, error, _auth_params) do
|
defp handle_create_authorization_error(conn, error, %{"authorization" => _}) do
|
||||||
Authenticator.handle_error(conn, error)
|
Authenticator.handle_error(conn, error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -151,7 +163,7 @@ def token_exchange(
|
||||||
conn,
|
conn,
|
||||||
%{"grant_type" => "password"} = params
|
%{"grant_type" => "password"} = params
|
||||||
) do
|
) 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),
|
%App{} = app <- get_app_from_request(conn, params),
|
||||||
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
|
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
|
||||||
{:user_active, true} <- {:user_active, !user.info.deactivated},
|
{:user_active, true} <- {:user_active, !user.info.deactivated},
|
||||||
|
@ -214,19 +226,19 @@ def token_revoke(conn, %{"token" => token} = params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Prepares OAuth request to provider for Ueberauth"
|
@doc "Prepares OAuth request to provider for Ueberauth"
|
||||||
def prepare_request(conn, %{"provider" => provider} = params) do
|
def prepare_request(conn, %{"provider" => provider, "authorization" => auth_attrs}) do
|
||||||
scope =
|
scope =
|
||||||
oauth_scopes(params, [])
|
oauth_scopes(auth_attrs, [])
|
||||||
|> Enum.join(" ")
|
|> Enum.join(" ")
|
||||||
|
|
||||||
state =
|
state =
|
||||||
params
|
auth_attrs
|
||||||
|> Map.delete("scopes")
|
|> Map.delete("scopes")
|
||||||
|> Map.put("scope", scope)
|
|> Map.put("scope", scope)
|
||||||
|> Poison.encode!()
|
|> Poison.encode!()
|
||||||
|
|
||||||
params =
|
params =
|
||||||
params
|
auth_attrs
|
||||||
|> Map.drop(~w(scope scopes client_id redirect_uri))
|
|> Map.drop(~w(scope scopes client_id redirect_uri))
|
||||||
|> Map.put("state", state)
|
|> Map.put("state", state)
|
||||||
|
|
||||||
|
@ -260,26 +272,26 @@ def callback(%{assigns: %{ueberauth_failure: failure}} = conn, params) do
|
||||||
def callback(conn, params) do
|
def callback(conn, params) do
|
||||||
params = callback_params(params)
|
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
|
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
|
if user do
|
||||||
create_authorization(
|
create_authorization(
|
||||||
conn,
|
conn,
|
||||||
%{"authorization" => auth_params},
|
%{"authorization" => auth_attrs},
|
||||||
user: user
|
user: user
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
registration_params =
|
registration_params =
|
||||||
Map.merge(auth_params, %{
|
Map.merge(auth_attrs, %{
|
||||||
"nickname" => Registration.nickname(registration),
|
"nickname" => Registration.nickname(registration),
|
||||||
"email" => Registration.email(registration)
|
"email" => Registration.email(registration)
|
||||||
})
|
})
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_session(:registration_id, registration.id)
|
|> put_session(:registration_id, registration.id)
|
||||||
|> registration_details(registration_params)
|
|> registration_details(%{"authorization" => registration_params})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -293,53 +305,44 @@ defp callback_params(%{"state" => state} = params) do
|
||||||
Map.merge(params, Poison.decode!(state))
|
Map.merge(params, Poison.decode!(state))
|
||||||
end
|
end
|
||||||
|
|
||||||
def registration_details(conn, params) do
|
def registration_details(conn, %{"authorization" => auth_attrs}) do
|
||||||
render(conn, "register.html", %{
|
render(conn, "register.html", %{
|
||||||
client_id: params["client_id"],
|
client_id: auth_attrs["client_id"],
|
||||||
redirect_uri: params["redirect_uri"],
|
redirect_uri: auth_attrs["redirect_uri"],
|
||||||
state: params["state"],
|
state: auth_attrs["state"],
|
||||||
scopes: oauth_scopes(params, []),
|
scopes: oauth_scopes(auth_attrs, []),
|
||||||
nickname: params["nickname"],
|
nickname: auth_attrs["nickname"],
|
||||||
email: params["email"]
|
email: auth_attrs["email"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def register(conn, %{"op" => "connect"} = params) do
|
def register(conn, %{"authorization" => _, "op" => "connect"} = params) do
|
||||||
authorization_params = Map.put(params, "name", params["auth_name"])
|
|
||||||
create_authorization_params = %{"authorization" => authorization_params}
|
|
||||||
|
|
||||||
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
|
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
|
||||||
%Registration{} = registration <- Repo.get(Registration, registration_id),
|
%Registration{} = registration <- Repo.get(Registration, registration_id),
|
||||||
{_, {:ok, auth}} <-
|
{_, {:ok, auth}} <-
|
||||||
{:create_authorization, do_create_authorization(conn, create_authorization_params)},
|
{:create_authorization, do_create_authorization(conn, params)},
|
||||||
%User{} = user <- Repo.preload(auth, :user).user,
|
%User{} = user <- Repo.preload(auth, :user).user,
|
||||||
{:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
|
{:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
|
||||||
conn
|
conn
|
||||||
|> put_session_registration_id(nil)
|
|> put_session_registration_id(nil)
|
||||||
|> after_create_authorization(auth, authorization_params)
|
|> after_create_authorization(auth, params)
|
||||||
else
|
else
|
||||||
{:create_authorization, error} ->
|
{:create_authorization, error} ->
|
||||||
{:register, handle_create_authorization_error(conn, error, create_authorization_params)}
|
{:register, handle_create_authorization_error(conn, error, params)}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
{:register, :generic_error}
|
{:register, :generic_error}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def register(conn, %{"op" => "register"} = params) do
|
def register(conn, %{"authorization" => _, "op" => "register"} = params) do
|
||||||
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
|
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
|
||||||
%Registration{} = registration <- Repo.get(Registration, registration_id),
|
%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
|
conn
|
||||||
|> put_session_registration_id(nil)
|
|> put_session_registration_id(nil)
|
||||||
|> create_authorization(
|
|> create_authorization(
|
||||||
%{
|
params,
|
||||||
"authorization" => %{
|
|
||||||
"client_id" => params["client_id"],
|
|
||||||
"redirect_uri" => params["redirect_uri"],
|
|
||||||
"scopes" => oauth_scopes(params, nil)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
user: user
|
user: user
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
@ -374,15 +377,15 @@ defp do_create_authorization(
|
||||||
%{
|
%{
|
||||||
"client_id" => client_id,
|
"client_id" => client_id,
|
||||||
"redirect_uri" => redirect_uri
|
"redirect_uri" => redirect_uri
|
||||||
} = auth_params
|
} = auth_attrs
|
||||||
} = params,
|
},
|
||||||
user \\ nil
|
user \\ nil
|
||||||
) do
|
) do
|
||||||
with {_, {:ok, %User{} = user}} <-
|
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),
|
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
||||||
true <- redirect_uri in String.split(app.redirect_uris),
|
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},
|
{:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes},
|
||||||
# Note: `scope` param is intentionally not optional in this context
|
# Note: `scope` param is intentionally not optional in this context
|
||||||
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
|
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<%= for scope <- @available_scopes do %>
|
<%= for scope <- @available_scopes do %>
|
||||||
<%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
|
<%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: assigns[:scope_param] || "scope[]" %>
|
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
|
||||||
<%= label @form, :"scope_#{scope}", String.capitalize(scope) %>
|
<%= label @form, :"scope_#{scope}", String.capitalize(scope) %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<h2>Sign in with external provider</h2>
|
<h2>Sign in with external provider</h2>
|
||||||
|
|
||||||
<%= form_for @conn, o_auth_path(@conn, :prepare_request), [method: "get"], fn f -> %>
|
<%= form_for @conn, o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %>
|
||||||
<%= render @view_module, "_scopes.html", Map.put(assigns, :form, f) %>
|
<%= render @view_module, "_scopes.html", Map.put(assigns, :form, f) %>
|
||||||
|
|
||||||
<%= hidden_input f, :client_id, value: @client_id %>
|
<%= hidden_input f, :client_id, value: @client_id %>
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
<h2>Registration Details</h2>
|
<h2>Registration Details</h2>
|
||||||
|
|
||||||
<p>If you'd like to register a new account, please provide the details below.</p>
|
<p>If you'd like to register a new account, please provide the details below.</p>
|
||||||
|
<%= form_for @conn, o_auth_path(@conn, :register), [as: "authorization"], fn f -> %>
|
||||||
<%= form_for @conn, o_auth_path(@conn, :register), [], fn f -> %>
|
|
||||||
|
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<%= label f, :nickname, "Nickname" %>
|
<%= label f, :nickname, "Nickname" %>
|
||||||
|
@ -25,8 +24,8 @@
|
||||||
<p>Alternatively, sign in to connect to existing account.</p>
|
<p>Alternatively, sign in to connect to existing account.</p>
|
||||||
|
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<%= label f, :auth_name, "Name or email" %>
|
<%= label f, :name, "Name or email" %>
|
||||||
<%= text_input f, :auth_name %>
|
<%= text_input f, :name %>
|
||||||
</div>
|
</div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<%= label f, :password, "Password" %>
|
<%= label f, :password, "Password" %>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<%= password_input f, :password %>
|
<%= password_input f, :password %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f, scope_param: "authorization[scope][]"}) %>
|
<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>
|
||||||
|
|
||||||
<%= hidden_input f, :client_id, value: @client_id %>
|
<%= hidden_input f, :client_id, value: @client_id %>
|
||||||
<%= hidden_input f, :response_type, value: @response_type %>
|
<%= hidden_input f, :response_type, value: @response_type %>
|
||||||
|
|
|
@ -68,11 +68,13 @@ test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %
|
||||||
"/oauth/prepare_request",
|
"/oauth/prepare_request",
|
||||||
%{
|
%{
|
||||||
"provider" => "twitter",
|
"provider" => "twitter",
|
||||||
|
"authorization" => %{
|
||||||
"scope" => "read follow",
|
"scope" => "read follow",
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"redirect_uri" => app.redirect_uris,
|
"redirect_uri" => app.redirect_uris,
|
||||||
"state" => "a_state"
|
"state" => "a_state"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response = html_response(conn, 302)
|
assert response = html_response(conn, 302)
|
||||||
|
@ -104,7 +106,7 @@ test "with user-bound registration, GET /oauth/<provider>/callback redirects to
|
||||||
}
|
}
|
||||||
|
|
||||||
with_mock Pleroma.Web.Auth.Authenticator,
|
with_mock Pleroma.Web.Auth.Authenticator,
|
||||||
get_registration: fn _, _ -> {:ok, registration} end do
|
get_registration: fn _ -> {:ok, registration} end do
|
||||||
conn =
|
conn =
|
||||||
get(
|
get(
|
||||||
conn,
|
conn,
|
||||||
|
@ -134,7 +136,7 @@ test "with user-unbound registration, GET /oauth/<provider>/callback renders reg
|
||||||
}
|
}
|
||||||
|
|
||||||
with_mock Pleroma.Web.Auth.Authenticator,
|
with_mock Pleroma.Web.Auth.Authenticator,
|
||||||
get_registration: fn _, _ -> {:ok, registration} end do
|
get_registration: fn _ -> {:ok, registration} end do
|
||||||
conn =
|
conn =
|
||||||
get(
|
get(
|
||||||
conn,
|
conn,
|
||||||
|
@ -193,6 +195,7 @@ test "GET /oauth/registration_details renders registration details form", %{
|
||||||
conn,
|
conn,
|
||||||
"/oauth/registration_details",
|
"/oauth/registration_details",
|
||||||
%{
|
%{
|
||||||
|
"authorization" => %{
|
||||||
"scopes" => app.scopes,
|
"scopes" => app.scopes,
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"redirect_uri" => app.redirect_uris,
|
"redirect_uri" => app.redirect_uris,
|
||||||
|
@ -200,6 +203,7 @@ test "GET /oauth/registration_details renders registration details form", %{
|
||||||
"nickname" => nil,
|
"nickname" => nil,
|
||||||
"email" => "john@doe.com"
|
"email" => "john@doe.com"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response = html_response(conn, 200)
|
assert response = html_response(conn, 200)
|
||||||
|
@ -221,6 +225,7 @@ test "with valid params, POST /oauth/register?op=register redirects to `redirect
|
||||||
"/oauth/register",
|
"/oauth/register",
|
||||||
%{
|
%{
|
||||||
"op" => "register",
|
"op" => "register",
|
||||||
|
"authorization" => %{
|
||||||
"scopes" => app.scopes,
|
"scopes" => app.scopes,
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"redirect_uri" => app.redirect_uris,
|
"redirect_uri" => app.redirect_uris,
|
||||||
|
@ -228,6 +233,7 @@ test "with valid params, POST /oauth/register?op=register redirects to `redirect
|
||||||
"nickname" => "availablenick",
|
"nickname" => "availablenick",
|
||||||
"email" => "available@email.com"
|
"email" => "available@email.com"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response = html_response(conn, 302)
|
assert response = html_response(conn, 302)
|
||||||
|
@ -244,6 +250,7 @@ test "with invalid params, POST /oauth/register?op=register renders registration
|
||||||
|
|
||||||
params = %{
|
params = %{
|
||||||
"op" => "register",
|
"op" => "register",
|
||||||
|
"authorization" => %{
|
||||||
"scopes" => app.scopes,
|
"scopes" => app.scopes,
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"redirect_uri" => app.redirect_uris,
|
"redirect_uri" => app.redirect_uris,
|
||||||
|
@ -251,10 +258,15 @@ test "with invalid params, POST /oauth/register?op=register renders registration
|
||||||
"nickname" => "availablenickname",
|
"nickname" => "availablenickname",
|
||||||
"email" => "available@email.com"
|
"email" => "available@email.com"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for {bad_param, bad_param_value} <-
|
for {bad_param, bad_param_value} <-
|
||||||
[{"nickname", another_user.nickname}, {"email", another_user.email}] do
|
[{"nickname", another_user.nickname}, {"email", another_user.email}] do
|
||||||
bad_params = Map.put(params, bad_param, bad_param_value)
|
bad_registration_attrs = %{
|
||||||
|
"authorization" => Map.put(params["authorization"], bad_param, bad_param_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_params = Map.merge(params, bad_registration_attrs)
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -281,13 +293,15 @@ test "with valid params, POST /oauth/register?op=connect redirects to `redirect_
|
||||||
"/oauth/register",
|
"/oauth/register",
|
||||||
%{
|
%{
|
||||||
"op" => "connect",
|
"op" => "connect",
|
||||||
|
"authorization" => %{
|
||||||
"scopes" => app.scopes,
|
"scopes" => app.scopes,
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"redirect_uri" => app.redirect_uris,
|
"redirect_uri" => app.redirect_uris,
|
||||||
"state" => "a_state",
|
"state" => "a_state",
|
||||||
"auth_name" => user.nickname,
|
"name" => user.nickname,
|
||||||
"password" => "testpassword"
|
"password" => "testpassword"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response = html_response(conn, 302)
|
assert response = html_response(conn, 302)
|
||||||
|
@ -304,13 +318,15 @@ test "with invalid params, POST /oauth/register?op=connect renders registration_
|
||||||
|
|
||||||
params = %{
|
params = %{
|
||||||
"op" => "connect",
|
"op" => "connect",
|
||||||
|
"authorization" => %{
|
||||||
"scopes" => app.scopes,
|
"scopes" => app.scopes,
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"redirect_uri" => app.redirect_uris,
|
"redirect_uri" => app.redirect_uris,
|
||||||
"state" => "a_state",
|
"state" => "a_state",
|
||||||
"auth_name" => user.nickname,
|
"name" => user.nickname,
|
||||||
"password" => "wrong password"
|
"password" => "wrong password"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
|
Loading…
Reference in a new issue