DirectoryTree / LdapRecord

A fully-featured LDAP framework.
https://ldaprecord.com
MIT License
500 stars 44 forks source link

Change password at same time as other attributes #699

Open Albvadi opened 5 months ago

Albvadi commented 5 months ago

Hi, before all, as always, thank so much for this fantastic project. My applications would be nothing without this library!!

I'm having trouble trying to update a user attribute at the same time as making a password change.

If I do it all at the same time, it gives me an attribute error, but if I divide it into two modifications (first the password change and then the attribute modification) it works correctly.

I have looked for documentation regarding whether it is not possible to do everything together, but I have not found anything. Therefore, I don't know if it is an active directory restriction or some bug in the library.

Change password and attributes at same time


try {
    $user = User::where('samaccountname', 'my.user')->first();

    // Password change
    $user->unicodepwd = ["oldPassword", "newPassword"];

    // Modifyng attribute
    $user->setFirstAttribute('givenName', "TESTING FROM PHP");

    // Dump modifications
    dump($user->getModifications());

    // Save user    
    $userSaved = $user->save();

    // Dump result save user
    dump("User saved: $userSaved");

} catch (\LdapRecord\LdapRecordException $ex) {
    dump($ex);
    dump($error);
}
^ array:3 [▼
  0 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 2
    "values" => array:1 [▼
      0 => ""\x00o\x00l\x00d\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
  1 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 1
    "values" => array:1 [▼
      0 => ""\x00n\x00e\x00w\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
  2 => array:3 [▼
    "attrib" => "givenname"
    "modtype" => 3
    "values" => array:1 [▼
      0 => "TESTING FROM PHP"
    ]
  ]
]
^ LdapRecord\LdapRecordException {#28 ▼
  #message: "ldap_modify_batch(): Batch Modify: No such attribute"
  #code: 2
  #file: "D:\Proyectos\php\scripts\directorio_activo\vendor\directorytree\ldaprecord\src\LdapRecordException.php"
  #line: 19
  -previous: ErrorException {[#26 ▶](http://scripts.test/directorio_activo/reseteo_clave/reseteo_clave.php#sf-dump-2135024159-ref226)}
  #detailedError: LdapRecord\DetailedError {[#25 ▶](http://scripts.test/directorio_activo/reseteo_clave/reseteo_clave.php#sf-dump-2135024159-ref225)}
  trace: {▶}
}
^ LdapRecord\DetailedError {#25 ▼
  #errorCode: 16
  #errorMessage: "No such attribute"
  #diagnosticMessage: """
    00002085: AtrErr: DSID-0319074C, #1:
    \t0: 00002085: DSID-0319074C, problem 1001 (NO_ATTRIBUTE_OR_VAL), data 0, Att 9005a (unicodePwd):len 34
    """
}

First change password and then change attribute


try {
    $user = User::where('samaccountname', 'my.user')->first();

    // Password change
    $user->unicodepwd = ["oldPassword", "newPassword"];

    // Dump modifications
    dump($user->getModifications());

    // Save user    
    $userSaved = $user->save();

    // Dump result save user
    dump("User saved: $userSaved");

    // Modifyng attribute
    $user->setFirstAttribute('givenName', "TESTING FROM PHP");

    // Dump modifications
    dump($user->getModifications());

    // Save user    
    $userSaved = $user->save();

    // Dump result save user
    dump("User saved: $userSaved");

} catch (\LdapRecord\LdapRecordException $ex) {
    dump($ex);
    dump($error);
}
^ array:2 [▼
  0 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 2
    "values" => array:1 [▼
      0 => ""\x00o\x00l\x00d\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
  1 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 1
    "values" => array:1 [▼
      0 => ""\x00n\x00e\x00w\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
]

^ "User saved: "

^ array:1 [▼
  0 => array:3 [▼
    "attrib" => "givenname"
    "modtype" => 3
    "values" => array:1 [▼
      0 => "TESTING FROM PHP"
    ]
  ]
]

^ "User saved: "

Environment:

stevebauman commented 5 months ago

Hi @Albvadi,

Thanks for your kind words! Really glad you enjoy using LdapRecord 😄 🙏

Does this error still occur if you set the users givenName before you set their password so that change is seen first by the server? Ex:

$user->setFirstAttribute('givenName', "TESTING FROM PHP");

$user->unicodepwd = ["oldPassword", "newPassword"];

You may need to append the modification manually if you find the batch modifications are still in the same order:

$user->unicodepwd = ["oldPassword", "newPassword"];

$user->addModification(
    $user->newBatchModification(
        'givenName',
        LDAP_MODIFY_BATCH_REPLACE,
        ['new name']
    )
);

Also, Microsoft docs (and everything I could find online) regarding this always show this operation occurring on its own, so this may be an Active Directory limitation?

https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2#main https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2

Albvadi commented 5 months ago

Hi, I tested your suggestions and fails too.

If I set givenName before the password, the batch modifications are still in the same order (as you said), and fails too (obviously). I created manually the batchModification before the set password, and still fails.

$user->addModification(
    $user->newBatchModification(
        'givenName',
        LDAP_MODIFY_BATCH_REPLACE,
        ['TESTING FROM PHP']
    )
);

$user->unicodepwd = [$oldPassword, $newPassword];
^ array:3 [▼
  0 => array:3 [▼
    "attrib" => "givenName"
    "modtype" => 3
    "values" => array:1 [▼
      0 => "TESTING FROM PHP"
    ]
  ]
  1 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 2
    "values" => array:1 [▼
      0 => ""\x00o\x00l\x00d\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
  2 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 1
    "values" => array:1 [▼
      0 => ""\x00n\x00e\x00w\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
]
^ LdapRecord\LdapRecordException {#28 ▼
  #message: "ldap_modify_batch(): Batch Modify: No such attribute"
  #code: 2
  #file: "D:\Proyectos\php\scripts\directorio_activo\vendor\directorytree\ldaprecord\src\LdapRecordException.php"
  #line: 19
  -previous: ErrorException {[#26 ▶](http://scripts.test/directorio_activo/reseteo_clave/reseteo_clave.php#sf-dump-1043334202-ref226)}
  #detailedError: LdapRecord\DetailedError {[#25 ▶](http://scripts.test/directorio_activo/reseteo_clave/reseteo_clave.php#sf-dump-1043334202-ref225)}
  trace: {▶}
}
^ LdapRecord\DetailedError {#25 ▼
  #errorCode: 16
  #errorMessage: "No such attribute"
  #diagnosticMessage: """
    00002085: AtrErr: DSID-0319074C, #1:
    \t0: 00002085: DSID-0319074C, problem 1001 (NO_ATTRIBUTE_OR_VAL), data 0, Att 9005a (unicodePwd):len 34
    """
}

However, doing more tests I have realized that if I assign the password as a string (to perform a reset instead of a password change), I can modify other attributes at the same time and it works correctly.

$user->setFirstAttribute('givenName', "TESTING FROM PHP");

// Do password reset instead change
$user->unicodepwd = "newPassword";
^ array:2 [▼
  0 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 3
    "values" => array:1 [▼
      0 => ""\x00n\x00e\x00w\x00P\x00a\x00s\x00s\x00w\x00o\x00r\x00d\x002\x000\x002\x004\x00"\x00"
    ]
  ]
  1 => array:3 [▼
    "attrib" => "givenname"
    "modtype" => 3
    "values" => array:1 [▼
      0 => "TESTING FROM PHP2"
    ]
  ]
]
^ "User saved: "

Or even create a new user, I can create the user with the attributes and password at same time too.

$user = new User([
    'cn' => 'php.testing'
]);

$user->inside('OU=TESTING,DC=company,DC=com');

$user->unicodepwd = "test";

dump($user->getModifications());

$user->save();
^ array:2 [▼
  0 => array:3 [▼
    "attrib" => "unicodepwd"
    "modtype" => 1
    "values" => array:1 [▼
      0 => ""\x00t\x00e\x00s\x00t\x00"\x00"
    ]
  ]
  1 => array:3 [▼
    "attrib" => "cn"
    "modtype" => 1
    "values" => array:1 [▼
      0 => "php.prueba2"
    ]
  ]
]
^ "User saved!"

It´s really weird... :thinking: