mirror of
https://github.com/team-alembic/ash_authentication.git
synced 2024-09-21 13:53:25 +12:00
improvement: remove the need for a strategy in changeset/query contexts. (#89)
The action -> strategy mapping is now stored directly in the resource DSL. Closes #84.
This commit is contained in:
parent
83d04170bb
commit
6dfbf03f11
16 changed files with 98 additions and 35 deletions
|
@ -26,7 +26,6 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
||||||
{:ok, user} <- AshAuthentication.subject_to_user(subject, strategy.resource) do
|
{:ok, user} <- AshAuthentication.subject_to_user(subject, strategy.resource) do
|
||||||
user
|
user
|
||||||
|> Changeset.new()
|
|> Changeset.new()
|
||||||
|> Changeset.set_context(%{strategy: strategy})
|
|
||||||
|> Changeset.for_update(strategy.confirm_action_name, params)
|
|> Changeset.for_update(strategy.confirm_action_name, params)
|
||||||
|> api.update(options)
|
|> api.update(options)
|
||||||
else
|
else
|
||||||
|
@ -53,7 +52,6 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
||||||
{:ok, _token_record} <-
|
{:ok, _token_record} <-
|
||||||
token_resource
|
token_resource
|
||||||
|> Changeset.new()
|
|> Changeset.new()
|
||||||
|> Changeset.set_context(%{strategy: strategy})
|
|
||||||
|> Changeset.for_create(store_changes_action, %{
|
|> Changeset.for_create(store_changes_action, %{
|
||||||
token: token,
|
token: token,
|
||||||
extra_data: changes,
|
extra_data: changes,
|
||||||
|
|
|
@ -4,7 +4,7 @@ defmodule AshAuthentication.AddOn.Confirmation.ConfirmChange do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
use Ash.Resource.Change
|
use Ash.Resource.Change
|
||||||
alias AshAuthentication.{AddOn.Confirmation.Actions, Jwt}
|
alias AshAuthentication.{AddOn.Confirmation.Actions, Info, Jwt}
|
||||||
|
|
||||||
alias Ash.{
|
alias Ash.{
|
||||||
Changeset,
|
Changeset,
|
||||||
|
@ -17,12 +17,13 @@ defmodule AshAuthentication.AddOn.Confirmation.ConfirmChange do
|
||||||
@impl true
|
@impl true
|
||||||
@spec change(Changeset.t(), keyword, Change.context()) :: Changeset.t()
|
@spec change(Changeset.t(), keyword, Change.context()) :: Changeset.t()
|
||||||
def change(changeset, _opts, _context) do
|
def change(changeset, _opts, _context) do
|
||||||
case Map.fetch(changeset.context, :strategy) do
|
case Info.strategy_for_action(changeset.resource, changeset.action.name) do
|
||||||
{:ok, strategy} ->
|
{:ok, strategy} ->
|
||||||
do_change(changeset, strategy)
|
do_change(changeset, strategy)
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
raise AssumptionFailed, message: "Strategy is missing from the changeset context."
|
raise AssumptionFailed,
|
||||||
|
message: "Action does not correlate with an authentication strategy"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -66,13 +66,16 @@ defmodule AshAuthentication.AddOn.Confirmation.Transformer do
|
||||||
:ok <- validate_confirmed_at_attribute(dsl_state, strategy),
|
:ok <- validate_confirmed_at_attribute(dsl_state, strategy),
|
||||||
{:ok, dsl_state} <- maybe_build_change(dsl_state, Confirmation.ConfirmationHookChange),
|
{:ok, dsl_state} <- maybe_build_change(dsl_state, Confirmation.ConfirmationHookChange),
|
||||||
{:ok, resource} <- persisted_option(dsl_state, :module) do
|
{:ok, resource} <- persisted_option(dsl_state, :module) do
|
||||||
|
strategy = %{strategy | resource: resource}
|
||||||
|
|
||||||
dsl_state =
|
dsl_state =
|
||||||
dsl_state
|
dsl_state
|
||||||
|> Transformer.replace_entity(
|
|> Transformer.replace_entity(
|
||||||
[:authentication, :add_ons],
|
[:authentication, :add_ons],
|
||||||
%{strategy | resource: resource},
|
strategy,
|
||||||
&(&1.name == strategy.name)
|
&(&1.name == strategy.name)
|
||||||
)
|
)
|
||||||
|
|> Transformer.persist({:authentication_action, strategy.confirm_action_name}, strategy)
|
||||||
|
|
||||||
{:ok, dsl_state}
|
{:ok, dsl_state}
|
||||||
else
|
else
|
||||||
|
|
|
@ -7,10 +7,15 @@ defmodule AshAuthentication.Info do
|
||||||
extension: AshAuthentication,
|
extension: AshAuthentication,
|
||||||
sections: [:authentication]
|
sections: [:authentication]
|
||||||
|
|
||||||
|
alias AshAuthentication.Strategy
|
||||||
|
alias Spark.Dsl.Extension
|
||||||
|
|
||||||
|
@type dsl_or_resource :: module | map
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Retrieve a named strategy from a resource.
|
Retrieve a named strategy from a resource.
|
||||||
"""
|
"""
|
||||||
@spec strategy(dsl_or_resource :: map | module, atom) :: {:ok, strategy} | :error
|
@spec strategy(dsl_or_resource | module, atom) :: {:ok, strategy} | :error
|
||||||
when strategy: struct
|
when strategy: struct
|
||||||
def strategy(dsl_or_resource, name) do
|
def strategy(dsl_or_resource, name) do
|
||||||
dsl_or_resource
|
dsl_or_resource
|
||||||
|
@ -24,7 +29,7 @@ defmodule AshAuthentication.Info do
|
||||||
@doc """
|
@doc """
|
||||||
Retrieve a named strategy from a resource (raising version).
|
Retrieve a named strategy from a resource (raising version).
|
||||||
"""
|
"""
|
||||||
@spec strategy!(dsl_or_resource :: map | module, atom) :: strategy | no_return
|
@spec strategy!(dsl_or_resource | module, atom) :: strategy | no_return
|
||||||
when strategy: struct
|
when strategy: struct
|
||||||
def strategy!(dsl_or_resource, name) do
|
def strategy!(dsl_or_resource, name) do
|
||||||
case strategy(dsl_or_resource, name) do
|
case strategy(dsl_or_resource, name) do
|
||||||
|
@ -35,4 +40,31 @@ defmodule AshAuthentication.Info do
|
||||||
raise "No strategy named `#{inspect(name)}` found on resource `#{inspect(dsl_or_resource)}`"
|
raise "No strategy named `#{inspect(name)}` found on resource `#{inspect(dsl_or_resource)}`"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Given an action name, retrieve the strategy it is for from the DSL
|
||||||
|
configuration.
|
||||||
|
"""
|
||||||
|
@spec strategy_for_action(dsl_or_resource, atom) :: {:ok, Strategy.t()} | :error
|
||||||
|
def strategy_for_action(dsl_or_resource, action_name) do
|
||||||
|
case Extension.get_persisted(dsl_or_resource, {:authentication_action, action_name}) do
|
||||||
|
nil -> :error
|
||||||
|
value -> {:ok, value}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Given an action name, retrieve the strategy it is for from the DSL
|
||||||
|
configuration.
|
||||||
|
"""
|
||||||
|
@spec strategy_for_action!(dsl_or_resource, atom) :: Strategy.t() | no_return
|
||||||
|
def strategy_for_action!(dsl_or_resource, action_name) do
|
||||||
|
case strategy_for_action(dsl_or_resource, action_name) do
|
||||||
|
{:ok, value} ->
|
||||||
|
value
|
||||||
|
|
||||||
|
:error ->
|
||||||
|
raise "No strategy action named `#{inspect(action_name)}` found on resource `#{inspect(dsl_or_resource)}`"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,6 @@ defmodule AshAuthentication.Strategy.OAuth2.Actions do
|
||||||
|
|
||||||
strategy.resource
|
strategy.resource
|
||||||
|> Query.new()
|
|> Query.new()
|
||||||
|> Query.set_context(%{strategy: strategy})
|
|
||||||
|> Query.for_read(strategy.sign_in_action_name, params)
|
|> Query.for_read(strategy.sign_in_action_name, params)
|
||||||
|> api.read(options)
|
|> api.read(options)
|
||||||
|> case do
|
|> case do
|
||||||
|
@ -45,7 +44,6 @@ defmodule AshAuthentication.Strategy.OAuth2.Actions do
|
||||||
|
|
||||||
strategy.resource
|
strategy.resource
|
||||||
|> Changeset.new()
|
|> Changeset.new()
|
||||||
|> Changeset.set_context(%{strategy: strategy})
|
|
||||||
|> Changeset.for_create(strategy.register_action_name, params,
|
|> Changeset.for_create(strategy.register_action_name, params,
|
||||||
upsert?: true,
|
upsert?: true,
|
||||||
upsert_identity: action.upsert_identity
|
upsert_identity: action.upsert_identity
|
||||||
|
|
|
@ -4,7 +4,7 @@ defmodule AshAuthentication.Strategy.OAuth2.IdentityChange do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
use Ash.Resource.Change
|
use Ash.Resource.Change
|
||||||
alias AshAuthentication.UserIdentity
|
alias AshAuthentication.{Info, UserIdentity}
|
||||||
alias Ash.{Changeset, Error.Framework.AssumptionFailed, Resource.Change}
|
alias Ash.{Changeset, Error.Framework.AssumptionFailed, Resource.Change}
|
||||||
import AshAuthentication.Utils, only: [is_falsy: 1]
|
import AshAuthentication.Utils, only: [is_falsy: 1]
|
||||||
|
|
||||||
|
@ -12,13 +12,15 @@ defmodule AshAuthentication.Strategy.OAuth2.IdentityChange do
|
||||||
@impl true
|
@impl true
|
||||||
@spec change(Changeset.t(), keyword, Change.context()) :: Changeset.t()
|
@spec change(Changeset.t(), keyword, Change.context()) :: Changeset.t()
|
||||||
def change(changeset, _opts, _context) do
|
def change(changeset, _opts, _context) do
|
||||||
case Map.fetch(changeset.context, :strategy) do
|
case Info.strategy_for_action(changeset.resource, changeset.action.name) do
|
||||||
{:ok, strategy} ->
|
{:ok, strategy} ->
|
||||||
do_change(changeset, strategy)
|
do_change(changeset, strategy)
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
{:error,
|
{:error,
|
||||||
AssumptionFailed.exception(message: "Strategy is missing from the changeset context.")}
|
AssumptionFailed.exception(
|
||||||
|
message: "Action does not correlate with an authentication strategy"
|
||||||
|
)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ defmodule AshAuthentication.Strategy.OAuth2.SignInPreparation do
|
||||||
"""
|
"""
|
||||||
use Ash.Resource.Preparation
|
use Ash.Resource.Preparation
|
||||||
alias Ash.{Error.Framework.AssumptionFailed, Query, Resource.Preparation}
|
alias Ash.{Error.Framework.AssumptionFailed, Query, Resource.Preparation}
|
||||||
alias AshAuthentication.{Errors.AuthenticationFailed, Jwt, UserIdentity}
|
alias AshAuthentication.{Errors.AuthenticationFailed, Info, Jwt, UserIdentity}
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
import AshAuthentication.Utils, only: [is_falsy: 1]
|
import AshAuthentication.Utils, only: [is_falsy: 1]
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ defmodule AshAuthentication.Strategy.OAuth2.SignInPreparation do
|
||||||
@impl true
|
@impl true
|
||||||
@spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t()
|
@spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t()
|
||||||
def prepare(query, _opts, _context) do
|
def prepare(query, _opts, _context) do
|
||||||
case Map.fetch(query.context, :strategy) do
|
case Info.strategy_for_action(query.resource, query.action.name) do
|
||||||
:error ->
|
:error ->
|
||||||
{:error,
|
{:error,
|
||||||
AssumptionFailed.exception(message: "Strategy is missing from the changeset context.")}
|
AssumptionFailed.exception(message: "Strategy is missing from the changeset context.")}
|
||||||
|
|
|
@ -52,13 +52,23 @@ defmodule AshAuthentication.Strategy.OAuth2.Transformer do
|
||||||
:ok <- maybe_validate_register_action(dsl_state, strategy),
|
:ok <- maybe_validate_register_action(dsl_state, strategy),
|
||||||
:ok <- maybe_validate_sign_in_action(dsl_state, strategy),
|
:ok <- maybe_validate_sign_in_action(dsl_state, strategy),
|
||||||
{:ok, resource} <- persisted_option(dsl_state, :module) do
|
{:ok, resource} <- persisted_option(dsl_state, :module) do
|
||||||
|
strategy = %{strategy | resource: resource}
|
||||||
|
|
||||||
dsl_state =
|
dsl_state =
|
||||||
dsl_state
|
dsl_state
|
||||||
|> Transformer.replace_entity(
|
|> Transformer.replace_entity(
|
||||||
[:authentication, :strategies],
|
~w[authentication strategies]a,
|
||||||
%{strategy | resource: resource},
|
strategy,
|
||||||
&(&1.name == strategy.name)
|
&(&1.name == strategy.name)
|
||||||
)
|
)
|
||||||
|
|> then(fn dsl_state ->
|
||||||
|
~w[register_action_name sign_in_action_name]a
|
||||||
|
|> Stream.map(&Map.get(strategy, &1))
|
||||||
|
|> Enum.reduce(
|
||||||
|
dsl_state,
|
||||||
|
&Transformer.persist(&2, {:authentication_action, &1}, strategy)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
{:ok, dsl_state}
|
{:ok, dsl_state}
|
||||||
else
|
else
|
||||||
|
|
|
@ -19,7 +19,6 @@ defmodule AshAuthentication.Strategy.Password.Actions do
|
||||||
|
|
||||||
strategy.resource
|
strategy.resource
|
||||||
|> Query.new()
|
|> Query.new()
|
||||||
|> Query.set_context(%{strategy: strategy})
|
|
||||||
|> Query.for_read(strategy.sign_in_action_name, params)
|
|> Query.for_read(strategy.sign_in_action_name, params)
|
||||||
|> api.read(options)
|
|> api.read(options)
|
||||||
|> case do
|
|> case do
|
||||||
|
@ -37,7 +36,6 @@ defmodule AshAuthentication.Strategy.Password.Actions do
|
||||||
|
|
||||||
strategy.resource
|
strategy.resource
|
||||||
|> Changeset.new()
|
|> Changeset.new()
|
||||||
|> Changeset.set_context(%{strategy: strategy})
|
|
||||||
|> Changeset.for_create(strategy.register_action_name, params)
|
|> Changeset.for_create(strategy.register_action_name, params)
|
||||||
|> api.create(options)
|
|> api.create(options)
|
||||||
end
|
end
|
||||||
|
@ -55,7 +53,6 @@ defmodule AshAuthentication.Strategy.Password.Actions do
|
||||||
|
|
||||||
strategy.resource
|
strategy.resource
|
||||||
|> Query.new()
|
|> Query.new()
|
||||||
|> Query.set_context(%{strategy: strategy})
|
|
||||||
|> Query.for_read(resettable.request_password_reset_action_name, params)
|
|> Query.for_read(resettable.request_password_reset_action_name, params)
|
||||||
|> api.read(options)
|
|> api.read(options)
|
||||||
|> case do
|
|> case do
|
||||||
|
@ -85,7 +82,6 @@ defmodule AshAuthentication.Strategy.Password.Actions do
|
||||||
|
|
||||||
user
|
user
|
||||||
|> Changeset.new()
|
|> Changeset.new()
|
||||||
|> Changeset.set_context(%{strategy: strategy})
|
|
||||||
|> Changeset.for_update(resettable.password_reset_action_name, params)
|
|> Changeset.for_update(resettable.password_reset_action_name, params)
|
||||||
|> api.update(options)
|
|> api.update(options)
|
||||||
else
|
else
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule AshAuthentication.Strategy.Password.HashPasswordChange do
|
||||||
|
|
||||||
use Ash.Resource.Change
|
use Ash.Resource.Change
|
||||||
alias Ash.{Changeset, Error.Framework.AssumptionFailed, Resource.Change}
|
alias Ash.{Changeset, Error.Framework.AssumptionFailed, Resource.Change}
|
||||||
|
alias AshAuthentication.Info
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -15,7 +16,7 @@ defmodule AshAuthentication.Strategy.Password.HashPasswordChange do
|
||||||
def change(changeset, _opts, _) do
|
def change(changeset, _opts, _) do
|
||||||
changeset
|
changeset
|
||||||
|> Changeset.before_action(fn changeset ->
|
|> Changeset.before_action(fn changeset ->
|
||||||
with {:ok, strategy} <- Map.fetch(changeset.context, :strategy),
|
with {:ok, strategy} <- Info.strategy_for_action(changeset.resource, changeset.action.name),
|
||||||
value when is_binary(value) <-
|
value when is_binary(value) <-
|
||||||
Changeset.get_argument(changeset, strategy.password_field),
|
Changeset.get_argument(changeset, strategy.password_field),
|
||||||
{:ok, hash} <- strategy.hash_provider.hash(value) do
|
{:ok, hash} <- strategy.hash_provider.hash(value) do
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule AshAuthentication.Strategy.Password.PasswordConfirmationValidation do
|
||||||
|
|
||||||
use Ash.Resource.Validation
|
use Ash.Resource.Validation
|
||||||
alias Ash.{Changeset, Error.Changes.InvalidArgument, Error.Framework.AssumptionFailed}
|
alias Ash.{Changeset, Error.Changes.InvalidArgument, Error.Framework.AssumptionFailed}
|
||||||
|
alias AshAuthentication.Info
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Validates that the password and password confirmation fields contain
|
Validates that the password and password confirmation fields contain
|
||||||
|
@ -15,7 +16,7 @@ defmodule AshAuthentication.Strategy.Password.PasswordConfirmationValidation do
|
||||||
@impl true
|
@impl true
|
||||||
@spec validate(Changeset.t(), keyword) :: :ok | {:error, String.t() | Exception.t()}
|
@spec validate(Changeset.t(), keyword) :: :ok | {:error, String.t() | Exception.t()}
|
||||||
def validate(changeset, _) do
|
def validate(changeset, _) do
|
||||||
case Map.fetch(changeset.context, :strategy) do
|
case Info.strategy_for_action(changeset.resource, changeset.action.name) do
|
||||||
{:ok, %{confirmation_required?: true} = strategy} ->
|
{:ok, %{confirmation_required?: true} = strategy} ->
|
||||||
validate_password_confirmation(changeset, strategy)
|
validate_password_confirmation(changeset, strategy)
|
||||||
|
|
||||||
|
@ -24,7 +25,9 @@ defmodule AshAuthentication.Strategy.Password.PasswordConfirmationValidation do
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
{:error,
|
{:error,
|
||||||
AssumptionFailed.exception(message: "Strategy is missing from the changeset context.")}
|
AssumptionFailed.exception(
|
||||||
|
message: "Action does not correlate with an authentication strategy"
|
||||||
|
)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,14 @@ defmodule AshAuthentication.Strategy.Password.RequestPasswordResetPreparation do
|
||||||
"""
|
"""
|
||||||
use Ash.Resource.Preparation
|
use Ash.Resource.Preparation
|
||||||
alias Ash.{Query, Resource.Preparation}
|
alias Ash.{Query, Resource.Preparation}
|
||||||
alias AshAuthentication.Strategy.Password
|
alias AshAuthentication.{Info, Strategy.Password}
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@impl true
|
@impl true
|
||||||
@spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t()
|
@spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t()
|
||||||
def prepare(query, _opts, _context) do
|
def prepare(query, _opts, _context) do
|
||||||
strategy = Map.fetch!(query.context, :strategy)
|
strategy = Info.strategy_for_action!(query.resource, query.action.name)
|
||||||
|
|
||||||
if Enum.any?(strategy.resettable) do
|
if Enum.any?(strategy.resettable) do
|
||||||
identity_field = strategy.identity_field
|
identity_field = strategy.identity_field
|
||||||
|
|
|
@ -5,13 +5,13 @@ defmodule AshAuthentication.Strategy.Password.ResetTokenValidation do
|
||||||
|
|
||||||
use Ash.Resource.Validation
|
use Ash.Resource.Validation
|
||||||
alias Ash.{Changeset, Error.Changes.InvalidArgument}
|
alias Ash.{Changeset, Error.Changes.InvalidArgument}
|
||||||
alias AshAuthentication.Jwt
|
alias AshAuthentication.{Info, Jwt}
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@impl true
|
@impl true
|
||||||
@spec validate(Changeset.t(), keyword) :: :ok | {:error, Exception.t()}
|
@spec validate(Changeset.t(), keyword) :: :ok | {:error, Exception.t()}
|
||||||
def validate(changeset, _) do
|
def validate(changeset, _) do
|
||||||
with {:ok, strategy} <- Map.fetch(changeset.context, :strategy),
|
with {:ok, strategy} <- Info.strategy_for_action(changeset.resource, changeset.action.name),
|
||||||
token when is_binary(token) <- Changeset.get_argument(changeset, :reset_token),
|
token when is_binary(token) <- Changeset.get_argument(changeset, :reset_token),
|
||||||
{:ok, %{"act" => token_action}, _} <- Jwt.verify(token, changeset.resource),
|
{:ok, %{"act" => token_action}, _} <- Jwt.verify(token, changeset.resource),
|
||||||
{:ok, [resettable]} <- Map.fetch(strategy, :resettable),
|
{:ok, [resettable]} <- Map.fetch(strategy, :resettable),
|
||||||
|
|
|
@ -13,7 +13,7 @@ defmodule AshAuthentication.Strategy.Password.SignInPreparation do
|
||||||
an authentication failed error.
|
an authentication failed error.
|
||||||
"""
|
"""
|
||||||
use Ash.Resource.Preparation
|
use Ash.Resource.Preparation
|
||||||
alias AshAuthentication.{Errors.AuthenticationFailed, Jwt}
|
alias AshAuthentication.{Errors.AuthenticationFailed, Info, Jwt}
|
||||||
alias Ash.{Query, Resource.Preparation}
|
alias Ash.{Query, Resource.Preparation}
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ defmodule AshAuthentication.Strategy.Password.SignInPreparation do
|
||||||
@impl true
|
@impl true
|
||||||
@spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t()
|
@spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t()
|
||||||
def prepare(query, _opts, _context) do
|
def prepare(query, _opts, _context) do
|
||||||
strategy = Map.fetch!(query.context, :strategy)
|
strategy = Info.strategy_for_action!(query.resource, query.action.name)
|
||||||
identity_field = strategy.identity_field
|
identity_field = strategy.identity_field
|
||||||
identity = Query.get_argument(query, identity_field)
|
identity = Query.get_argument(query, identity_field)
|
||||||
|
|
||||||
|
|
|
@ -71,13 +71,35 @@ defmodule AshAuthentication.Strategy.Password.Transformer do
|
||||||
:ok <- validate_sign_in_action(dsl_state, strategy),
|
:ok <- validate_sign_in_action(dsl_state, strategy),
|
||||||
{:ok, dsl_state, strategy} <- maybe_transform_resettable(dsl_state, strategy),
|
{:ok, dsl_state, strategy} <- maybe_transform_resettable(dsl_state, strategy),
|
||||||
{:ok, resource} <- persisted_option(dsl_state, :module) do
|
{:ok, resource} <- persisted_option(dsl_state, :module) do
|
||||||
|
strategy = %{strategy | resource: resource}
|
||||||
|
|
||||||
dsl_state =
|
dsl_state =
|
||||||
dsl_state
|
dsl_state
|
||||||
|> Transformer.replace_entity(
|
|> Transformer.replace_entity(
|
||||||
[:authentication, :strategies],
|
~w[authentication strategies]a,
|
||||||
%{strategy | resource: resource},
|
strategy,
|
||||||
&(&1.name == strategy.name)
|
&(&1.name == strategy.name)
|
||||||
)
|
)
|
||||||
|
|> then(fn dsl_state ->
|
||||||
|
~w[sign_in_action_name register_action_name]a
|
||||||
|
|> Stream.map(&Map.get(strategy, &1))
|
||||||
|
|> Enum.reduce(
|
||||||
|
dsl_state,
|
||||||
|
&Transformer.persist(&2, {:authentication_action, &1}, strategy)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|> then(fn dsl_state ->
|
||||||
|
strategy
|
||||||
|
|> Map.get(:resettable, [])
|
||||||
|
|> Stream.flat_map(fn resettable ->
|
||||||
|
~w[request_password_reset_action_name password_reset_action_name]a
|
||||||
|
|> Stream.map(&Map.get(resettable, &1))
|
||||||
|
end)
|
||||||
|
|> Enum.reduce(
|
||||||
|
dsl_state,
|
||||||
|
&Transformer.persist(&2, {:authentication_action, &1}, strategy)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
{:ok, dsl_state}
|
{:ok, dsl_state}
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,12 +79,9 @@ defmodule DataCase do
|
||||||
|> Map.put_new(:password, password)
|
|> Map.put_new(:password, password)
|
||||||
|> Map.put_new(:password_confirmation, password)
|
|> Map.put_new(:password_confirmation, password)
|
||||||
|
|
||||||
{:ok, strategy} = AshAuthentication.Info.strategy(Example.User, :password)
|
|
||||||
|
|
||||||
user =
|
user =
|
||||||
Example.User
|
Example.User
|
||||||
|> Ash.Changeset.new()
|
|> Ash.Changeset.new()
|
||||||
|> Ash.Changeset.set_context(%{strategy: strategy})
|
|
||||||
|> Ash.Changeset.for_create(:register_with_password, attrs)
|
|> Ash.Changeset.for_create(:register_with_password, attrs)
|
||||||
|> Example.create!()
|
|> Example.create!()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue