LDAP 专有名称验证器

LDAP 专有名称验证器

是否有一个库、程序或简单的正则表达式来检查输入中指定的 DN 是否格式正确?

例如:输入:manager,ou=company,dc=net ---> 输出:格式不正确

输入:cn=manager,ou=company,dc=net ---> 输出:格式正确

答案1

在 perl 中,Net::LDAP这几乎是微不足道的:

#!/usr/bin/perl
use strict;
use warnings;
use Net::LDAP::Util qw/canonical_dn/;
foreach my $dn (@ARGV) {
   if (!defined(canonical_dn($dn))) { print "not well formed: $dn\n"; }
   else                             { print "well formed: $dn\n"; }
}

然后:

$ perl ldapdn.pl "manager, ou=company, dc=net" "cn=manager, ou=company, dc=net"
not well formed: manager, ou=company, dc=net
well formed: cn=manager, ou=company, dc=net

有许多函数可以验证 DN,ldap_explode_dn()如果您希望规范化和进一步处理 DN,这些函数也可能有用。

值得注意的是,“格式良好”和“有效”并不是一回事,因为语法上格式良好的 DN 可能与特定 LDAP DIT 的模式不匹配,因此被拒绝。

如果你有 OpenLDAP,任何较新的版本都应该附带一个slapdn程序。这正确的模式检查,但您必须slapd.conf在运行它的系统上设置可行的模式(由于操作配置文件的文件权限,可能需要以 root 或特殊用户身份运行它)。

$ /usr/local/sbin/slapdn  -v "cn=manager, ou=company, dc=net"
DN: <cn=manager, ou=company, dc=net> check succeeded
normalized: <cn=manager,ou=company,dc=net>
pretty:     <cn=manager,ou=company,dc=net>

(如果您从源代码构建了 OpenLDAP,它还会附带一个dntest作为其测试套件的一部分构建的程序。它仅解析 DN,不检查模式。遗憾的是它没有可用的错误代码,并且似乎偶尔会用段错误指示格式错误的 DN……)

最后,正则表达式方法。正如@voretaq7所建议的,你可以使用澳大利亚国家橄榄球联盟RFC 4514,不过你还需要RFC 4512(§1.4)。通过任何 ABNF 到 ERE 转换器运行它们(例如abnf2regex,用 Java 实现),然后它就弹出来了。我不会在这里粘贴它,它大约有 4k 的线路噪音。abnf2regex不过,你可以用以下方法破解整个难题:

$ java -jar abnf2regex.jar -t distinguishedName \
        "cn=manager,ou=company,dc=net" rfc4512.abnf rfc4514dn.abnf
Rule "distinguishedName" matches: cn=manager,ou=company,dc=net
Rule: [relativeDistinguishedName *(COMMA relativeDistinguishedName)]
Expanded: [(((%x41-5a / %x61-7a) *(%x41-5a / %x61-7a / %x30 / %x31-39 / %x2d))
 ... <<expanded ABNF snipped>>
Regex: (?:(?:[A-Za-z][\-01-9A-Za-z]*|(?:[01-9]|[1-9][01-9]+)(?:\.(?:[01-9]
 ... <<expanded regex snipped>>

以上代码是针对特定命名规则 ( -t distinguishedName) 生成的正则表达式测试字符串。如果你眼尖的话,你会注意到我做了一点小手脚,我从 DN 中删除了空格,因为它从技术上来说,不属于 DN并会中断比赛。


最后(这次是真的)简化且不完善 正则表达式你可以使用pcregrep -i

 ^([a-z][a-z0-9-]*)=(?![ #])(((?![\\="+,;<>]).)|(\\[ \\#="+,;<>])|(\\[a-f0-9][a-f0-9]))*
(,([a-z][a-z0-9-]*)=(?![ #])(((?![\\="+,;<>]).)|(\\[ \\#="+,;<>])|(\\[a-f0-9][a-f0-9]))*)*$

我已经将它填充并包裹起来,以便可以清晰地阅读,或者说,可能不那么难以辨认。简化的分解如下

^(attributename)=(attributevalue)(,(attributename)=(attributevalue))*$

 attributevalue = not leading space or octothorpe |
                  any char except specials | 
                  escaped specials |
                  escaped hex-digit pair         

这需要至少以下自由:

  • 它在很大程度上忽略了 Unicode(尽管你可能会发现pcregrep --utf有帮助),并且不会验证 UTF-8
  • 它不支持属性类型中的直接数字 OID
  • 它不支持多值 RDN(例如cn=Bob+sn=Smith
  • 它不处理未转义的尾随空格

按照规范,它不处理“,”开头、结尾或周围的不必要的格式化空格。

答案2

别担心。您正在与之通信的 LDAP 服务器已经知道无效 DN 是什么样子。只需捕获错误(响应代码)并采取适当措施即可。

答案3

openldap 库提供了这个子程序,我不知道 ruby​​、perl 等的任何 ldap 接口是否提供对此 api 的访问。但我没有仔细查看。

ldap_str2dn() parses a string representation of  a  distinguished  name
   contained  in  str  into  its  components,  which  are  stored in dn as
   ldap_ava structures, arranged in LDAPAVA, LDAPRDN,  and  LDAPDN  terms,
   defined as:

   typedef struct ldap_ava {
       char *la_attr;
       struct berval *la_value;
       unsigned la_flags;
   } LDAPAVA;

答案4

我改进了我的问题,添加了我的简单(可能太简单了)替代答案:我创建了一个正则表达式来匹配所有可能的 DNS

(\w+[=]{1}[a-zA-Z0-9\-\$&\(\)\[\]\{\}\.\s]+)([,{1}]\w+[=]{1}[a-zA-Z0-9\-\(\)\[\]\{\}\.\s]+)*

相关内容