花了2天在这个topic上面。有以下总结
一,解决方案:目前有两种
1. DirectoryEntry.(ADSI). 这种就是直接用ldap的路径,对dn的object进行修改。如:
entity = new DirectoryEntry("http://www.cnblogs.com/sdikerdong/admin/ldap://domain%20machine/CN=user,CN=Users,DC=test,DC=com", "administrator", "password");
//entity.Invoke("SetPassword", new object[] { "AAAA999" });
//entity.Properties["LockOutTime"].Value = 0; //unlock account
entity.Invoke("ChangePassword", new object[] { "Hel3lMa$3123d", "AAAA999" });
entity.CommitChanges();
entity.Close() ;
这种方案稳定,但是要多写一些代码。注意:SetPassword是不管AD Policy的,是可以直接设定的,就与reset password功能一样。
2. ActiveDirectoryMembershipProvider. 用这种方案也可以达到上述目的。
3. 在.net 40中有System.DirectoryServices.AccountManagement,也可以解决上述问题
二,一些问题必须知道
1. 如果用ActiveDirctoryMembershipProvider,调试的时候不能用VS本身的webServer. 因为要调用COM,VS开启的webserver有问题。必须要在IIS上进行调试
2. 微软的MSDN上有一个坑爹的错误,就是"minRequiredNonalphanumericCharacters",这是对的,但在MSDN上写的却是minRequiredNonAlphanumericCharacters。就会一直说这个attribute不识别
3. ActiveDirctoryMembershipProvider.ChangePassword中的第一个参数要用username@test.com,这个也跟配置有关系,即sAMAccountName有关系
4. 对于配置我就简单配置如下就能工作:
<add name="ADString" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConn" connectionUsername="test\Administrator"
connectionPassword="AAA123" applicationName="none"
connectionProtection ="Secure"
minRequiredNonalphanumericCharacters="0"
passwordStrengthRegularExpression="^.*$"
minRequiredPasswordLength="7"
maxInvalidPasswordAttempts = "999"
passwordAttemptWindow = "999"/>
5. 经过上述配置,还有可能要提示说:password不符合default provider之 类的,用debug方式,得到是COM抛出来的异常(System.Runtime.InteropServices.COMException: The password does not meet the password policy requirements),这说明不是.net本身的配置问题,而是出在AD服务器上的配置,到底是什么呢?原来就是"minimum password age",这一选项被设定了1天或更多,导致你在开发过程中改了一次之后,再测试就是这种错误了。
6. change password的时候可能会返回false, debug的时候看到的错误是“logon failed, user name or password is not valide..."。可明明就是存在,密码也对,这很有可能是这个帐号被设置成的只能登录某一台机器。如果是这样,只能在那台特定机器上修改自己 的密码。
7. 当帐号被设成"user must change password at next logon"时,用activedirectorymemershipprovider或directoryservice是修改不成功的。用userPrinciple是可以修改成的,因为它是用AD管理权限设置的。这个时候可以用userPrinciple.lastPasswordSet().HasValue为判断是否"user must change password at next logon"被check上。(false).如果check上,就调用userPrinciple.RefreshExpiredPassword ().将这一选项uncheck, 然后用membershipprovider去change password.如果change过程中有问题,就用userPrinciple.ExpirePasswordNow()来让他再check上。
8. userPrinciple.changepassword函数所使用的principlacontext, principal是采用username+password方式,这个帐号在AD中的permission设定只要在account manager系统预定义的角色即可。但是,用userPrinciple.RefreshExiredPassword()时,它所使用的context身份需要对指定的AD节点进行特别设定才可以,否则会出现"general access error...."。当然可以直接用domain admin或enterprise admin,便在生产环境下管理员是不会这样给的。还有一点就是用特殊设定对某一节点进行设定的时候,似乎对系统默认的users是没有用的。
9. 还有一个小技巧,就是设定节点特别权限的时候,要一点点摸索,可以用一个帐号来模拟操作看是否可以将"user must change password at next logon",用组合健shift + 鼠标右健,可以用run as来快速模拟。