ユーザー・セキュリティ資格証明をOracle Internet Directory以外のリポジトリ(データベースや他のLDAPディレクトリなど)に格納し、Oracleコンポーネントに対するユーザー認証に使用できます。資格証明をOracle Internet Directoryに格納する必要はなく、常に同期化させる必要はありません。外部リポジトリに格納された資格証明によるユーザー認証を、外部認証と呼びます。
この章の項目は次のとおりです。
| 注意:この章で言及するOracle Single Sign-Onはすべて、Oracle Single Sign-On 10g(10.1.4.3.0)以上のことです。 | 
Oracle Internet Directoryに格納されたセキュリティ資格証明に基づく認証を、ネイティブ認証と呼びます。ユーザーがセキュリティ資格証明を入力すると、ディレクトリ・サーバーはOracle Internet Directoryに格納されている資格証明とそれを比較します。資格証明が一致すると、ディレクトリ・サーバーはユーザーを認証します。
一方、Oracle Internet Directory以外のディレクトリに格納されたセキュリティ資格証明に基づく認証を外部認証と呼びます。ユーザーがセキュリティ資格証明を入力すると、ディレクトリ・サーバーは他のディレクトリに格納されている資格証明とそれを比較します。この比較は次のものを使用して行われます。
この例では、PL/SQLプログラムoidexaup.sqlを使用します。「PL/SQLパッケージoidexaup.sqlの作成」でこのプログラムについて説明します。このパッケージは、外部認証プラグインPL/SQLパッケージをインストールするために使用します。このパッケージには次のものが含まれています。
2つのプラグイン(when_compare_replaceおよびwhen_modify_replace)
ユーティリティ・ファンクション(get_nickname)
統合パッケージは、プラグイン・パッケージOIDEXTAUTHです。このパッケージは、テンプレートとして使用し、デプロイメント環境に合せて変更することもできます。
外部認証プラグインをインストールおよび構成し、有効にする手順は、次のとおりです。
スタンドアロンの外部認証PL/SQLプログラムを実装します。たとえば、ユーザー名とパスワードで認証する場合は、この2つのパラメータを取るPL/SQLプログラムを使用する必要があります。
サンプル・コードoidexaup.sqlで、auth_externalはプログラム・パッケージ名、authenticate_userは認証を行う関数です。次の手順に進む前に、このスタンドアロン・プログラムが適切に動作することを確認します。
スタンドアロンのプログラムをプラグイン・モジュールに登録します。
プラグイン・パッケージをデータベースにロードします。この例では、次のように入力します。
sqlplus ods/odspwd @oidexaup.sql
プラグインを登録します。プラグインの起動に必要な情報をディレクトリ・サーバーに提供するLDIFファイルを作成し、アップロードすることにより登録します。
この例では、次の内容のファイルoidexauth.ldifを使用します。
dn: cn=whencompare,cn=plugin,cn=subconfigsubentry objectclass:orclPluginConfig objectclass:top orclpluginname:oidextauth orclplugintype:configuration orclplugintiming:when orclpluginldapoperation:ldapcompare orclpluginenable:1 orclpluginversion:1.0.1 orclPluginIsReplace:1 cn:whencompare orclpluginsubscriberdnlist:dc=com;o=IMC,c=US orclpluginattributelist:userpassword orclpluginrequestgroup:$prgdn dn: cn=whenmodify,cn=plugin,cn=subconfigsubentry objectclass:orclPluginConfig objectclass:top orclpluginname:oidextauth orclplugintype:configuration orclplugintiming:when orclpluginldapoperation:ldapmodify orclpluginenable:1 orclpluginversion:1.0.1 orclPluginIsReplace:1 cn:whenmodify orclpluginsubscriberdnlist:dc=com;o=IMC,c=US orclpluginattributelist:userpassword orclpluginrequestgroup:$prgdn
このファイルでは、ldapcompareリクエストまたはldapmodifyリクエストがあった際に2つのプラグインが起動することをディレクトリ・サーバーに通知します。
ターゲット・エントリがdc=comまたはo=IMC,c=US下の場合のみプラグインが起動するように、orclpluginsubscriberdnlist:dc=com;o=IMC,c=USを使用します。
$prgdnを、プラグイン・リクエスト・グループ識別名に置換します。これはオプションの推奨セキュリティ機能です。Oracle Single Sign-Onとの統合には、この値が必須フィールドです。入力されたグループのメンバーのみがプラグインを起動できます。複数のグループの入力が可能です。エントリを区切るには、セミコロンを使用します。
推奨デフォルトは、cn=OracleUserSecurityAdmins,cn=Groups,cn=OracleContextおよびcn=OracleDASAdminGroup,cn=Groups,cn=OracleContext,o=default_subscriber,dc=comです。Oracle Single Sign-On Serverは、最初のグループのメンバーです。また、デプロイメント環境に合せてo=default_subscriberを正しい値に置換してください。
このファイルをディレクトリに追加するには、次のとおり入力します。
ldapadd -p portnum -h hostname -D cn=orcladmin -q -v \
        -f oidexauth.ldif
これで、すべての準備が完了しました。ldapcompareコマンドライン・ツールを使用すると、Oracle Single Sign-Onからユーザーを認証する前にプラグインおよび認証プログラムが適切に動作していることを確認できます。
この例では、ユーザー・パスワードを外部変更するためのプラグイン・コードも提供されています。
ディレクトリ・サーバー・プラグインを設定すると、プラグインのプロセスと内容を調べることができます。
ディレクトリ・サーバー・プラグインのデバッグを設定するには、次のコマンドを実行します。
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
この例で使用するスクリプトoidexaup.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;