mirror of
https://github.com/team-alembic/ash_authentication.git
synced 2024-09-19 12:52:55 +12:00
fix(Confirmation): Only allow the confirmation token to be used once. (#623)
Fixes a potential issue where the confirmation token can be used multiple times, potentially opening a replay attack. Closes #618
This commit is contained in:
parent
1fdc3af0b3
commit
c22439f48f
2 changed files with 33 additions and 6 deletions
|
@ -24,7 +24,8 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
with {:ok, domain} <- Info.domain(strategy.resource),
|
||||
{:ok, token} <- Map.fetch(params, "confirm"),
|
||||
{:ok, %{"sub" => subject}, _} <- Jwt.verify(token, strategy.resource),
|
||||
{:ok, user} <- AshAuthentication.subject_to_user(subject, strategy.resource, opts) do
|
||||
{:ok, user} <- AshAuthentication.subject_to_user(subject, strategy.resource, opts),
|
||||
{:ok, token_resource} <- Info.authentication_tokens_token_resource(strategy.resource) do
|
||||
user
|
||||
|> Changeset.new()
|
||||
|> Changeset.set_context(%{
|
||||
|
@ -33,6 +34,12 @@ defmodule AshAuthentication.AddOn.Confirmation.Actions do
|
|||
}
|
||||
})
|
||||
|> Changeset.for_update(strategy.confirm_action_name, params)
|
||||
|> Changeset.after_action(fn _changeset, record ->
|
||||
case TokenResource.revoke(token_resource, token) do
|
||||
:ok -> {:ok, record}
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end)
|
||||
|> domain.update(opts)
|
||||
else
|
||||
:error -> {:error, InvalidToken.exception(type: :confirmation)}
|
||||
|
|
|
@ -5,7 +5,14 @@ defmodule AshAuthentication.AddOn.Confirmation.ActionsTest do
|
|||
import Ecto.Query
|
||||
|
||||
alias Ash.Changeset
|
||||
alias AshAuthentication.{AddOn.Confirmation, AddOn.Confirmation.Actions, Info, Jwt}
|
||||
|
||||
alias AshAuthentication.{
|
||||
AddOn.Confirmation,
|
||||
AddOn.Confirmation.Actions,
|
||||
Errors.InvalidToken,
|
||||
Info,
|
||||
Jwt
|
||||
}
|
||||
|
||||
describe "confirm/2" do
|
||||
test "it returns an error when there is no corresponding user" do
|
||||
|
@ -51,12 +58,25 @@ defmodule AshAuthentication.AddOn.Confirmation.ActionsTest do
|
|||
DateTime.to_unix(DateTime.utc_now()),
|
||||
1.0
|
||||
|
||||
# I don't know why this is failing. I even tried changing
|
||||
# `AshAuthentication.AddOn.Confirmation.ConfirmChange` to use
|
||||
# `Ash.Changeset.force_change_attributes/2` to no avail.
|
||||
# I can see the updated_at being set, but not the new username.
|
||||
assert to_string(confirmed_user.username) == new_username
|
||||
end
|
||||
|
||||
test "the same token can't be used more than once" do
|
||||
{:ok, strategy} = Info.strategy(Example.User, :confirm)
|
||||
|
||||
user = build_user()
|
||||
new_username = username()
|
||||
|
||||
changeset =
|
||||
user
|
||||
|> Changeset.for_update(:update, %{"username" => new_username})
|
||||
|
||||
{:ok, token} = Confirmation.confirmation_token(strategy, changeset, user)
|
||||
|
||||
assert {:ok, _user} = Actions.confirm(strategy, %{"confirm" => token}, [])
|
||||
|
||||
assert {:error, %InvalidToken{}} = Actions.confirm(strategy, %{"confirm" => token}, [])
|
||||
end
|
||||
end
|
||||
|
||||
describe "store_changes/3" do
|
||||
|
|
Loading…
Reference in a new issue