47 カスタマイズされた外部認証プラグインの構成
次のトピックでは、カスタマイズされた外部認証プラグインを使用する方法、外部プラグインをインストール、構成、有効化およびデバッグする方法や、PL/SQLパッケージを作成する方法について説明します。
ノート:
この章で言及するOracle Single Sign-Onはすべて、Oracle Single Sign-On 10g (10.1.4.3.0)以上のことです。
47.1 カスタマイズされた外部認証プラグインの概要
Oracle Internet Directoryに格納されたセキュリティ資格証明に基づく認証を、ネイティブ認証と呼びます。
ユーザーがセキュリティ資格証明を入力すると、ディレクトリ・サーバーはOracle Internet Directoryに格納されている資格証明とそれを比較します。資格証明が一致すると、ディレクトリ・サーバーはユーザーを認証します。
一方、Oracle Internet Directory以外のディレクトリに格納されたセキュリティ資格証明に基づく認証を外部認証と呼びます。ユーザーがセキュリティ資格証明を入力すると、ディレクトリ・サーバーは他のディレクトリに格納されている資格証明とそれを比較します。この比較は次のものを使用して行われます。
-
外部認証作業を行うPL/SQLプログラム
-
このPL/SQLプログラムを起動する外部認証プラグイン
47.2 外部認証プラグインのインストール、構成および有効化
パッケージoidexaup.sql
を使用して、外部認証プラグインPL/SQLパッケージをインストールします。
この例は、PL/SQLプログラムoidexaup.sql
を使用しています。「PL/SQLパッケージoidexaup.sqlの作成」でこのプログラムについて説明します。次の項目が含まれます。
-
2つのプラグイン(
when_compare_replace
およびwhen_modify_replace
) -
ユーティリティ・ファンクション(
get_nickname
)
統合されたパッケージはプラグイン・パッケージOIDEXTAUTH
です。これは、デプロイメントの要件に応じて変更できるテンプレートとしても機能します。
外部認証プラグインをインストールおよび構成し、有効にするステップは、次のとおりです。
これで、すべての準備が完了しました。ldapcompareコマンド行ツールを使用すると、Oracle Single Sign-Onからユーザーを認証する前にプラグインおよび認証プログラムが適切に動作していることを確認できます。
この例では、ユーザー・パスワードを外部変更するためのプラグイン・コードも提供されています。
47.3 外部認証プラグインのデバッグ
プラグインのプロセスと内容を調べるには、ディレクトリ・サーバー・プラグインを有効にする必要があります。
ディレクトリ・サーバー・プラグインのデバッグを設定するには、次のコマンドを実行します。
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdsu.sql
ディレクトリ・サーバー・プラグインのデバッグを有効にするには、次のコマンドを実行します。
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdon.sql
ディレクトリ・サーバー・プラグインのデバッグを無効にするには、次のコマンドを実行します。
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdof.sql
ディレクトリ・サーバー・プラグインのデバッグ・メッセージを表示するには、次のコマンドを実行します。
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdsh.sql
ディレクトリ・サーバー・プラグインのデバッグ・メッセージを削除するには、次のコマンドを実行します。
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdde.sql
47.4 PL/SQLパッケージoidexaup.sqlの作成
この例で使用するスクリプトoidexaup.sql
を使用して、PL/SQLパッケージを作成します。
PL/SQLパッケージには次のものが含まれます。
CREATE OR REPLACE PACKAGE OIDEXTAUTH AS PROCEDURE when_compare_replace (ldapplugincontext IN ODS.plugincontext, result OUT INTEGER, dn IN VARCHAR2, attrname IN VARCHAR2, attrval IN VARCHAR2, rc OUT INTEGER, errormsg OUT VARCHAR2 ); PROCEDURE when_modify_replace (ldapplugincontext IN ODS.plugincontext, dn IN VARCHAR2, mods IN ODS.modlist, rc OUT INTEGER, errormsg OUT VARCHAR2 ); FUNCTION get_nickname (dn IN VARCHAR2, my_session IN DBMS_LDAP.session) RETURN VARCHAR2; END OIDEXTAUTH; / SHOW ERROR CREATE OR REPLACE PACKAGE BODY OIDEXTAUTH AS -- We use this function to convert the dn to nickname. -- When OID server receives the ldapcompare request, it -- only has the dn information. We need to use DBMS_LDAP_UTL -- package to find out the nickname attribute value of -- the entry. FUNCTION get_nickname (dn IN VARCHAR2, my_session IN DBMS_LDAP.session) RETURN VARCHAR2 IS my_pset_coll DBMS_LDAP_UTL.PROPERTY_SET_COLLECTION; my_property_names DBMS_LDAP.STRING_COLLECTION; my_property_values DBMS_LDAP.STRING_COLLECTION; user_handle DBMS_LDAP_UTL.HANDLE; user_id VARCHAR2(2000); user_type PLS_INTEGER; user_nickname VARCHAR2(256) DEFAULT NULL; my_attrs DBMS_LDAP.STRING_COLLECTION; retval PLS_INTEGER; BEGIN plg_debug( '=== Beginning of get_nickname() === '); user_type := DBMS_LDAP_UTL.TYPE_DN; user_id := dn; retval := DBMS_LDAP_UTL.create_user_handle(user_handle, user_type, user_id); plg_debug('create_user_handle() Returns ' || To_char(retval)); retval := DBMS_LDAP_UTL.get_user_properties(my_session, user_handle, my_attrs, DBMS_LDAP_UTL.NICKNAME_PROPERTY, my_pset_coll); plg_debug( 'get_user_properties() Returns ' || To_char(retval)); IF my_pset_coll.COUNT > 0 THEN FOR i IN my_pset_coll.first .. my_pset_coll.last LOOP retval := DBMS_LDAP_UTL.get_property_names(my_pset_coll(i), my_property_names); IF my_property_names.COUNT > 0 THEN FOR j IN my_property_names.first .. my_property_names.last LOOP retval := DBMS_LDAP_UTL.get_property_values(my_pset_coll(i), my_property_names(j), my_property_values); IF my_property_values.COUNT > 0 THEN FOR k IN my_property_values.FIRST..my_property_values.LAST LOOP user_nickname := my_property_values(k); plg_debug( 'user nickname = ' || user_nickname); END LOOP; END IF; END LOOP; END IF; -- IF my_property_names.count > 0 END LOOP; END IF; -- If my_pset_coll.count > 0 plg_debug( 'got user_nickname: ' || user_nickname); -- Free my_properties IF my_pset_coll.count > 0 then DBMS_LDAP_UTL.free_propertyset_collection(my_pset_coll); END IF; DBMS_LDAP_UTL.free_handle(user_handle); RETURN user_nickname; EXCEPTION WHEN OTHERS THEN plg_debug('Exception in get_nickname. Error code is ' || to_char(sqlcode)); plg_debug(' ' || Sqlerrm); RETURN NULL; END; PROCEDURE when_compare_replace (ldapplugincontext IN ODS.plugincontext, result OUT INTEGER, dn IN VARCHAR2, attrname IN VARCHAR2, attrval IN VARCHAR2, rc OUT INTEGER, errormsg OUT VARCHAR2 ) IS retval pls_integer; lresult BOOLEAN; my_session DBMS_LDAP.session; my_property_names DBMS_LDAP.STRING_COLLECTION; my_property_values DBMS_LDAP.STRING_COLLECTION; my_attrs DBMS_LDAP.STRING_COLLECTION; my_pset_coll DBMS_LDAP_UTL.PROPERTY_SET_COLLECTION; user_handle DBMS_LDAP_UTL.HANDLE; user_id VARCHAR2(2000); user_type PLS_INTEGER; user_nickname VARCHAR2(60); remote_dn VARCHAR2(256); i PLS_INTEGER; j PLS_INTEGER; k PLS_INTEGER; BEGIN plg_debug( '=== Begin of WHEN-COMPARE-REPLACE plug-in'); plg_debug( 'DN = ' || dn); plg_debug( 'Attr = ' || attrname); --plg_debug( 'Attrval = ' || attrval); DBMS_LDAP.USE_EXCEPTION := FALSE; errormsg := 'No error msg'; rc := 0; -- converting dn to nickname my_session := LDAP_PLUGIN.init(ldapplugincontext); plg_debug( 'ldap_session =' || RAWTOHEX(SUBSTR(my_session,1,8))); retval := LDAP_PLUGIN.simple_bind_s(ldapplugincontext, my_session); plg_debug( 'simple_bind_res =' || TO_CHAR(retval)); user_nickname := get_nickname(dn, my_session); plg_debug( 'user_nickname =' || user_nickname); -- unbind from the directory retval := DBMS_LDAP.unbind_s(my_session); plg_debug( 'unbind_res Returns ' || To_char(retval)); IF (user_nickname IS NULL) THEN result := 32; errormsg := 'Can''t find the nickname'; plg_debug( 'Can''t find the nickname'); RETURN; END IF; plg_debug( '=== Now go to extauth '); BEGIN retval := auth_external.authenticate_user(user_nickname, attrval); plg_debug( 'auth_external.authenticate_user() returns = ' || 'True'); result := 6; -- compare result is TRUE EXCEPTION WHEN OTHERS THEN result := 5; -- compare result is FALSE plg_debug( 'auth_external.authenticate_user() returns = ' || 'False'); RETURN; END; plg_debug( '=== End of WHEN-COMPARE-REPLACE plug-in'); EXCEPTION WHEN OTHERS THEN rc := 1; errormsg := 'Exception: when_compare_replace plugin'; plg_debug( 'EXCEPTION: ' || retval); plg_debug('Exception in when_compare. Error code is ' || to_char(sqlcode)); plg_debug(' ' || Sqlerrm); END; PROCEDURE when_modify_replace (ldapplugincontext IN ODS.plugincontext, dn IN VARCHAR2, mods IN ODS.modlist, rc OUT INTEGER, errormsg OUT VARCHAR2 ) IS retval pls_integer; lresult BOOLEAN; my_session DBMS_LDAP.SESSION; my_property_names DBMS_LDAP.STRING_COLLECTION; my_property_values DBMS_LDAP.STRING_COLLECTION; my_attrs DBMS_LDAP.STRING_COLLECTION; my_modval DBMS_LDAP.BERVAL_COLLECTION; my_pset_coll DBMS_LDAP_UTL.PROPERTY_SET_COLLECTION; user_handle DBMS_LDAP_UTL.HANDLE; l_mod_array RAW(32); user_id VARCHAR2(2000); user_type PLS_INTEGER; user_nickname VARCHAR2(2000); old_passwd VARCHAR2(60) DEFAULT NULL; new_passwd VARCHAR2(60) DEFAULT NULL; remote_dn VARCHAR2(256); i PLS_INTEGER; j PLS_INTEGER; k PLS_INTEGER; BEGIN plg_debug( '=== Begin of WHEN-MODIFY-REPLACE plug-in'); DBMS_LDAP.USE_EXCEPTION := FALSE; user_type := DBMS_LDAP_UTL.TYPE_DN; user_id := dn; -- converting dn to nickname my_session := LDAP_PLUGIN.init(ldapplugincontext); plg_debug( 'ldap_session =' || RAWTOHEX(SUBSTR(my_session,1,8))); retval := LDAP_PLUGIN.simple_bind_s(ldapplugincontext, my_session); plg_debug( 'simple_bind_res =' || TO_CHAR(retval)); user_nickname := get_nickname(dn, my_session); plg_debug( 'user_nickname =' || user_nickname); -- unbind from the directory retval := DBMS_LDAP.unbind_s(my_session); FOR l_counter1 IN 1..mods.COUNT LOOP IF (mods(l_counter1).operation = 2) AND (mods(l_counter1).type = 'userpassword') THEN FOR l_counter2 IN 1..mods(l_counter1).vals.COUNT LOOP new_passwd := mods(l_counter1).vals(l_counter2).val; END LOOP; END IF; IF (mods(l_counter1).operation = 0) AND (mods(l_counter1).type = 'userpassword') THEN FOR l_counter2 IN 1..mods(l_counter1).vals.COUNT LOOP new_passwd := mods(l_counter1).vals(l_counter2).val; END LOOP; END IF; IF (mods(l_counter1).operation = 1) AND (mods(l_counter1).type = 'userpassword') THEN FOR l_counter2 IN 1..mods(l_counter1).vals.COUNT LOOP old_passwd := mods(l_counter1).vals(l_counter2).val; END LOOP; END IF; END LOOP; IF new_passwd IS NOT NULL AND old_passwd IS NOT NULL THEN BEGIN auth_external.change_passwd(user_nickname, old_passwd, new_passwd); EXCEPTION WHEN OTHERS THEN rc := 1; plg_debug( 'auth_external.change_passwd() raised exception.'); errormsg := 'auth_external.change_passwd() raised exception.'; RETURN; END; ELSIF new_passwd IS NOT NULL AND old_passwd IS NULL THEN BEGIN auth_external.reset_passwd(user_nickname, new_passwd); EXCEPTION WHEN OTHERS THEN plg_debug( 'auth_external.reset_passwd() raised exception.'); rc := 1; errormsg := 'auth_external.reset_passwd() raised exception.'; RETURN; END; ELSE rc := 1; errormsg := 'PLG_Exception. Not enough info to change passwd.'; END IF; plg_debug( 'external change password succeed'); rc := 0; errormsg := 'No when_mod_replace plguin error msg'; retval := DBMS_LDAP.unbind_s(my_session); plg_debug( 'End of WHEN-MODIFY-REPLACE'); --COMMIT; EXCEPTION WHEN others THEN rc := 1; errormsg := 'PLG_Exception: when_modify_replace plguin'; plg_debug('Exception in when_modify. Error code is ' || to_char(sqlcode)); plg_debug(' ' || Sqlerrm); END; END OIDEXTAUTH; / SHOW ERRORS --list EXIT;