Packages
ash_authentication
5.0.0-rc.11
5.0.0-rc.12
5.0.0-rc.11
5.0.0-rc.10
5.0.0-rc.9
5.0.0-rc.8
5.0.0-rc.7
5.0.0-rc.6
5.0.0-rc.5
5.0.0-rc.4
5.0.0-rc.3
5.0.0-rc.2
5.0.0-rc.1
5.0.0-rc.0
4.14.1
4.14.0
4.13.7
4.13.6
4.13.5
4.13.4
4.13.3
4.13.2
retired
4.13.1
retired
4.13.0
4.12.0
4.11.0
4.10.0
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.7
4.8.6
4.8.5
4.8.3
4.8.2
4.8.1
4.8.0
4.7.6
4.7.5
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.6
4.5.5
4.5.4
4.5.3
4.5.2
4.5.1
4.5.0
4.4.9
4.4.8
4.4.7
4.4.6
4.4.5
4.4.4
4.4.3
4.4.2
4.4.1
4.4.0
4.3.12
4.3.11
4.3.10
4.3.9
4.3.8
4.3.7
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.7
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
4.0.0-rc.6
4.0.0-rc.5
4.0.0-rc.3
4.0.0-rc.2
4.0.0-rc.1
4.0.0-rc.0
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.0
3.7.9
3.7.8
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.1
3.6.0
3.5.3
3.5.2
3.5.1
3.5.0
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.0
3.0.3
Authentication extension for the Ash Framework.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/ash_authentication.add_strategy.api_key.ex
# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
# credo:disable-for-this-file Credo.Check.Design.AliasUsage
if Code.ensure_loaded?(Igniter) do
defmodule Mix.Tasks.AshAuthentication.AddStrategy.ApiKey do
use Igniter.Mix.Task
@example "mix ash_authentication.add_strategy.api_key"
@shortdoc "Adds API key authentication to your user resource"
@moduledoc """
#{@shortdoc}
## Example
```bash
#{@example}
```
## Options
* `--user`, `-u` - The user resource. Defaults to `YourApp.Accounts.User`
* `--api-key`, `-k` - The API key resource name. Defaults to `<domain>.ApiKey`
"""
def info(_argv, _composing_task) do
%Igniter.Mix.Task.Info{
group: :ash,
example: @example,
extra_args?: false,
only: nil,
positional: [],
schema: [
accounts: :string,
user: :string,
api_key: :string
],
aliases: [
a: :accounts,
u: :user,
k: :api_key
]
}
end
def igniter(igniter) do
options = parse_options(igniter)
case Igniter.Project.Module.module_exists(igniter, options[:user]) do
{true, igniter} ->
igniter
|> api_key(options)
|> AshAuthentication.Igniter.codegen_for_strategy(:api_key)
{false, igniter} ->
Igniter.add_issue(igniter, """
User module #{inspect(options[:user])} was not found.
Perhaps you have not yet installed ash_authentication?
""")
end
end
defp parse_options(igniter) do
options =
igniter.args.options
|> Keyword.put_new_lazy(:accounts, fn ->
Igniter.Project.Module.module_name(igniter, "Accounts")
end)
options
|> Keyword.put_new_lazy(:user, fn ->
Module.concat(options[:accounts], User)
end)
|> Keyword.update!(:accounts, &AshAuthentication.Igniter.maybe_parse_module/1)
|> Keyword.update!(:user, &AshAuthentication.Igniter.maybe_parse_module/1)
end
defp api_key(igniter, options) do
otp_app = Igniter.Project.Application.app_name(igniter)
api_key =
if api_key = options[:api_key] do
Igniter.Project.Module.parse(api_key)
else
options[:user]
|> Module.split()
|> :lists.droplast()
|> Enum.concat([ApiKey])
|> Module.concat()
end
{exists?, igniter} = Igniter.Project.Module.module_exists(igniter, api_key)
if exists? do
Igniter.add_issue(
igniter,
"""
Api key resource already exists: #{inspect(api_key)}.
Please use the `--api-key` option to provide a different name.
"""
)
else
extensions =
cond do
Code.ensure_loaded?(AshPostgres.DataLayer) ->
"Ash.Policy.Authorizer,postgres"
Code.ensure_loaded?(AshSqlite.DataLayer) ->
"Ash.Policy.Authorizer,sqlite"
true ->
"Ash.Policy.Authorizer"
end
token_prefix = ":" <> String.replace(String.downcase(to_string(otp_app)), "_", "")
igniter
|> Ash.Resource.Igniter.add_new_relationship(
options[:user],
:valid_api_keys,
"""
has_many :valid_api_keys, #{inspect(api_key)} do
filter expr(valid)
end
"""
)
|> Igniter.compose_task("ash.gen.resource", [
inspect(api_key),
"--uuid-primary-key",
"id",
"--default-actions",
"read,destroy",
"--attribute",
"api_key_hash:binary:required:sensitive",
"--attribute",
"expires_at:utc_datetime_usec:required",
"--relationship",
"belongs_to:user:#{inspect(options[:user])}",
"--extend",
extensions
])
|> Ash.Resource.Igniter.add_new_action(api_key, :create, """
create :create do
primary? true
accept [:user_id, :expires_at]
change {AshAuthentication.Strategy.ApiKey.GenerateApiKey, prefix: #{token_prefix}, hash: :api_key_hash}
end
""")
|> Ash.Resource.Igniter.add_new_identity(api_key, :unique_api_key, """
identity :unique_api_key, [:api_key_hash]
""")
|> Ash.Resource.Igniter.add_new_calculation(api_key, :valid, """
calculate :valid, :boolean, expr(expires_at > now())
""")
|> Ash.Resource.Igniter.add_bypass(
api_key,
quote do
AshAuthentication.Checks.AshAuthenticationInteraction
end,
quote do
authorize_if always()
end
)
|> setup_api_key_phoenix(options)
|> Ash.Resource.Igniter.add_new_action(options[:user], :sign_in_with_api_key, """
read :sign_in_with_api_key do
argument :api_key, :string, allow_nil?: false
prepare AshAuthentication.Strategy.ApiKey.SignInPreparation
end
""")
|> AshAuthentication.Igniter.add_new_strategy(
options[:user],
:api_key,
:api_key,
"""
api_key :api_key do
api_key_relationship :valid_api_keys
api_key_hash_attribute :api_key_hash
end
"""
)
end
end
defp setup_api_key_phoenix(igniter, options) do
case Igniter.Libs.Phoenix.select_router(
igniter,
"Which router would you like to add api key authentication to?"
) do
{igniter, nil} ->
igniter
{igniter, router} ->
igniter
|> Igniter.Libs.Phoenix.append_to_pipeline(
:api,
"""
plug AshAuthentication.Strategy.ApiKey.Plug,
resource: #{inspect(options[:user])},
# if you want to require an api key to be supplied, set `required?` to true
required?: false
""",
router: router
)
end
end
end
else
defmodule Mix.Tasks.AshAuthentication.AddStrategy.ApiKey do
@shortdoc "Adds API key authentication to your user resource"
@moduledoc @shortdoc
use Mix.Task
def run(_argv) do
Mix.shell().error("""
The task 'ash_authentication.add_strategy.api_key' requires igniter to be run.
Please install igniter and try again.
For more information, see: https://hexdocs.pm/igniter
""")
exit({:shutdown, 1})
end
end
end