Skip to content

Commit

Permalink
improvement: validate that tokens are enabled when password resets ar…
Browse files Browse the repository at this point in the history
…e enabled.

Closes #232.
  • Loading branch information
jimsynz committed Aug 5, 2024
1 parent 866d806 commit 712a847
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 52 deletions.
2 changes: 1 addition & 1 deletion lib/ash_authentication/add_ons/confirmation/transformer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ defmodule AshAuthentication.AddOn.Confirmation.Transformer do
:ok <- validate_action_argument_option(action, :confirm, :type, [Type.String]),
:ok <- validate_action_has_change(action, GenerateTokenChange),
:ok <- validate_action_option(action, :require_atomic?, [false]) do
accept_fields = MapSet.new(action.accept || [])
accept_fields = MapSet.new(action.accept)

strategy.monitor_fields
|> MapSet.new()
Expand Down
2 changes: 1 addition & 1 deletion lib/ash_authentication/jwt.ex
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ defmodule AshAuthentication.Jwt do
{:ok, token, claims}
else
{:error, reason} ->
Logger.error("Failed to generate token for user: #{inspect reason, pretty: true}")
Logger.error("Failed to generate token for user: #{inspect(reason, pretty: true)}")
:error
end
end
Expand Down
38 changes: 37 additions & 1 deletion lib/ash_authentication/strategies/password/verifier.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ defmodule AshAuthentication.Strategy.Password.Verifier do
@spec verify(Password.t(), map) :: :ok | {:error, Exception.t()}
def verify(strategy, dsl_state) do
with :ok <- validate_behaviour(strategy.hash_provider, HashProvider),
:ok <- validate_tokens_enabled_for_sign_in_tokens(dsl_state, strategy) do
:ok <- validate_tokens_enabled_for_sign_in_tokens(dsl_state, strategy),
:ok <- validate_tokens_enabled_for_resettable(dsl_state, strategy) do
maybe_validate_resettable_sender(dsl_state, strategy)
end
end
Expand Down Expand Up @@ -69,6 +70,41 @@ defmodule AshAuthentication.Strategy.Password.Verifier do

defp validate_tokens_enabled_for_sign_in_tokens(_, _), do: :ok

defp validate_tokens_enabled_for_resettable(dsl_state, %{resettable: resettable, name: name})
when is_struct(resettable) do
resource = Verifier.get_persisted(dsl_state, :module)

if Info.authentication_tokens_enabled?(dsl_state) do
:ok
else
{:error,
DslError.exception(
module: resource,
path: [
:authentication,
:strategies,
:password,
name,
:resettable
],
message: """
The `resettable` option requires that tokens are enabled for your resource. For example:
authentication do
...
tokens do
enabled? true
end
end
"""
)}
end
end

defp validate_tokens_enabled_for_resettable(_, _), do: :ok

defp maybe_validate_resettable_sender(dsl_state, %{resettable: resettable})
when is_struct(resettable) do
with {:ok, {sender, _opts}} <- Map.fetch(resettable, :sender),
Expand Down
105 changes: 56 additions & 49 deletions test/ash_authentication/user_with_bad_token_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,61 @@ defmodule AshAuthentication.UserWithBadTokenTest do
use DataCase, async: true

test "cannot compile with bad token_resource configured" do
assert_raise Spark.Error.DslError, ~r/`BadToken` is not a valid token resource module name/, fn ->
defmodule UserWithBadToken do
@moduledoc false
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication],
validate_domain_inclusion?: false,
domain: Example

attributes do
uuid_primary_key :id, writable?: true
attribute :email, :ci_string, allow_nil?: false, public?: true
attribute :hashed_password, :string, allow_nil?: true, sensitive?: true, public?: false
create_timestamp :created_at
update_timestamp :updated_at
end

authentication do
tokens do
enabled? true
token_resource BadToken
signing_secret fn _, _ -> :dummy end
end

strategies do
password do
identity_field :email

resettable do
sender fn _user, _token, _opts -> :noop end
end
end
end
end

actions do
defaults [:create, :read, :update, :destroy]
end

identities do
identity :email, [:email], eager_check_with: Example
end

postgres do
table "user_with_bad_token_required"
repo Example.Repo
end
end
end
assert_raise Spark.Error.DslError,
~r/`BadToken` is not a valid token resource module name/,
fn ->
defmodule UserWithBadToken do
@moduledoc false
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication],
validate_domain_inclusion?: false,
domain: Example

attributes do
uuid_primary_key :id, writable?: true
attribute :email, :ci_string, allow_nil?: false, public?: true

attribute :hashed_password, :string,
allow_nil?: true,
sensitive?: true,
public?: false

create_timestamp :created_at
update_timestamp :updated_at
end

authentication do
tokens do
enabled? true
token_resource BadToken
signing_secret fn _, _ -> :dummy end
end

strategies do
password do
identity_field :email

resettable do
sender fn _user, _token, _opts -> :noop end
end
end
end
end

actions do
defaults [:create, :read, :update, :destroy]
end

identities do
identity :email, [:email], eager_check_with: Example
end

postgres do
table "user_with_bad_token_required"
repo(Example.Repo)
end
end
end
end
end

0 comments on commit 712a847

Please sign in to comment.