@@ -64,7 +64,7 @@ pub(crate) async fn login_through_ldap_with_connection(
6464 debug ! ( "User {ldap_user} logged in through LDAP" ) ;
6565 // The user is logging in through LDAP, so we can infer that there are no other login options
6666 // (Defguard password), so we should mark them as from_ldap.
67- let user = if let Some ( mut defguard_user) =
67+ let ( mut user, is_new_user ) = if let Some ( mut defguard_user) =
6868 User :: find_by_username ( & mut * transaction, & ldap_user. username ) . await ?
6969 {
7070 debug ! (
@@ -73,7 +73,7 @@ pub(crate) async fn login_through_ldap_with_connection(
7373 ) ;
7474 defguard_user. from_ldap = true ;
7575 defguard_user. save ( & mut * transaction) . await ?;
76- defguard_user
76+ ( defguard_user, false )
7777 } else {
7878 debug ! (
7979 "User {ldap_user} doesn't exist in Defguard, creating them first based on LDAP data"
@@ -89,13 +89,20 @@ pub(crate) async fn login_through_ldap_with_connection(
8989 }
9090
9191 ldap_user. from_ldap = true ;
92- let mut saved_user = ldap_user. save ( & mut * transaction) . await ?;
93- try_send_ldap_enrollment_invite ( & mut saved_user, & mut transaction) . await ;
94- saved_user
92+ ( ldap_user. save ( & mut * transaction) . await ?, true )
9593 } ;
9694
9795 transaction. commit ( ) . await ?;
9896
97+ // Attempt to send enrollment invite after the original DB transaction is committed,
98+ // so that the user row is visible to the new transaction inside try_send_ldap_enrollment_invite.
99+ // Only send for newly-created users — returning users must not receive a second invite.
100+ if is_new_user {
101+ let mut transaction = pool. begin ( ) . await ?;
102+ try_send_ldap_enrollment_invite ( & mut user, & mut transaction) . await ;
103+ transaction. commit ( ) . await ?;
104+ }
105+
99106 Ok ( user)
100107}
101108
0 commit comments