Mozilla LDAP SDK Programmer's Guide/SASL Authentication With LDAP C SDK

From MozillaWiki
Jump to: navigation, search

This section describes the process of using a Simple Authentication and Security Layer (SASL) mechanism to authenticate an LDAP client to an LDAP server.

Understanding SASL and LDAP C SDK

The ability to authenticate to an LDAP server with a SASL mechanism is a feature that is new to LDAP v3. LDAP v2 servers do not support this method of authentication.

SASL is described in RFC 4422, Simple Authentication and Security Layer (SASL).

Determining Supported SASL Mechanisms With LDAP C SDK

To determine the SASL mechanisms supported by an LDAP v3 server, get the root DSE of the server, and check the supportedSASLMechanisms attribute. The values of this attribute are the names of the SASL mechanisms supported by the server.

If the root DSE does not have a supportedSASLMechanisms attribute, the server does not support any SASL mechanisms.

Authenticating Using SASL With LDAP C SDK

  • The synchronous ldap_sasl_bind_s() function
  • The asynchronous ldap_sasl_bind() function
    If you call the asynchronous function ldap_sasl_bind(), you need to call the ldap_result() and ldap_parse_sasl_bind_result() functions to get the result of the SASL bind operation.

Authentication with a SASL mechanism can take one or more roundtrips between your client and the server. The server might send a number of challenges to the client. You might need to call ldap_sasl_bind_s() several times, or ldap_sasl_bind(), ldap_result(), and ldap_parse_sasl_bind_result() several times in order to respond to each server challenge.

Before calling the function to perform a SASL bind operation, make sure to specify that your client is LDAP v3 compliant. If you do not, an LDAP_NOT_SUPPORTED result code is returned.


Synchronous SASL Bind Operation


If you want to wait for the results of the SASL bind operation to complete before continuing, call the synchronous ldap_sasl_bind_s() function. This function sends a SASL bind request to the server. This function blocks other work until the server sends the results of the operation back to your client.

  • LDAP_SUCCESS if your client has successfully authenticated.
  • LDAP_SASL_BIND_IN_PROGRESS if the server sends a challenge to your client. If you receive this result code, check the servercredp argument for the berval structure that contains the servers challenge. Call the ldap_sasl_bind function again to send a response to that challenge.
  • An LDAP error code if a problem occurred or if authentication failed. See the ldap_sasl_bind_s() function documentation for a list of the possible result codes.


Asynchronous SASL Bind Operation


If you want to perform other work in parallel while waiting for the SASL bind operation to complete, use the following procedure.

To Bind Asynchronously Over SASL

  1. Call the asynchronous ldap_sasl_bind() function to send an LDAP SASL bind request.
    This function returns an LDAP_SUCCESS result code if the request was successfully sent, or an LDAP result code if an error occurred while sending the request. The function also sets the msgidp argument to point to a message ID identifying the SASL bind operation.
  2. Call the ldap_result() function, passing in this message ID to determine whether the server sent a response for this operation to your client.
    The ldap_result() function uses the message ID to determine if the server sent a SASL bind response. The function passes back the response in an LDAPMessage structure.
  3. Call the ldap_parse_sasl_bind_result() function to parse the LDAPMessage structure and retrieve information from the servers response.
    If the server sent a challenge to your client, the challenge is specified in the berval structure passed back as the servercredp argument.
  4. Call the ldap_get_lderrno function to get the LDAP result code for the operation.
    • LDAP_SUCCESS if your client successfully authenticated to the server.
    • LDAP_SASL_BIND_IN_PROGRESS if the server sent a challenge to your client.
      If the server returned an LDAP_SASL_BIND_IN_PROGRESS result code, check the servercredp argument for the berval structure that contains the servers challenge.
    • An LDAP error code if a problem occurred or if authentication failed.
      See the ldap_sasl_bind() function documentation for a list of result codes that the server can return for this operation.
  5. If the result code is LDAP_SASL_BIND_IN_PROGRESS and if the server passed back another challenge, determine the response to that challenge by calling the ldap_sasl_bind() function again to send that response to the server.
    You can call ldap_result() and ldap_parse_sasl_bind_result() again to get the next challenge sent from the server, if the result is again LDAP_SASL_BIND_IN_PROGRESS.

This example shows an LDAP client that authenticates using the SASL mechanism that is named babsmechanism.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ldap.h"

int
main( int argc, char **argv )
{
    LDAP        *ld;
    LDAPMod     mod0;
    LDAPMod     mod1;
    LDAPMod     *mods[ 3 ];
    char        *vals0[ 2 ];
    char        *vals1[ 2 ];
    time_t      now;
    char        buf[ 128 ];
    struct berval   cred;
    struct berval   *servcred;
    int         version;
    /* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
    if ( (ld = ldap_init( "localhost", 389 )) == NULL ) {
      perror( "ldap_init" );
      return( 1 );
    }
    /* Set the LDAP protocol version supported by the client
       to 3. (By default, this is set to 2. SASL authentication
       is part of version 3 of the LDAP protocol.) */
    version = LDAP_VERSION3;
    ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, version );
    /* authenticate */
    cred.bv_val = "magic";
    cred.bv_len = sizeof( "magic" ) - 1;
    if ( ldap_sasl_bind_s( ld, "uid=bjensen,ou=people,dc=example,dc=com",
                           "babsmechanism", cred, NULL, NULL,
                           servcred ) != LDAP_SUCCESS ) {
      ldap_perror( ld, "ldap_sasl_bind_s" );
      return( 1 );
    }
    /* get and print the credentials returned by the server */
    printf( "Server credentials: %s\n", servcred->bv_val );
    /* construct the list of modifications to make */
    mod0.mod_op = LDAP_MOD_REPLACE;
    mod0.mod_type = "mail";
    vals0[0] = "babs@example.com";
    vals0[1] = NULL;
    mod0.mod_values = vals0;
    mod1.mod_op = LDAP_MOD_ADD;
    mod1.mod_type = "description";
    time( now );
    sprintf( buf, "This entry was modified with the modattrs program on %s",
      ctime( now ));
    /* Get rid of \n which ctime put on the end of the time string */
    if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
      buf[ strlen( buf ) - 1 ] = '\0';
    }
    vals1[ 0 ] = buf;
    vals1[ 1 ] = NULL;
    mod1.mod_values = vals1;
    mods[ 0 ] = mod0;
    mods[ 1 ] = mod1;
    mods[ 2 ] = NULL;
    /* make the change */
    if ( ldap_modify_s(ld, "uid=bjensen,ou=people,dc=example,dc=com", mods)
      != LDAP_SUCCESS ) {
      ldap_perror( ld, "ldap_modify_s" );
      return( 1 );
    }
    ldap_unbind( ld );
    printf( "modification was successful\n" );
    return( 0 );
}