Skip to content

Commit

Permalink
improvement: Add opts to retrieve funs of AshAuthentication.Plug.Help…
Browse files Browse the repository at this point in the history
…ers (#847)
  • Loading branch information
nallwhy authored Nov 26, 2024
1 parent 5616ae1 commit a451338
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 28 deletions.
36 changes: 24 additions & 12 deletions lib/ash_authentication/plug/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ defmodule AshAuthentication.Plug.Helpers do
If there is no user present for a resource then the assign is set to `nil`.
"""
@spec retrieve_from_session(Conn.t(), module) :: Conn.t()
def retrieve_from_session(conn, otp_app) do
@spec retrieve_from_session(Conn.t(), module, keyword) :: Conn.t()
def retrieve_from_session(conn, otp_app, opts \\ []) do
otp_app
|> AshAuthentication.authenticated_resources()
|> Stream.map(
Expand All @@ -91,9 +91,14 @@ defmodule AshAuthentication.Plug.Helpers do
context: Ash.PlugHelpers.get_context(conn) || %{}
),
{:ok, user} <-
AshAuthentication.subject_to_user(subject, resource,
tenant: Ash.PlugHelpers.get_tenant(conn),
context: Ash.PlugHelpers.get_context(conn) || %{}
AshAuthentication.subject_to_user(
subject,
resource,
[
tenant: Ash.PlugHelpers.get_tenant(conn),
context: Ash.PlugHelpers.get_context(conn) || %{}
]
|> Keyword.merge(opts)
) do
Conn.assign(conn, current_subject_name, user)
else
Expand All @@ -105,8 +110,10 @@ defmodule AshAuthentication.Plug.Helpers do

with subject when is_binary(subject) <- Conn.get_session(conn, options.subject_name),
{:ok, user} <-
AshAuthentication.subject_to_user(subject, resource,
tenant: Ash.PlugHelpers.get_tenant(conn)
AshAuthentication.subject_to_user(
subject,
resource,
[tenant: Ash.PlugHelpers.get_tenant(conn)] |> Keyword.merge(opts)
) do
Conn.assign(conn, current_subject_name, user)
else
Expand All @@ -128,8 +135,8 @@ defmodule AshAuthentication.Plug.Helpers do
If there is no user present for a resource then the assign is set to `nil`.
"""
@spec retrieve_from_bearer(Conn.t(), module) :: Conn.t()
def retrieve_from_bearer(conn, otp_app) do
@spec retrieve_from_bearer(Conn.t(), module, keyword) :: Conn.t()
def retrieve_from_bearer(conn, otp_app, opts \\ []) do
conn
|> Conn.get_req_header("authorization")
|> Stream.filter(&String.starts_with?(&1, "Bearer "))
Expand All @@ -140,9 +147,14 @@ defmodule AshAuthentication.Plug.Helpers do
{:ok, token_record} <-
validate_token(resource, jti),
{:ok, user} <-
AshAuthentication.subject_to_user(subject, resource,
tenant: Ash.PlugHelpers.get_tenant(conn),
context: Ash.PlugHelpers.get_context(conn) || %{}
AshAuthentication.subject_to_user(
subject,
resource,
[
tenant: Ash.PlugHelpers.get_tenant(conn),
context: Ash.PlugHelpers.get_context(conn) || %{}
]
|> Keyword.merge(opts)
),
{:ok, subject_name} <- Info.authentication_subject_name(resource),
current_subject_name <- current_subject_name(subject_name) do
Expand Down
12 changes: 6 additions & 6 deletions lib/ash_authentication/plug/macros.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ defmodule AshAuthentication.Plug.Macros do
@doc """
Attempt to retrieve all users from the connections' session.
A wrapper around `AshAuthentication.Plug.Helpers.retrieve_from_session/2`
A wrapper around `AshAuthentication.Plug.Helpers.retrieve_from_session/3`
with the `otp_app` already present.
"""
@spec load_from_session(Conn.t(), any) :: Conn.t()
def load_from_session(conn, _opts),
do: Helpers.retrieve_from_session(conn, unquote(otp_app))
def load_from_session(conn, opts),
do: Helpers.retrieve_from_session(conn, unquote(otp_app), opts)
end
end

Expand All @@ -78,11 +78,11 @@ defmodule AshAuthentication.Plug.Macros do
@doc """
Attempt to retrieve users from the `Authorization` header(s).
A wrapper around `AshAuthentication.Plug.Helpers.retrieve_from_bearer/2` with the `otp_app` already present.
A wrapper around `AshAuthentication.Plug.Helpers.retrieve_from_bearer/3` with the `otp_app` already present.
"""
@spec load_from_bearer(Conn.t(), any) :: Conn.t()
def load_from_bearer(conn, _opts),
do: Helpers.retrieve_from_bearer(conn, unquote(otp_app))
def load_from_bearer(conn, opts),
do: Helpers.retrieve_from_bearer(conn, unquote(otp_app), opts)
end
end

Expand Down
48 changes: 46 additions & 2 deletions test/ash_authentication/plug/helpers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule AshAuthentication.Plug.HelpersTest do
end
end

describe "retrieve_from_session/2" do
describe "retrieve_from_session/3" do
test "when token presence is not required it loads any subjects stored in the session", %{
conn: conn
} do
Expand Down Expand Up @@ -120,9 +120,32 @@ defmodule AshAuthentication.Plug.HelpersTest do

refute conn.assigns.current_user_with_token_required
end

test "with opts", %{conn: conn} do
# without token
user = build_user()
subject = AshAuthentication.user_to_subject(user)

conn0 =
conn
|> Conn.put_session("user", subject)
|> Helpers.retrieve_from_session(:ash_authentication, load: [:dummy_calc])

assert conn0.assigns.current_user.dummy_calc == "dummy"

# with token
user_with_token = build_user_with_token_required()

conn1 =
conn
|> Conn.put_session("user_with_token_required_token", user_with_token.__metadata__.token)
|> Helpers.retrieve_from_session(:ash_authentication, load: [:dummy_calc])

assert conn1.assigns.current_user_with_token_required.dummy_calc == "dummy"
end
end

describe "retrieve_from_bearer/2" do
describe "retrieve_from_bearer/3" do
test "when token presense is not required it loads any subjects from authorization header(s)",
%{conn: conn} do
user = build_user()
Expand Down Expand Up @@ -200,6 +223,27 @@ defmodule AshAuthentication.Plug.HelpersTest do

refute is_map_key(conn.assigns, :current_user_with_token_required)
end

test "with opts", %{conn: conn} do
user = build_user()

conn0 =
conn
|> Conn.put_req_header("authorization", "Bearer #{user.__metadata__.token}")
|> Helpers.retrieve_from_bearer(:ash_authentication, load: [:dummy_calc])

assert conn0.assigns.current_user.dummy_calc == "dummy"

# with token
user_with_token = build_user_with_token_required()

conn1 =
conn
|> Conn.put_req_header("authorization", "Bearer #{user_with_token.__metadata__.token}")
|> Helpers.retrieve_from_bearer(:ash_authentication, load: [:dummy_calc])

assert conn1.assigns.current_user_with_token_required.dummy_calc == "dummy"
end
end

describe "revoke_bearer_tokens/2" do
Expand Down
18 changes: 10 additions & 8 deletions test/ash_authentication/plug_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,35 @@ defmodule AshAuthentication.PlugTest do
end
end

describe "load_from_session/2" do
test "it delegates to Helpers.retrieve_from_session/2" do
describe "load_from_session/3" do
test "it delegates to Helpers.retrieve_from_session/3" do
conn = conn(:get, "/", %{})

Helpers
|> expect(:retrieve_from_session, fn rx_conn, otp_app ->
|> expect(:retrieve_from_session, fn rx_conn, otp_app, opts ->
assert otp_app == :ash_authentication
assert conn == rx_conn
assert opts == [load: [:company]]
end)

conn
|> AuthPlug.load_from_session([])
|> AuthPlug.load_from_session(load: [:company])
end
end

describe "load_from_bearer/2" do
test "it delegates to Helpers.retrieve_from_bearer/2" do
describe "load_from_bearer/3" do
test "it delegates to Helpers.retrieve_from_bearer/3" do
conn = conn(:get, "/", %{})

Helpers
|> expect(:retrieve_from_bearer, fn rx_conn, otp_app ->
|> expect(:retrieve_from_bearer, fn rx_conn, otp_app, opts ->
assert otp_app == :ash_authentication
assert conn == rx_conn
assert opts == [load: [:company]]
end)

conn
|> AuthPlug.load_from_bearer([])
|> AuthPlug.load_from_bearer(load: [:company])
end
end

Expand Down
4 changes: 4 additions & 0 deletions test/support/example/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ defmodule Example.User do
end
end

calculations do
calculate :dummy_calc, :string, expr("dummy")
end

code_interface do
define :update_user, action: :update
end
Expand Down
4 changes: 4 additions & 0 deletions test/support/example/user_with_token_required.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ defmodule Example.UserWithTokenRequired do
defaults [:create, :read, :update, :destroy]
end

calculations do
calculate :dummy_calc, :string, expr("dummy")
end

identities do
identity :email, [:email]
end
Expand Down

0 comments on commit a451338

Please sign in to comment.