存档

文章标签 ‘Active Directory’

活动目录中时间日期格式的总结

2009年5月3日

活动目录中关于日期和时间的存储还是比较复杂的,如果是用ldap直接操作的话,需要了解得比较清楚的。这里查了一些文档,做一个笔记。

AD中关于时间的属性有两种类型:

1.NT时间戳型:

以lastLogon、pwdLastSet、accountExpires等属性为代表,这类属性的类型(syntax)其实就是一个大整数。NT时间戳与Unix时间戳的思想是一样的,只是前者的定义更bt一些:从1601年1月1日0时起经过的1E-7秒(即100纳秒)的个数(时间是GMT的)。

官方文档可以参考:How to convert date/time attributes in Active Directory to standard time format

如果用PHP之类的语言操作AD,可以先求出标准的Unix时间戳,然后乘上1E7,再加上1970年1月1日00:00:00的NT时间戳(常量:116445312000000000)即得到了NT时间戳。这需要用到计算大数值的BC库,如果没有的话也可以改用字符串,不乘那个1E7,而是直接转成字符串接上7个”0″

2. Generalized Time/Universal time 类型

这种以whenCreated、whenChanged属性为代表,这种属性的类型是真正的时间类型。

这种格式的说明在MSDN上的这个页面:http://msdn.microsoft.com/en-us/library/cc223266(PROT.10).aspx

格式的核心是由ISO8601定义的,W3上的 Date and Time Formats一文介绍得比较易读。不过实际使用的格式不包括横线、冒号等分隔符,具体格式是由ITUX680规定的(在64~65页)。

概括起来,这种格式就是年月日时分秒连续地写在一起,加上一个小数点后的秒值(一般为0),再加上时区,小数点和时区都不可省略。
对于UTC时间,它就形如:20090502173227.0Z 
对于本地时间,它就形如:20090503013227.0+0800 (这两个时间是同一个)

一般来说,向AD中写入时,可以用本地的表示也可以用UTC的表示,但是读出来的时候,都是UTC表示(也就是以Z结尾的) 

 

如果你是PHP用户,可以参照下面的代码实现DateTime对象与Generalized Time格式的相互转化:

 

    function DateTimeToGeneralizedTime($datetime) {
        return $datetime->format(‘YmdHis.0O’);
    }

    function GeneralizedTimeToDateTime($str) {
        $ret = strptime($str, ‘%Y%m%d%H%M%S.0%z’);
        if (!$ret) $ret = strptime($str, ‘%Y%m%d%H%M%S.0%Z’);

        $gmtTimestamp = gmmktime($ret['tm_hour'], $ret['tm_min'], $ret['tm_sec'], $ret['tm_mon'] + 1, $ret['tm_mday'], $ret['tm_year'] + 1900);

        $ret = getdate($gmtTimestamp);

        $datetime = new DateTime();
        $datetime->setDate($ret['year'], $ret['mon'], $ret['mday']);
        $datetime->setTime($ret['hours'], $ret['minutes'], $ret['seconds']);

        return $datetime;
    }

 

 

编程, 技术 , ,

用PHP通过LDAP操作活动目录(AD)的笔记

2007年11月12日

最近一周一直在研究AD这方面的问题,主要难题就是用跑在Linux上的PHP通过LDAP来读写Windows上的活动目录中用户的信息。一般来说需要这么做的情况不常见,因为既然是用AD了就可以用很多现在的LDAP模块,但是我现在要做的是把已有的一个非标准的用户/密码的库转换到AD里去,所以必须亲自来完成一些底层的工作。这方面的文章网上不多见,所以这里综述一下。

首先,是安装配置AD本身的这部分工作:
主要包括:装Win2k3(或2008哈),建立域控制器,建DNS服务,把要加入域的几个机器加进域来,然后建设OU(放用户的OU及放计算机的OU),建立安全组(我用它来限制哪些用户可以登录哪些计算机),设立组策略并应用到各OU等。
这部分内容的文章很多,微软给的文档就足够详细了,比如这个Step by Step的教程:http://www.microsoft.com/china/technet/prodtechnol/windowsserver2003/technologies/directory/activedirectory/stepbystep/default.mspx
(ps.这中间在密码策略上浪费了大量时间,后来才弄清一个域中只能在根下设置密码策略,就算把带有密码策略的组策略应用在OU上,也是无效的。2008里已经可以针对安全组甚至用户设置独立的密码策略了,期待~~)

然后是一些为了就乎linux的准备工作:
先去http://www.microsoft.com/windowsserversystem/sfu/downloads/default.mspx下载一套Windows Services for UNIX,这个装上以后AD里用户的属性页里会出现一个UNIX属于页,有uid,gid什么的,这是为了让linux能结合AD验证用户登录的(比如pam),我目前没用上,不过装它没坏处。
还有是要建立一个proxyuser,这个user是ldap客户端连AD时登录用的,想让PHP实现对AD的什么操作,就给这个proxyuser赋予什么权限。
这里推荐一套很好的文档,是微软的Windows Security and Directory Services for UNIX Guide(还是要pf一下m$,文档就是全,这里对linux中安全体系的介绍比专方介绍的文档都详细。。。)

下面就是资料不好找的工作啦,一步一步来:

1.关于AD与ldap的符合性。AD被做成基本符合ldap的模式,每个用户和计算机或是组什么的都有一个DN,形如CN=loudly,OU=bbs,DC=bdwm,DC=net这样子,而用户的每个属性就是这条记录里的一个attribute,所以可以用ldap_search(),ldap_add()这些标准的函数来操作AD。一个特殊但是关键的地方就是用户的密码,很不易地找到这两个文档介绍这个事情:
How To Change a Windows 2000 User’s Password Through LDAP
User Management with Active Directory―LDAP Password Modification
文章中的核心内容就是:用户的密码是一个叫unicodePwd的属性表示的,这个属于只能写不能读,写的时候的格式是用一对双引号括起密码原文,再编码为unicode传给它,还有,要想改用户密码,必须是通过SSL方式连接LDAP(636端口,而不是普通的389端口)。因为如上要求,就要有以下步骤的工作了。

2.生成根证书
用SSL的话嘛,就需要证书。可以在域控制器上开启认证服务来创建企业的CA(注意这个服务开启后域的设置就不能改了,包括域名,这个机器的名等,所以要在进行这步之前设置好)。这里要做的就是创建CA,然后验证一下是不是ok的。其实这部分内容我也不懂,主要就是照着下面两篇参考着做的,具体步骤怎么回事(尤其是验证的时候)我也不知道是在做什么。
a.Install an enterprise root certification authority
b.就是上面提到的Windows Security and Directory Services for UNIX Guide第二卷的第Chapter4的Build a Certification Authority那一节
如果不自己建CA,而是从别处获得CA,那就看下面这篇:
c.How to enable LDAP over SSL with a third-party certification authority
下面这篇也可以参考,不过该文的主题是别的
d.如何在 Windows 2000 域控制器中配置数字证书来确保 LDAP 和 SMTP 复制的安全
上面的工作做好后,如果正常,那么域控制器就会开始listen 636端口,也就可以通过SSL连AD了(一般ldap客户端的规矩是:连的时候直接写DC地址就是用非加密方法连,连的时候如果写ldaps://地址,就是用SSL方法连接DC)

3.LDAP客户端的配置
客户端,就是要去连AD的机器,也就是本文中跑着PHP的那个机器,要做的工作主要是把DC上的CA导出成.cer,然后拷到客户端上来,然后转化为.pem(可是我的.cer和.pem文件是一样的)放到某个位置,然后再修改一下/etc/openldap/ldap.conf,这样连DC的时候系统就可以去查相应的证书。主要参考的文档是这篇:
Communicating between OpenLDAP and Active Directory over SSL
下面两篇也可以参考:
Configuring Microsoft Active Directory for SSL access
LDAP over SSL – Modifying Active Directory with PHP
上面的文章里最后都要用linux下的ldapsearch命令来测试连接是否可以进行,不过语法不同,我最后成功地连上DC用的语句是:
ldapsearch -x -H “ldaps://theDC.yourdomain.net” -s base -D “cn=proxyuser,cn=users,dc=yourdomain,dc=net” -W -b “dc=yourdomain,dc=net”(回车后提示输proxyuser的密码)
还有,要强调的是,连DC一定要用它的域名,不要用IP或是NetBIOS名,因为CA里写的是域名,要匹配
另,上面说的是linux的ldap客户端,win下也有啊,比如说win2k和2k3的support-tools里的ldp.exe,可是我还没搞清楚它应该怎么才能以SSL连AD。。。

4.用PHP来操作活动目录
这步算是最轻松的了,就是学一学PHP的相关函数的语法就好了。不过大概是没几个人用到ldap这方面的功能吧,PHP manual中ldap这部分的说明很简略,特别是用TLS的文档里写着这部分没有文档。。。所以最好的办法还是看一些源代码,这里推荐的是我在SourceForge上找到一个的PHP连AD的类:http://adldap.sourceforge.net/
这个类写的并不是特别好,比如添用户时非要求填几个没用的属性,还有至少在一层的OU里的样子,所以推荐它主要是为了看它的原码(30k左右,不是很多)学习用ldap来添加、查询、修改、加组等操作应该怎么写,如果你的应用比较复杂,建议还是自己来写,不直接用它的类。
下面几个地址也列出来考虑吧,它们都是我google到的别人问的问题,本身没有确切解答,不过还是有功劳的,比如我认识到了没有验证一个用户的密码对不对的函数,要做的就是用那个用户名和密码去bind一下,bind上
就是对,否则就是错。
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_21296510.html?qid=21296510
http://topic.csdn.net/t/20060524/10/4774581.html
http://www.ideawu.net/ideablog/category6/article238.html
http://topic.csdn.net/t/20030520/15/1809327.html#

上面列出的文章链接真的不是那么好挑选出来,真怕他们哪天没了,回头我下载完打包传上来吧

编程, 技术 , , ,