47 Configuring a Customized External Authentication Plug-in
The following topics describe how to use a customized external authentication plug-in, how to install, configure, enable, and debug the external plug-in, and how to create a PL/SQL package:
Note:
All references to Oracle Single Sign-On in this chapter refer to Oracle Single Sign-On 10g (10.1.4.3.0) or later.
47.1 Overview of Customized External Authentication Plug-in
Authentication that relies on security credentials stored in Oracle Internet Directory is called native authentication.
When a user enters her security credentials, the directory server compares them with the credentials stored in Oracle Internet Directory. If the credentials match, then the directory server authenticates the user.
By contrast, authentication that relies on security credentials stored in a directory other than Oracle Internet Directory is called external authentication. When a user enters her security credentials, the directory server compares them with the credentials stored in the other directory. This is done by using:
-
A PL/SQL program that does the external authentication work
-
An external authentication plug-in that invokes this PL/SQL program
47.2 Installing, Configuring, and Enabling the External Authentication Plug-in
The package, oidexaup.sql
, is used for installing the external authentication plug-in PL/SQL package.
This example uses the PL/SQL program, oidexaup.sql
. Creating the PL/SQL Package oidexaup.sql describes this program. It contains:
-
Two plug-ins: namely,
when_compare_replace
andwhen_modify_replace
-
One utility function: namely,
get_nickname
The integrated package is the plug-in package, OIDEXTAUTH
. It can also serve as a template to modify according to the requirements of your deployment.
To install, configure, and enable the external authentication plug-in, follow these steps:
Now, everything should be ready. Use the ldapcompare command-line tool to verify that the plug-in and authentication program are working properly before you try to authenticate the user from Oracle Single Sign-On.
In our example, we also provide the plug-in code for externally modifying user password.
47.3 Debugging the External Authentication Plug-in
You must enable directory server plug-in to help you to examine the process and content of plug-ins.
To setup directory server plug-in debugging, execute the following command:
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdsu.sql
To enable directory server plug-in debugging, execute the following command:
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdon.sql
To disable directory server plug-in debugging, execute the following command:
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdof.sql
To show directory server plug-in debugging messages, execute the following command:
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdsh.sql
To delete directory server plug-in debugging messages, execute the following command:
sqlplus ods @$ORACLE_HOME/ldap/admin/oidspdde.sql
47.4 Creating the PL/SQL Package oidexaup.sql
You use the script oidexaup.sql,
as used in this example, to create the PL/SQL package.
The PL/SQL package contains the following:
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;