Packages
ash_authentication
5.0.0-rc.3
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/strategies/oauth2/transformer.ex
# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Strategy.OAuth2.Transformer do
@moduledoc """
DSL transformer for oauth2 strategies.
Iterates through any oauth2 strategies and ensures that all the correct
actions and settings are in place.
"""
alias Ash.{Resource, Type}
alias AshAuthentication.{GenerateTokenChange, Info, Strategy, Strategy.OAuth2}
alias Spark.{Dsl.Transformer, Error.DslError}
import AshAuthentication.Strategy.Custom.Helpers
import AshAuthentication.Utils
import AshAuthentication.Validations
import AshAuthentication.Validations.Action
@doc false
@spec transform(OAuth2.t(), map) :: {:ok, OAuth2.t() | map} | {:error, Exception.t()}
def transform(strategy, dsl_state) do
with strategy <- set_defaults(strategy),
{:ok, dsl_state} <- maybe_build_identity_relationship(dsl_state, strategy),
:ok <- maybe_validate_register_action(dsl_state, strategy),
:ok <- maybe_validate_sign_in_action(dsl_state, strategy),
{:ok, resource} <- persisted_option(dsl_state, :module) do
strategy = %{strategy | resource: resource}
dsl_state =
dsl_state
|> Transformer.replace_entity(
~w[authentication strategies]a,
strategy,
&(Strategy.name(&1) == strategy.name)
)
|> then(fn dsl_state ->
~w[register_action_name sign_in_action_name]a
|> Enum.map(&Map.get(strategy, &1))
|> register_strategy_actions(dsl_state, strategy)
end)
{:ok, dsl_state}
else
{:error, reason} when is_binary(reason) ->
{:error,
DslError.exception(path: [:authentication, :strategies, strategy.name], message: reason)}
{:error, reason} ->
{:error, reason}
end
end
# sobelow_skip ["DOS.BinToAtom"]
defp set_defaults(strategy) do
strategy
|> maybe_set_field_lazy(:register_action_name, &:"register_with_#{&1.name}")
|> maybe_set_field_lazy(:sign_in_action_name, &:"sign_in_with_#{&1.name}")
end
defp maybe_build_identity_relationship(dsl_state, strategy)
when is_falsy(strategy.identity_resource),
do: {:ok, dsl_state}
defp maybe_build_identity_relationship(dsl_state, strategy) do
maybe_build_relationship(
dsl_state,
strategy.identity_relationship_name,
&build_identity_relationship(&1, strategy)
)
end
defp build_identity_relationship(_dsl_state, strategy) do
Transformer.build_entity(Resource.Dsl, [:relationships], :has_many,
name: strategy.identity_relationship_name,
destination: strategy.identity_resource,
destination_attribute: strategy.identity_relationship_user_id_attribute
)
end
defp maybe_validate_register_action(dsl_state, strategy) when strategy.registration_enabled? do
with {:ok, action} <- validate_action_exists(dsl_state, strategy.register_action_name),
:ok <- validate_action_has_argument(action, :user_info),
:ok <- validate_action_argument_option(action, :user_info, :type, [Type.Map, :map]),
:ok <- validate_action_argument_option(action, :user_info, :allow_nil?, [false]),
:ok <- validate_action_has_argument(action, :oauth_tokens),
:ok <-
validate_action_argument_option(action, :oauth_tokens, :type, [Type.Map, :map]),
:ok <- validate_action_argument_option(action, :oauth_tokens, :allow_nil?, [false]),
:ok <- maybe_validate_action_has_token_change(dsl_state, action),
:ok <- validate_field_in_values(action, :upsert?, [true]),
:ok <-
validate_field_with(
action,
:upsert_identity,
&(is_atom(&1) and not is_falsy(&1)),
"Expected `upsert_identity` to be set"
),
:ok <- maybe_validate_action_has_identity_change(action, strategy) do
:ok
else
{:error, reason} when is_binary(reason) ->
{:error, "`#{inspect(strategy.register_action_name)}` action: #{reason}"}
{:error, reason} ->
{:error, reason}
end
end
defp maybe_validate_register_action(_dsl_state, _strategy), do: :ok
defp maybe_validate_action_has_token_change(dsl_state, action) do
if Info.authentication_tokens_enabled?(dsl_state) do
validate_action_has_change(action, GenerateTokenChange)
else
:ok
end
end
defp maybe_validate_action_has_identity_change(_action, strategy)
when is_falsy(strategy.identity_resource),
do: :ok
defp maybe_validate_action_has_identity_change(action, _strategy),
do: validate_action_has_change(action, OAuth2.IdentityChange)
defp maybe_validate_sign_in_action(_dsl_state, strategy) when strategy.registration_enabled?,
do: :ok
defp maybe_validate_sign_in_action(dsl_state, strategy) do
with {:ok, action} <- validate_action_exists(dsl_state, strategy.sign_in_action_name),
:ok <- validate_action_has_argument(action, :user_info),
:ok <- validate_action_argument_option(action, :user_info, :type, [Ash.Type.Map, :map]),
:ok <- validate_action_argument_option(action, :user_info, :allow_nil?, [false]),
:ok <- validate_action_has_argument(action, :oauth_tokens),
:ok <-
validate_action_argument_option(action, :oauth_tokens, :type, [Ash.Type.Map, :map]),
:ok <- validate_action_argument_option(action, :oauth_tokens, :allow_nil?, [false]),
:ok <- validate_action_has_preparation(action, OAuth2.SignInPreparation) do
:ok
else
{:error, reason} -> {:error, reason}
end
end
end