fix oidc security bug
This commit is contained in:
parent
4f3d0c21a8
commit
293e85334f
3 changed files with 177 additions and 1 deletions
|
|
@ -171,6 +171,40 @@ defmodule Mv.Accounts.User do
|
|||
change AshAuthentication.Strategy.Password.HashPasswordChange
|
||||
end
|
||||
|
||||
# Action to link an OIDC account to an existing password-only user
|
||||
# This is called after the user has verified their password
|
||||
update :link_oidc_id do
|
||||
description "Links an OIDC ID to an existing user after password verification"
|
||||
accept []
|
||||
argument :oidc_id, :string, allow_nil?: false
|
||||
argument :oidc_user_info, :map, allow_nil?: false
|
||||
require_atomic? false
|
||||
|
||||
change fn changeset, _ctx ->
|
||||
oidc_id = Ash.Changeset.get_argument(changeset, :oidc_id)
|
||||
oidc_user_info = Ash.Changeset.get_argument(changeset, :oidc_user_info)
|
||||
|
||||
# Get the new email from OIDC user_info
|
||||
new_email = Map.get(oidc_user_info, "preferred_username")
|
||||
|
||||
changeset
|
||||
|> Ash.Changeset.change_attribute(:oidc_id, oidc_id)
|
||||
# Update email if it differs from OIDC provider
|
||||
|> then(fn cs ->
|
||||
if new_email && to_string(cs.data.email) != new_email do
|
||||
Ash.Changeset.change_attribute(cs, :email, new_email)
|
||||
else
|
||||
cs
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
# Sync email changes to member if email was updated
|
||||
change Mv.EmailSync.Changes.SyncUserEmailToMember do
|
||||
where [changing(:email)]
|
||||
end
|
||||
end
|
||||
|
||||
read :get_by_subject do
|
||||
description "Get a user by the subject claim in a JWT"
|
||||
argument :subject, :string, allow_nil?: false
|
||||
|
|
@ -183,7 +217,11 @@ defmodule Mv.Accounts.User do
|
|||
argument :oauth_tokens, :map, allow_nil?: false
|
||||
prepare AshAuthentication.Strategy.OAuth2.SignInPreparation
|
||||
|
||||
filter expr(email == get_path(^arg(:user_info), [:preferred_username]))
|
||||
# SECURITY: Filter by oidc_id, NOT by email!
|
||||
# This ensures that OIDC sign-in only works for users who have already
|
||||
# linked their account via OIDC. Password-only users (oidc_id = nil)
|
||||
# cannot be accessed via OIDC login without password verification.
|
||||
filter expr(oidc_id == get_path(^arg(:user_info), [:sub]))
|
||||
end
|
||||
|
||||
create :register_with_rauthy do
|
||||
|
|
@ -204,6 +242,10 @@ defmodule Mv.Accounts.User do
|
|||
|> Ash.Changeset.change_attribute(:oidc_id, user_info["sub"] || user_info["id"])
|
||||
end
|
||||
|
||||
# Check for email collisions with existing password-only accounts
|
||||
# This validation must run AFTER email and oidc_id are set above
|
||||
validate Mv.Accounts.User.Validations.OidcEmailCollision
|
||||
|
||||
# Sync user email to member when linking (User → Member)
|
||||
change Mv.EmailSync.Changes.SyncUserEmailToMember
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue