AD LDS (ADAM) 通过 SSL 更改密码

发布于 2024-11-26 09:45:28 字数 3855 浏览 1 评论 0原文

我已经在互联网上搜索了好几天试图解决这个问题。

我正在开发一个项目,需要允许用户使用 ASP.NET Web 应用程序更改密码。

我必须使用“ChangePassword”而不是“SetPassword”,因为我必须强制执行密码历史记录,并且不允许 LDS 中的任何用户拥有超出其需要的权限。我正在尝试在开发环境中完成此任务。我有两台机器“Server1”(LDS、PingFederate、CA)和“Server2”(IIS)。我认为我可能会遇到问题,因为我在两个机器之间没有设置 SSL,所以我昨天花了半天时间为两台机器设置 CA 并创建证书。我相当确定它正在工作,因为我在错误日志中不再看到任何错误,并且我可以使用 LDP 使用端口 636 并检查 SSL 登录到 LDS。我还应该提到这些机器并不在域环境中。我已经编辑了测试网络上所有机器上的主机文件。

我尝试了不同的代码变体:

public static bool ChangePassword(string email, string pwd, string newPwd)
{
    DirectoryEntry user  = GetCN(email);
    string username = user.Properties["cn"][0].ToString();

    DirectoryEntry de = new DirectoryEntry();
    de.AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer;
    de.Path = user.Path;
    de.Username = username;
    de.Password = pwd;
    try
    {
        Object obj = de.NativeObject;
        de.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl;
        de.Options.PasswordPort = Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]);
        de.Invoke("ChangePassword", new object[] { pwd, newPwd });
        de.CommitChanges();
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

public static bool ChangePassword(string email, string pwd, string newPwd)
{
    DirectoryEntry user  = GetCN(email);
    string username = user.Properties["cn"][0].ToString();

    DirectoryEntry de = new DirectoryEntry(user.Path, username, pwd, AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer);
    try
    {
        de.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl;
        de.Options.PasswordPort = Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]);
        de.Invoke("ChangePassword", new object[] { pwd, newPwd });
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

public static bool ChangePassword(string email, string pwd, string newPwd)
{
    DirectoryEntry userInc  = GetCN(email);
    string username = userInc.Properties["cn"][0].ToString();

    using (DirectoryEntry searchRoot = new DirectoryEntry(ConfigurationManager.AppSettings["LDAPConnectionString_ExternalUsers"], username, pwd, AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure))
    using (DirectorySearcher ds = new DirectorySearcher(searchRoot))
    {
        ds.Filter = "(|(objectCategory=user)(cn=" + username + "))";
        SearchResult sr = ds.FindOne();
        if (sr != null)
        {
            using (DirectoryEntry user = sr.GetDirectoryEntry())
            {
                user.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingClear;
                user.Options.PasswordPort = Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]);
                //user.Invoke("SetOption", new object[] { 6, Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]) });
                //user.Invoke("SetOption", new object[] { 7, 1 });
                user.Invoke("ChangePassword", new object[] { pwd, newPwd });
            }
            return true;
        }
    }
    return false;
}

我在第一个版本的 Object obj = de.NativeObject; 处遇到异常。我用它来确定绑定是否正确发生,并作为调试步骤插入,因为这是我通过端口 389 验证用户身份的方式。例外是“登录失败:未知的用户名或错误的密码”。

我在 de.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl; 的第二个版本上遇到异常例外情况是“登录失败:未知的用户名或错误的密码”。

我在第三个版本中遇到异常 SearchResult sr = ds.FindOne();例外情况是“登录失败:未知的用户名或错误的密码”。

如果我确实尝试使用 AuthenticatioTypes.None 在端口 389 下运行此代码 | AuthenticationTypes.FastBind,它将在 de.Invoke("ChangePassword", new object[] { pwd, newPwd }); 处失败;但“未知名称”除外。我真的很想让它在 SSL 下运行,或者至少不以明文形式传输任何密码。我的网站确实通过 HTTPS 运行。我确实尝试修改 LDS 上的 dsHeuristics 值,以便可以通过非 SSL 连接更改密码,但这也不起作用。

任何人可能提出的任何建议将不胜感激。

I have been searching the internet for days trying to solve this problem.

I am working on a project where I have a requirement of allowing the user to change their password using an ASP.NET web application.

I must use "ChangePassword" and not "SetPassword" since I must enforce password history, and not allow any users in the LDS any more privileges than they need. I am trying to complete this task on a dev environment. I have two machines "Server1" (LDS, PingFederate, CA), and "Server2" (IIS). I thought I might be running into problems because I did not have SSL setup between the two boxes, so I spent half the day yesterday setting up a CA and creating certificates for both machines. I am fairly certain it is working since I am no longer seeing any errors in the error log, and I can login to the LDS using LDP using port 636 with SSL checked. I should also mention that these machines are not in a domain environment. I have edited the hosts file on all machines on the test network.

I have tried different variations of code:

public static bool ChangePassword(string email, string pwd, string newPwd)
{
    DirectoryEntry user  = GetCN(email);
    string username = user.Properties["cn"][0].ToString();

    DirectoryEntry de = new DirectoryEntry();
    de.AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer;
    de.Path = user.Path;
    de.Username = username;
    de.Password = pwd;
    try
    {
        Object obj = de.NativeObject;
        de.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl;
        de.Options.PasswordPort = Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]);
        de.Invoke("ChangePassword", new object[] { pwd, newPwd });
        de.CommitChanges();
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

public static bool ChangePassword(string email, string pwd, string newPwd)
{
    DirectoryEntry user  = GetCN(email);
    string username = user.Properties["cn"][0].ToString();

    DirectoryEntry de = new DirectoryEntry(user.Path, username, pwd, AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer);
    try
    {
        de.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl;
        de.Options.PasswordPort = Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]);
        de.Invoke("ChangePassword", new object[] { pwd, newPwd });
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

public static bool ChangePassword(string email, string pwd, string newPwd)
{
    DirectoryEntry userInc  = GetCN(email);
    string username = userInc.Properties["cn"][0].ToString();

    using (DirectoryEntry searchRoot = new DirectoryEntry(ConfigurationManager.AppSettings["LDAPConnectionString_ExternalUsers"], username, pwd, AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure))
    using (DirectorySearcher ds = new DirectorySearcher(searchRoot))
    {
        ds.Filter = "(|(objectCategory=user)(cn=" + username + "))";
        SearchResult sr = ds.FindOne();
        if (sr != null)
        {
            using (DirectoryEntry user = sr.GetDirectoryEntry())
            {
                user.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingClear;
                user.Options.PasswordPort = Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]);
                //user.Invoke("SetOption", new object[] { 6, Convert.ToInt32(ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"]) });
                //user.Invoke("SetOption", new object[] { 7, 1 });
                user.Invoke("ChangePassword", new object[] { pwd, newPwd });
            }
            return true;
        }
    }
    return false;
}

I get an exception on the first version at Object obj = de.NativeObject;. I was using this to determine if a bind was happening correctly, and was inserted as a debugging step since this is how I was authenticating a user over port 389. The exception is "Logon failure: unknown user name or bad password."

I get an exception on the second version at de.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl; The exception is "Logon failure: unknown user name or bad password."

I get an exception on the third version at SearchResult sr = ds.FindOne(); The exception is "Logon failure: unknown user name or bad password."

If I do attempt to run this code under port 389 with AuthenticatioTypes.None | AuthenticationTypes.FastBind, it will fail at de.Invoke("ChangePassword", new object[] { pwd, newPwd }); with the exception "Unknown Name". I would really like to get this running under SSL or at least not transmit any passwords in the clear. I do have the site running over HTTPS. I did try modifying the dsHeuristics value on the LDS so that I could do password changes over a non-SSL connection, but that did not work either.

Any suggestions that anybody might have would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱给你人给你 2024-12-03 09:45:28

我终于能够成功更改密码了。我使用了 http://www.informit.com 上提供的信息/articles/article.aspx?p=474649&seqNum=4

我使用了这三个函数:

private static DirectoryConnection GetConnection(string server, NetworkCredential credential, bool useSsl)
{
LdapConnection connection =
  new LdapConnection(server);

     if (useSsl)
     {
          connection.SessionOptions.SecureSocketLayer = true;
     }
     else
     {
          connection.SessionOptions.Sealing = true;
     }

     connection.Bind(credential);
     return connection;
}

private static void ChangePassword(DirectoryConnection connection, string userDN, string oldPassword, string newPassword)
{
     DirectoryAttributeModification deleteMod = new DirectoryAttributeModification();
     deleteMod.Name = "unicodePwd";
     deleteMod.Add(GetPasswordData(oldPassword));
     deleteMod.Operation= DirectoryAttributeOperation.Delete;

     DirectoryAttributeModification addMod = new DirectoryAttributeModification();
     addMod.Name = "unicodePwd";
     addMod.Add(GetPasswordData(newPassword));
     addMod.Operation = DirectoryAttributeOperation.Add;

     ModifyRequest request = new ModifyRequest(userDN, deleteMod, addMod);

     DirectoryResponse response = connection.SendRequest(request);
}

private static byte[] GetPasswordData(string password)
{
     string formattedPassword;
     formattedPassword = String.Format("\"{0}\"", password);
     return (Encoding.Unicode.GetBytes(formattedPassword));
}

我从允许更改密码的页面后面的代码中像这样调用了该函数:

NetworkCredential credential = new NetworkCredential("[user with access to the LDS", "pwd");
            DirectoryConnection connection;
            try
            {
                //Setup our connection
                connection = ADAuth.GetConnection(ConfigurationManager.AppSettings["LDAPServer_ExternalUsers"] + ":" + ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"], credential, true);

                //Attempt to change the password
                ADAuth.ChangePassword(connection, ADAuth.GetDN(userID.Text).Properties["distinguishedName"].Value.ToString(), currPass.Text, newPass.Text);

                //Send success message to user
                ErrorLit.Text = "<p>Password change successful!</p>";
                //Dispose the connection
                IDisposable disposable = connection as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
            }
            catch (Exception ex)
            {
                //There was an error, tell the user
                errors += "<li>Error changing password</li>";
                ErrorLit.Text = errors + "</ul>";
                return;
            }

I was able to finally get the password change working. I used the information presented on http://www.informit.com/articles/article.aspx?p=474649&seqNum=4

I used these three functions:

private static DirectoryConnection GetConnection(string server, NetworkCredential credential, bool useSsl)
{
LdapConnection connection =
  new LdapConnection(server);

     if (useSsl)
     {
          connection.SessionOptions.SecureSocketLayer = true;
     }
     else
     {
          connection.SessionOptions.Sealing = true;
     }

     connection.Bind(credential);
     return connection;
}

private static void ChangePassword(DirectoryConnection connection, string userDN, string oldPassword, string newPassword)
{
     DirectoryAttributeModification deleteMod = new DirectoryAttributeModification();
     deleteMod.Name = "unicodePwd";
     deleteMod.Add(GetPasswordData(oldPassword));
     deleteMod.Operation= DirectoryAttributeOperation.Delete;

     DirectoryAttributeModification addMod = new DirectoryAttributeModification();
     addMod.Name = "unicodePwd";
     addMod.Add(GetPasswordData(newPassword));
     addMod.Operation = DirectoryAttributeOperation.Add;

     ModifyRequest request = new ModifyRequest(userDN, deleteMod, addMod);

     DirectoryResponse response = connection.SendRequest(request);
}

private static byte[] GetPasswordData(string password)
{
     string formattedPassword;
     formattedPassword = String.Format("\"{0}\"", password);
     return (Encoding.Unicode.GetBytes(formattedPassword));
}

I called the function like so from the code behind of the page that allows password changes:

NetworkCredential credential = new NetworkCredential("[user with access to the LDS", "pwd");
            DirectoryConnection connection;
            try
            {
                //Setup our connection
                connection = ADAuth.GetConnection(ConfigurationManager.AppSettings["LDAPServer_ExternalUsers"] + ":" + ConfigurationManager.AppSettings["LDAPPort_ExternalUsers"], credential, true);

                //Attempt to change the password
                ADAuth.ChangePassword(connection, ADAuth.GetDN(userID.Text).Properties["distinguishedName"].Value.ToString(), currPass.Text, newPass.Text);

                //Send success message to user
                ErrorLit.Text = "<p>Password change successful!</p>";
                //Dispose the connection
                IDisposable disposable = connection as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
            }
            catch (Exception ex)
            {
                //There was an error, tell the user
                errors += "<li>Error changing password</li>";
                ErrorLit.Text = errors + "</ul>";
                return;
            }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文