improvement: allow turning new authorization behavior off

This commit is contained in:
Zach Daniel 2024-02-20 13:28:32 -05:00
parent 2b8a6926ae
commit 27d0ebb154
5 changed files with 75 additions and 31 deletions

View file

@ -22,7 +22,7 @@ if Mix.env() == :test do
triggered_say_hello: 10
]
config :ash_oban, :actor_persister, AshOban.Test.ActorPersister
config :ash_oban, actor_persister: AshOban.Test.ActorPersister
config :ash_oban, AshOban.Test.Repo,
username: "postgres",

View file

@ -114,6 +114,23 @@ and
}
```
## Authorizing actions
As of v0.2, `authorize?: true` is passed into every action that is called. This may be a breaking change for some users that are using policies. There are two ways to get around this:
1. you can set `config :ash_oban, authorize?: false` (easiest, reverts to old behavior, but not recommended)
2. you can install the bypass at the top of your policies in any resource that you have triggers on that has policies:
```elixir
policies do
bypass AshOban.Checks.AshObanInteraction do
authorize_if always()
end
...the rest of your policies
end
```
## Persisting the actor along with a job
Create a module that is responsible for translating the current user to a value that will be JSON encoded, and for turning that encoded value back into an actor.

View file

@ -394,22 +394,27 @@ defmodule AshOban do
|> case do
%AshOban.Schedule{worker: worker} ->
%{}
|> persist_actor(opts[:actor])
|> store_actor(opts[:actor])
|> worker.new()
|> Oban.insert!()
%AshOban.Trigger{scheduler: scheduler} ->
%{}
|> persist_actor(opts[:actor])
|> store_actor(opts[:actor])
|> scheduler.new()
|> Oban.insert!()
end
end
@spec persist_actor(args :: map, actor :: any) :: any
def persist_actor(args, nil), do: args
@spec authorize? :: boolean
def authorize? do
Application.get_env(:ash_oban, :authorize?, true)
end
def persist_actor(args, actor) do
@spec store_actor(args :: map, actor :: any) :: any
def store_actor(args, nil), do: args
def store_actor(args, actor) do
case Application.get_env(:ash_oban, :actor_persister) do
nil ->
args
@ -463,7 +468,7 @@ defmodule AshOban do
end
%{primary_key: Map.take(record, primary_key), metadata: metadata}
|> AshOban.persist_actor(opts[:actor])
|> AshOban.store_actor(opts[:actor])
|> trigger.worker.new(oban_job_opts)
|> Oban.insert!()
end

View file

@ -73,27 +73,39 @@ defmodule AshOban.Transformers.DefineActionWorkers do
require Logger
@impl unquote(worker)
def unquote(function_name)(%Oban.Job{} = job) do
AshOban.debug(
"Scheduled action #{unquote(inspect(resource))}.#{unquote(scheduled_action.name)} triggered.",
unquote(scheduled_action.debug?)
)
def unquote(function_name)(%Oban.Job{args: args} = job) do
case AshOban.lookup_actor(args["actor"]) do
{:ok, actor} ->
authorize? = AshOban.authorize?()
input = unquote(Macro.escape(scheduled_action.action_input || %{}))
AshOban.debug(
"Scheduled action #{unquote(inspect(resource))}.#{unquote(scheduled_action.name)} triggered.",
unquote(scheduled_action.debug?)
)
input =
if job.max_attempts == job.attempt do
Map.put(input, :last_oban_attempt?, true)
else
Map.put(input, :last_oban_attempt?, false)
end
input = unquote(Macro.escape(scheduled_action.action_input || %{}))
unquote(resource)
|> Ash.ActionInput.for_action(
unquote(scheduled_action.action),
input
)
|> unquote(api).run_action()
input =
if job.max_attempts == job.attempt do
Map.put(input, :last_oban_attempt?, true)
else
Map.put(input, :last_oban_attempt?, false)
end
unquote(resource)
|> Ash.ActionInput.for_action(
unquote(scheduled_action.action),
input,
authorize?: authorize?,
actor: actor
)
|> unquote(api).run_action!()
:ok
{:error, error} ->
raise Ash.Error.to_ash_error(error)
end
end
end,
Macro.Env.location(__ENV__)

View file

@ -100,7 +100,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> Ash.Query.select(unquote(primary_key))
|> limit_stream()
|> Ash.Query.for_read(unquote(trigger.read_action), %{},
authorize?: true,
authorize?: AshOban.authorize?(),
actor: actor
)
|> unquote(api).stream!(unquote(batch_opts))
@ -115,7 +115,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> limit_stream()
|> filter()
|> Ash.Query.for_read(unquote(trigger.read_action), %{},
authorize?: true,
authorize?: AshOban.authorize?(),
actor: actor
)
|> unquote(api).stream!()
@ -432,12 +432,17 @@ defmodule AshOban.Transformers.DefineSchedulers do
primary_key,
stacktrace
) do
authorize? = AshOban.authorize?()
case AshOban.lookup_actor(args["actor"]) do
{:ok, actor} ->
query()
|> Ash.Query.do_filter(primary_key)
|> Ash.Query.set_context(%{private: %{ash_oban?: true}})
|> Ash.Query.for_read(unquote(read_action), %{}, authorize?: true, actor: actor)
|> Ash.Query.for_read(unquote(read_action), %{},
authorize?: authorize?,
actor: actor
)
|> unquote(api).read_one()
|> case do
{:error, error} ->
@ -468,7 +473,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> prepare_error(primary_key)
|> Ash.Changeset.set_context(%{private: %{ash_oban?: true}})
|> Ash.Changeset.for_action(unquote(trigger.on_error), %{error: error},
authorize?: true,
authorize?: authorize?,
actor: actor
)
|> AshOban.update_or_destroy(unquote(api))
@ -546,10 +551,15 @@ defmodule AshOban.Transformers.DefineSchedulers do
case AshOban.lookup_actor(args["actor"]) do
{:ok, actor} ->
authorize? = AshOban.authorize?()
query()
|> Ash.Query.do_filter(primary_key)
|> Ash.Query.set_context(%{private: %{ash_oban?: true}})
|> Ash.Query.for_read(unquote(read_action), %{}, authorize?: true, actor: actor)
|> Ash.Query.for_read(unquote(read_action), %{},
authorize?: authorize?,
actor: actor
)
|> unquote(api).read_one()
|> case do
{:ok, nil} ->
@ -575,7 +585,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> Ash.Changeset.for_action(
unquote(trigger.action),
Map.merge(unquote(Macro.escape(trigger.action_input || %{})), args),
authorize?: true,
authorize?: authorize?,
actor: actor
)
|> AshOban.update_or_destroy(unquote(api))