了解LDAP
LDAP是Light Directory Access Protocol轻量级目录访问协议的简称,LDAP与数据库有很大的区别,它的数据是树状的,而且每个节点的属性也比较固定。
LDAP协议中用dn表示一条记录的位置,dc表示一条记录所属区域,ou表示一条记录所属组织,cn表示一条记录的名称,uid表示一条记录的ID,其中dn是根据dc、ou、cn或uid的组合来表示的,对于某条记录dn是唯一的,但是dc、ou、cn及uid可以有多个,
例如,常见的用户表示:
dn:cn=张三,cn=users,dc=google,dc=cn
这条记录中dc和cn都有两个。
DBMS_LDAP包
PL/SQL中通过DBMS_LDAP包来管理LDAP服务器。
在默认情况下,DBMS_LDAP包并不载入,需要使用以下sql:
SQL> CONNECT / AS SYSDBA
SQL> @$ORACLE_HOME/rdbms/admin/catldap.sql
数据类型:
SESSION
用于保存LDAP会话的句柄,几乎所有DBMS_LDAP中的函数都需要此类型做参数。MESSAGE
用于接收结果集. 用于所有关于记录属性和值的函数(如接收搜索函数返回的记录集合)。MOD_ARRAY
用于modify_s() or add_s()操作的待修改或新增的数组。TIMEVAL
用于设置LDAP API函数的超时时间。BER_ELEMENT
保存BER 结构的句柄,用于引入消息的解码。STRING_COLLECTION
可传给LDAP服务器的VARCHAR2字符串集合。BINVAL_COLLECTION
RAW data集合,为二进制形式。BERVAL_COLLECTION
BERVAL数据集合。BLOB_COLLECTION
BLOB data集合。
函数:
1、init
init() 用户初始化一个LDAP服务器会话。 本操作将会创建一个LDAP服务器的连接,成功后将返回一个SESSION。
FUNCTION init (
hostname IN VARCHAR2, --服务器地址portnum IN PLS_INTEGER --连接端口
)
RETURN SESSION;
2、simple_bind_s
本函数根据特定的用户和密码登陆LDAP服务器,成功后返回PLS_INTEGER类型。
FUNCTION simple_bind_s (
ld IN SESSION, --init返回的sessiondn IN VARCHAR2,--登陆用户的dn passwd IN VARCHAR2 --登陆用户的密码
)
RETURN PLS_INTEGER;
3、unbind_s
关闭LDAP会话。
FUNCTION unbind_s (
ld IN OUT SESSION --init返回的session
)
RETURN PLS_INTEGER
4、create_mod_array
创建一个MOD_ARRAY,用于modify_s()或add_s()。执行成功返回MOD_ARRAY,失败返回NULL。
FUNCTION create_mod_array (
num IN PLS_INTEGER --数组个数
)
RETURN MOD_ARRAY;
5、populate_mod_array
为MOD_ARRAY集合中的一个元素设置属性及操作方式。根据modval值类型的不同,过程有一下三钟方式:
PROCEDURE populate_mod_array (
modptr IN DBMS_LDAP.MOD_ARRAY,--待操作的MOD_ARRAY
mod_op IN PLS_INTEGER,--操作类型
mod_type IN VARCHAR2, --属性
modval IN DBMS_LDAP.STRING_COLLECTION --值(字符型)
);
PROCEDURE populate_mod_array (
modptr IN DBMS_LDAP.MOD_ARRAY,mod_op IN PLS_INTEGER,
mod_type IN VARCHAR2,
modbval IN DBMS_LDAP.BERVAL_COLLECTION --BERVAL类型
);
PROCEDURE populate_mod_array (
modptr IN DBMS_LDAP.MOD_ARRAY,
mod_op IN PLS_INTEGER,
mod_type IN VARCHAR2,
modbval IN DBMS_LDAP.BLOB_COLLECTION --BLOB类型
);
mod_op可为:
修改 dbms_ldap.MOD_REPLACE
增加 dbms_ldap.MOD_ADD
删除 dbms_ldap.MOD_DELETE
6、modify_s
修改一个已经存在的记录。
FUNCTION modify_s (
ld IN DBMS_LDAP.SESSION, --sessionentrydn IN VARCHAR2, --待修改的记录dn
modptr IN DBMS_LDAP.MOD_ARRAY --待修改的属性 MOD_ARRAY
)
RETURN PLS_INTEGER;
7、add_s
向LDAP服务器添加一条记录。
FUNCTION add_s (
ld IN DBMS_LDAP.SESSION, --sessionentrydn IN VARCHAR2, --要新增的记录dn
modptr IN DBMS_LDAP.MOD_ARRAY --属性MOD_ARRAY
)
RETURN PLS_INTEGER;
8、delete_s
删除一条记录。
FUNCTION delete_s (
ld IN SESSION, --sessionentrydn IN VARCHAR2 --要删除的记录dn
)
9、free_mod_array
是否之前创建的MOD_ARRAY
PROCEDURE free_mod_array (
modptr IN DBMS_LDAP.MOD_ARRAY --MOD_ARRAY
);
10、其他
其他函数起参照:
http://docs.huihoo.com/oracle/docs/B14099_19/idmanage.1012/b14087/dbmsldap_ref.htm
例程(LDAP服务器为ORACLE的OID)
这是一个相对完整的ORACLE应用服务用户管理例程,实现了用户的新增,密码初始化,解锁,禁用,启用及删除等操作。本程序可在PL/SQL Developer测试窗口中运行,若要使用本程序,需修改变量ldap_host,ldap_port,ldap_user,ldap_passwd,ldap_base的初始值。
DECLARE
retval PLS_INTEGER; --返回
my_session dbms_ldap.session;
my_dn VARCHAR(256);
ldap_host VARCHAR(256);
ldap_port VARCHAR(256);
ldap_user VARCHAR(256);
ldap_passwd VARCHAR(256);
ldap_base VARCHAR(256);
mod_user VARCHAR(256); --需要操作的用户帐号
mod_type VARCHAR(1); --操作类型 0-初始化密码 1-解锁 2-禁用 3--启用 4-删除 5-新增
mod_attr VARCHAR(256);
my_array dbms_ldap.mod_array;
my_vals dbms_ldap.string_collection;
my_entry dbms_ldap.message;
my_message dbms_ldap.message;
my_attrs dbms_ldap.string_collection;
BEGIN
retval := -1;
ldap_host := '127.0.0.1'; --LDAP服务器IP地址
ldap_port := '389'; --LDAP服务器端口
ldap_user := 'cn=admin,cn=users,dc=test,dc=cn'; --管理员dn
ldap_passwd := '111111'; --管理员密码
ldap_base := 'cn=Users,dc=test,dc=cn';
dbms_ldap.use_exception := TRUE; --打开异常
:err_msg := '';
--打开会话
my_session := dbms_ldap.init(ldap_host, ldap_port);
--登陆管理员
retval := dbms_ldap.simple_bind_s(my_session, ldap_user, ldap_passwd);
dbms_output.put_line('初始化会话成功!');
mod_user := 'cn=' || :帐号 || ',' || ldap_base;
mod_type := :操作类型;
IF mod_type IN ('0', '2', '3') THEN
CASE
WHEN mod_type = '0' THEN
--如果用户不输入密码则初始化密码为当天日期
my_vals(1) := :密码;
IF my_vals(1) = '' OR my_vals(1) IS NULL THEN
my_vals(1) := to_char(SYSDATE, 'yymmdd');
END IF;
mod_attr := 'userpassword';
WHEN mod_type = '2' THEN
--禁用用户
my_vals(1) := 'disabled';
mod_attr := 'orclisenabled';
WHEN mod_type = '3' THEN
--启用用户
my_vals(1) := 'enabled';
mod_attr := 'orclisenabled';
ELSE
NULL;
END CASE;
/*
属性修改步骤:先创建一个MOD_ARRAY,再调用populate_mod_array填入操作类型和值,然后调用 modify_s实现修改,最后用free_mod_array释放MOD_ARRAY。
*/
my_array := dbms_ldap.create_mod_array(1);
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_replace, mod_attr, my_vals);
retval := dbms_ldap.modify_s(my_session, mod_user, my_array);
:err_msg := :帐号 || ' 修改 ' || mod_attr || ' 属性' || '为' || my_vals(1);
dbms_ldap.free_mod_array(my_array);
ELSIF mod_type = '1' THEN
--解锁
my_vals(1) := '1';
mod_attr := 'orclpwdaccountunlock';
my_array := dbms_ldap.create_mod_array(1);
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, mod_attr, my_vals);
retval := dbms_ldap.modify_s(my_session, mod_user, my_array);
:err_msg := :帐号 || ' 解锁成功 ';
ELSIF mod_type = '4' THEN
--删除用户
retval := dbms_ldap.delete_s(my_session, mod_user);
:err_msg := :帐号 || '删除成功!';
ELSIF mod_type = '5' THEN
--新增用户
my_array := dbms_ldap.create_mod_array(14);
my_vals(1) := :帐号;
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, 'cn', my_vals);
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, 'uid', my_vals);
my_vals(1) := :姓名;
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, 'sn', my_vals);
my_vals(1) := '111111';
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, 'userpassword', my_vals);
my_vals(1) := substr(:帐号, 1, 4);
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, 'mail', my_vals);
my_vals(1) := 'top';
my_vals(2) := 'person';
my_vals(3) := 'organizationalPerson';
my_vals(4) := 'inetOrgPerson';
my_vals(5) := 'orcluser';
my_vals(6) := 'orcluserv2';
dbms_ldap.populate_mod_array(my_array, dbms_ldap.mod_add, 'objectclass', my_vals);
retval := dbms_ldap.add_s(my_session, mod_user, my_array);
dbms_ldap.free_mod_array(my_array);
:err_msg := '用户新增完成! ' || :姓名 || '(' || :帐号 || ')';
ELSE
:err_msg := '操作类型错误!请输入:0-初始化密码 1-解锁 2-禁用 3--启用 4-删除 5-新增';
END IF;
--获取姓名属性
IF mod_type <> '4' THEN
my_attrs(1) := '*';
retval := dbms_ldap.search_s(my_session,
mod_user,
dbms_ldap.scope_subtree,
'objectclass=*',
my_attrs,
0,
my_message);
retval := dbms_ldap.count_entries(my_session, my_message);
IF retval > 0 THEN
my_entry := dbms_ldap.first_entry(my_session, my_message);
my_vals := dbms_ldap.get_values(my_session, my_entry, 'sn');
:姓名 := my_vals(my_vals.FIRST);
ELSE
:err_msg := '没有找到用户:' || :帐号;
END IF;
END IF;
retval := dbms_ldap.unbind_s(my_session);
EXCEPTION
WHEN OTHERS THEN
:err_msg := 'ERR:' || to_char(SQLCODE) || ' ' || SQLERRM;
END;