2
votes

In an asp.net MVC application, i am encountering the Access denied error when trying to reset the password using directoryEntry.Invoke.

The page is accessed by the user trying to change his/her password and SSL required and Client Certificates - Required are marked in IIS.

Relevant code:

directoryEntry.Invoke("SetPassword", new object[] { model.Password });
                directoryEntry.Properties["LockOutTime"].Value = 0;
                directoryEntry.Close();

The exact error is –

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
   --- End of inner exception stack trace ---
   at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args)

Web.config –

<authentication mode="Windows" />
    <identity impersonate="false" />
    <authorization>
      <deny users="?" />
    </authorization>
  • The app pool is running under an AD account; also part of the local admin group [Domain1\AppPoolUser].
  • The application requests the user certificate
  • The user trying to change password [Domain2\testUser] and the account under which the app pool are running are in different domains but this is not likely an issue. Effective permissions for the AppPoolUser allows ChangePassword on the testUser account.
  • I even tried running the app pool under the same user account as the test account but it doesn't change anything.

Have checked online but its not clear to me what the issue might be. The closest related thing i see is this - Setting ASP.Net Permissions - Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

However, as mentioned in my case the app pool is running under a limited technical account and i don't think there is any issue with SSL certificates.

  1. Do i need to request Delegation of Control for the application pool account in the AD?
  2. Or is there likely another issue that i m missing.
1
Were you ever able to resolve this? - joym8

1 Answers

-1
votes

We had the similar requirement to change or reset the password. We use following code snippet.

        /// <summary>
        /// Resets the user password.
        /// </summary>        
        public static void ResetUserPassword(string domain, string domainUsername, string domainPassword, string sAMAccountName, string newPassword,
            bool askToChangePassword, bool unlockAccount, bool passRespectDomainPolicy, bool superuser)
        {
            // Get root directory entry
            using (var entry = GetDirectoryEntry(domain, domainUsername, domainPassword, AuthenticationTypes.Secure))
            {
                var displayName = string.Empty;

                // Search for the user with the same sAMAccountName
                using (var searcher = new DirectorySearcher(entry))
                {
                    // Filter results by SAMAccountName
                    searcher.Filter = string.Format("(SAMAccountName={0})", sAMAccountName);

                    // Search and return only one result
                    var result = searcher.FindOne();

                    // Check if result is returned
                    if (result == null) throw new Exception("Could not find user: " + sAMAccountName);

                    // Get the user directory entry
                    var userEntry = result.GetDirectoryEntry();

                    // Read name value
                    if (userEntry.Properties.Contains("displayName") && userEntry.Properties["displayName"].Count > 0)
                        displayName = Convert.ToString(userEntry.Properties["displayName"][0]);

                    // Validate password
                   // string errorMessage;
                   // if (passRespectDomainPolicy &&
                     //   !IsValidPassword(domain, sAMAccountName, newPassword, displayName, userEntry, superuser, out errorMessage))
                    // {
                      //  if (!string.IsNullOrEmpty(errorMessage)) throw new Exception(errorMessage);
                      //  throw new Exception("Password is not valid as per AD policy. Please consult Administrator.");
                    // }

                    // Earlier we used impersonation to reset password on same DC.
                    // But that didn't worked and so removed.
                    userEntry.Invoke("SetPassword", newPassword);

                    // 0(for on) and -1(for off) for LDAP case. For WinNT it is opposite.
                    // Set "Ask to change password at next login"
                    if (askToChangePassword)
                        userEntry.Properties["pwdLastSet"].Value = 0;

                    // Unlock account if required
                    if (unlockAccount)
                        userEntry.Properties["lockoutTime"].Value = 0;

                    // Commit changes
                    userEntry.CommitChanges();
                }
            }
        }

The noticeable point is that we are running the code userEntry.Invoke("SetPassword", newPassword); inside the context of root directory entry using (var entry = GetDirectoryEntry(domain, domainUsername, domainPassword, AuthenticationTypes.Secure)){.

I mean that entry represents the object holding the domain' administrator user and password. This administrator user must have full permission to make changes in AD.

Let us know your testing results.