AD LDS (ADAM) ChangePassword через SSL - PullRequest
0 голосов
/ 22 июля 2011

Я искал в интернете несколько дней, пытаясь решить эту проблему.

Я работаю над проектом, в котором у меня есть требование разрешить пользователю изменять свой пароль с помощью веб-приложения ASP.NET.

Я должен использовать «ChangePassword», а не «SetPassword», так как я должен применять историю паролей и не позволять пользователям в LDS больше привилегий, чем им нужно.Я пытаюсь выполнить эту задачу в среде разработчика.У меня есть две машины: «Сервер1» (LDS, PingFederate, CA) и «Сервер2» (IIS).Я подумал, что у меня могут возникнуть проблемы, потому что у меня не было настройки SSL между двумя полями, поэтому вчера я потратил полдня на настройку ЦС и создание сертификатов для обеих машин.Я вполне уверен, что это работает, так как я больше не вижу никаких ошибок в журнале ошибок, и я могу войти в LDS, используя LDP, используя порт 636 с проверенным SSL.Я должен также упомянуть, что эти машины не находятся в доменной среде.Я отредактировал файл hosts на всех машинах в тестовой сети.

Я пробовал разные варианты кода:

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 ();Исключение составляет «Ошибка входа в систему: неизвестное имя пользователя или неверный пароль».

Если я попытаюсь запустить этот код через порт 389 с AuthenticatioTypes.None |AuthenticationTypes.FastBind, произойдет сбой при de.Invoke («ChangePassword», new object [] {pwd, newPwd});за исключением «Неизвестное имя».Я бы очень хотел, чтобы это работало по SSL или, по крайней мере, не передавало пароли в открытом виде.У меня есть сайт, работающий по HTTPS.Я попытался изменить значение dsHeuristics в LDS, чтобы можно было изменять пароли через не-SSL-соединение, но это тоже не сработало.

Будем весьма благодарны за любые предложения, которые кто-либо может получить.

1 Ответ

0 голосов
/ 26 июля 2011

Мне удалось, наконец, заставить работать смену пароля.Я использовал информацию, представленную на 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;
            }
...