Метод DirectoryEntry SetPassword возвращает исключение "Отказано в доступе"
В приложении asp.net MVC я сталкиваюсь с ошибкой " Отказано в доступе" при попытке сброса пароля с помощью directoryEntry.Invoke
,
К странице обращается пользователь, пытающийся изменить свой пароль и SSL required
а также Client Certificates - Required
помечены в IIS.
Соответствующий код:
directoryEntry.Invoke("SetPassword", new object[] { model.Password });
directoryEntry.Properties["LockOutTime"].Value = 0;
directoryEntry.Close();
Точная ошибка -
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>
- Пул приложений работает под учетной записью AD; также является частью локальной группы администраторов
[Domain1\AppPoolUser]
, - Приложение запрашивает сертификат пользователя
- Пользователь пытается сменить пароль
[Domain2\testUser]
и учетная запись, под которой запущен пул приложений, находится в разных доменах, но это вряд ли проблема. Действующие разрешения для AppPoolUser позволяют ChangePassword для учетной записи testUser. - Я даже пытался запустить пул приложений под той же учетной записью, что и тестовая, но это ничего не меняет.
Проверил онлайн, но мне не ясно, в чем проблема. Самая близкая связанная вещь, которую я вижу, - это - Установка разрешений ASP.Net - Доступ запрещен. (Исключение из HRESULT: 0x80070005 (E_ACCESSDENIED))
Однако, как упоминалось в моем случае, пул приложений работает под ограниченной технической учетной записью, и я не думаю, что есть какие-либо проблемы с сертификатами SSL.
- Нужно ли запрашивать делегирование контроля для учетной записи пула приложений в AD?
- Или есть другая проблема, которая мне не хватает.
1 ответ
У нас было похожее требование изменить или сбросить пароль. Мы используем следующий фрагмент кода.
/// <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();
}
}
}
Заметным моментом является то, что мы запускаем код userEntry.Invoke("SetPassword", newPassword);
внутри контекста записи корневого каталога using (var entry = GetDirectoryEntry(domain, domainUsername, domainPassword, AuthenticationTypes.Secure)){
,
я имею в виду, что entry
представляет объект, содержащий имя пользователя и пароль администратора домена. Этот администратор должен иметь полное разрешение на внесение изменений в AD.
Дайте нам знать ваши результаты тестирования.