improvement: Set Ash actor and tenant when executing internal plugs. (#115)

Closes #114.
This commit is contained in:
James Harton 2023-01-09 16:30:00 +13:00 committed by GitHub
parent 757290f508
commit 34b9d94f51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 47 deletions

View file

@ -6,7 +6,7 @@ defmodule AshAuthentication.Plug.Router do
Used internally by `AshAuthentication.Plug`.
"""
alias AshAuthentication.{Info, Strategy}
alias AshAuthentication.{Info, Plug.Dispatcher, Strategy}
@doc false
@spec __using__(keyword) :: Macro.t()
@ -41,10 +41,10 @@ defmodule AshAuthentication.Plug.Router do
|> Map.new()
for {path, config} <- routes do
match(path, to: AshAuthentication.Plug.Dispatcher, init_opts: [config])
match(path, to: Dispatcher, init_opts: [config])
end
match(_, to: AshAuthentication.Plug.Dispatcher, init_opts: [unquote(return_to)])
match(_, to: Dispatcher, init_opts: [unquote(return_to)])
end
end
end

View file

@ -8,6 +8,7 @@ defmodule AshAuthentication.Strategy.OAuth2.Plug do
alias Assent.{Config, HTTPAdapter.Mint}
alias Assent.Strategy.OAuth2, as: Assent
alias Plug.Conn
import Ash.PlugHelpers, only: [get_actor: 1, get_tenant: 1]
import AshAuthentication.Plug.Helpers, only: [store_authentication_result: 2]
import Plug.Conn
@ -46,8 +47,13 @@ defmodule AshAuthentication.Strategy.OAuth2.Plug do
conn <- delete_session(conn, session_key),
config <- Config.put(config, :session_params, session_params),
{:ok, %{user: user, token: token}} <- Assent.callback(config, conn.params),
action_opts <- action_opts(conn),
{:ok, user} <-
register_or_sign_in_user(strategy, %{user_info: user, oauth_tokens: token}) do
register_or_sign_in_user(
strategy,
%{user_info: user, oauth_tokens: token},
action_opts
) do
store_authentication_result(conn, {:ok, user})
else
nil -> store_authentication_result(conn, {:error, nil})
@ -55,6 +61,11 @@ defmodule AshAuthentication.Strategy.OAuth2.Plug do
end
end
defp action_opts(conn) do
[actor: get_actor(conn), tenant: get_tenant(conn)]
|> Enum.reject(&is_nil(elem(&1, 1)))
end
defp config_for(strategy) do
with {:ok, client_id} <- fetch_secret(strategy, :client_id),
{:ok, site} <- fetch_secret(strategy, :site),
@ -83,10 +94,11 @@ defmodule AshAuthentication.Strategy.OAuth2.Plug do
end
end
defp register_or_sign_in_user(strategy, params) when strategy.registration_enabled?,
do: Strategy.action(strategy, :register, params)
defp register_or_sign_in_user(strategy, params, opts) when strategy.registration_enabled?,
do: Strategy.action(strategy, :register, params, opts)
defp register_or_sign_in_user(strategy, params), do: Strategy.action(strategy, :sign_in, params)
defp register_or_sign_in_user(strategy, params, opts),
do: Strategy.action(strategy, :sign_in, params, opts)
# We need to temporarily store some information about the request in the
# session so that we can verify that there hasn't been a CSRF-related attack.

View file

@ -7,66 +7,43 @@ defmodule AshAuthentication.Strategy.Password.Plug do
alias AshAuthentication.{Info, Strategy, Strategy.Password}
alias Plug.Conn
import Ash.PlugHelpers, only: [get_actor: 1, get_tenant: 1]
import AshAuthentication.Plug.Helpers, only: [store_authentication_result: 2]
@doc "Handle a registration request"
@spec register(Conn.t(), Password.t()) :: Conn.t()
def register(conn, strategy) do
params =
conn
|> subject_params(strategy)
result =
strategy
|> Strategy.action(:register, params)
conn
|> store_authentication_result(result)
params = subject_params(conn, strategy)
opts = opts(conn)
result = Strategy.action(strategy, :register, params, opts)
store_authentication_result(conn, result)
end
@doc "Handle a sign-in request"
@spec sign_in(Conn.t(), Password.t()) :: Conn.t()
def sign_in(conn, strategy) do
params =
conn
|> subject_params(strategy)
result =
strategy
|> Strategy.action(:sign_in, params)
conn
|> store_authentication_result(result)
params = subject_params(conn, strategy)
opts = opts(conn)
result = Strategy.action(strategy, :sign_in, params, opts)
store_authentication_result(conn, result)
end
@doc "Handle a reset request request"
@spec reset_request(Conn.t(), Password.t()) :: Conn.t()
def reset_request(conn, strategy) do
params =
conn
|> subject_params(strategy)
result =
strategy
|> Strategy.action(:reset_request, params)
conn
|> store_authentication_result(result)
params = subject_params(conn, strategy)
opts = opts(conn)
result = Strategy.action(strategy, :reset_request, params, opts)
store_authentication_result(conn, result)
end
@doc "Handle a reset request"
@spec reset(Conn.t(), Password.t()) :: Conn.t()
def reset(conn, strategy) do
params =
conn
|> subject_params(strategy)
result =
strategy
|> Strategy.action(:reset, params)
conn
|> store_authentication_result(result)
params = subject_params(conn, strategy)
opts = opts(conn)
result = Strategy.action(strategy, :reset, params, opts)
store_authentication_result(conn, result)
end
defp subject_params(conn, strategy) do
@ -77,4 +54,9 @@ defmodule AshAuthentication.Strategy.Password.Plug do
Map.get(conn.params, subject_name, %{})
end
defp opts(conn) do
[actor: get_actor(conn), tenant: get_tenant(conn)]
|> Enum.reject(&is_nil(elem(&1, 1)))
end
end