Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions lib/ash_authentication/plug/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,13 @@ defmodule AshAuthentication.Plug.Helpers do
authenticate_resource_from_session(resource, session, otp_app, opts),
resource,
options,
session
session,
opts
)
end)
end

defp handle_session_auth_result(conn, {:ok, user}, _resource, options, session) do
defp handle_session_auth_result(conn, {:ok, user}, _resource, options, session, _opts) do
current_subject_name = current_subject_name(options.subject_name)

# Restore authentication metadata from the session onto the user
Expand All @@ -230,7 +231,7 @@ defmodule AshAuthentication.Plug.Helpers do
Conn.assign(conn, current_subject_name, user)
end

defp handle_session_auth_result(conn, :error, resource, options, _session) do
defp handle_session_auth_result(conn, :error, resource, options, _session, opts) do
current_subject_name = current_subject_name(options.subject_name)

require_token? =
Expand All @@ -239,9 +240,22 @@ defmodule AshAuthentication.Plug.Helpers do
session_key =
if require_token?, do: session_key(options.subject_name), else: options.subject_name

conn
|> Conn.assign(current_subject_name, nil)
|> Conn.delete_session(session_key)
conn = Conn.assign(conn, current_subject_name, nil)

if tenant_required?(resource, opts) do
# The lookup was rejected before it could reach the data layer because this
# request has no tenant, so we know nothing about whether the session is
# valid and must leave it alone rather than signing the user out.
conn
else
Conn.delete_session(conn, session_key)
end
end

defp tenant_required?(resource, opts) do
is_nil(Keyword.get(opts, :tenant)) and
not is_nil(Resource.Info.multitenancy_strategy(resource)) and
not Resource.Info.multitenancy_global?(resource)
end

defp restore_metadata_from_session(user, subject_name, session) do
Expand Down
27 changes: 27 additions & 0 deletions test/ash_authentication/plug/helpers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,33 @@ defmodule AshAuthentication.Plug.HelpersTest do
refute conn.assigns.current_user_with_token_required
end

test "when the subject can't be found it removes the session", %{conn: conn} do
conn =
conn
|> Conn.put_session("user", "jti:user?id=#{Ash.UUID.generate()}")
|> Helpers.retrieve_from_session(:ash_authentication)

refute conn.assigns.current_user
refute conn.private.plug_session["user"]
end

test "when a resource requires a tenant and the request has none it keeps the session", %{
conn: conn
} do
# Without a tenant the query is rejected by Ash before it reaches the data
# layer, so we have learned nothing about whether the session is valid and
# must not discard it.
session_value = "jti:multi_tenant_user_with_web_authn?id=#{Ash.UUID.generate()}"

conn =
conn
|> Conn.put_session("multi_tenant_user_with_web_authn", session_value)
|> Helpers.retrieve_from_session(:ash_authentication)

refute conn.assigns.current_multi_tenant_user_with_web_authn
assert conn.private.plug_session["multi_tenant_user_with_web_authn"] == session_value
end

test "with opts", %{conn: conn} do
# without token
user = build_user()
Expand Down