gheeres / node-activedirectory

ActiveDirectory is an Node.js ldapjs client for authN (authentication) and authZ (authorization) for Microsoft Active Directory with range retrieval support for large Active Directory installations.
MIT License
534 stars 147 forks source link

change password #127

Closed KannarFr closed 8 years ago

KannarFr commented 8 years ago

Hi,

Is it possible to create a function to change user's password in AD?

gheeres commented 8 years ago

At present, the AD module is just for querying data. However the underlying ldapjs module does have modify/delete capabilities so it is technically possible to implement.

To change the password on AD, here are the requirements:

Note: Assuming the account attempting to change the password doesn't have the "Reset Password" permission, you'll need to send a "delete" ldap change with the correct old password as well as an "add" change with the new password in the same operation.

The unicodePwd attribute cannot be queried or viewed for obvious security reasons.

There is no plan to add this functionality at this time. Pull requests accepted.

KannarFr commented 8 years ago

I wrote the following code and it works :) (ldaps is required). Didn't find how to pull request on github..

 /**
 * Change user password
 *
 * WARN : this function needs to an LDAPS connection to works. 
 *
 * @public
 * @param {String} username The username to retrieve the user.
 * @param {String} oldPassword The oldPassword to authenticate user.
 * @param {String} newPassword The new password to change user's password.
 * @param {Function} callback The callback to execute when the changePassword is completed. callback(err: {Object}, result: {Object})
 */
ActiveDirectory.prototype.changePassword = function changePassword(username, oldPassword, newPassword, callback) {
  /**
   * Inline function to encode string to base 64
   *
   * @private
   */
  function encodePassword(password) {
    return new Buffer('"' + password + '"', 'utf16le').toString();
  }

  var client = createClient.call(this);

  client.search(this.baseDN, {
    filter: '(cn=' + username + ')',
    attributes: 'dn',
    scope: 'sub'
  }, function(err, res) {
    if (err) {
      callback(err);
      return;
    }
    res.on('searchEntry', function(entry) {
      var userDN = entry.object.dn;
      client.bind(userDN, oldPassword, function(err) {
        if (err) {
          callback(err);
          return;
        }
        client.modify(userDN, [
          new ldap.Change({
            operation: 'delete',
            modification: {
              unicodePwd: encodePassword(oldPassword)
            }
          }),
          new ldap.Change({
            operation: 'add',
            modification: {
              unicodePwd: encodePassword(newPassword)
            }
          })
        ], function(err) {
          if (err) {
            callback(err);
          } else {
            callback();
            client.unbind();
          }
        });
      });
    });
  });
};```
jcsalberto commented 6 years ago

Hi!!! @KannarFr I'm trying to implement your change password, but I try it, and I can not, you can explain something else Thank you

KannarFr commented 6 years ago

Heyo,

It's quite an old work to me. Can you explain which kind of thing you need ?

jcsalberto commented 6 years ago

Hi!!! @KannarFr The problem is here image return this image

I do not know the problem Thank you

KannarFr commented 6 years ago

Seems that your baseDN is null and btw the response content is null.

jcsalberto commented 6 years ago

the config is correct image I try with this example image and is working any idea?

KannarFr commented 6 years ago

The filter that I'm using is based on username which is cn at the baseDN, is that the same schema for you ?

I mean on your baseDN, does it exist cn for username ?

KannarFr commented 6 years ago

And for password edition, IIRC you need an ldapS connection not only ldap.

jcsalberto commented 6 years ago

my baseDN finds user I will try with ldapS connection

Thank you

jcsalberto commented 6 years ago

Hello @KannarFr I'm back, but I'm unable to call ldaps from NODE I have verified that the configuration works using simple authentication with user and password with LDAP and LDAPS, from a windows program I do not use certificate from my pc my configuration options are like this

image

and he returns this message

image

Thank you @KannarFr

KannarFr commented 6 years ago

Hi, IIRC you must have an SSL certificate to perform password edition.

jcsalberto commented 6 years ago

Thank you @KannarFr

jcsalberto commented 6 years ago

Hi @KannarFr it works I needed to add this in the configuration parameters image Thank you!!!

KannarFr commented 6 years ago

Sure but now your passwords are clearly write on packets on edition ;).

kishore-indraganti commented 6 years ago

createClient reference error, what is that createClient refer to?

KannarFr commented 6 years ago

A connection client to LDAP.

jjayaraman commented 5 years ago

Nice post. Thanks, guys I too get the same createClient reference error. Trying to fix it. Any help would be nice guys. Thx again

jjayaraman commented 5 years ago

Hello @KannarFr I'm back, but I'm unable to call ldaps from NODE I have verified that the configuration works using simple authentication with user and password with LDAP and LDAPS, from a windows program I do not use certificate from my pc my configuration options are like this

image

and he returns this message

image

Thank you @KannarFr

$ NODE_EXTRA_CA_CERTS=c:/cert.pub nodemon

jjayaraman commented 5 years ago

@KannarFr Thanks for the code. I tried your code and now get this error. during modify operation. Any idea?

{ ConstraintViolationError: 0000052D: AtrErr: DSID-03190F80, #1: 0: 0000052D: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 9005a (unicodePwd)

at messageCallback (C:\Project_Gitlab\xxx\node_modules\ldapjs\lib\client\client.js:1419:45)
at Parser.onMessage (C:\Project_Gitlab\xxx\node_modules\ldapjs\lib\client\client.js:1089:14)
at Parser.emit (events.js:182:13)
at Parser.write (C:\Project_Gitlab\xxx\node_modules\ldapjs\lib\messages\parser.js:111:8)
at TLSSocket.onData (C:\Project_Gitlab\xxx\node_modules\ldapjs\lib\client\client.js:1076:22)
at TLSSocket.emit (events.js:182:13)
at addChunk (_stream_readable.js:283:12)
at readableAddChunk (_stream_readable.js:264:11)
at TLSSocket.Readable.push (_stream_readable.js:219:10)
at TLSWrap.onread (net.js:639:20)

lde_message: '0000052D: AtrErr: DSID-03190F80, #1:\n\t0: 0000052D: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 9005a (unicodePwd)\n\u0000', lde_dn: null }

KannarFr commented 5 years ago

Hi, It means that the password is refused by AD. Either because the password is not complex enough, either because the user has no rights to change it.

veronicasantana1 commented 5 months ago

Is there any way that i can change the user password without the old password? i'm trying to do that using "replace" instead of "delete" and "add" but it's not working, i can change others attributes with my function, including "userPassword", but not "unicodePwd"