我有一个MVC 4应用程序,允许用户通过密码重置功能页面更改其Active Directory密码。我有以下代码来设置新密码:
DirectoryEntry de = sr.GetDirectoryEntry();
de.Invoke("SetPassword", new object[] { newPassword });
de.Properties["LockOutTime"].Value = 0;
尝试使用新密码详细信息提交表单时,我将以下错误写入应用程序事件日志:
0x80070005 (E_ACCESSDENIED))
我已将应用程序池的Identity属性设置为NetworkService,并认为这样可以解决连接问题。还有什么需要确保,以便我的ASPNET应用程序可以连接到AD。
答案 0 :(得分:1)
<强> TL;博士强>
在我们的案例中,这开始随机发生。事实证明这是因为我们的自签名SSL证书已过期。在IIS中创建一个新问题后,问题就解决了。
<强>解释强>
This thread引导我走向事业。
我将简要回顾
SetPassword
在这里所做的事情,以便您了解为什么需要它。特定的ADSI方法真正捆绑了3种方法。它首先尝试使用LDAP在安全的SSL通道上设置密码。接下来,它尝试使用Kerberos设置密码协议进行设置。最后,它使用NetUserSetInfo
来尝试设置它。主要问题是前两种方法通常只会尊重您在
DirectoryEntry
上提供的凭据。 例如,如果您提供正确的凭据和SSL通道,则LDAP更改密码机制将使用这些凭据...如果您检查NetUserSetInfo方法,您会注意到没有地方可以放置用户名/密码进行授权。换句话说,它只能使用非托管线程的安全上下文。这意味着为了使其正常工作,它必须首先模拟您以编程方式提供的用户名/密码组合...
LDAP over SSL显然是最好的方式(并且是我们一直使用的方法),并且看起来(澄清欢迎),一旦我们的自签名SSL证书过期,它就会跳过Kerberos并回到NetUserSetInfo
,由于未使用我们提供的凭据而失败。 (或者它只是在Kerberos上失败了,因为海报说他从未见过为Kerberos传递的凭据)
因此,在创建新的自签名证书(COMPUTER.DOMAIN.local
)后,问题得以解决。
这是代码(如果有人在寻找它):
DirectoryEntry myDE = new DirectoryEntry(@"LDAP://OU=GroupName,DC=DOMAIN,DC=local");
myDE.Username = "administrator";
myDE.Password = "adminPassword";
DirectoryEntries myEntries = myDE.Children;
DirectoryEntry myDEUser = myEntries.Find("CN=UserName");
myDEUser.Invoke("SetPassword", new object[] { "NewPassword" });
myDEUser.Properties["LockOutTime"].Value = 0;
// the following 2 lines are free =)
myDEUser.Properties["userAccountControl"].Value = (int)myDEUser.Properties["userAccountControl"].Value | 0x10000; // don't expire password
myDEUser.Properties["userAccountControl"].Value = (int)myDEUser.Properties["userAccountControl"].Value & ~0x0002; // ensure account is enabled
myDEUser.CommitChanges();