fix: correctly generate sign-in tokens when requested.

This commit is contained in:
James Harton 2024-06-06 14:34:30 +12:00
parent d8588b9b89
commit 81236e1ed5
Signed by: james
GPG key ID: 90E82DAA13F624F4
4 changed files with 64 additions and 28 deletions

View file

@ -38,17 +38,11 @@ defmodule AshAuthentication.Strategy.Password.SignInPreparation do
if strategy.hash_provider.valid?(
password,
Map.get(record, strategy.hashed_password_field)
),
do:
{:ok,
[
maybe_generate_token(
query.context[:token_type] || :user,
record,
strategy
)
]},
else:
) do
token_type = query.context[:token_type] || :user
{:ok, [maybe_generate_token(token_type, record, strategy)]}
else
{:error,
AuthenticationFailed.exception(
strategy: strategy,
@ -60,6 +54,7 @@ defmodule AshAuthentication.Strategy.Password.SignInPreparation do
message: "Password is not valid"
}
)}
end
query, [] ->
strategy.hash_provider.simulate()
@ -118,11 +113,11 @@ defmodule AshAuthentication.Strategy.Password.SignInPreparation do
end
end
defp generate_token(purpose, record, strategy)
when is_integer(strategy.sign_in_token_lifetime) and purpose == :sign_in do
defp generate_token(:sign_in, record, strategy) when strategy.sign_in_tokens_enabled? do
{:ok, token, _claims} =
Jwt.token_for_user(record, %{"purpose" => to_string(purpose)},
token_lifetime: strategy.sign_in_token_lifetime
Jwt.token_for_user(record, %{"purpose" => "sign_in"},
token_lifetime: strategy.sign_in_token_lifetime,
purpose: :sign_in
)
Ash.Resource.put_metadata(record, :token, token)

View file

@ -24,7 +24,7 @@ defmodule AshAuthentication.Strategy.Password.StrategyTest do
assert MapSet.equal?(phases, MapSet.new(~w[register sign_in reset_request reset]a))
end
test "it returns the correct phases when the strategy doesn't suport resetting" do
test "it returns the correct phases when the strategy doesn't support resetting" do
strategy = %Password{}
phases =
@ -48,7 +48,7 @@ defmodule AshAuthentication.Strategy.Password.StrategyTest do
assert MapSet.equal?(actions, MapSet.new(~w[register sign_in reset_request reset]a))
end
test "it returns the correct actions when the strategy doesn't suport resetting" do
test "it returns the correct actions when the strategy doesn't support resetting" do
strategy = %Password{}
actions =

View file

@ -13,6 +13,8 @@ defmodule AshAuthentication.Strategy.PasswordTest do
Strategy.Password.Resettable
}
alias Example.User
doctest Password
describe "reset_token_for/1" do
@ -26,4 +28,39 @@ defmodule AshAuthentication.Strategy.PasswordTest do
assert claims["act"] == to_string(resettable.password_reset_action_name)
end
end
describe "regressions" do
test "only one user token is generated for a new user registration" do
user = build_user()
subject = AshAuthentication.user_to_subject(user)
tokens = Example.Token |> Ash.read!() |> Enum.group_by(& &1.purpose)
assert [%{subject: ^subject}] = tokens["user"]
token_types = tokens |> Map.keys() |> MapSet.new()
assert token_types == MapSet.new(["user", "confirm"])
end
test "only one token is generated for a user sign-in" do
user = build_user()
subject = AshAuthentication.user_to_subject(user)
Example.Token |> Ash.bulk_destroy!(:destroy, %{})
strategy = AshAuthentication.Info.strategy!(User, :password)
{:ok, _signed_in_user} =
Strategy.action(
strategy,
:sign_in,
%{
username: user.username,
password: user.__metadata__.password
},
context: [token_type: :sign_in]
)
assert [%{subject: ^subject, purpose: "sign_in"}] = Example.Token |> Ash.read!()
end
end
end

View file

@ -9,4 +9,8 @@ defmodule Example.Token do
table("tokens")
repo(Example.Repo)
end
actions do
defaults [:read, :destroy]
end
end