Packages
ash_authentication
4.13.6
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/api_key/verifier.ex
# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Strategy.ApiKey.Verifier do
@moduledoc """
DSL verifier for API key authentication.
"""
alias Ash.Resource.Info, as: ResourceInfo
alias AshAuthentication.{Strategy.ApiKey}
alias Spark.Dsl.Transformer
alias Spark.Error.DslError
import AshAuthentication.Validations
import AshAuthentication.Validations.Action
@doc false
@spec verify(ApiKey.t(), map) :: :ok | {:error, Exception.t()}
def verify(strategy, dsl_state) do
with :ok <- validate_api_key_relationship(dsl_state, strategy),
:ok <- validate_multitenancy_relationship(dsl_state, strategy),
:ok <- validate_api_key_hash_attribute(dsl_state, strategy),
:ok <- validate_api_key_id_attribute(dsl_state, strategy) do
validate_sign_in_action(dsl_state, strategy)
end
end
defp validate_api_key_relationship(dsl_state, strategy) do
case ResourceInfo.relationship(dsl_state, strategy.api_key_relationship) do
nil ->
resource = Transformer.get_persisted(dsl_state, :module)
{:error,
DslError.exception(
path: [:relationships],
message:
"The resource `#{inspect(resource)}` does not define a relationship named `#{inspect(strategy.api_key_relationship)}`"
)}
_relationship ->
:ok
end
end
defp validate_multitenancy_relationship(_dsl_state, %{multitenancy_relationship: nil}), do: :ok
defp validate_multitenancy_relationship(dsl_state, strategy) do
relationship = ResourceInfo.relationship(dsl_state, strategy.api_key_relationship)
destination = relationship.destination
case ResourceInfo.relationship(destination, strategy.multitenancy_relationship) do
nil ->
{:error,
DslError.exception(
path: [:relationships],
message:
"The API key resource `#{inspect(destination)}` does not define a relationship named `#{inspect(strategy.multitenancy_relationship)}`"
)}
_relationship ->
:ok
end
end
defp validate_api_key_hash_attribute(dsl_state, strategy) do
relationship = ResourceInfo.relationship(dsl_state, strategy.api_key_relationship)
destination = relationship.destination
case ResourceInfo.attribute(destination, strategy.api_key_hash_attribute) do
nil ->
{:error,
DslError.exception(
path: [:authentication, :strategies, strategy.name],
message:
"The API key resource `#{inspect(destination)}` does not define an attribute named `#{inspect(strategy.api_key_hash_attribute)}`"
)}
_attribute ->
:ok
end
end
defp validate_api_key_id_attribute(dsl_state, strategy) do
relationship = ResourceInfo.relationship(dsl_state, strategy.api_key_relationship)
destination = relationship.destination
case ResourceInfo.attribute(destination, :id) do
nil ->
{:error,
DslError.exception(
path: [:authentication, :strategies, strategy.name],
message:
"The API key resource `#{inspect(destination)}` does not define an attribute named `id`"
)}
attribute ->
validate_id_is_primary_key(dsl_state, destination, attribute)
end
end
defp validate_id_is_primary_key(_dsl_state, destination, attribute) do
if attribute.primary_key? do
:ok
else
{:error,
DslError.exception(
path: [:authentication, :strategies],
message: "The API key resource `#{inspect(destination)}` must have `id` as a primary key"
)}
end
end
defp 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, :api_key),
:ok <-
validate_action_argument_option(action, :api_key, :type, [
:string,
Ash.Type.String
]),
:ok <-
validate_action_argument_option(action, :api_key, :allow_nil?, [false]),
:ok <- validate_field_in_values(action, :type, [:read]) do
validate_action_has_preparation(action, ApiKey.SignInPreparation)
else
{:error, message} when is_binary(message) ->
{:error,
DslError.exception(
path: [:actions, :read, strategy.sign_in_action_name, :type],
message: message
)}
{:error, exception} when is_exception(exception) ->
{:error, exception}
end
end
end