Sun Directory Server Enterprise Edition 7.0 Developer's Guide

Locating the Simple Authentication Example

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.