我在那里的用户对象驻留在OU例如一个活动目录架构,IT,技术,人力资源,会计等。我希望写出与AD认证用户PHP脚本,并根据他们的集团提供aproperiate Web服务。
ldap_search()需要基本DN。 我试着用
搜索 ldap_search($ LDAP,DC =国,DC =公司,DC =合作,直流=英国,(SAM帐户名= $的用户名),阵列(成员) );
但是PHP提供了操作错误。相反,如果我指定的OU
ldap_search($ LDAP,OU =销售额,DC =国,DC =公司,DC =合作,直流=英国,(SAM帐户=杰克),阵列(成员));
那么搜索就可以了。
有一个通配符可以使用吗?
在一个侧面说明,应用户对象在OU呢?因为我是谁摆在首位!
感动他们里面的小白编辑: 随着学分JPBlanc在正确的方向引导我, http://blog.redbranch.net/?p=76
该解决方案是增加连接和绑定的2行。
ldap_connect(..)
ldap_set_option($ LDAP,LDAP_OPT_REFERRALS,0);
ldap_set_option($ LDAP,LDAP_OPT_PROTOCOL_VERSION,3);
的ldap_bind(..)
感谢=)
编辑2 - 全code:
< PHP
命名空间的LDAP;
抽象类AuthStatus
{
常量FAIL =验证失败;
常量OK =认证OK;
常量SERVER_FAIL =无法连接到LDAP服务器;
常量匿名=匿名登录;
}
// LDAP服务器
一流的LDAP
{
私人$服务器=127.0.0.1;
私人$域=localhost的;
私人$管理=管理;
私人$密码=;
公共职能__construct($服务器,$领域,$管理=,$密码=)
{
$这个 - >服务器= $服务器;
$这个 - >域= $域;
$这个 - >管理= $管理;
$这个 - >密码= $密码;
}
//验证了对服务器的域\用户名和密码组合。
公共功能验证($用户)
{
$用户可>的auth_status = AuthStatus ::失败;
$ LDAP = ldap_connect($这个 - >服务器)或$用户自>的auth_status = AuthStatus :: SERVER_FAIL;
ldap_set_option($ LDAP,LDAP_OPT_REFERRALS,0);
ldap_set_option($ LDAP,LDAP_OPT_PROTOCOL_VERSION,3);
$ ldapbind =的ldap_bind($ LDAP,$用户可>用户名@$这 - >域名,用户可$>密码);
如果($ ldapbind)
{
如果(空($用户自>密码))
{
$用户可>的auth_status = AuthStatus ::匿名的;
}
其他
{
$结果= $用户自>的auth_status = AuthStatus ::确定;
$这个 - > _get_user_info($ LDAP,$用户);
}
}
其他
{
$结果= $用户自>的auth_status = AuthStatus ::失败;
}
ldap_close($ LDAP);
}
//获取用户的数组或返回错误的错误
公共职能get_users()
{
如果(($ LDAP = ldap_connect($这个 - >!服务器)))返回false;
ldap_set_option($ LDAP,LDAP_OPT_REFERRALS,0);
ldap_set_option($ LDAP,LDAP_OPT_PROTOCOL_VERSION,3);
$ ldapbind =的ldap_bind($ LDAP,$这个 - >联系@$这 - >域名,$这个 - >密码);
$ DC =爆炸(,$这个 - &GT。域名);
$ base_dn =;
的foreach($直流如$ _dc)$ base_dn =直流=$ _直流,。;
$ base_dn = SUBSTR($ base_dn,0,-1);
$ SR = ldap_search($ LDAP,$ base_dn, "(&(objectClass=user)(objectCategory=person)(|(mail=*)(telephonenumber=*))(!(userAccountControl:1.2.840.113556.1.4.803:=2)))",阵列(CN,DN,成员,邮件,telephonenumber,othertelephone,手机,IPPHONE,部,标题));
$信息= ldap_get_entries($ LDAP,$ SR);
为($ i = 0; $ I< $信息[伯爵]; $ I ++)
{
$用户[$ i] [名称] = $信息[$ i] [CN] [0];
$用户[$ i] [电子邮件] = $信息[$ i] [电子邮件] [0];
$用户[$ i] [手机] = $信息[$ i] [手机] [0];
$用户[$ i] [Skype的] = $信息[$ i] [IPPHONE] [0];
$用户[$ i] [电话] = $信息[$ i] [telephonenumber] [0];
$用户[$ i] [部门] = $信息[$ i] [部门] [0];
$用户[$ i] [标题] = $信息[$ i] [标题] [0];
为($ T = 0; $ T< $信息[$ i] [othertelephone] [数量]; $ T ++)
$用户[$ i] [othertelephone] [$ T] = $信息[$ i] [othertelephone] [$ T]
//设置为空数组
如果(!is_array($用户[$ i] [othertelephone]))$用户[$ i] [othertelephone] =阵列();
}
返回$用户;
}
私有函数_get_user_info($ LDAP,$用户)
{
$ DC =爆炸(,$这个 - &GT。域名);
$ base_dn =;
的foreach($直流如$ _dc)$ base_dn =直流=$ _直流,。;
$ base_dn = SUBSTR($ base_dn,0,-1);
$ SR = ldap_search($ LDAP,$ base_dn,(及(objectClass的=用户)(objectCategory属性=人)(Sam帐户=$用户可与GT;用户名)),阵列(CN,DN ,成员,邮件,telephonenumber,othertelephone,手机,IPPHONE,部,标题));
$信息= ldap_get_entries($ LDAP,$ SR);
$用户可基团取代=阵列();
为($ i = 0; $ I< $信息[0] [成员] [伯爵]; $ I ++)
array_push($用户可基团取代,$信息[0] [成员] [$ i]于);
$用户可>名称= $信息[0] [CN] [0];
$用户可>的dn = $信息[0] [DN];
$用户可>邮件= $信息[0] [电子邮件] [0];
$用户可>电话= $信息[0] [telephonenumber] [0];
$用户可>移动= $信息[0] [手机] [0];
$用户可> Skype的= $信息[0] [IPPHONE] [0];
$用户可>部门= $信息[0] [部门] [0];
$用户可>标题= $信息[0] [标题] [0];
为($ T = 0; $ T< $信息[$ i] [othertelephone] [数量]; $ T ++)
$用户可> other_telephone [$ T] = $信息[$ i] [othertelephone] [$ T]
如果(is_array($用户自>!other_telephone [$ T]))$用户可> other_telephone [$ T] =阵列();
}
}
类用户
{
变量$的auth_status = AuthStatus ::失败;
变量$用户名=无名氏;
变量$密码=;
变量$组=阵列();
变量$ DN =;
变量$ NAME =;
变量$电子邮件=;
变量$电话=;
变量$ other_telephone =阵列();
变量$手机=;
变量$ Skype的=;
变量$部门=;
变量$标题=;
公共职能__construct($的用户名,密码$)
{
$这个 - >的auth_status = AuthStatus ::失败;
$这个 - >用户名= $的用户名;
$这个 - >密码= $密码;
}
公共职能get_auth_status()
{
返回$这个 - >的auth_status;
}
}
?>
用法:
$ LDAP =新的LDAP \ LDAP(192.168.1.123,company.com,管理,输入mypassword);
$用户= $ LDAP-> get_users();
解决方案
如果您尝试在Windows 2003 Server的Active Directory或以上进行搜索,似乎你的LDAP_OPT_REFERRALS选项设置为0:
ldap_set_option($ LDAP,LDAP_OPT_REFERRALS,0);
ldap_set_option($ LDAP,LDAP_OPT_PROTOCOL_VERSION,3);
如果没有这个,你会得到操作错误如果您尝试到整个AD(领域中使用根作为$ base_dn)进行搜索。
在LDAP目录一般任何点头可以在任何点头(用户是一个点头,一个OU是点头)。
但是主动 - 指南的行为以不同的方式的模式中定义,其中容器中的对象可存在。所以,如果你找一个用户,允许上级是: builtinDomain
, domainDNS
和组织单位
,你可以在这里看到:
I have an Active-Directory structure where User objects reside in OU for example, IT, Technical, HR, Accounts etc.. I want to write a PHP script that authenticates the user with AD and depending on their Group to provide the aproperiate web services.
ldap_search() requires base DN. I tried to search with
ldap_search($ldap, "dc=country,dc=company,dc=co,dc=uk", "(samaccountname=$username)", array("memberof"));
but PHP gives "Operation Error". If instead i specify the OU
ldap_search($ldap, "ou=sales,dc=country,dc=company,dc=co,dc=uk", "(samaccountname=jake)", array("memberof"));
then the search is ok.
Is there a wildcard I can use?
On a side note, should user objects be in OU at all? Because I am the noob who moved them inside in the first place!
EDIT: With credits to JPBlanc for guiding me in the right direction and http://blog.redbranch.net/?p=76
The solution is to add 2 lines between connect and bind.
ldap_connect(..)
ldap_set_option ($ldap, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_bind(..)
Thanks =)
EDIT 2 - Fullcode:
<?php
namespace ldap;
abstract class AuthStatus
{
const FAIL = "Authentication failed";
const OK = "Authentication OK";
const SERVER_FAIL = "Unable to connect to LDAP server";
const ANONYMOUS = "Anonymous log on";
}
// The LDAP server
class LDAP
{
private $server = "127.0.0.1";
private $domain = "localhost";
private $admin = "admin";
private $password = "";
public function __construct($server, $domain, $admin = "", $password = "")
{
$this->server = $server;
$this->domain = $domain;
$this->admin = $admin;
$this->password = $password;
}
// Authenticate the against server the domain\username and password combination.
public function authenticate($user)
{
$user->auth_status = AuthStatus::FAIL;
$ldap = ldap_connect($this->server) or $user->auth_status = AuthStatus::SERVER_FAIL;
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind = ldap_bind($ldap, $user->username."@".$this->domain, $user->password);
if($ldapbind)
{
if(empty($user->password))
{
$user->auth_status = AuthStatus::ANONYMOUS;
}
else
{
$result = $user->auth_status = AuthStatus::OK;
$this->_get_user_info($ldap, $user);
}
}
else
{
$result = $user->auth_status = AuthStatus::FAIL;
}
ldap_close($ldap);
}
// Get an array of users or return false on error
public function get_users()
{
if(!($ldap = ldap_connect($this->server))) return false;
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind = ldap_bind($ldap, $this->admin."@".$this->domain, $this->password);
$dc = explode(".", $this->domain);
$base_dn = "";
foreach($dc as $_dc) $base_dn .= "dc=".$_dc.",";
$base_dn = substr($base_dn, 0, -1);
$sr=ldap_search($ldap, $base_dn, "(&(objectClass=user)(objectCategory=person)(|(mail=*)(telephonenumber=*))(!(userAccountControl:1.2.840.113556.1.4.803:=2)))", array("cn", "dn", "memberof", "mail", "telephonenumber", "othertelephone", "mobile", "ipphone", "department", "title"));
$info = ldap_get_entries($ldap, $sr);
for($i = 0; $i < $info["count"]; $i++)
{
$users[$i]["name"] = $info[$i]["cn"][0];
$users[$i]["mail"] = $info[$i]["mail"][0];
$users[$i]["mobile"] = $info[$i]["mobile"][0];
$users[$i]["skype"] = $info[$i]["ipphone"][0];
$users[$i]["telephone"] = $info[$i]["telephonenumber"][0];
$users[$i]["department"] = $info[$i]["department"][0];
$users[$i]["title"] = $info[$i]["title"][0];
for($t = 0; $t < $info[$i]["othertelephone"]["count"]; $t++)
$users[$i]["othertelephone"][$t] = $info[$i]["othertelephone"][$t];
// set to empty array
if(!is_array($users[$i]["othertelephone"])) $users[$i]["othertelephone"] = Array();
}
return $users;
}
private function _get_user_info($ldap, $user)
{
$dc = explode(".", $this->domain);
$base_dn = "";
foreach($dc as $_dc) $base_dn .= "dc=".$_dc.",";
$base_dn = substr($base_dn, 0, -1);
$sr=ldap_search($ldap, $base_dn, "(&(objectClass=user)(objectCategory=person)(samaccountname=".$user->username."))", array("cn", "dn", "memberof", "mail", "telephonenumber", "othertelephone", "mobile", "ipphone", "department", "title"));
$info = ldap_get_entries($ldap, $sr);
$user->groups = Array();
for($i = 0; $i < $info[0]["memberof"]["count"]; $i++)
array_push($user->groups, $info[0]["memberof"][$i]);
$user->name = $info[0]["cn"][0];
$user->dn = $info[0]["dn"];
$user->mail = $info[0]["mail"][0];
$user->telephone = $info[0]["telephonenumber"][0];
$user->mobile = $info[0]["mobile"][0];
$user->skype = $info[0]["ipphone"][0];
$user->department = $info[0]["department"][0];
$user->title = $info[0]["title"][0];
for($t = 0; $t < $info[$i]["othertelephone"]["count"]; $t++)
$user->other_telephone[$t] = $info[$i]["othertelephone"][$t];
if(!is_array($user->other_telephone[$t])) $user->other_telephone[$t] = Array();
}
}
class User
{
var $auth_status = AuthStatus::FAIL;
var $username = "Anonymous";
var $password = "";
var $groups = Array();
var $dn = "";
var $name = "";
var $mail = "";
var $telephone = "";
var $other_telephone = Array();
var $mobile = "";
var $skype = "";
var $department = "";
var $title = "";
public function __construct($username, $password)
{
$this->auth_status = AuthStatus::FAIL;
$this->username = $username;
$this->password = $password;
}
public function get_auth_status()
{
return $this->auth_status;
}
}
?>
Usage:
$ldap = new ldap\LDAP("192.168.1.123", "company.com", "admin", "mypassword");
$users = $ldap->get_users();
解决方案
If you try to perform the searches on Windows 2003 Server Active Directory or above, it seems that you have to set the LDAP_OPT_REFERRALS option to 0:
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
Without this, you will get "Operations error" if you try to search the whole AD (using root of the domain as a $base_dn).
In LDAP Directories in general any nod can be under any nod (a user is a nod, an ou is a nod).
But Active-Directory behave in a different way the SCHEMA define in which container an object can exist. So, if you look for a user, superiors allowed are : builtinDomain
, domainDNS
and organizationalUnit
as you can see here under :