Packages
ash_authentication
4.13.1
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.
Retired package: This break Google auth flows due to an assent upgrade, will be fixed in next release
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/ash_authentication.add_add_on.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.AddAddOn do
use Igniter.Mix.Task
@example "mix ash_authentication.add_add_on audit_log"
@shortdoc "Adds the provided add-on to your user resource"
@add_ons [
audit_log: "Track authentication events for security and compliance."
]
@add_on_explanation Enum.map_join(@add_ons, "\n", fn {name, description} ->
" * `#{name}` - #{description}"
end)
@add_on_names @add_ons |> Keyword.keys() |> Enum.map(&to_string/1)
@add_on_options [
audit_log: [
"audit-log":
"The audit log resource name. Defaults to `<domain>.AuditLog`.",
"include-fields":
"Comma-separated list of sensitive fields to include in audit logs.",
"exclude-strategies":
"Comma-separated list of authentication strategies to exclude from logging.",
"exclude-actions":
"Comma-separated list of actions to exclude from logging."
]
]
|> Enum.reduce("", fn {add_on, opts}, result ->
add_on_title =
add_on
|> to_string()
|> String.split("_")
|> Enum.map_join(" ", &String.capitalize/1)
result <>
"## #{add_on_title} options\n\n" <>
Enum.map_join(opts, "\n", &" - `#{elem(&1, 0)}` - #{elem(&1, 1)}")
end)
@moduledoc """
#{@shortdoc}
This task will add the provided add-on to your user resource and set up any required supporting resources.
The following add-ons are available:
#{@add_on_explanation}
## Example
```bash
#{@example}
```
## Global options
* `--user`, `-u` - The user resource. Defaults to `YourApp.Accounts.User`
#{@add_on_options}
"""
def info(_argv, _composing_task) do
%Igniter.Mix.Task.Info{
group: :ash,
example: @example,
extra_args?: false,
only: nil,
positional: [
add_on: []
],
schema: [
user: :string,
audit_log: :string,
include_fields: :csv,
exclude_strategies: :csv,
exclude_actions: :csv
],
aliases: [
u: :user,
a: :audit_log
]
}
end
def igniter(igniter) do
add_on_list = igniter.args.positional[:add_on] || []
add_on = if is_list(add_on_list), do: List.first(add_on_list), else: add_on_list
default_user = Igniter.Project.Module.module_name(igniter, "Accounts.User")
options =
igniter.args.options
|> Keyword.update(:user, default_user, &Igniter.Project.Module.parse/1)
if add_on not in @add_on_names do
Mix.shell().error("""
Invalid add-on provided: `#{add_on || "none"}`
Not all add-ons can be installed using `ash_authentication.add_add_on` yet.
Want to see an add-on added? Open an issue (or even better, a PR!) on GitHub.
See a list of add-ons and how to install them here:
https://hexdocs.pm/ash_authentication/get-started.html
Available Add-ons:
#{@add_on_explanation}
""")
exit({:shutdown, 1})
end
case Igniter.Project.Module.module_exists(igniter, options[:user]) do
{true, igniter} ->
case add_on do
"audit_log" ->
igniter
|> audit_log(options)
|> Ash.Igniter.codegen("add_audit_log")
end
{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 audit_log(igniter, options) do
audit_log_resource =
if audit_log = options[:audit_log] do
Igniter.Project.Module.parse(audit_log)
else
options[:user]
|> Module.split()
|> :lists.droplast()
|> Enum.concat([AuditLog])
|> Module.concat()
end
{exists?, igniter} = Igniter.Project.Module.module_exists(igniter, audit_log_resource)
if exists? do
Igniter.add_issue(
igniter,
"""
Audit log resource already exists: #{inspect(audit_log_resource)}.
Please use the `--audit-log` option to provide a different name.
"""
)
else
otp_app = Igniter.Project.Application.app_name(igniter)
extensions =
cond do
Code.ensure_loaded?(AshPostgres.DataLayer) ->
"postgres"
Code.ensure_loaded?(AshSqlite.DataLayer) ->
"sqlite"
true ->
nil
end
domain =
options[:user]
|> Module.split()
|> :lists.droplast()
|> Module.concat()
{igniter, resource_args, _repo} = data_layer_args(igniter, options)
resource_args =
if extensions do
resource_args ++ ["--extend", extensions, "--domain", inspect(domain)]
else
resource_args ++ ["--domain", inspect(domain)]
end
igniter
|> Igniter.compose_task("ash.gen.resource", [
inspect(audit_log_resource),
"--default-actions",
"read"
| resource_args
])
|> Igniter.compose_task("ash.extend", [
inspect(audit_log_resource),
"AshAuthentication.AuditLogResource"
])
|> add_audit_log_add_on(options[:user], audit_log_resource, options)
|> ensure_supervisor(otp_app)
end
end
defp add_audit_log_add_on(igniter, user_resource, audit_log_resource, options) do
include_fields = options[:include_fields] || []
exclude_strategies = options[:exclude_strategies] || []
exclude_actions = options[:exclude_actions] || []
include_fields_config =
if include_fields != [] do
fields = Enum.map_join(include_fields, ", ", &":#{&1}")
"include_fields [#{fields}]"
else
""
end
exclude_strategies_config =
if exclude_strategies != [] do
strategies = Enum.map_join(exclude_strategies, ", ", &":#{&1}")
"exclude_strategies [#{strategies}]"
else
""
end
exclude_actions_config =
if exclude_actions != [] do
actions = Enum.map_join(exclude_actions, ", ", &":#{&1}")
"exclude_actions [#{actions}]"
else
""
end
configs =
[include_fields_config, exclude_strategies_config, exclude_actions_config]
|> Enum.reject(&(&1 == ""))
|> Enum.join("\n ")
configs_section = if configs != "", do: "\n #{configs}", else: ""
AshAuthentication.Igniter.add_new_add_on(
igniter,
user_resource,
:audit_log,
nil,
"""
audit_log do
audit_log_resource #{inspect(audit_log_resource)}#{configs_section}
end
"""
)
end
defp ensure_supervisor(igniter, otp_app) do
# Check if AshAuthentication.Supervisor is already in the supervision tree
Igniter.Project.Application.add_new_child(
igniter,
{AshAuthentication.Supervisor, otp_app: otp_app},
after: fn _ -> true end
)
end
cond do
Code.ensure_loaded?(AshPostgres.Igniter) ->
def data_layer_args(igniter, opts) do
{igniter, repo} =
AshPostgres.Igniter.select_repo(igniter, generate?: false, yes: opts[:yes])
{igniter, ["--repo", inspect(repo)], repo}
end
Code.ensure_loaded?(AshSqlite.Igniter) ->
def data_layer_args(igniter, opts) do
{igniter, repo} =
AshSqlite.Igniter.select_repo(igniter, generate?: false, yes: opts[:yes])
{igniter, ["--repo", inspect(repo)], repo}
end
true ->
def data_layer_args(igniter, _) do
{igniter, [], nil}
end
end
end
else
defmodule Mix.Tasks.AshAuthentication.AddAddOn do
@shortdoc "Adds the provided add-on to your user resource"
@moduledoc @shortdoc
use Mix.Task
def run(_argv) do
Mix.shell().error("""
The task 'ash_authentication.add_add_on' 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