Skip Navigation Links | |
Exit Print View | |
Oracle Directory Server Enterprise Edition Developer's Guide 11 g Release 1 (11.1.1.5.0) |
Part I Directory Server Plug-In API Guide
1. Before You Start Writing Plug-Ins
2. Changes to the Plug-In API Since Directory Server 5.2
3. Getting Started With Directory Server Plug-Ins
4. Working With Entries Using Plug-Ins
5. Extending Client Request Handling Using Plug-Ins
6. Handling Authentication Using Plug-Ins
Client Identification During the Bind
Bind Processing in Directory Server
How Directory Server Processes the Bind
How a Plug-In Modifies Authentication
Developing a SASL Authentication Plug-In
Registering the SASL Mechanism
7. Performing Internal Operations With Plug-Ins
8. Writing Entry Store and Entry Fetch Plug-Ins
9. Writing Extended Operation Plug-Ins
10. Writing Matching Rule Plug-Ins
11. Writing Password Storage Scheme Plug-Ins
12. Writing Password Quality Check Plug-Ins
13. Writing Computed Attribute Plug-Ins
Part II Directory Server Plug-In API Reference
14. Data Type and Structure Reference
15. Function Reference, Part I
16. Function Reference, Part II
This section shows how a preoperation bind plug-in can use the plug-in API to authenticate a user. The example used in this section obtains the appropriate bind information from the parameter block. The example then handles the authentication if the request is for LDAP_AUTH_SIMPLE, but allows the server to continue the bind if the authentication succeeds.
Notice that some binds are performed by the front end before preoperation bind functions are called.
The following example shows a code excerpt from the source file install-path/examples/testbind.c.
Example 6-1 Preoperation Bind Function (testbind.c)
#include "slapi-plugin.h" int test_bind(Slapi_PBlock * pb) { char * dn; /* Target DN */ int method; /* Authentication method */ struct berval * credentials; /* Client SASL credentials */ Slapi_DN * sdn = NULL; /* DN used in internal srch */ char * attrs[2] = { /* Look at userPassword only */ SLAPI_USERPWD_ATTR, NULL }; Slapi_Entry * entry = NULL; /* Entry returned by srch */ Slapi_Attr * attr = NULL; /* Pwd attr in entry found */ int is_repl; /* Is this replication? */ int is_intl; /* Is this an internal op? */ int connId, opId, rc = 0; long msgId; /* Obtain the bind information from the parameter block. */ rc |= slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn); rc |= slapi_pblock_get(pb, SLAPI_BIND_METHOD, &method); rc |= slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &credentials); rc |= slapi_pblock_get(pb, SLAPI_OPERATION_MSGID, &msgId); rc |= slapi_pblock_get(pb, SLAPI_CONN_ID, &connId); rc |= slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opId); rc |= slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl); rc |= slapi_pblock_get(pb, SLAPI_IS_INTERNAL_OPERATION, &is_intl); if (rc != 0) { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, SLAPI_LOG_NO_MSGID, SLAPI_LOG_NO_CONNID, SLAPI_LOG_NO_OPID, "test_bind in test-bind plug-in", "Could not get parameters for bind operation (error %d).\n", rc ); slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL); return (LDAP_OPERATIONS_ERROR);/* Server aborts bind here. */ } /* The following code handles simple authentication, where a * user offers a bind DN and a password for authentication. * * Handling simple authentication is a matter of finding the * entry corresponding to the bind DN sent in the request, * then if the entry is found, checking whether the password * sent in the request matches a value found on the * userPassword attribute of the entry. */ /* Avoid interfering with replication or internal operations. */ if (!is_repl && !is_intl) switch (method) { case LDAP_AUTH_SIMPLE: /* Find the entry specified by the bind DN... */ sdn = slapi_sdn_new_dn_byref(dn); rc |= slapi_search_internal_get_entry( sdn, attrs, &entry, plugin_id ); slapi_sdn_free(&sdn); if (rc != 0 || entry == NULL) { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Could not find entry: %s\n", dn ); rc = LDAP_NO_SUCH_OBJECT; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return (rc); } else { /* ...check credentials against the userpassword... */ Slapi_Value * credval; /* Value of credentials */ Slapi_ValueSet * pwvalues; /* Password attribute values */ rc |= slapi_entry_attr_find( entry, SLAPI_USERPWD_ATTR, &attr ); if (attr == NULL) { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Entry %s has no userpassword.\n", dn ); rc = LDAP_INAPPROPRIATE_AUTH; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return (rc); } rc |= slapi_attr_get_valueset( attr, &pwvalues ); if (rc != 0 || slapi_valueset_count(pwvalues) == 0) { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Entry %s has no %s attribute values.\n", dn, SLAPI_USERPWD_ATTR ); rc = LDAP_INAPPROPRIATE_AUTH; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); slapi_valueset_free(pwvalues); return (rc); } credval = slapi_value_new_berval(credentials); rc = slapi_pw_find_valueset(pwvalues, credval); slapi_value_free(&credval); slapi_valueset_free(pwvalues); if (rc != 0) { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Credentials are not correct.\n" ); rc = LDAP_INVALID_CREDENTIALS; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return (rc); } } /* ...if successful, set authentication for the connection. */ if (rc != 0) return (rc); rc |=slapi_pblock_set(pb, SLAPI_CONN_DN, slapi_ch_strdup(dn)); rc |=slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_SIMPLE); if (rc != 0) { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Failed to set connection info.\n" ); rc = LDAP_OPERATIONS_ERROR; slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return (rc); } else { slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Authenticated: %s\n", dn ); /* Now that authentication succeeded, the plug-in * returns a value greater than 0, even though the * authentication has been successful. A return * code > 0 tells the server not to continue * processing the bind. A return code of 0, such * as LDAP_SUCCESS tells the server to continue * processing the operation. */ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL); rc = 1; } break; /* This plug-in supports only simple authentication. */ case LDAP_AUTH_NONE: /* Anonymous binds are handled by the front-end before * pre-bind plug-in functions are called, so this * part of the code should never be reached. */ case LDAP_AUTH_SASL: default: slapi_log_info_ex( SLAPI_LOG_INFO_AREA_PLUGIN, SLAPI_LOG_INFO_LEVEL_DEFAULT, msgId, connId, opId, "test_bind in test-bind plug-in", "Plug-in does not handle auth. method: %d\n", method ); rc = 0; /* Let server handle bind. */ break; } return (rc); /* Server stops processing * the bind if rc > 0. */ }
The bulk of the code processes the LDAP_AUTH_SIMPLE case. In the simple authentication case, the plug-in uses the DN and the password to authenticate the user binding through plug-in API calls.
The plug-in demonstration works by turning on informational logging for plug-ins. You read the log messages written by the plug-in at different stages in its operation. Before using the plug-in, load a few example users and data because you cannot demonstrate the functionality while binding as a directory superuser. without calling the preoperation bind functions.
If you have not done so already, set up a directory instance with a suffix, dc=example,dc=com, containing data loaded from a sample LDIF file, install-path/resources/ldif/Example.ldif.
For example:
$ dsadm create -h localhost -p 1389 /local/ds Choose the Directory Manager password: Confirm the Directory Manager password: $
For example:
$ dsadm start /local/ds Server started: pid=4705 $
For example, with long lines folded for the printed page:
$ dsconf create-suffix -h localhost -p 1389 dc=example,dc=com Enter "cn=directory manager" password: Certificate "CN=defaultCert, CN=hostname:1636" presented by the server is not trusted. Type "Y" to accept, "y" to accept just once, "n" to refuse, "d" for more details: Y $
For example, with long lines folded for the printed page:
$ dsconf import -h localhost -p 1389 \ install-path/resources/ldif/Example.ldif dc=example,dc=com Enter "cn=directory manager" password: New data will override existing data of the suffix "dc=example,dc=com". Initialization will have to be performed on replicated suffixes. Do you want to continue [y/n] ? y ## Index buffering enabled with bucket size 16 ## Beginning import job... ## Processing file "install-path/resources/ldif/Example.ldif" ## Finished scanning file "install-path/resources/ldif/Example.ldif" (160 entries) ## Workers finished; cleaning up... ## Workers cleaned up. ## Cleaning up producer thread... ## Indexing complete. ## Starting numsubordinates attribute generation. This may take a while, please wait for further activity reports. ## Numsubordinates attribute generation complete. Flushing caches... ## Closing files... ## Import complete. Processed 160 entries in 5 seconds. (32.00 entries/sec) Task completed (slapd exit code: 0). $
See Also
You can use Directory Service Control Center to perform this task. For more information, see the Directory Service Control Center online help.
If you have not already done so, build the example plug-in library and activate both plug-in informational logging and the example plug-in.
Hint Use install-path/examples/Makefile or install-path/examples/Makefile64.
$ dsconf create-plugin -F custom-plugin-init-function -G custom-plugin-argument -H lib-path \ -Y custom-plugin-type "Custom Plugin" $ dsconf enable-plugin "Custom Plugin"
Hint For more information, use the commands specified in the plug-in source file.
$ dsadm restart instance-path
The example suffix contains a number of people. If you look up the entry for one of those people, Barbara Jensen, either anonymously or as Directory Manager, the test_bind() plug-in function is never called. The plug-in therefore never logs informational messages to the errors log.
$ ldapsearch -h localhost -p 1389 -b dc=example,dc=com uid=bjensen sn version: 1 dn: uid=bjensen, ou=People, dc=example,dc=com sn: Jensen $ grep test_bind /local/ds/logs/errors $
Notice that the server bypasses preoperation bind plug-ins when special users request a bind.
$ ldapsearch -h localhost -p 1389 -b dc=example,dc=com \ -D uid=bjensen,ou=people,dc=example,dc=com -w hifalutin uid=bjensen sn version: 1 dn: uid=bjensen, ou=People, dc=example,dc=com sn: Jensen $ grep test_bind /local/ds/logs/errors [04/Jan/2006:11:34:31 +0100] - INFORMATION - test_bind in test-bind plug-in - conn=4 op=0 msgId=1 - Authenticated: uid=bjensen,ou=people,dc=example,dc=com $
$ ldapsearch -h localhost -p 1389 -b dc=example,dc=com \ -D uid=bjensen,ou=people,dc=example,dc=com -w bogus uid=bjensen sn ldap_simple_bind: Invalid credentials $ grep test_bind /local/ds/logs/errors | grep -i credentials [04/Jan/2006:11:36:07 +0100] - INFORMATION - test_bind in test-bind plug-in - conn=5 op=0 msgId=1 - Credentials are not correct. $
Here, the LDAP result is interpreted correctly by the command-line client. The plug-in message to the same effect is written to the errors log.
$ ldapmodify -h localhost -p 1389 \ -D uid=kvaughan,ou=people,dc=example,dc=com -w bribery dn: uid=bjensen,ou=people,dc=example,dc=com changetype: modify delete: userpassword modifying entry uid=bjensen,ou=people,dc=example,dc=com ^D $ ldapsearch -h localhost -p 1389 -b dc=example,dc=com \ -D uid=bjensen,ou=people,dc=example,dc=com -w - uid=bjensen sn Enter bind password: ldap_simple_bind: Inappropriate authentication $ grep test_bind /local/ds/logs/errors | grep -i password [04/Jan/2006:11:41:25 +0100] - INFORMATION - test_bind in test-bind plug-in - conn=8 op=0 msgId=1 - Entry uid=bjensen,ou=people,dc=example,dc=com has no userpassword. $
Here, the LDAP result is displayed correctly by the command-line client. The plug-in message will provide more information about what went wrong during Barbara’s attempt to bind, no userpassword attribute values.