Extending the Netscape Server: A Simple Plug-in Example

   

Sometimes the cars available from the major automobile manufacturers simply do not meet all your needs. Or perhaps you just enjoy getting your hands dirty and cannot resist adding a turbocharger or reprogramming your engine computer. Some people need or want to make analogous enhancements to their server software. As mentioned in the preceding Feature Set section, Netscape Directory Server provides a plug-in API to allow developers outside of Netscape to extend the functionality of the server.

A plug-in is a Unix shared object or a Microsoft Windows DLL that presents a C interface to the directory server. Most plug-ins are written in C or C++. Plug-ins can be used to implement preoperation filters, postoperation triggers, new extended operations, new controls, and other extensions of the LDAP server functionality. Netscape uses plug-ins to provide some of the functionality of its server; therefore, many plug-ins are installed by default. Figure 4.10 shows the plug-ins configuration window within Netscape Console, with Netscape's Referential Integrity plug-in selected.

Figure 4.10. The Netscape Console Plug-ins Configuration Window

Each plug-in is managed through a plug-in configuration entry that resides in a special area within the DIT. For example, the configuration for Netscape's Referential Integrity plug-in is stored in an entry named cn=referential integrity postoperation, cn=plugins,cn=config . Listing 4.15 shows a sample configuration entry for the Referential Integrity plug-in (in LDIF format).

Listing 4.15 A Plug-in Configuration Entry
 dn: cn=referential integrity postoperation,cn=plugins,cn=config objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: referential integrity postoperation nsslapd-pluginPath: C:/Netscape/Servers/lib/referint-plugin.dll nsslapd-pluginInitfunc: referint_postop_init nsslapd-pluginType: postoperation nsslapd-pluginEnabled: on nsslapd-pluginarg0: 0 nsslapd-pluginarg1: C:/Netscape/Servers/slapd-example/logs/referint nsslapd-pluginarg2: 0 nsslapd-pluginarg3: member nsslapd-pluginarg4: uniquemember nsslapd-pluginarg5: owner nsslapd-pluginarg6: seeAlso nsslapd-pluginarg7: nsroledn nsslapd-plugin-depends-on-type: database nsslapd-pluginId: referint nsslapd-pluginVersion: 6.01 nsslapd-pluginVendor: Netscape Communications Corp. nsslapd-pluginDescription: referential integrity plugin 

The remainder of this section demonstrates how to develop and use a custom plug-in. Complete information on writing plug-ins can be found in the Netscape Directory Server Plug-in Programmers' Guide .

Problem Statement

Netscape Directory Server does not provide a way to limit the values of an attribute to a predefined set. For example, the inetOrgPerson object class defined in RFC 2798 allows person entries to include an employeeType attribute. Typically only a few values are supposed to be used for this attribute; however, the set of valid values is specific to each directory deployment. Although LDAP clients can be written so that they limit the set of values that users and directory data administrators may enter, it would be nice if the directory server itself were able to reject invalid values. The custom plug-in presented in this part of the chapter is named the Value Constraint plug-in . It extends the Netscape server so that LDAP add and modify operations that include invalid employeeType values are rejected, with an appropriate error message sent back to the LDAP client.

The Design of the Value Constraint Plug-In

To restrict employeeType values to a predefined set, the plug-in must be invoked before an LDAP add or modify operation is processed by the server. Therefore, the Value Constraint plug-in is implemented as a preoperation plug-in. Preoperation plug-ins can be used to alter operation parameters, to reject an operation entirely, or just to make note of something and allow the Netscape server to process the operation as usual.

The valid set of employeeType values is assumed to be

  • Contractor

  • Employee

  • Intern

  • Temp

The plug-in will check the employeeType values sent in LDAP add and modify operations to ensure that they match one of these values. If not, a "constraint violation" error will be returned to the LDAP client, and the server will not process the operation. The "constraint violation" error is a standard LDAP error that indicates that an attribute value is too large, is in the wrong format, or otherwise does not meet constraints imposed by the LDAP information model or by a local policy.

Note

Netscape Directory Server pre- and postoperation plug-ins are executed only when the server is processing regular LDAP operations. They are not executed for special tasks such as ldif2db (which bulk-loads an LDIF file into a database instance). Therefore, the Value Constraint plug-in cannot enforce any constraints during data import; you need to use a different method to do so.


The Source Code for the Value Constraint Plug-In

The Value Constraint plug-in source code consists of three files: valueconstraint.c , dllmain.c , and valueconstraint.def . The latter two files are required on Microsoft Windows only; the dllmain.c code is not shown in this book because it is simply copied from the sample plug-in code that Netscape ships with its server. The dllmain.c file you need to copy can be found in this location ( assuming you installed the server in the default location as recommended earlier in this chapter):

 C:\Netscape\Servers\plugins\slapd\slapi\examples\dllmain.c 

Listing 4.16 shows the contents of the valueconstraint.def file, which is a Microsoft Windows DLL definition file.

Listing 4.16 The valueconstraint.def File
 ; Microsoft Windows DLL definition file for the valueconstraint ;    Netscape Directory Server 6 plugin. ; ; From the book "Understanding and Deploying LDAP Directory Services" ;   by Timothy A. Howes, Mark C. Smith, and Gordon S. Good. ; DESCRIPTION     'valueconstraint plugin for Netscape Directory Server' EXPORTS     valueconstraint_init       @1 

The valueconstraint_init() function is the only function that is exported from the Value Constraint plug-in DLL. It is the main entry point to the Value Constraint plug-in, and the directory server will be configured to call this function during server startup.

The plug-in's interesting code is written in C and is housed in a file named valueconstraint.c . Listing 4.17 shows the first portion of that file.

Listing 4.17 The Beginning of the valueconstraint.c File
 1. /*  2.  * A valueconstraint plug-in for Netscape Directory Server  3.  *  4.  * From the book "Understanding and Deploying LDAP Directory Services"  5.  *  by Timothy A. Howes, Mark C. Smith, and Gordon S. Good  6.  */  7. #include <string.h>  8. #include <stdio.h>  9. #include "slapi-plugin.h" 10. 11. /* Name and result code macros (to make the code easier to read) */ 12. #define PLUGIN_NAME             "valueconstraint" 13. #define PLUGIN_RC_ERROR         (-1) 14. #define PLUGIN_RC_CONTINUE      0 15. #define PLUGIN_RC_RESULT_SENT   1 16. 17. /* Macros to take care of platform specifics */ 18. #ifdef _WIN32 19. #define PLUGIN_STRCASECMP           stricmp 20. #define PLUGIN_EXPORTED_FUNCTION    __declspec(dllexport) 21. #else 22. #define PLUGIN_STRCASECMP           strcasecmp 23. #define PLUGIN_EXPORTED_FUNCTION 24. #endif 25. 26. /* Static variables to hold the plug-in name and description */ 27. static Slapi_PluginDesc pdesc = { PLUGIN_NAME, 28.         "Howes/Smith/Good", "2.0", PLUGIN_NAME " plugin" }; 29. 30. /* Static variables to hold attribute constraint configuration */ 31. static const char *attr_to_check = "employeeType"; 32. static const char *valid_values[] = { 33.     "Contractor", "Employee", "Intern", "Temp", NULL 34. }; 35. 36. /* Function prototypes */ 37. static int valueconstraint_preadd( Slapi_PBlock *pb ); 38. static int valueconstraint_premodify( Slapi_PBlock *pb ); 39. static int valueconstraint_is_one_of( Slapi_PBlock *pb, 40.         const char *attrname, const char *val, 41.         const char *allowed[] ); 42. 

Lines 1 through 25 contain comments, include statements, and some simple macro definitions. The main header file for the Netscape Directory Server plug-in interface is called slapi-plugin.h ; it is included on line 9. A plug-in description structure is defined on lines 26 through 28; later that structure is registered with the directory server so that descriptive information about the plug-in is available through Netscape Console and elsewhere.

In this example the attribute and the set of valid values allowed are hard-coded into the valueconstraint.c file (a good alternative would be to store this information in a directory entry such as the plug-in's own configuration entry). Lines 30 through 34 define an attr_to_check variable ( employeeType ) and a NULL- terminated valid_values array. Prototypes for the static functions that are internal to the plug-in implementation appear on lines 36 through 41.

Listing 4.18 shows the valueconstraint_init() function that is called by the directory server during server startup. The purpose of this function is to perform any required initialization and to register plug-in callback functions with the directory server.

Listing 4.18 The valueconstraint_init() Function
 43. /* Function valueconstraint_init(): initialization (called during 44.  *  server startup). 45.  */ 46. PLUGIN_EXPORTED_FUNCTION int 47. valueconstraint_init( Slapi_PBlock *pb ) 48. { 49.     int     rc = PLUGIN_RC_CONTINUE; 50. 51.     slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "=> init\n" ); 52. 53.     /* 54.      * Register the plug-in version, plug-in description, 55.      * and two preoperation functions. 56.      */ 57.     if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, 58.             SLAPI_PLUGIN_VERSION_01 ) != 0  59.             slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, 60.             &pdesc ) != 0  61.             slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ADD_FN, 62.             (void *)valueconstraint_preadd ) != 0  63.             slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODIFY_FN, 64.             (void *)valueconstraint_premodify ) != 0 ) { 65.         slapi_log_error( SLAPI_LOG_FATAL, PLUGIN_NAME, 66.                 "init: a slapi_pblock_set() call failed\n" ); 67.         rc = PLUGIN_RC_ERROR; 68.     } 69. 70.     slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, 71.             "<= init (%d)\n", rc ); 72.     return rc; 73. } 74. 

The Netscape Directory Server plug-in API is sometimes referred to as the SLAPI API (which loosely stands for "standalone LDAP server API"), and most of the functions provided by Netscape have names that begin with "slapi". On line 51 in Listing 4.18, a call is made to slapi_log_error() , which is a utility function that writes a message to the directory server's error log if the debug level provided in the first parameter ( SLAPI_LOG_PLUGIN ) is enabled in the server's configuration. By default, SLAPI_ LOG_PLUGIN messages are not logged, but SLAPI_LOG_FATAL messages (used on line 65) are.

Information is passed back and forth between plug-ins and the core of the Netscape server through a parameter block data structure named Slapi_PBlock that can hold a variety of items. In fact, the only parameter passed to the valueconstraint_init() function is a pointer to a Slapi_PBlock data structure. The following two functions are used to get and set items within a SLAPI parameter block:

  1. slapi_pblock_get() . Retrieves the value of an item from a Slapi_PBlock data structure. The item is identified by a macro whose name begins with SLAPI_PLUGIN , and the value of the item requested is returned via the last parameter, which is a pointer to an area to hold the value.

  2. slapi_pblock_set() . Sets the value of an item in a Slapi_PBlock data structure. This function takes the same parameters as slapi_pblock_get() , except the last parameter is the value to set (not a pointer to the value).

The slapi_pblock_get() and slapi_pblock_set() functions are used often in the writing of SLAPI plug-ins. The code on lines 53 through 68 in Listing 4.18 includes four calls to the slapi_pblock_set() function to register four things: the API version used by the plug-in ( SLAPI_PLUGIN_VERSION ), the plug-in description structure ( SLAPI_PLUGIN_DESCRIPTION ), and two callback functions that will be called before each add or modify operation is executed in the server ( SLAPI_PLUGIN_PRE_ADD_FN and SLAPI_PLUGIN_PRE_MODIFY_FN ). A preoperation plug-in such as the Value Constraint plug-in can register one preoperation callback function for each kind of LDAP operation (bind, add, modify, delete, and so on). In this plug-in, there are only two such callback functions:

  1. valueconstraint_preadd() . Called before the server executes each LDAP add operation but after the entire request has been received from the LDAP client and the request parameters have been parsed and placed in the Slapi_PBlock data structure. This function enforces the desired constraints on the employeeType attribute.

  2. valueconstraint_premodify() . Called before the server executes each LDAP modify operation but after the entire request has been received from the LDAP client and the request parameters have been parsed and placed in the Slapi_PBlock data structure. This function also enforces constraints on the employeeType attribute.

Preoperation callback functions return an integer value that is examined by the Netscape server to determine if the operation should continue to execute or if processing should halt. In the latter case, the plug-in is responsible for sending an LDAP result message to the client. The two return values typically used are

  • . The server should continue executing the operation.

  • 1 . The plug-in sends a result to the LDAP client, and the server should stop execution.

The macros defined on lines 14 ( PLUGIN_RC_CONTINUE ) and 15 ( PLUGIN_RC_ RESULT_SENT ) of Listing 4.17 capture these special return values.

Listing 4.19 shows the code for the valueconstraint_preadd() function. It, too, is passed only one parameter, a Slapi_PBlock pointer. On lines 82 and 83, some additional Netscape-defined data types are used: Slapi_Entry (to represent a directory entry) and Slapi_Attr (to represent an attribute within an entry). Most of the data types defined by the Netscape SLAPI API, including these two and the Slapi_PBlock data structure introduced earlier, are opaque structures. This means that you can declare pointers to them, but you can't define them, determine their size , or look at their fields. Accessor functions are provided to manipulate these opaque data structures. This technique gives Netscape freedom to change the underlying implementation of its server without changing the SLAPI plug-in API.

Listing 4.19 The valueconstraint_preadd() Function
 75. /* Function valueconstraint_preadd(): called by the directory  76.  *  server before an add operation is processed.  77.  */  78. static int  79. valueconstraint_preadd( Slapi_PBlock *pb )  80. {  81.     int         rc = PLUGIN_RC_CONTINUE;  82.     Slapi_Entry *entry = NULL;  83.     Slapi_Attr  *attr = NULL;  84.  85.     slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "=> preadd\n" );  86.  87.     /* Retrieve the entry that was sent in the add operation */  88.     if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &entry ) != 0 ) {  89.         slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,  90.                 PLUGIN_NAME ": unable to retrieve entry", 0, NULL );  91.         rc = PLUGIN_RC_RESULT_SENT;  92.     } else if ( slapi_entry_attr_find( entry, attr_to_check,  93.                 &attr ) == 0 ) {  94.         /* Check the attribute values to make sure they are valid */  95.         int         hint;  96.         Slapi_Value *value;  97.         const char  *strvalue;  98.  99.         for ( hint = slapi_attr_first_value( attr, &value ); 100.                 hint != -1; 101.                 hint = slapi_attr_next_value( attr, hint, &value )) { 102.             strvalue = slapi_value_get_string( value ); 103.             if ( !valueconstraint_is_one_of( pb, strvalue, 104.                     attr_to_check, valid_values )) { 105.                 rc = PLUGIN_RC_RESULT_SENT; 106.                 break; 107.             } 108.         } 109.     } 110. 111.     slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, 112.             "<= preadd (%d)\n", rc ); 113.     return rc; 114. } 115. 

The valueconstraint_preadd() function first retrieves the entry that is being added (lines 87 “91), and then it calls a slapi_entry_attr_find() Slapi_Entry accessor function to locate the attribute whose name is in the attr_to_check variable (which is employeeType ). If that attribute is found, a for loop (lines 99 “108) is used to examine each of the values and check that they are valid. Within the loop, the slapi_attr_first_value() and slapi_attr_next_value() functions are used to step through the values contained in the Slapi_Attr data structure, and the slapi_value_get_string() function is used to retrieve the string value. Finally, a utility function named valueconstraint_is_one_of() is used to determine if strvalue is in the set of valid values. If not, the function return code is set to PLUGIN_RC_RESULT_SENT (line 105). The valueconstraint_is_one_of() function sends an error result to the LDAP client if the value is not valid; the code for valueconstraint_is_one_of() is shown in Listing 4.21.

Listing 4.20 shows the code for the valueconstraint_premodify() function, which is quite similar to valueconstraint_preadd() . The code on lines 128 through 133 retrieves from the parameter block the list of modifications submitted by the LDAP client. The modifications are returned as a NULL-terminated array of pointers to LDAPMod structures. The LDAPMod structure is one of the few structures used in the Netscape plug-in API that is not opaque; it is actually part of the LDAP C API that is commonly used to write LDAP client applications.

Listing 4.20 The valueconstraint_premodify() Function
 116. /* Function valueconstraint_premodify(): called by the directory 117.  *  server before a modify operation is processed. 118.  */ 119. static int 120. valueconstraint_premodify( Slapi_PBlock *pb ) 121. { 122.     int         rc = PLUGIN_RC_CONTINUE; 123.     LDAPMod     *mp, **mods = NULL; 124.     int         i, j; 125. 126.     slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "=> premodify\n" ); 127. 128.     /* Retrieve the modifications sent in the modify operation */ 129.     if ( slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ) != 0 ) { 130.         slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, 131.                 PLUGIN_NAME ": unable to retrieve modifications", 132.                 0, NULL ); 133.         rc = PLUGIN_RC_RESULT_SENT; 134.     } else { 135.         /* 136.          * Check the modify suboperations to make sure the values 137.          *  they contain are valid. Delete suboperations are 138.          *  ignored (any value may be deleted). 139.          */ 140.         for ( i = 0; rc == PLUGIN_RC_CONTINUE && mods[i] != NULL; 141.                     ++i ) { 142.             mp = mods[i]; 143.             if ( 0 == slapi_attr_type_cmp( mp->mod_type, 144.                     attr_to_check, SLAPI_TYPE_CMP_BASE ) 145.                     && LDAP_MOD_DELETE != 146.                     ( mp->mod_op & ~LDAP_MOD_BVALUES )) { 147.                 for ( j = 0; mp->mod_bvalues[j] != NULL; ++j ) { 148.                     if ( !valueconstraint_is_one_of( pb, 149.                             mp->mod_bvalues[j]->bv_val, 150.                             attr_to_check, valid_values )) { 151.                         rc = PLUGIN_RC_RESULT_SENT; 152.                         break; 153.                     } 154.                 } 155.             } 156.         } 157.     } 158. 159.     slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, 160.             "<= premodify (%d)\n", rc ); 161.     return rc; 162. } 163. 

The code on lines 135 through 156 loops through the modifications and checks each one to see if it is an "add value" or a "replace value" operation on the employeeType attribute (recall that attr_to_check was initialized to the constant string "employeeType" ). The Netscape-provided slapi_attr_type_cmp() utility function is used to compare the attribute type name in the LDAPMod structures with attr_to_check . The for loop on lines 147 through 154 steps through the values, calling the valueconstraint_ is_one_of() function for each one to check for invalid values.

Listing 4.21 shows the code for the valueconstraint_is_one_of() function, which returns an indication of whether a string value is in the array of allowed values. This function sends an error result to the LDAP client if an invalid value is detected .

Listing 4.21 The valueconstraint_is_one_of() Utility Function
 164. /* Function valueconstraint_is_one_of(): return a nonzero value 165.  *  if "val" is in the NULL-terminated "allowed" array and 0 if not. 166.  *  Comparisons are case insensitive. If "val" is not present, a 167.  *  "constraint violation" error is sent to the LDAP client. 168.  */ 169. static int 170. valueconstraint_is_one_of( Slapi_PBlock *pb, const char *val, 171.         const char *attrname, const char *allowed[] ) 172. { 173.     int         i; 174.     char        *msg; 175.     const char  *fmt = "invalid value \"%s\" for %s"; 176. 177.     if ( val == NULL ) { 178.         return 1;   /* ignore NULL values */ 179.     } 180. 181.     for ( i = 0; allowed[i] != NULL; ++i ) { 182.         if ( PLUGIN_STRCASECMP( val, allowed[i] ) == 0 ) { 183.             return 1;   /* found it */ 184.         } 185.     } 186. 187.     /* Not found: send back a "constraint violation" error */ 188.     msg = slapi_ch_malloc( strlen(fmt) + strlen(val) 189.             + strlen(attrname) + 1 ); 190.     sprintf( msg, fmt, val, attrname ); 191.     slapi_send_ldap_result( pb, LDAP_CONSTRAINT_VIOLATION, 192.             NULL, msg, 0, NULL ); 193.     slapi_ch_free_string( &msg ); 194.     return 0;   /* not found */ 195. } 

The valueconstraint_is_one_of() function is the last function in valueconstraint.c . The code on lines 181 through 185 looks for val (the value) within the allowed array using a case-insensitive comparison function ( strcasecmp() or stricmp() , abstracted away by the PLUGIN_STRCASECMP() macro). If the value is in the set of allowed values, a nonzero value is returned by line 183.

The code on lines 187 through 194 constructs a human-readable error message and uses the slapi_send_ldap_result() Netscape plug-in API utility function to send that message along with an LDAP "constraint violation" result code to the client. The LDAP_CONSTRAINT_VIOLATION macro is defined by the ldap.h header file that is part of the LDAP C API. The ldap.h file is included from slapi-plugin.h .

Compiling and Installing the Value Constraint Plug-In

On Microsoft Windows, execute the following three commands at the command prompt to compile the two .c files that make up the plug-in (using the Microsoft Visual C++ cl command) and create a DLL named valueconstraint.dll (using the Visual C++ link command):

 cl -IC:\Netscape\Servers\plugins\slapd\slapi\include /c valueconstraint.c cl -IC:\Netscape\Servers\plugins\slapd\slapi\include /c dllmain.c link /dll /def:valueconstraint.def /out:valueconstraint.dll /DEFAULTLIB:kernel32.lib  user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib  oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib C:\Netscape\Servers\plugins\  slapd\slapi\lib\libslapd.lib C:\Netscape\Servers\plugins\slapd\slapi\lib\libnspr4.lib  valueconstraint.obj dllmain.obj 

Yes, the link command is very long. On Solaris, use these two commands to compile the valueconstraint.c file and create a shared library named valueconstraint.so :

 cc -I/export/ds6/plugins/slapd/slapi/include -D_REENTRANT -KPIC -c valueconstraint.c ld -G -o valueconstraint.so valueconstraint.o /export/ds6/lib/libslapd.so /export/ds6/lib/  libnspr4.so 

The commands for other platforms are similar; consult the Netscape documentation for details.

To install the plug-in, shut down the directory server using the stop-slapd command. Next , edit the dse.ldif file located in the server config directory within the file system to add a configuration entry for the plug-in. Listing 4.22 shows the correct entry for a Solaris installation, assuming the Value Constraint shared library is located in a directory named /usr/netscape-server-plugins .

Listing 4.22 The Value Constraint Plug-in Configuration Entry
 dn: cn=valueconstraint,cn=plugins,cn=config objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: valueconstraint nsslapd-pluginPath: /usr/netscape-server-plugins/valueconstraint.so nsslapd-pluginInitfunc: valueconstraint_init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on nsslapd-plugin-depends-on-type: database nsslapd-pluginId: valueconstraint nsslapd-pluginVersion: 2.0 nsslapd-pluginVendor: Howes/Smith/Good nsslapd-pluginDescription: valueconstraint plugin 

For a Microsoft Windows installation, change nsslapd-pluginPath to point to your valueconstraint.dll file. After saving your changes to the dse.ldif file, restart the server. You can also add the plug-in configuration entry over LDAP while the directory server is running and then restart the server to load the plug-in.

Note

Adding new plug-ins always requires a restart of Netscape Directory Server. Through the use of Netscape Console or modification of the nsslapd-pluginEnabled attribute within a plug-in's configuration entry, plug-ins that were present when the server was last started can be disabled or enabled while the server is running. The value of nsslapd-pluginEnabled may be off or on .


Using Netscape Console to examine the list of active plug-ins, you can verify that your Value Constraint plug-in was recognized by the server and correctly loaded.

The Resulting Server Behavior

Verify that the plug-in is working correctly by trying some add and modify operations. Any LDAP client that supports those operations may be used.

Listing 4.23 shows an LDIF file that contains two entries. The first includes an employeeType value of unknown , which should be rejected by the Value Constraint plug-in as invalid. The second entry includes a valid value ( contractor ).

Note

The commands shown in this section assume that the entries from Netscape's Example.ldif file have been loaded into your server. If in doubt, execute a command like this to load the Example.ldif file:

 ./ldif2db -n userRoot -i - <ldif/Example.ldif 

The ldif2db command must be executed from the \Netscape\Servers\ slapd-example directory on Windows or from the /export/ds6/slapd-example directory on Solaris. The other commands in this section rely on the presence of some of the entries and aci attributes from the Example.ldif file.


Listing 4.23 Entries with Different employeeType Values
 version: 1 # this add operation should fail with constraintViolation dn: uid=cjones,ou=People,dc=example,dc=com cn: Christina Jones sn: Jones givenName: Christina objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson ou: Accounting ou: People L: Sunnyvale uid: cjones mail: cjones@example.com userPassword: secret employeeType: unknown # this add operation should succeed dn: uid=cjones,ou=People,dc=example,dc=com cn: Christina Jones sn: Jones givenName: Christina objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson ou: Accounting ou: People L: Sunnyvale uid: cjones mail: cjones@example.com userPassword: secret employeeType: contractor 

Place the contents of Listing 4.23 in a file named testadds.ldif and use the ldapmodify command to test the Value Constraint plug-in's behavior when processing LDAP add operations. Listing 4.24 shows the command and the result. The -a option (add entries) and the -c option (continue even if an error occurs) are passed to ldapmodify so that the command will try to add the second entry even if the first add fails. The result indicates that the test was a success; the plug-in returned a "constraint violation" error.

Listing 4.24 Testing the Value Constraint Plug-in with Add Operations
  ./ldapmodify -ac -D "uid=kvaughan,ou=People,dc=example,dc=com" -w bribery < testadds.ldif  adding new entry uid=cjones,ou=People,dc=example,dc=com ldap_add: Constraint violation ldap_add: additional info: invalid value "unknown" for employeeType adding new entry uid=cjones,ou=People,dc=example,dc=com 

Next, test the behavior of the Value Constraint plug-in when it is confronted with LDAP modify operations. Listing 4.25 shows an LDIF file that contains a series of modify operations. Comments are included in the file to indicate whether the operation should succeed or not.

Listing 4.25 Modify Operations that Use Different employeeType Values
 version: 1 # this modify operation should fail with constraintViolation dn: uid=cjones,ou=People,dc=example,dc=com changeType: modify replace: employeeType employeeType: fulltime - # this modify operation should succeed dn: uid=cjones,ou=People,dc=example,dc=com changeType: modify replace: employeeType employeeType: employee - # this modify operation should succeed dn: uid=cjones,ou=People,dc=example,dc=com changeType: modify delete: employeeType employeeType: employee - # this modify operation should fail with noSuchAttributeValue dn: uid=cjones,ou=People,dc=example,dc=com changeType: modify delete: employeeType employeeType: vice president - # this modify operation should fail with constraintViolation dn: uid=cjones,ou=People,dc=example,dc=com changeType: modify add: employeeType employeeType: employee employeeType: vice president - 

Use the ldapmodify command one more time to verify that modify operations containing invalid employeeType values are rejected by the plug-in (and therefore by the directory server) and that those containing valid values are allowed. Listing 4.26 shows the command and the result. This time, the -c (continue if an error occurs) and the -v (verbose) options are used.

Listing 4.26 Testing the Value Constraint Plug-in with Modify Operations
  ./ldapmodify -c -v -D "uid=kvaughan,ou=People,dc=example,dc=com" -w bribery <  testmodifies.ldif  ldapmodify: started Tue Aug  2 22:02:54 2002 ldap_init( localhost, 3389 ) Processing a version 1 LDIF file... replace employeeType:         fulltime modifying entry uid=cjones,ou=People,dc=example,dc=com ldap_modify: Constraint violation ldap_modify: additional info: invalid value "fulltime" for employeeType replace employeeType:         employee modifying entry uid=cjones,ou=People,dc=example,dc=com modify complete delete employeeType:         employee modifying entry uid=cjones,ou=People,dc=example,dc=com modify complete delete employeeType:         vice president modifying entry uid=cjones,ou=People,dc=example,dc=com ldap_modify: No such attribute add employeeType:         employee         vice president modifying entry uid=cjones,ou=People,dc=example,dc=com ldap_modify: Constraint violation ldap_modify: additional info: invalid value "vice president" for employeeType 

The plug-in worked as expected. Now perform one more quick test using a different LDAP client. Start Netscape Console and use the Directory tab to navigate to the People container. The employeeType attribute is not listed on any of Netscape's built-in tabs within the entry editor. Follow the steps described here to try to add an invalid employeeType value to an entry:

Step 1. Open an Edit Entry window for the person entry named awhite (Alan White) by double-clicking on the entry name in the right-hand pane of the Directory window. Alan White's entry is the first one listed in the People container.

Step 2. Click the Advanced... button to open a Property Editor window that provides access to all of the available attributes and object classes.

Step 3. Click the Add Attribute... button and select employeeType from the list that appears. An empty attribute labeled Employee category is added to the list of attributes in the Property Editor window. This is the descriptive name used by Netscape Console for the employeeType attribute.

Step 4. Type "Visitor" in the Employee category field, click the OK button to close the Property Editor window, and click the OK button on the Edit Entry window.

Netscape Console will try to write your changes to the directory server. Figure 4.11 shows the resulting error alert.

Figure 4.11. A Failed Attempt to Add an Invalid employeeType Value

Although this was not an exhaustive test, you should now be convinced that the Value Constraint plug-in is working as designed. The ability to extend Netscape Directory Server using plug-ins is one of its strengths.

Ideas for Improvement

The Value Constraint plug-in could be enhanced in many ways. Here are a few ideas:

  • Remove the hard-coded attribute name and the list of valid values from the valueconstraint.c file, and change the plug-in to read the necessary configuration information from the Value Constraint plug-in's own entry.

  • Support regular expressions or a similar, flexible pattern-matching scheme when checking for valid attribute values.

  • Modify the plug-in so that it enforces constraints for only those entries that contain a specific object class value. Although employeeType attributes typically appear only in person entries, you may want to enforce constraints on an attribute such as a person's cn (common name). Because the cn attribute is used in many other kinds of entries, in this case the Value Constraint plug-in needs to be intelligent enough to ignore add and modify operations for nonperson entries.

Your customized directory server is better able to meet your needs. As with a car that you own for many years , with experience you can make specific directory products perform in ways that better match your own needs. Now park the car and shut off the ignition:

 ./stop-slapd 

This driving lesson is finished.

   


Understanding and Deploying LDAP Directory Services
Understanding and Deploying LDAP Directory Services (2nd Edition)
ISBN: 0672323168
EAN: 2147483647
Year: 2002
Pages: 242

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net