Packages
ash_authentication
3.11.7
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.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash_authentication/token_resource/transformer.ex
defmodule AshAuthentication.TokenResource.Transformer do
@moduledoc """
The token resource transformer.
Sets up the default schema and actions for the token resource.
"""
use Spark.Dsl.Transformer
require Ash.Expr
alias Ash.{Resource, Type}
alias AshAuthentication.{TokenResource, TokenResource.Info}
alias Spark.Dsl.Transformer
import AshAuthentication.Utils
import AshAuthentication.Validations
import AshAuthentication.Validations.Action
import AshAuthentication.Validations.Attribute
@doc false
@impl true
@spec after?(any) :: boolean()
def after?(Resource.Transformers.ValidatePrimaryActions), do: true
def after?(_), do: false
@doc false
@impl true
@spec before?(any) :: boolean
def before?(Resource.Transformers.CachePrimaryKey), do: true
def before?(Resource.Transformers.DefaultAccept), do: true
def before?(_), do: false
@doc false
@impl true
@spec transform(map) ::
:ok | {:ok, map} | {:error, term} | {:warn, map, String.t() | [String.t()]} | :halt
def transform(dsl_state) do
with {:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :jti, :string,
primary_key?: true,
allow_nil?: false,
sensitive?: true,
writable?: true
),
:ok <- validate_jti_field(dsl_state),
{:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :subject, :string, allow_nil?: false, writable?: true),
:ok <- validate_subject_field(dsl_state),
{:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :expires_at, :utc_datetime,
allow_nil?: false,
writable?: true
),
:ok <- validate_expires_at_field(dsl_state),
{:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :purpose, :string,
allow_nil?: false,
writable?: true
),
:ok <- validate_purpose_field(dsl_state),
{:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :extra_data, :map,
allow_nil?: true,
writable?: true
),
{:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :created_at, :utc_datetime_usec,
allow_nil?: false,
private?: true,
default: &DateTime.utc_now/0
),
{:ok, dsl_state} <-
maybe_build_attribute(dsl_state, :updated_at, :utc_datetime_usec,
allow_nil?: false,
private?: true,
default: &DateTime.utc_now/0,
update_default: &DateTime.utc_now/0
),
:ok <- validate_extra_data_field(dsl_state),
{:ok, expunge_expired_action_name} <- Info.token_expunge_expired_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
expunge_expired_action_name,
&build_expunge_expired_action(&1, expunge_expired_action_name)
),
:ok <- validate_expunge_expired_action(dsl_state, expunge_expired_action_name),
{:ok, read_expired_action_name} <- Info.token_read_expired_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
read_expired_action_name,
&build_read_expired_action(&1, read_expired_action_name)
),
:ok <- validate_read_expired_action(dsl_state, read_expired_action_name),
{:ok, revoke_token_action_name} <-
Info.token_revocation_revoke_token_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
revoke_token_action_name,
&build_revoke_token_action(&1, revoke_token_action_name)
),
:ok <- validate_revoke_token_action(dsl_state, revoke_token_action_name),
{:ok, is_revoked_action_name} <- Info.token_revocation_is_revoked_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
is_revoked_action_name,
&build_is_revoked_action(&1, is_revoked_action_name)
),
:ok <- validate_is_revoked_action(dsl_state, is_revoked_action_name),
{:ok, get_confirmation_changes_action_name} <-
Info.token_confirmation_get_changes_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
get_confirmation_changes_action_name,
&build_get_confirmation_changes_action(&1, get_confirmation_changes_action_name)
),
:ok <-
validate_get_confirmation_changes_action(
dsl_state,
get_confirmation_changes_action_name
),
{:ok, store_confirmation_changes_action_name} <-
Info.token_confirmation_store_changes_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
store_confirmation_changes_action_name,
&build_store_confirmation_changes_action(&1, store_confirmation_changes_action_name)
),
:ok <-
validate_store_confirmation_changes_action(
dsl_state,
store_confirmation_changes_action_name
),
{:ok, store_token_action_name} <-
Info.token_store_token_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
store_token_action_name,
&build_store_token_action(&1, store_token_action_name)
),
:ok <- validate_store_token_action(dsl_state, store_token_action_name),
{:ok, get_token_action_name} <- Info.token_get_token_action_name(dsl_state),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
get_token_action_name,
&build_get_token_action(&1, get_token_action_name)
),
:ok <- validate_get_token_action(dsl_state, get_token_action_name) do
{:ok, dsl_state}
end
end
defp validate_subject_field(dsl_state) do
with {:ok, resource} <- persisted_option(dsl_state, :module),
{:ok, attribute} <- find_attribute(dsl_state, :subject),
:ok <- validate_attribute_option(attribute, resource, :type, [Type.String, :string]) do
validate_attribute_option(attribute, resource, :writable?, [true])
end
end
defp validate_get_token_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name),
:ok <-
validate_action_argument_option(action, :token, :type, [Ash.Type.String, :string]),
:ok <- validate_action_argument_option(action, :token, :allow_nil?, [true]),
:ok <- validate_action_argument_option(action, :token, :sensitive?, [true]),
:ok <- validate_action_argument_option(action, :jti, :type, [Ash.Type.String, :string]),
:ok <- validate_action_argument_option(action, :jti, :allow_nil?, [true]),
:ok <-
validate_action_argument_option(action, :purpose, :type, [Ash.Type.String, :string]) do
validate_action_has_preparation(action, TokenResource.GetTokenPreparation)
end
end
defp build_get_token_action(_dsl_state, action_name) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: :token,
type: :string,
sensitive?: true
),
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: :jti,
type: :string,
sensitive?: false
),
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: :purpose,
type: :string,
sensitive?: false
)
]
preparations = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :prepare,
preparation: TokenResource.GetTokenPreparation
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :read,
name: action_name,
arguments: arguments,
preparations: preparations,
get?: true
)
end
defp validate_store_token_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name),
:ok <- validate_token_argument(action) do
validate_action_has_change(action, TokenResource.StoreTokenChange)
end
end
defp build_store_token_action(_dsl_state, action_name) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :argument,
name: :token,
type: :string,
allow_nil?: false,
sensitive?: true
)
]
changes = [
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :change,
change: TokenResource.StoreTokenChange
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :create,
name: action_name,
arguments: arguments,
changes: changes,
accept: [:extra_data, :purpose]
)
end
defp build_store_confirmation_changes_action(_dsl_state, action_name) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :argument,
name: :token,
type: :string,
allow_nil?: false,
sensitive?: true
)
]
changes = [
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :change,
change: TokenResource.StoreConfirmationChangesChange
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :create,
name: action_name,
arguments: arguments,
changes: changes,
accept: [:extra_data, :purpose]
)
end
defp validate_store_confirmation_changes_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name),
:ok <- validate_token_argument(action) do
validate_action_has_change(action, TokenResource.StoreConfirmationChangesChange)
end
end
defp build_get_confirmation_changes_action(_dsl_state, action_name) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: :jti,
type: :string,
allow_nil?: false,
sensitive?: true
)
]
preparations = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :prepare,
preparation: TokenResource.GetConfirmationChangesPreparation
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :read,
name: action_name,
arguments: arguments,
preparations: preparations,
get?: true
)
end
defp validate_get_confirmation_changes_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name),
:ok <- validate_action_argument_option(action, :jti, :type, [Ash.Type.String, :string]),
:ok <-
validate_action_has_preparation(
action,
TokenResource.GetConfirmationChangesPreparation
) do
validate_field_in_values(action, :type, [:read])
end
end
defp build_read_expired_action(_dsl_state, action_name) do
import Ash.Filter.TemplateHelpers
Transformer.build_entity(Resource.Dsl, [:actions], :read,
name: action_name,
filter: expr(expires_at < now())
)
end
defp validate_read_expired_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name) do
validate_field_in_values(action, :type, [:read])
end
end
defp validate_is_revoked_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name),
:ok <-
validate_action_argument_option(action, :token, :type, [Ash.Type.String, :string]),
:ok <- validate_action_argument_option(action, :jti, :type, [Ash.Type.String, :string]),
:ok <- validate_action_has_preparation(action, TokenResource.IsRevokedPreparation) do
validate_field_in_values(action, :type, [:read])
end
end
defp build_is_revoked_action(_dsl_state, action_name) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: :token,
type: :string,
allow_nil?: true,
sensitive?: true
),
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: :jti,
type: :string,
allow_nil?: true,
sensitive?: true
)
]
preparations = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :prepare,
preparation: TokenResource.IsRevokedPreparation
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :read,
name: action_name,
get?: true,
preparations: preparations,
arguments: arguments
)
end
defp validate_token_argument(action) do
with :ok <-
validate_action_argument_option(action, :token, :type, [Ash.Type.String, :string]),
:ok <- validate_action_argument_option(action, :token, :allow_nil?, [false]) do
validate_action_argument_option(action, :token, :sensitive?, [true])
end
end
defp validate_revoke_token_action(dsl_state, revoke_token_action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, revoke_token_action_name),
:ok <- validate_token_argument(action) do
validate_action_has_change(action, TokenResource.RevokeTokenChange)
end
end
defp build_revoke_token_action(_dsl_state, action_name) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :argument,
name: :token,
type: :string,
allow_nil?: false,
sensitive?: true
)
]
changes = [
Transformer.build_entity!(Resource.Dsl, [:actions, :create], :change,
change: TokenResource.RevokeTokenChange
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :create,
name: action_name,
arguments: arguments,
changes: changes,
accept: [:extra_data]
)
end
defp validate_expunge_expired_action(dsl_state, action_name) do
with {:ok, action} <- validate_action_exists(dsl_state, action_name) do
validate_field_in_values(action, :type, [:destroy])
end
end
defp build_expunge_expired_action(_dsl_state, action_name),
do: Transformer.build_entity(Resource.Dsl, [:actions], :destroy, name: action_name)
defp validate_jti_field(dsl_state) do
with {:ok, resource} <- persisted_option(dsl_state, :module),
{:ok, attribute} <- find_attribute(dsl_state, :jti),
:ok <- validate_attribute_option(attribute, resource, :type, [Type.String, :string]),
:ok <- validate_attribute_option(attribute, resource, :allow_nil?, [false]),
:ok <- validate_attribute_option(attribute, resource, :sensitive?, [true]),
:ok <- validate_attribute_option(attribute, resource, :writable?, [true]),
:ok <- validate_attribute_option(attribute, resource, :primary_key?, [true]) do
validate_attribute_option(attribute, resource, :private?, [false])
end
end
defp validate_expires_at_field(dsl_state) do
with {:ok, resource} <- persisted_option(dsl_state, :module),
{:ok, attribute} <- find_attribute(dsl_state, :expires_at),
:ok <-
validate_attribute_option(attribute, resource, :type, [Type.UtcDatetime, :utc_datetime]),
:ok <- validate_attribute_option(attribute, resource, :allow_nil?, [false]) do
validate_attribute_option(attribute, resource, :writable?, [true])
end
end
defp validate_purpose_field(dsl_state) do
with {:ok, resource} <- persisted_option(dsl_state, :module),
{:ok, attribute} <- find_attribute(dsl_state, :purpose),
:ok <- validate_attribute_option(attribute, resource, :type, [Type.String, :string]),
:ok <- validate_attribute_option(attribute, resource, :allow_nil?, [false]) do
validate_attribute_option(attribute, resource, :writable?, [true])
end
end
defp validate_extra_data_field(dsl_state) do
with {:ok, resource} <- persisted_option(dsl_state, :module),
{:ok, attribute} <- find_attribute(dsl_state, :extra_data),
:ok <- validate_attribute_option(attribute, resource, :type, [Type.Map, :map]),
:ok <- validate_attribute_option(attribute, resource, :allow_nil?, [true]) do
validate_attribute_option(attribute, resource, :writable?, [true])
end
end
end