46 カスタマイズされた外部認証プラグインの構成
次のトピックでは、カスタマイズされた外部認証プラグインを使用する方法、外部プラグインをインストール、構成、有効化およびデバッグする方法や、PL/SQLパッケージを作成する方法について説明します。
ノート:
この章で言及するOracle Single Sign-Onはすべて、Oracle Single Sign-On 10g (10.1.4.3.0)以上のことです。
46.1 カスタマイズされた外部認証プラグインの概要
Oracle Internet Directoryに格納されたセキュリティ資格証明に基づく認証を、ネイティブ認証と呼びます。
ユーザーがセキュリティ資格証明を入力すると、ディレクトリ・サーバーはOracle Internet Directoryに格納されている資格証明とそれを比較します。資格証明が一致すると、ディレクトリ・サーバーはユーザーを認証します。
一方、Oracle Internet Directory以外のディレクトリに格納されたセキュリティ資格証明に基づく認証を外部認証と呼びます。ユーザーがセキュリティ資格証明を入力すると、ディレクトリ・サーバーは他のディレクトリに格納されている資格証明とそれを比較します。この比較は次のものを使用して行われます。
-
外部認証作業を行うPL/SQLプログラム
-
このPL/SQLプログラムを起動する外部認証プラグイン
46.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からユーザーを認証する前にプラグインおよび認証プログラムが適切に動作していることを確認できます。
この例では、ユーザー・パスワードを外部変更するためのプラグイン・コードも提供されています。
46.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.sql46.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;