2017-09-13 375 views
0

我想添加一个groupOfUniqueNames对象的新成员,但我得到一个“ENTRY_ALREADY_EXISTS”错误。LDAP - 如何将条目添加到groupOfUniqueNames? (ERR_250_ENTRY_ALREADY_EXISTS)

服务器是ApacheDS中,我的代码是红宝石,使用使用net-LDAP:

ldap.add(dn: 'cn=janitors,dc=tidy,dc=example,dc=com', 
     attributes: 
      { 
      :objectclass => "groupOfUniqueNames", 
      :uniqueMember => 
       "uid=broom001,o=users,dc=tidy,dc=example,dc=com" 
      } 
) 

中已经有门卫一个成员 - mop99。当我打电话ldap.add,我得到(格式化略有可读性):

ldap.response: ERR_250_ENTRY_ALREADY_EXISTS cn=janitors,dc=tidy,dc=example,dc=com already exists! 
OpenStruct { 
      :code => 68, 
    :error_message => "ENTRY_ALREADY_EXISTS: failed for MessageType : ADD_REQUEST 
         Message ID : 2 
          Add Request : 
          Entry 
          dn[n]: cn=janitors,dc=tidy,dc=example,dc=com 
          objectclass: groupOfUniqueNames 
          uniqueMember: uid=mop99,o=users,dc=tidy,dc=example,dc=com 
          : ERR_250_ENTRY_ALREADY_EXISTS cn=janitors,dc=tidy,dc=example,dc=com already exists! 
         ", 
     :matched_dn => "", 
      :message => "Entry Already Exists" 
} 

我试图改变ldap.add()来ldap.modify(),但只是替换mop99与broom001,只留下一个看门人。我需要的是add broom001,最终成为一支不断增长的门卫队伍。

我可以从LDAP中读取现有列表,将新条目附加到Ruby中的列表中,然后将列表写回到LDAP中......但是这引入了一种竞争状态,在两种情况下可能会丢失管理员同时添加。我的看门人太贵了,所以这是不可接受的。

我已经广泛地搜索了网页,但没有发现太多内容,也没有涉及net-ldap。我找到了https://www.openldap.org/lists/openldap-software/199912/msg00164.html,它描述了一个解决方案WRT .LDIF文件,但我不知道如何将其转换为net-ldap。

我错过了什么?

+1

就协议而言,ldapadd操作是在目录中创建一个新条目。如果你想**修改一个属性的值(即在'uniqueMember'列表中添加一个新值,你必须使用'ldapmodify'操作。我不知道它是如何转化为ruby的,但是这是LDAP协议的方式 – Esteban

回答

0

添加对象类没有意义。它已经在那里。

只需添加唯一的成员值即可。

+0

这就是我最初的......但是我得到一个错误,“ERR_60条目不包含STRUCTURAL ObjectClass”代码:65.一些研究和测试导致添加objectclass属性来解决这个问题,但是当我解决所有其他问题时,我会尝试将它退出,看看它是否是一条红色鲱鱼 –

+0

现在我理解你的意思了,我忽略了“add_attribute”方法正如你所描述的那样。谢谢你的提示,EJP。 –

0

[更新 - 忽略本答案。看到我的新答案,开始,“好吧,我感到愚蠢......”]

据我所知,你不能像我试图做的那样添加到groupOfUniqueNames。我怀疑那些使你看起来可以做的只是用瓷器覆盖管道的工具。

简单的方法是从LDAP读取当前列表,操作它(添加/删除值),并将整个列表写回到LDAP。如果您的应用不关心在同步更新之间的竞赛中丢失数据,那很可能是好的。

从这里开始的一个步骤是在代码中使用序列化的阻塞,以确保没有同时更新。这很棘手(特别是在集群或异构系统进行更新时),但是可行。

我最终做的是完全避开所有这些问题,在我的应用程序中从头开始重建列表,然后覆盖列表。当然,这取决于你有源数据来建立列表。在我的情况下,源数据从LDAP本身来了,像这样的查询:

def janitor_user_dns 
    # Looks up all janitors. 
    # returns a list of DN's, not full User records. 

    role_filter = Net::LDAP::Filter.eq(:role, janitor_role_dn) 
    entries = mc_ldap.search(base: ldap_base, filter: role_filter, attributes: 'dn', 
          scope: Net::LDAP::SearchScope_SingleLevel) {} 
    entries.map { |user| user[:dn][0] } 
    end 

就这样,实在是小巫见大巫写入新列表返回的groupOfUniqueNames:

def update_janitor_users 
    mc_ldap.save(true, janitor_role_dn, objectclass: 'groupOfUniqueNames', uniqueMember: janitor_user_dns) 
end 

有了这个方法,在竞争条件下仍然可能会丢失数据,但下一次更新时会自行修复。如果这是不可接受的,你可以读回列表并测试它是否正确写入。如果不是,只需再次重新生成列表(从竞争对手中选择更改),然后重复。

0

好吧......我觉得有点笨。下面是正确答案:

ldap.add_attribute(dn, attribute, value) 

或者专门为我的新的看门人:

ldap.add_attribute('cn=janitors,dc=tidy,dc=example,dc=com', 
        'uniqueMember', 
        'uid=broom001,o=users,dc=tidy,dc=example,dc=com') 

钡热潮。而已。正是我需要的。 脸红

我要走了我以前的答案可笑的,因为它是从头开始填充列表的一种方式,而可能是在某些情况下非常有用。

我也离开了这个令人尴尬的问题,以防其他人忽略了文档中的add_attribute(),并且在尝试搜索这个问题时感到沮丧。

对ruby-net-ldap似乎仍然存在的一个挫折是delete_attribute()不接受第三个参数 - 即要从组中删除的值。您只能使用delete_attribute删除整个组,而不是单个条目。但我不需要删除组中的单个值,所以la-ti-da ...