如何使用 Oracle dbms_ldap 包获取 LDAP 组名称?

Posted

技术标签:

【中文标题】如何使用 Oracle dbms_ldap 包获取 LDAP 组名称?【英文标题】:How to get LDAP groups name using Oracle dbms_ldap package? 【发布时间】:2013-10-08 17:24:38 【问题描述】:

我用这个例子成功连接到LDAP服务器-http://www.oracle-base.com/articles/9i/ldap-from-plsql-9i.php

SET SERVEROUTPUT ON SIZE 1000000
DECLARE
  -- Adjust as necessary.
  l_ldap_host    VARCHAR2(256) := 'server01.tshcomputing.com';
  l_ldap_port    VARCHAR2(256) := '389';
  l_ldap_user    VARCHAR2(256) := 'cn=orcladmin';
  l_ldap_passwd  VARCHAR2(256) := 'password';
  l_ldap_base    VARCHAR2(256) := 'cn=Users,dc=tshcomputing,dc=com';

  l_retval       PLS_INTEGER; 
  l_session      DBMS_LDAP.session;
  l_attrs        DBMS_LDAP.string_collection;
  l_message      DBMS_LDAP.message;
  l_entry        DBMS_LDAP.message;
  l_attr_name    VARCHAR2(256);
  l_ber_element  DBMS_LDAP.ber_element;
  l_vals         DBMS_LDAP.string_collection;

BEGIN
  -- Choose to raise exceptions.
  DBMS_LDAP.USE_EXCEPTION := TRUE;

  -- Connect to the LDAP server.
  l_session := DBMS_LDAP.init(hostname => l_ldap_host,
                              portnum  => l_ldap_port);

  l_retval := DBMS_LDAP.simple_bind_s(ld     => l_session,
                                      dn     => l_ldap_user,
                                      passwd => l_ldap_passwd);

  -- Get all attributes
  l_attrs(1) := '*'; -- retrieve all attributes 
  l_retval := DBMS_LDAP.search_s(ld       => l_session, 
                                 base     => l_ldap_base, 
                                 scope    => DBMS_LDAP.SCOPE_SUBTREE,
                                 filter   => 'objectclass=*',
                                 attrs    => l_attrs,
                                 attronly => 0,
                                 res      => l_message);

  IF DBMS_LDAP.count_entries(ld => l_session, msg => l_message) > 0 THEN
    -- Get all the entries returned by our search.
    l_entry := DBMS_LDAP.first_entry(ld  => l_session,
                                     msg => l_message);

    << entry_loop >>
    WHILE l_entry IS NOT NULL LOOP
      -- Get all the attributes for this entry.
      DBMS_OUTPUT.PUT_LINE('---------------------------------------');
      l_attr_name := DBMS_LDAP.first_attribute(ld        => l_session,
                                               ldapentry => l_entry,
                                               ber_elem  => l_ber_element);
      << attributes_loop >>
      WHILE l_attr_name IS NOT NULL LOOP
        -- Get all the values for this attribute.
        l_vals := DBMS_LDAP.get_values (ld        => l_session,
                                        ldapentry => l_entry,
                                        attr      => l_attr_name);
        << values_loop >>
        FOR i IN l_vals.FIRST .. l_vals.LAST LOOP
          DBMS_OUTPUT.PUT_LINE('ATTIBUTE_NAME: ' || l_attr_name || ' = ' || SUBSTR(l_vals(i),1,200));
        END LOOP values_loop;
        l_attr_name := DBMS_LDAP.next_attribute(ld        => l_session,
                                                ldapentry => l_entry,
                                                ber_elem  => l_ber_element);
      END LOOP attibutes_loop;
      l_entry := DBMS_LDAP.next_entry(ld  => l_session,
                                      msg => l_entry);
    END LOOP entry_loop;
  END IF;

  -- Disconnect from the LDAP server.
  l_retval := DBMS_LDAP.unbind_s(ld => l_session);
  DBMS_OUTPUT.PUT_LINE('L_RETVAL: ' || l_retval);
END;
/

我得到了这个结果:

实际上,用户有3组,但一组是Primary并存储在primaryGroupID中。我试图对组进行查询,但找不到像 ID 这样的属性。如何通过primaryGroupID 获取群组信息(例如memberOf 属性的值)?

【问题讨论】:

【参考方案1】:

尽管可能很烦人,但这必然是一个由两部分组成的过程。 memberOf(和 LDAP 多值属性)存储所有组成员身份除了primaryGroup 成员身份,正如您所发现的,它以完全不同的方式存储。关键是组对象的“primaryGroupToken”属性,与用户的primaryGroupID相关。

我正在做相反的事情,因此作为对自己的服务,我创建了自己的函数,该函数将提供 primaryGroup ID 值/“令牌”:

   --Special from of group membership not appearing in the memberof attribute.
   --Function accepts (flexibly) a SID or a group name and return the token that  
   --would be stored in the attribute "primaryGroupID" of a user object.
FUNCTION get_primaryGroupToken(p_sid_samid IN VARCHAR2) RETURN VARCHAR2 IS
  l_retval PLS_INTEGER;
  l_attrs dbms_ldap.string_collection;
  l_message dbms_ldap.message;
  l_entry dbms_ldap.message;
  l_attr_name VARCHAR2(256);
  l_ber_element dbms_ldap.ber_element;
  l_vals dbms_ldap.string_collection;
  l_primaryGroupToken VARCHAR2(256) := NULL;
  l_filter            VARCHAR2(256);
BEGIN
  IF SUBSTR( p_sid_samid, 2, 1 ) = '-' THEN
    dbms_output.put_line('group spec Is sid');
    l_filter := '(objectSid=' || p_sid_samid || ')';
  ELSE
    dbms_output.put_line('group spec Is samid');
    -- You could probably also use CN here instead of sAMAccountName
    l_filter := '(&(sAMAccountName=' || p_sid_samid || ')(objectClass=group))';
  END IF;
  l_retval   := get_ldap_session();
  l_attrs(1) := 'primaryGroupToken';
  l_retval   := DBMS_LDAP.search_s(ld => g_session, 
                    base => g_ldap_auth_base, 
                    scope => DBMS_LDAP.SCOPE_SUBTREE, 
                    filter => l_filter, 
                    attrs => l_attrs, 
                    attronly => 0, 
                    res => l_message);
  IF DBMS_LDAP.count_entries(ld => g_session, msg => l_message) > 0 THEN
    --Get all the entries returned by our search.
    l_entry := DBMS_LDAP.first_entry(ld => g_session,msg => l_message);
    <<entry_loop>>
    WHILE l_entry IS NOT NULL
    LOOP
      -- Get all the attributes for this entry.
      l_attr_name           := DBMS_LDAP.first_attribute(ld => g_session,ldapentry => l_entry, ber_elem => l_ber_element);
      IF lower(l_attr_name) <> 'primarygrouptoken' THEN
        DBMS_OUTPUT.PUT_LINE('ATTIBUTE_NAME unexpected : ' || l_attr_name );
      ELSE
        l_vals := DBMS_LDAP.get_values (ld => g_session, ldapentry => l_entry, attr => l_attr_name);
      END IF;
      << values_loop >>
      FOR i IN l_vals.FIRST .. l_vals.LAST
      LOOP
        l_primaryGroupToken := l_vals(i);
      END LOOP values_loop;
      IF l_primaryGroupToken IS NULL THEN
        l_attr_name          := DBMS_LDAP.next_attribute(ld => g_session, ldapentry => l_entry, ber_elem => l_ber_element);
        l_entry              := DBMS_LDAP.next_entry(ld => g_session,msg => l_entry);
      ELSE
        EXIT;
      END IF;
    END LOOP entry_loop;
  END IF;
  -- Disconnect from the LDAP server.
  l_retval := DBMS_LDAP.unbind_s(ld => g_session);
  RETURN l_primaryGroupToken;
END get_primaryGroupToken; 

请注意,此函数在包中,“g_”变量是包全局变量。当然也消除了仅开发 dbms_output 调用等。

然后我只进行了 两个 过滤搜索,一个在 primaryGroupID 上,一个在 memberOf 上,以获取组的 所有 成员。

在您的情况下,正好相反,拥有自己的函数,首先评估所有 memberOf 值,然后使用 LDAP 搜索具有该 primaryGroupToken 的组单独处理 primaryGroupToken。

【讨论】:

【参考方案2】:

我认为组中有一个属性持有该值,但我没有看到它。

再想一想,我认为它是基于 SID 的 RID 组件。您必须解析 SID 以获取 RID(相对 ID)组件。

【讨论】:

然后我得到一些组的数据,SID为空(或==''),我不知道为什么。

以上是关于如何使用 Oracle dbms_ldap 包获取 LDAP 组名称?的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE。使用LDAP进行身份验证始终返回-16

Oracle APEX - 来自 LDAP 的 LOV

如何使用 PL-SQL 在 Oracle 中获取列数据类型

RODBC 包:如何获取“表是不是存在?”的逻辑值查询类型?

如何使用 APEX 函数编译 Oracle 包?

使用 JDBC 从存储过程中获取 Oracle 表类型