参考:https://seanstuber.com/2018/08/01/how-to-use-dbms_ldap-part-1/
建立关闭连接
下面示例是基本的匿名连接示例。
DECLARE v_session dbms_ldap.session; v_result PLS_INTEGER; BEGIN --init 初始化连接session v_session := dbms_ldap.init(hostname => '180.76.186.73', portnum => dbms_ldap.port); if v_session is null then DBMS_OUTPUT.put_line('init failed'); else --unbind 关闭session v_result := dbms_ldap.unbind_s(v_session); if v_result != DBMS_LDAP.success THEN DBMS_OUTPUT.put_line(TO_CHAR(v_result , 'fm9999') || ' ' || DBMS_LDAP.err2string(V_result)); end if ; end if ; END;
连接认证
在LDAP中认证鉴权就是提供用户和密码,在LDAP的技术术语中称为binding。
认证方法:SIMPLE_BIND_S
使用固定的认证方式
在LDAP中,用户密码的形式和普通不同,使用DN作为用户名。DECLARE v_session DBMS_LDAP.session; v_result PLS_INTEGER; BEGIN DBMS_LDAP.use_exception := TRUE; -- Establish a connection to LDAP server v_session := DBMS_LDAP.init(hostname => '180.76.186.73', portnum => DBMS_LDAP.port); -- Login with the DN for a user account and password v_result := DBMS_LDAP.simple_bind_s( ld => v_session, dn => 'cn=admin,dc=dezohty,dc=com', passwd => 'adminpw'); -- Even if you don't BIND a username/password, you should still UNBIND -- to close the session, there is no close v_result := DBMS_LDAP.unbind_s(v_session); END;
- BIND_S
可选择认证方式
Strangely,DBMS_LDAP defines multiple authentication constants but the documentation, as of 18c, claims: “The only valid value is DBMS_LDAP_UTL.AUTH_SIMPLE.” - 使用SSL
搜索查询
DECLARE v_result PLS_INTEGER; v_session DBMS_LDAP.session; v_search_attrs DBMS_LDAP.string_collection; v_search_results DBMS_LDAP.MESSAGE; v_entry DBMS_LDAP.MESSAGE; v_distinguished_name VARCHAR2(256); v_dn_pieces DBMS_LDAP.string_collection; v_values DBMS_LDAP.string_collection; BEGIN --初始化session v_session := DBMS_LDAP.init(hostname => '180.76.186.73', portnum => DBMS_LDAP.port); --binding , 如果不进行此操作,则必须开启LDAP匿名访问权限 v_result := DBMS_LDAP.simple_bind_s( ld => v_session, dn => 'cn=admin,dc=dezohty,dc=com', passwd => 'adminpw'); --指定搜索的属性,1.1 = 不返回属性信息 v_search_attrs(1) := '1.1'; --搜索 , FILTER 指定过滤器 -- orjectclass=* 表示返回所有结果 -- uid=chaofeng.li 表示返回uid = chaofeng.li的条目 , uid在LDAP中是唯一的 -- DBMS_LDAP.scope_base => 只搜索指定的base -- DBMS_LDAP.scope_onelevel => 搜索指定的base及base下一level的entities -- DBMS_LDAP.scope_subtree => 搜索整个base树结构 -- attronly 0 表示属性和属性值均返回 1 表示只返回属性名 -- search_s 普通搜索 search_st 指定超时时间 tv => v_timeout DBMS_LDAP.timeval v_result := DBMS_LDAP.search_s(ld => v_session, base => 'ou=dc=dezohty,dc=com', -- scope => DBMS_LDAP.scope_base, scope => DBMS_LDAP.scope_onelevel, -- scope => DBMS_LDAP.scope_subtree, filter => 'objectclass=*', attrs => v_search_attrs, attronly => NULL, res => v_search_results); -- 获得结果总数 v_result := DBMS_LDAP.count_entries(v_session, v_search_results); DBMS_OUTPUT.put_line(v_result) ; v_entry := DBMS_LDAP.first_entry(v_session, v_search_results); -- 遍历查询结果 while v_entry is not null LOOP v_distinguished_name := DBMS_LDAP.get_dn(v_session, v_entry); DBMS_OUTPUT.put_line('DN: ' || v_distinguished_name); -- 搜索属性值 FOR i IN 1 .. v_search_attrs.COUNT LOOP v_values := DBMS_LDAP.get_values(v_session, v_entry, v_search_attrs(i)); IF v_values.COUNT > 0 THEN FOR j IN v_values.FIRST .. v_values.LAST LOOP DBMS_OUTPUT.put_line(v_search_attrs(i) || ' : ' || v_values(j)); END LOOP; ELSE DBMS_OUTPUT.put_line(v_search_attrs(i) || ' not found'); END IF; END LOOP; -- 切分DN片段 -- v_dn_pieces := DBMS_LDAP.explode_dn(dn => v_distinguished_name, notypes => 0); -- FOR i IN v_dn_pieces.FIRST .. v_dn_pieces.LAST -- LOOP -- DBMS_OUTPUT.put_line(i || ': ' || v_dn_pieces(i)); -- END LOOP; v_entry := DBMS_LDAP.next_entry(v_session, v_entry ); end loop ; v_result := DBMS_LDAP.unbind_s(v_session); END; /
查询示例
base => 'ou=dc=dezohty,dc=com', 搜索结果示例:
-- DBMS_LDAP.scope_base => 只搜索指定的base
-- DBMS_LDAP.scope_onelevel => 搜索指定的base及base下一level的entities
-- DBMS_LDAP.scope_subtree => 搜索整个base树结构
修改数据
插入
--本例LDAP服务器为AD域 DECLARE v_session DBMS_LDAP.session; v_result PLS_INTEGER; v_attributes DBMS_LDAP.mod_array; v_strings DBMS_LDAP.string_collection; BEGIN DBMS_LDAP.use_exception := FALSE; v_session := DBMS_LDAP.init(hostname => '10.7.37.10', portnum => DBMS_LDAP.port); v_result := DBMS_LDAP.simple_bind_s(ld => v_session, dn => 'CN=chaofeng li,CN=Users,DC=cf,DC=com', passwd => '!Beijing'); -- dn => 'CN=test_name6 li,CN=Users,DC=cf,DC=com', -- passwd => '!Beijing'); IF v_result != DBMS_LDAP.success THEN DBMS_OUTPUT.put_line('Bind Result: ' || v_result || ' ' || DBMS_LDAP.err2string(v_result)); ELSE v_attributes := DBMS_LDAP.create_mod_array(num => 4); v_strings(1) := '123461'; DBMS_LDAP.populate_mod_array(modptr => v_attributes, mod_op => DBMS_LDAP.mod_add, mod_type => 'sAMAccountName', --sAMAccountName是唯一的 modval => v_strings); v_strings(1) := 'user'; DBMS_LDAP.populate_mod_array(modptr => v_attributes, mod_op => DBMS_LDAP.mod_add, mod_type => 'objectclass', modval => v_strings); v_strings(1) := '544'; DBMS_LDAP.populate_mod_array(modptr => v_attributes, mod_op => DBMS_LDAP.mod_add, mod_type => 'userAccountControl', --544表示ldap中enable , 546表示disable modval => v_strings); v_strings(1) := '!Beijing'; DBMS_LDAP.populate_mod_array(modptr => v_attributes, mod_op => DBMS_LDAP.mod_add, mod_type => 'userpassword', --设置用户密码,必须符合密码规则, 否则即使添加成功也不会认证 modval => v_strings); -- -- v_strings(1) := -- '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myserver)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=myservice)))'; -- DBMS_LDAP.populate_mod_array(modptr => v_attributes, -- mod_op => DBMS_LDAP.mod_add, -- mod_type => 'orclNetDescString', -- modval => v_strings); v_result := DBMS_LDAP.add_s(ld => v_session, entrydn => 'cn=test_name6,CN=Users,DC=cf,DC=com', -- cn唯一 modptr => v_attributes); IF v_result = DBMS_LDAP.success THEN DBMS_OUTPUT.put_line('Add successful'); ELSE DBMS_OUTPUT.put_line('Add Result: ' || v_result || ' ' || DBMS_LDAP.err2string(v_result)); END IF; DBMS_LDAP.free_mod_array(modptr => v_attributes); v_result := DBMS_LDAP.unbind_s(v_session); END IF; END; /
删除
DBMS_LDAP没有提供批量删除功能,如果需要批量删除,则需要循环执行删除命令v_result := DBMS_LDAP.delete_s(ld => v_session, entrydn => 'cn=test_name,cn=OracleContext,dc=example,dc=net');
修改
DBMS_LDAP.populate_mod_array(modptr => v_attributes, mod_op => DBMS_LDAP.mod_replace, mod_type => 'orclNetDescString', modval => v_strings); v_result := DBMS_LDAP.modify_s(ld => v_session, entrydn => 'cn=test_name,cn=OracleContext,dc=example,dc=net', modptr => v_attributes);