Fix OIDC account linking by using SystemActor in LinkOidcAccountLive
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- Add SystemActor to all Ash operations in LinkOidcAccountLive - Enables user lookup, reload, and oidc_id linking during OIDC flow - User is not yet logged in during linking, so SystemActor provides authorization
This commit is contained in:
parent
bad4e5ca7c
commit
41e342a1d6
1 changed files with 16 additions and 4 deletions
|
|
@ -20,10 +20,13 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, session, socket) do
|
def mount(_params, session, socket) do
|
||||||
|
# Use SystemActor for authorization during OIDC linking (user is not yet logged in)
|
||||||
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
||||||
with user_id when not is_nil(user_id) <- Map.get(session, "oidc_linking_user_id"),
|
with user_id when not is_nil(user_id) <- Map.get(session, "oidc_linking_user_id"),
|
||||||
oidc_user_info when not is_nil(oidc_user_info) <-
|
oidc_user_info when not is_nil(oidc_user_info) <-
|
||||||
Map.get(session, "oidc_linking_user_info"),
|
Map.get(session, "oidc_linking_user_info"),
|
||||||
{:ok, user} <- Ash.get(Mv.Accounts.User, user_id) do
|
{:ok, user} <- Ash.get(Mv.Accounts.User, user_id, actor: system_actor) do
|
||||||
# Check if user is passwordless
|
# Check if user is passwordless
|
||||||
if passwordless?(user) do
|
if passwordless?(user) do
|
||||||
# Auto-link passwordless user immediately
|
# Auto-link passwordless user immediately
|
||||||
|
|
@ -46,9 +49,12 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp reload_user!(user_id) do
|
defp reload_user!(user_id) do
|
||||||
|
# Use SystemActor for authorization during OIDC linking (user is not yet logged in)
|
||||||
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
||||||
Mv.Accounts.User
|
Mv.Accounts.User
|
||||||
|> Ash.Query.filter(id == ^user_id)
|
|> Ash.Query.filter(id == ^user_id)
|
||||||
|> Ash.read_one!()
|
|> Ash.read_one!(actor: system_actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp reset_password_form(socket) do
|
defp reset_password_form(socket) do
|
||||||
|
|
@ -58,13 +64,16 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
defp auto_link_passwordless_user(socket, user, oidc_user_info) do
|
defp auto_link_passwordless_user(socket, user, oidc_user_info) do
|
||||||
oidc_id = Map.get(oidc_user_info, "sub") || Map.get(oidc_user_info, "id")
|
oidc_id = Map.get(oidc_user_info, "sub") || Map.get(oidc_user_info, "id")
|
||||||
|
|
||||||
|
# Use SystemActor for authorization (passwordless user auto-linking)
|
||||||
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
||||||
case user.id
|
case user.id
|
||||||
|> reload_user!()
|
|> reload_user!()
|
||||||
|> Ash.Changeset.for_update(:link_oidc_id, %{
|
|> Ash.Changeset.for_update(:link_oidc_id, %{
|
||||||
oidc_id: oidc_id,
|
oidc_id: oidc_id,
|
||||||
oidc_user_info: oidc_user_info
|
oidc_user_info: oidc_user_info
|
||||||
})
|
})
|
||||||
|> Ash.update() do
|
|> Ash.update(actor: system_actor) do
|
||||||
{:ok, updated_user} ->
|
{:ok, updated_user} ->
|
||||||
Logger.info(
|
Logger.info(
|
||||||
"Passwordless account auto-linked to OIDC: user_id=#{updated_user.id}, oidc_id=#{oidc_id}"
|
"Passwordless account auto-linked to OIDC: user_id=#{updated_user.id}, oidc_id=#{oidc_id}"
|
||||||
|
|
@ -187,6 +196,9 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
defp link_oidc_account(socket, user, oidc_user_info) do
|
defp link_oidc_account(socket, user, oidc_user_info) do
|
||||||
oidc_id = Map.get(oidc_user_info, "sub") || Map.get(oidc_user_info, "id")
|
oidc_id = Map.get(oidc_user_info, "sub") || Map.get(oidc_user_info, "id")
|
||||||
|
|
||||||
|
# Use SystemActor for authorization (user just verified password but is not yet logged in)
|
||||||
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
||||||
# Update the user with the OIDC ID
|
# Update the user with the OIDC ID
|
||||||
case user.id
|
case user.id
|
||||||
|> reload_user!()
|
|> reload_user!()
|
||||||
|
|
@ -194,7 +206,7 @@ defmodule MvWeb.LinkOidcAccountLive do
|
||||||
oidc_id: oidc_id,
|
oidc_id: oidc_id,
|
||||||
oidc_user_info: oidc_user_info
|
oidc_user_info: oidc_user_info
|
||||||
})
|
})
|
||||||
|> Ash.update() do
|
|> Ash.update(actor: system_actor) do
|
||||||
{:ok, updated_user} ->
|
{:ok, updated_user} ->
|
||||||
# After successful linking, redirect to OIDC login
|
# After successful linking, redirect to OIDC login
|
||||||
# Since the user now has an oidc_id, the next OIDC login will succeed
|
# Since the user now has an oidc_id, the next OIDC login will succeed
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue