Oracle® Internet Directory Administrator's Guide,
10g Release 2 (10.1.2) B14082-02 |
|
Previous |
Next |
Oracle Internet Directory uses plug-ins to add password value checking to its other password policy management capabilities. These plug-ins enable you to verify that, for example, a new or modified password has the specified minimum length. You can customize password value checking to meet your own requirements.
This chapter contains these topics:
When a user wants to add or modify a password, customized password value checking takes place as follows:
The client sends the directory server either an ldapadd or ldapmodify request.
Before the directory server makes the addition or modification, it passes the password value to the plug-in.
The plug-in
Parses the entry
Captures the userpassword
attribute value in clear text
Implements whatever password value checking you have specified
If the password meets the specification, then the plug-in notifies the directory server accordingly, and the directory server makes the addition or modification. Otherwise, the plug-in sends one of the following error messages to the directory server, which, in turn, passes it to the client.
ldap_add: UnKnown Error Encountered ldap_add: additional info: PASSWORD POLICY VIOLATION:0000X, less than 8 chars ldap_add: UnKnown Error Encountered ldap_add: additional info: PASSWORD POLICY VIOLATION:0000X, contains dictionary word
The same logic applies to the PRE ldapmodify plug-in.
The various kinds of value checks that a password policy plug-in could perform include:
Minimum and maximum number of alphabetic characters
Maximum number of numeric characters
Minimum and maximum number of punctuation characters
Maximum number of consecutive characters
Maximum number of instances of any character
Whether it is a dictionary word
This example uses the a PL/SQL program, pluginpkg.sql
, which is described in "Contents of Sample PL/SQL Package pluginpkg.sql". In general, this package contains:
Two plug-in modules—pre_add
and pre_modify
One value checking function, isGoodPwd
, which verifies that a password meets the minimum length requirement of eight characters and that it does not contain a dictionary word that is longer than four characters
Thus, in this example, if you try to add a user with the userpassword
value less than eight characters, then the request is rejected. Similarly, if you try to modify a user password, and the new password value is less than eight characters, then the request is rejected. Also, if you try to add or modify a user with the userpassword
supersunday, the password is rejected because super and sunday are dictionary words.
The dictionary is a list of words longer than four characters, initially stored in a file called words.txt. Before we implement the plug-in, we set up a database table and store the words into the table. To set up the table we use create.sql
, which has the following contents:
drop table mydic; create table mydic (word varchar2(1024)); commit; exit;
Then we load the words into the table using the sqlldr command:
sqlldr control=words.txt userid=ods/ods_password
This section contains these topics:
Once you have implemented the standalone value checking PL/SQL program, do the following:.
Load the plug-in package into the database. In this example, we enter:
sqlplus ods/odspwd @pluginpkg.sql
Register the plug-in. This example uses a file named pluginreg.dat
, which contains the following:
### add plugin ### dn: cn=pre_add_plugin,cn=plugin,cn=subconfigsubentry objectclass:orclPluginConfig objectclass:top orclpluginname:pwd_plugin orclplugintype:operational orclplugintiming:pre orclpluginldapoperation:ldapadd orclpluginenable:1 orclpluginversion:1.0.1 cn:pre_add_plugin orclpluginsubscriberdnlist:dc=com;o=IMC ,c=US ### modify plugin ### dn: cn=pre_mod_plugin,cn=plugin,cn=subconfigsubentry objectclass:orclPluginConfig objectclass:top orclpluginname:pwd_plugin orclplugintype:operational orclplugintiming:pre orclpluginldapoperation:ldapmodify orclpluginenable:1 orclpluginversion:1.0.1 cn:pre_mod_plugin orclpluginsubscriberdnlist:dc=com;o=IMC ,c=US orclpluginattributelist:userpassword
Note that, in this plug-in, we let the directory server know that there are two plug-in modules to invoke when it receives ldapadd or ldapmodify requests. We use orclpluginsubscriberdnlist:dc=com;o=IMC,c=US
so that the plug-in is invoked ONLY if the target entry is under dc=com
or o=IMC,c=US
.
To add this file to the directory, enter the following:
ldapadd -p portnum -h hostname -D cn=orcladmin -w orcladminpwd -v \ -f pluginreg.dat
You can use standard PL/SQL character functions to process the password value. Download any PL/SQL program that can do regular expression. The important thing is to integrate the value checking functions with your plug-in modules.
Turn on the directory server plug-in to help you examine the process and content of plug-ins.
To setup the directory server plug-in debugging, execute the following command:
sqlplus ods/password @$ORACLE/ldap/admin/oidspdsu.pls
To enable directory server plug-in debugging, execute the following command:
sqlplus ods/password @$ORACLE/ldap/admin/oidspdon.pls
To disable directory server plug-in debugging, execute the following command:
sqlplus ods/password @$ORACLE/ldap/admin/oidspdof.pls
To show directory server plug-in debugging messages, execute the following command:
sqlplus ods/password @$ORACLE/ldap/admin/oidspdsh.pls
To delete directory server plug-in debugging messages, execute the following command:
sqlplus ods/password @$ORACLE/ldap/admin/oidspdde.pls
The script pluginpkg.sql
, as used in this example, contains the following:
CREATE OR REPLACE PACKAGE pwd_plugin AS PROCEDURE pre_add (ldapplugincontext IN ODS.plugincontext, dn IN VARCHAR2, entry IN ODS.entryobj, rc OUT INTEGER, errormsg OUT VARCHAR2 ); PROCEDURE pre_modify (ldapplugincontext IN ODS.plugincontext, dn IN VARCHAR2, mods IN ODS.modlist, rc OUT INTEGER, errormsg OUT VARCHAR2 ); -- Function: isGoodPwd -- Parameter: inpwd -- Purpose: 1. check if the password is at least -- 8 characters long -- 2. check if the password contains a -- dictionary word (longer than 4 characters) FUNCTION isGoodPwd(inpwd IN VARCHAR2) RETURN INTEGER; END pwd_plugin; / show error CREATE OR REPLACE PACKAGE BODY pwd_plugin AS FUNCTION isGoodPwd(inpwd IN VARCHAR2) RETURN INTEGER IS i NUMBER; ret NUMBER DEFAULT 1; minpwdlen NUMBER DEFAULT 8; len NUMBER DEFAULT 0; lcount NUMBER DEFAULT 0; matched VARCHAR2(1024) DEFAULT NULL; CURSOR c1 IS SELECT word FROM mydic WHERE length(word) > 4 AND instr(lower(inpwd), lower(word), 1, 1) > 0; BEGIN plg_debug( '=== begin of ISGOODPWD ==='); plg_debug( 'password = ' || inpwd); len := LENGTH(inpwd); plg_debug( 'password length = ' || len); IF len < minpwdlen THEN RETURN 0; ELSE OPEN c1; LOOP FETCH c1 INTO matched; EXIT WHEN c1%NOTFOUND; lcount := lcount + 1; END LOOP; plg_debug( 'count = ' || lcount); IF lcount > 0 THEN RETURN 2; ELSE RETURN ret; END IF; END IF; plg_debug( '=== end of ISGOODPWD ==='); EXCEPTION WHEN OTHERS THEN plg_debug( 'Exception in isGoodPwd(). Error code is ' || TO_CHAR(SQLCODE)); plg_debug( ' ' || Sqlerrm); RETURN 0; END; PROCEDURE pre_add (ldapplugincontext IN ODS.plugincontext, dn IN VARCHAR2, entry IN ODS.entryobj, rc OUT INTEGER, errormsg OUT VARCHAR2 ) IS inpwd VARCHAR2(256) DEFAULT NULL; ret NUMBER DEFAULT 1; BEGIN plg_debug( '=== begin of PRE_ADD_PLUGIN ==='); plg_debug( 'dn = ' || dn); plg_debug( 'entry obj ' || ':entryname = ' || entry.entryname); FOR l_counter1 IN 1..entry.attr.COUNT LOOP plg_debug( 'attrname[' || l_counter1 || '] = ' || entry.attr(l_counter1).attrname); FOR l_counter2 IN 1..entry.attr(l_counter1).attrval.COUNT LOOP plg_debug( entry.attr(l_counter1).attrname || '[' || l_counter1 || ']' || '.val[' || l_counter2 || '] = ' || entry.attr(l_counter1).attrval(l_counter2)); END LOOP; IF entry.attr(l_counter1).attrname = 'userpassword' THEN inpwd := entry.attr(l_counter1).attrval(1); -- assuming only one attr val for userpassword END IF; END LOOP; IF (inpwd IS NOT NULL) THEN ret := isGoodPwd(inpwd); END IF; IF (inpwd IS NULL OR ret = 0) THEN rc := 1; errormsg := 'PASSWORD POLICY VIOLATION:0000X, less than 8 chars'; plg_debug( ' we got an invalid password, too short '); ELSIF (ret = 2) THEN rc := 1; errormsg := 'PASSWORD POLICY VIOLATION:0000X, contains dictionary word'; plg_debug( ' we got an invalid password, dictionary word '); ELSE plg_debug( ' we got a good password '); rc := 0; errormsg := 'no pre_mod plguin error msg'; END IF; plg_debug( '=== end of PRE_ADD_PLUGIN ==='); EXCEPTION WHEN OTHERS THEN plg_debug( 'Exception in PRE_ADD plugin. Error code is ' || TO_CHAR(SQLCODE)); plg_debug( ' ' || Sqlerrm); rc := 1; errormsg := 'exception: pre_add plguin'; END; PROCEDURE pre_modify (ldapplugincontext IN ODS.plugincontext, dn IN VARCHAR2, mods IN ODS.modlist, rc OUT INTEGER, errormsg OUT VARCHAR2 ) IS old_passwd VARCHAR2(256) DEFAULT NULL; new_passwd VARCHAR2(256) DEFAULT NULL; ret NUMBER DEFAULT 1; BEGIN plg_debug( '=== begin of PRE_MOD_PLUGIN ==='); plg_debug( dn); 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; plg_debug(' new password: ' || new_passwd); plg_debug(' old password: ' || old_passwd); IF (new_passwd IS NOT NULL) THEN ret := isGoodPwd(new_passwd); END IF; IF (new_passwd IS NULL OR ret = 0) THEN rc := 1; errormsg := 'PASSWORD POLICY VIOLATION:0000X, less than 8 chars'; plg_debug( ' we got an invalid password, too short '); ELSIF (ret = 2) THEN rc := 1; errormsg := 'PASSWORD POLICY VIOLATION:0000X, contains dictionary word'; plg_debug( ' we got an invalid password, dictionary word '); ELSE plg_debug( ' we got a good password '); rc := 0; errormsg := 'no pre_mod plguin error msg'; END IF; plg_debug( '=== end of PRE_MOD_PLUGIN ==='); EXCEPTION WHEN OTHERS THEN plg_debug( 'Exception in PRE_MODIFY plugin. Error code is ' || TO_CHAR(SQLCODE)); plg_debug( ' ' || Sqlerrm); rc := 1; errormsg := 'exception: pre_mod plguin'; END; END pwd_plugin; / show error EXIT;