如何在远程LDAP服务器上的特定OU中搜索用户?

时间:2014-11-14 15:15:29

标签: c# active-directory ldap adlds

我想使用.NET 3.5中引入的AccountManagement命名空间来查找用户并设置其密码。但是,ADLDS服务器不属于我们公司的域名,因此我使用ContextType.Machine。当我搜索用户时,它从未找到(我怀疑它在错误的容器中搜索,但根据使用ContextType.Machine时的文档,您无法指定容器)。

using (var context = new PrincipalContext(ContextType.Machine, "test-server", null, "username", "password")) {
    using (var u = UserPrincipal.FindByIdentity(context, "SuperAdmin")) {
        //u is always null.   :(
    }
}

但是,我知道我可以找到使用普通ol' DirectoryEntry

using (var de = new DirectoryEntry("LDAP://test-server:389/CN=SuperAdmin,CN=SuperUsers,OU=test-server,DC=foo,DC=bar,DC=com", "username", "password", AuthenticationTypes.Secure)) {
    //The user is found, but SetPassword fails with "The directory property cannot be found in the cache"
    de.Invoke("SetPassword", new object[] { "foobar" });
}

最后要指出的是,我可以使用ADSI Edit使用这些相同的凭据更改密码。是否可以使用较新的目录对象来执行此搜索?

1 个答案:

答案 0 :(得分:0)

这真是一个老问题,但就在最近我不得不开展一个类似的项目......如果有人遇到同样的问题,我会发布答案。

您使用user课程找不到UserPrincipal的原因是您提到的使用ContextType.Machine进行搜索的原因。但是在DirectEntry课程中,您只是在进行简单的LDAP://查询。

这是我的解决方案。

我将服务器信息存储在.config文件中。

... 
//Server name and port
<add key ="ADLDS_Server" value="Servername:port"/> 
//Note* depending on structure container will be different for everybody
<add key ="ADLDS_Container" value="CN=Some Value, DC=some value,DC=value"/>
...

然后我创建了返回ADLDSUtility对象的PrincipalContext类。

...
using System.DirectoryServices.AccountManagement
...
public class ADLDSUtility
{
    public static ContextOptions ContextOptions = ContextOptions.SecureSocketLayer | ContextOptions.Negotiate;

    public static PrincipalContext Principal
    {
        get
        {
            return new PrincipalContext(
               ContextType.ApplicationDirectory,
               ConfigurationManager.AppSettings["ADLDS_Server"],
               ConfigurationManager.AppSettings["ADLDS_Container"],
               //you can specify username and password if need to
               ContextOptions);
        }
    }

从那里开始,我写了一个method接受(username,currentPassword和newPassword)作为参数。

public void ChangePassword(string userName, string currentPassword, string newPassword)
    {
        using (PrincipalContext ctx = ADLDSUtility.Principal)
        {
            using (UserPrincipal principal = new UserPrincipal(ctx))
            {
                using (var searchUser = UserPrincipal.FindByIdentity(ctx, IdentityType.UserPrincipalName, userName))
                {
                    if (searchUser != null)
                    {
                        searchUser.ChangePassword(currentPassword, newPassword);
                        // searchUser.SetPassword(newPassword);
                        if (String.IsNullOrEmpty(searchUser.Guid.ToString()))
                        {
                            throw new Exception("Could not change password");
                        }
                    }
                }
            }
        }
    }

在此示例中,我按UserPrincipalName搜索用户。但我们并不仅限于此。我们还可以按IdentityType.Guid等搜索用户

现在searchUser有两个涉及密码的方法。我提供了他们两个。

//requires current and new password
searchUser.ChangePassword(currentPassword, newPassword);
//setting a password. Only requires new password.
searchUser.SetPassword(newPassword);

注意首选使用SSL设置或更改密码。*