LdapRecord-Laravel icon indicating copy to clipboard operation
LdapRecord-Laravel copied to clipboard

[Bug] Delete and Restore not soft-deleting/restoring users

Open dereknutile opened this issue 1 year ago • 11 comments

Environment:

  • LDAP Server Type: ActiveDirectory
  • LdapRecord-Laravel Major Version: v3.3.5
  • PHP Version: 8.3.7
  • Laravel Framework: v11.34.2

Recently I upgraded both Laravel (9 to 11) and LdapRecord (v2 to v3). Since then the --delete and --restore functionality stopped. All the other synchronization works fine. I'm not sure how to capture verbosely what is happening with those functions, but the logs state the user is being synchronized. I set this user to disabled in AD and syncronized, here's the log output:

[2024-12-19 20:59:55] local.INFO: LDAP (ldap://my.domain:389) - Operation: Binding - Username: myserviceaccount
[2024-12-19 20:59:55] local.INFO: LDAP (ldap://my.domain:389) - Operation: Bound - Username: myserviceaccount
[2024-12-19 20:59:55] local.INFO: LDAP (ldap://my.domain:389) - Operation: Paginate - Base DN: DC=xxx,DC=xxx,DC=xxx,DC=xxx - Filter: (&(samAccountName=adent)(objectclass=\75\73\65\72)(objectclass=\50\65\72\73\6f\6e)) - Selected: (objectguid,*) - Time Elapsed: 91.61
[2024-12-19 20:59:55] local.INFO: Starting import of [1] LDAP objects.
[2024-12-19 20:59:55] local.INFO: Object with name [Dent, Arthur] is being synchronized.
[2024-12-19 20:59:56] local.INFO: Object with name [Dent, Arthur] has been successfully synchronized.
[2024-12-19 20:59:56] local.INFO: Completed import. Imported [0] new LDAP objects. Synchronized [1] existing LDAP objects.

The local user database no longer soft-deletes the user. image

dereknutile avatar Dec 19 '24 21:12 dereknutile

Hi @dereknutile, apologies for the late reply.

The import logic between v2 and v3 are functionally the same.

Does your users database table contain a domain column?

stevebauman avatar Jan 09 '25 01:01 stevebauman

Also, can you please post the whole command you are running?

stevebauman avatar Jan 09 '25 01:01 stevebauman

Hi @stevebauman, thank you for the reply. Yes, my users table does have a domain column. The command I'm using for my test user is as follows:

php artisan ldap:import ccso --delete --restore --filter "(samAccountName=adent)"

Found user [CN=Dent\2c Arthur]. Would you like to display the user(s) to be imported / synchronized? (yes/no) [no]: yes +------------------------------------------------------------------------------+--------------------+ | Name | Distinguished Name | +------------------------------------------------------------------------------+--------------------+ | CN=Dent, Arthur,OU=gptest,OU=Users,OU=xxx,DC=xxx,DC=ds,DC=xxx,DC=us | CN=Dent\2c Arthur | +------------------------------------------------------------------------------+--------------------+ Would you like these users to be imported / synchronized? (yes/no) [yes]: yes 1/1 [============================] 100% Successfully imported / synchronized [1] user(s).

It finds and synchronizes the user, but no longer flips the deleted_at flag.

image

dereknutile avatar Jan 13 '25 22:01 dereknutile

Thanks for the reply @dereknutile.

Do you also have a guid column? I'd recommend dumping the output from the queries in this file to debug further:

https://github.com/DirectoryTree/LdapRecord-Laravel/blob/bf579af1f2a1d4942a43e7dfd186860eb12b04fc/src/Import/Importer.php#L371-L405

Add dd() calls to the script and then re-run your import script with a deleted user to see where it's missing the user account.

stevebauman avatar Jan 13 '25 23:01 stevebauman

Hey @stevebauman , yes, I have a guid column in the users table named objectguid.

The account is found in AD. If I dd($object, $eloquent) on vendor\directorytree\ldaprecord-laravel\src\Import\Importer.php (line 271), I believe I'm capturing the two objects 1) the LDAP object and 2) the Users table object right before the synchronize(). If I understand how AD flags a user as disabled (https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/useraccountcontrol-manipulate-account-properties), the useraccountcontrol property will be set to 514 (512 for enabled).

What the dd() output shows below is the LDAP object retrieved from AD is disabled, and the User object retrieved from the table is not soft-deleted. The synchronize() that follows I would expect to soft-delete the user.

Found user [CN =Dent\2c Arthur]. App\Ldap\Ccso\User {#2234 +exists: true +wasRecentlyCreated: false +wasRecentlyRenamed: false #dn: "CN=Dent, Arthur,OU=gptest,OU=Users,OU=CCSO,DC=ccso,DC=ds,DC=clackamas,DC=us" #in: null #connection: "ccso" #guidKey: "objectguid" #modifications: [] #changes: [] #attributes: array:79 [ "objectclass" => array:4 [ 0 => "top" 1 => "person" 2 => "organizationalPerson" 3 => "user" ] "cn" => array:1 [ 0 => "Dent, Arthur" ] # ATTRIBUTES REMOVED FOR BREVITY # This account is disabled in AD... "useraccountcontrol" => array:1 [ 0 => "514" ] ] #dates: [] #casts: [] #appends: [] #dateFormat: null #defaultDates: array:2 [ "createtimestamp" => "ldap" "modifytimestamp" => "ldap" ] #hidden: [] #visible: [] } App\Models\User\User {#3235 #connection: "application" #table: "users" #primaryKey: "id" #keyType: "int" +incrementing: true #with: [] #withCount: [] +preventsLazyLoading: false #perPage: 15 +exists: true +wasRecentlyCreated: false #escapeWhenCastingToString: false #attributes: array:54 [ "id" => "2718" "name" => "Dent, Arthur" "username" => "ADent" # ATTRIBUTES REMOVED FOR BREVITY # This account is not soft-deleted in the users table ... "deleted_at" => null "created_at" => "2018-10-30 18:49:24.503" "updated_at" => "2025-01-14 14:07:06.023" ] #changes: [] #casts: array:1 [ "deleted_at" => "datetime" ] #classCastCache: [] #attributeCastCache: [] #dateFormat: null #appends: [] #dispatchesEvents: [] #observables: [] #relations: [] #touches: [] +timestamps: true +usesUniqueIds: false #hidden: array:1 [ 0 => "password" ] #visible: [] #guarded: array:1 [ 0 => "*" ] #authPasswordName: "password" #rememberTokenName: "remember_token" +mediaConversions: [] +mediaCollections: [] #deletePreservingMedia: false #unAttachedMediaLibraryItems: [] #forceDeleting: false } // vendor\directorytree\ldaprecord-laravel\src\Import\Importer.php:271

If I'm understanding this properly, I think I should next walk through the LdapRecord\Laravel\Import\Synchronizer::synchronize method to see if there is data not being seen or handled. Thoughts?

dereknutile avatar Jan 14 '25 15:01 dereknutile

Hmm, this is also something I am seeing; disabled users in our Active Directory are no longer being soft deleted when syncing with --delete

benjivm avatar Jun 20 '25 21:06 benjivm

@dereknutile do you have the SoftDeletes trait on your User model?

@benjivm are you able to share logs of the sync process?

stevebauman avatar Jun 23 '25 00:06 stevebauman

@stevebauman, yes, the SoftDeletes trait is on the User model.

dereknutile avatar Jun 23 '25 17:06 dereknutile

@dereknutile Does removing the --restore flag resolve the issue?

stevebauman avatar Jun 23 '25 17:06 stevebauman

@dereknutile Are you also certain your users table has a guid column? I don't see it in your provided screenshots. These must be populated for users to be soft-deleted:

https://github.com/DirectoryTree/LdapRecord-Laravel/blob/87fcfd52bc0bcb76d3bd5840fa8230569d07a90a/src/Import/Importer.php#L397-L399

stevebauman avatar Jun 23 '25 18:06 stevebauman

Also, it looks like you're using a custom LdapRecord User model as well (App\Ldap\Ccso\User). Can you share its code, as well as your auth configuration?

stevebauman avatar Jun 23 '25 18:06 stevebauman

@stevebauman Been slammed so I hadn't been able to get around to this, and now that I'm looking into it the fault is entirely mine; I had an object filter on my sync job that was skipping a small segment of users, so the disable/restore flags were not affecting them. My bad!

benjivm avatar Jul 11 '25 18:07 benjivm

Closing due to inactivity.

stevebauman avatar Oct 08 '25 15:10 stevebauman