- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的active directory上有一个用于身份验证的函数,它工作正常,除了一些包含特殊字符的密码,例如:
< >
总是返回“无效凭据”
我在网上看过好几篇文章,但似乎没有一篇是正确的。
我使用的是php version 5.3.8-zs(zend服务器)
以下是我的类构造函数中的设置:
ldap_set_option($this->_link, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($this->_link, LDAP_OPT_REFERRALS, 0);
public function login($userlogin,$userpassword){
$return=array();
$userlogin.="@".$this->_config["domaine"];
$ret=@ldap_bind($this->_link , $userlogin ,utf8_decode($userpassword));
if(!$ret){
$return[]=array("status"=>"error","message"=>"Erreur d'authentification ! <br/> Veuillez vérifier votre nom et mot de passe SVP","ldap_error"=>ldap_error($this->_link));
}
if($ret)
{
$return[]=array("status"=>"success","message"=>"Authentification réussie");
}
return json_encode($return);
}
最佳答案
我们发现自己处于一个类似的环境中,我们的企业环境ldap身份验证设置对于我们的一个内部托管web应用程序似乎工作得很好,直到用户的密码中有特殊字符,比如?*想使用该应用程序,然后很明显,有些东西实际上没有按预期工作。
当受影响的用户密码中出现特殊字符时,我们发现我们的身份验证请求失败到ldap_bind()
,并且常见的错误是如Invalid credentials
或NDS error: failed authentication (-669)
(从LDAP的扩展错误日志记录)输出到日志。事实上,是NDS error: failed authentication (-669)
错误导致了失败的绑定很可能是由于密码中存在特殊字符——通过Novell支持文章[AA],其中最显著的部分摘录如下:
管理密码包含LDAP无法理解的字符,即:“\
和“$”
已经对一系列修复进行了广泛的测试,包括通过html_entity_decode()
、utf8_encode()
等来“清除”密码,并确保web应用程序和各种服务器之间没有密码的错误编码,但是无论做什么来调整或保护输入文本,以确保其原始的UTF-8编码保持完整,ldap_bind()
当密码中存在一个或多个特殊字符时,总是失败(我们没有用用户名中的特殊字符测试用例)。但也有人报告说,当用户名包含特殊字符而不是密码或密码之外的字符时,也会出现类似的问题。
我们还使用在命令行上运行的最小php脚本直接测试了ldap_bind()
,该脚本使用硬编码用户名和密码对密码中包含特殊字符(包括问号、星号和感叹号)的测试ldap帐户进行了测试,试图尽可能多地消除失败的潜在原因,但是绑定操作仍然失败。因此,很明显,这不是密码在Web应用程序和服务器之间错误编码的问题,所有这些设计和构建都是符合UTF-8的端到端的。相反,它似乎有一个潜在的问题与CC及其特殊字符的处理。同一个测试脚本成功地绑定了另一个密码中没有任何特殊字符的帐户,进一步证实了我们的怀疑。
早期版本的ldap身份验证的工作方式如下,这是大多数php ldap身份验证教程建议的:
$success = false; // could we authenticate the user?
if(!defined("LDAP_OPT_DIAGNOSTIC_MESSAGE")) {
define("LDAP_OPT_DIAGNOSTIC_MESSAGE", 0x0032); // needed for more detailed logging
}
if(($ldap = ldap_connect($ldap_server)) !== false && is_resource($ldap)) {
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
if(@ldap_bind($ldap, sprintf("cn=%s,ou=Workers,o=Internal", $username), $password)) {
$success = true; // login succeeded...
} else {
error_log(sprintf("* Unable to authenticate user (%s) against LDAP!", $username));
error_log(sprintf(" * LDAP Error: %s", ldap_error($ldap)));
if(ldap_get_option($ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, $extended_error)) {
error_log(sprintf(" * LDAP Extended Error: %s\n", $extended_error));
unset($extended_error);
}
}
}
@ldap_close($ldap); unset($ldap);
ldap_bind()
和
ldap_connect()
的简单解决方案将不允许用户使用复杂的密码进行身份验证,我们必须找到一个替代方案。
ldap_bind()
搜索具有所提供用户名的用户帐户,然后使用
ldap_search()
将用户提供的密码与ldap中存储的密码进行比较。这个解决方案已经被证明是可靠和有效的,我们现在能够验证用户的特殊字符在他们的密码和那些没有!
if(!defined("LDAP_OPT_DIAGNOSTIC_MESSAGE")) {
define("LDAP_OPT_DIAGNOSTIC_MESSAGE", 0x0032); // needed for more detailed logging
}
$success = false; // could we authenticate the user?
if(($ldap = @ldap_connect($ldap_server)) !== false && is_resource($ldap)) {
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
// instead of trying to bind the user, we bind to the server...
if(@ldap_bind($ldap, $ldap_username, $ldap_password)) {
// then we search for the given user...
if(($search = ldap_search($ldap, "ou=Workers,o=Internal", sprintf("(&(uid=%s))", $username))) !== false && is_resource($search)) {
// they should be the first and only user found for the search...
if((ldap_count_entries($ldap, $search) == 1) && ($entry = ldap_first_entry($ldap, $search)) !== false && is_resource($entry)) {
// we ensure this is the case by obtaining the user identifier (UID) from the search which must match the provided $username...
if(($uid = ldap_get_values($ldap, $entry, "uid")) !== false && is_array($uid)) {
// ensure that just one entry was returned by ldap_get_values() and ensure the obtained value matches the provided $username (excluding any case-differences)
if((isset($uid["count"]) && $uid["count"] == 1) && (isset($uid[0]) && is_string($uid[0]) && (strcmp(mb_strtolower($uid[0], "UTF-8"), mb_strtolower($username, "UTF-8")) === 0))) {
// once we have compared the provied $username with the discovered username, we get the DN for the user, which we need to provide to ldap_compare()...
if(($dn = ldap_get_dn($ldap, $entry)) !== false && is_string($dn)) {
// we then use ldap_compare() to compare the user's password with the provided $password
// ldap_compare() will respond with a boolean true/false depending on if the comparison succeeded or not, and -1 on error...
if(($comparison = ldap_compare($ldap, $dn, "userPassword", $password)) !== -1 && is_bool($comparison)) {
if($comparison === true) {
$success = true; // user successfully authenticated, if we don't get this far, it failed...
}
}
}
}
}
}
}
}
if(!$success) { // if not successful, either an error occurred or the credentials were actually incorrect
error_log(sprintf("* Unable to authenticate user (%s) against LDAP!", $username));
error_log(sprintf(" * LDAP Error: %s", ldap_error($ldap)));
if(ldap_get_option($ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, $extended_error)) {
error_log(sprintf(" * LDAP Extended Error: %s\n", $extended_error));
unset($extended_error);
}
}
}
@ldap_close($ldap);
unset($ldap);
ldap_compare()
和使用
ldap_bind()
和
ldap_search()
的更复杂的解决方案之间的时间差实际上是微不足道的,平均可能要长0.1s。
ldap_compare()
连接到服务器,而不是通过
ldaps://...
连接,然后切换到tls连接被证明是更可靠的。如果您的设置有所不同,则需要相应地调整上面的代码,以包含对
ldap://...
的支持。
ldap_start_tls()
中使用的DN,因为这将取决于LDAP目录的配置方式以及您支持应用程序的用户组。很高兴,它在我们的环境中运行得非常好,希望这个解决方案在其他地方也能被证明是有用的。
关于php - 当密码包含“&”号时,php ldap_bind失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12858493/
Internal Server Error: /admin/account/customuser/add/ Traceback (most recent call last): File "C:\
有问题!虽然我发现几乎相似的线程但没有帮助:( 我编写了一个 php 脚本来从我的 MySQL 数据库中获取注册用户的数量。该脚本在我的本地主机上运行良好;它使用给定的用户名、密码和主机名,分别是“r
我正在做一项基于密码的作业,我将 key 和消息放在单独的数组中。我想创建第三个数组,其中包含围绕消息大小的 key ,如下所示: message keykeyk 我已经在这个问题上苦苦挣扎了一段时间
我的几个客户要求我实现图形密码检查器,例如 关于如何实现这种 UI 有什么想法吗? 最佳答案 试着看看这个:https://code.google.com/p/android-lockpattern/
我正在使用 MAMP,每次登录 phpMyAdmin 时,都会收到以下错误/警告消息: the configuration file now needs a secret passphrase (bl
我正在尝试通过将 Visual Studio 2013 连接到我的测试机来调试 WDF 驱动程序。它创建一个名为 WDKRemoteUser 的用户,并在进行测试时尝试自动登录。有人知道这个用户的密码
使用具有指定用户名和密码的 SVN 提交。我希望服务器抛出错误;所以我可以告诉我的用户他/她的密码错误。 相反,在使用错误密码提交后: svn commit "test_file.txt" --use
我正在尝试实现 friend 推荐。 它从节点“你”开始。而且,我想找到节点“安娜”。 换句话说,这是我的两个或更多 friend 共同认识的人。上面的示例节点是 Anna。 如果您的帮助,我将不胜感
我都尝试过 wget --user=myuser --password=mypassword myfile 和 wget --ftp-user=myuser --ftp-password=mypass
我的一位用户提示说,每当他尝试使用默认管理界面(Django 的管理员)添加新用户(auth.User)时,新用户名和密码都会自动填充他自己的。 问题是他在登录时要求 Firefox 记住他的用户名/
我们正在开发一款应用(当然)用于应用购买 (IAP)。我已完成指南中的所有操作以启用 iap,并且一切正常,直到我想要购买为止。 部分代码: MainViewController.m -(vo
我试图创建两个可选匹配项的并集(如下所示),但我得到的不是并集,而是两者的交集。我应该如何更改此查询以获得所需的联合? optional match (a:PA)-[r2:network*2]-(b:
我想将Ansible用作另一个Python软件的一部分。在该软件中,我有一个包含其用户名/密码的主机列表。 有没有一种方法可以将SSH连接的用户/密码传递给Ansible ad-hoc命令或以加密方式
嗨,我在使用xampp的Apache Web服务器上收到错误500。直到我使用.htaccess,.htpasswd文件,错误才出现。我搜索了,但找不到语法错误。我只有1张图片和要保护的索引文件。以下
我一直使用它来编辑用户帐户信息: $this->validate($request, [ 'password' => 'min:6', 'password_confirmation'
我需要使用InstallUtil来安装C# Windows服务。我需要设置服务登录凭据(用户名和密码)。这一切都需要默默地完成。 有没有办法做这样的事情: installutil.exe myserv
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
如果我有一个随机的、16 个字符长的字母数字盐(不同大小写),它是为每个用户生成和存储的,我是否还需要一个站点范围的盐? 换句话说,这样好吗? sha1($user_salt . $password)
我正在开发一个空白程序,该程序将允许用户创建一个帐户,以便他们可以存储其余额和提款/存款。用户输入用户名和密码后,如何存储这些信息以便用户可以登录并查看其余额?我不一定要尝试使其非常安全,我只是希望能
我正在尝试寻找一种通用方法来搜索没有链接到另一个节点或节点集的节点或节点集。例如,我能够找到特定类型(例如 :Style)的所有节点,这些节点以某种方式连接到一组特定的节点(例如 :MetadataR
我是一名优秀的程序员,十分优秀!