简体   繁体   中英

Determine AD password policy programmatically

I have been using the System.DirectoryService (ADSI) classes and methods to create and change users in an Active Directory.

Recently we added a feature to allow users to set their own password through the system. However, using the SetPassword method throws an exception when the password is not accepted by the Password Policy set.

userEntry.Invoke("SetPassword", new object[] {password});

My question is: How do I check to see if a password lives up to the password policy, before attempting to use the SetPassword-method?

I read in this post that you can get the Password Policy-settings from the root domain node, but where can I read more about what each attribute means? For instance, which characters are required to fullfill the "Complexity" policy?

Once I know this, I can implement my own password check-method, but as this is an error-prone approach, I would rather use a built-in check and give the user appropriate info on what is wrong with their password.

I am working on a similar project at my work. We are rolling a forgot password application. I ended up just doing an Invoke("SetPassword", "[randomString]") and saved the random string for the Invoke("ChangePassword","[randomString]","[user supplied pw]") . The result of the ChangePassword was returned to the user.

SetPassword does not check for password complexity or history rules. It is the same as right clicking a user in AD and selecting "Reset Password." ChangePassword however, does check for password history requirements.

The complexity policy is that it must contain three out of five of these types:

  • Upper case letters
  • Lower case letters
  • Digits
  • Non-alphanumeric characters: ~!@#$%^&*_-+=`|(){}[]:;"'<>,.?/
  • Unicode characters that are alphabetics but not uppercase or lowercase.

It also can't be the sAMAccountName or displayName (or parts of). You can read about it here . The other password policy rules are in adjacent documents .

You could try setting it and catch exceptions but from memory I don't think it tells you what's wrong with the password, just that it doesn't meet the requirements.

The API function you want is NetValidatePasswordPolicy .

There are three modes it operates in:

  • NetValidateAuthentication : if you are authenticating a user; so the function can check password expiration policies, bad login attempts, account lockouts, bad login attempts, etc
  • NetValidatePasswordChange : if the user is changing their password; so the function can check against lockout, or against the password policy

and the mode you want:

  • NetValidatePasswordReset : you are an admin resetting a user's password; which only checks the password complexity.

I'll try transcoding from another language to C# on the fly; but you will have to P/Invoke it.

<summary>Check password during password reset.

    The result from NetValidatePasswordReset, this member can be one of the following values.

        NERR_Success                        The password passes the validation check.
        NERR_PasswordTooShort           Validation failed. The password does not meet policy requirements because it is too short.
        NERR_PasswordTooLong                Validation failed. The password does not meet policy requirements because it is too long.
        NERR_PasswordNotComplexEnough   Validation failed. The password does not meet policy requirements because it is not complex enough.
        NERR_PasswordFilterError        Validation failed. The password does not meet the requirements of the password filter DLL.
</summary>
UInt32 TestPasswordComplexity(String username, SecureString password)
{
   //All code on stack overflow is in the public domain; no attribution
   //is required.
   const UInt32 NetValidatePasswordReset = 3;

   NET_VALIDATE_PASSWORD_RESET_INPUT_ARG args = new NET_VALIDATE_PASSWORD_RESET_INPUT_ARG();
   args.UserAccountName = Username; //some policies check that your password cannot contain your username
   args.ClearPassword = SecureStringToString(password);

   PNET_VALIDATE_OUTPUT_ARG res;

   DWORD le = NetValidatePasswordPolicy(null, null, NetValidatePasswordReset, @args, {out}Pointer(res));

   if (le <> NERR_Success)
      throw new WindowsException(le); //

   return res.ValidationStatus;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM