Using ldap add in PHP

From JQuantLib

Jump to: navigation, search
Image:RichardGomes-small.png

Richard Gomes founded JQuantLib in Sep/07. He is Brazilian and settled in London since Aug/06.
He has several years of experience in IT and experience with full software life-cycle, working as developer, architect, production support analyst. Read more...

Richard is available for immediate assignment as consultant specialized on Java technologies and open source tools.

See also: http://www.jquantlib.org/


Overview

  • We present here a method which prepares values to be added to OpenLDAP;
  • Example of how to call it and effectively add an entry to OpenLDAP;
  • Example of configuration parameters
  • Notes on objectClasses being used
  • Notes on password change and password synchronization with Kerberos and Samba
  • Notes: what about Micro$oft AD?


Requirements

  • OpenLDAP
  • Heimdal Kerberos (optional)
  • smbk5pwd overlay (optional) for password synchonization


Hands on it!

This is a method which prepares an entry to be added to OpenLDAP

/**
 * This is a typical record being produced by this method:
 * -----------------------------------------------------------
 * dn: uid=jsmith,ou=people,dc=example,dc=com
 * objectClass: krb5Principal
 * objectClass: krb5KDCEntry
 * objectClass: simpleSecurityObject
 * objectClass: inetOrgPerson
 * objectClass: person
 * objectClass: top
 * uid: jsmith
 * cn: JohnSmith
 * cn: John Smith
 * sn: Smith
 * description: John Paul Smith
 * givenName: John
 * displayName: Smith, John
 * mail: john.smith@example.com
 * userPassword: {K5KEY}
 * krb5PrincipalName: jsmith@EXAMPLE.COM
 * krb5KeyVersionNumber: 0
 * krb5KDCFlags: 126
 * krb5MaxLife: 86400
 * krb5MaxRenew: 604800
 * krb5Key:
 * -----------------------------------------------------------
 */
function ldap_prepare_entry( $p_username, $p_realname, $p_email ) {

    // Ensure username is lowecase
    $p_username = strtolower( $p_username );
    
    // split realname and test results
    if ( '' == $p_realname ) {
        trigger_error( "Realname cannot be empty", ERROR );
        return NULL;
    }
    $names = split(' ', $p_realname);
    if ( sizeof( $names ) < 2 ) {
        trigger_error( "Realname must have at least first and last names", ERROR );
        return NULL;
    }    

    // obtain name and surname
    $first  = $names[0];
    $last   = $names[sizeof($names)-1];

    // obtain Kerberos preferences
    $t_krb_vendor = strtolower( config_get( 'krb_vendor', 'none' ) );
    
    // set up basic objectClass(es)
    $classes = 0;
    if ( 'heimdal' == $t_krb_vendor ) {
        $entry['objectClass'][$classes++] = 'krb5Principal';
        $entry['objectClass'][$classes++] = 'krb5KDCEntry';
    }
    $entry['objectClass'][$classes++] = 'simpleSecurityObject';
    $entry['objectClass'][$classes++] = 'inetOrgPerson';
    $entry['objectClass'][$classes++] = 'person';
    $entry['objectClass'][$classes++] = 'top';

    // attributes uid and cn are mandatory in objectClass=account
    $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' );
    $t_ldap_cn_field  = config_get( 'ldap_cn_field', 'cn' );
    $entry[$t_ldap_uid_field]   = $p_username;
    $entry[$t_ldap_cn_field][0] = $first;
    $entry[$t_ldap_cn_field][1] = $first.$last;
    $entry[$t_ldap_cn_field][2] = $first.' '.$last;

    // attribute sn is mandatory in objectClass=inetOrgPerson
    $entry['sn'] = $last;

    // attribute mail is optional in objectClass=inetOrgPerson
    // but highly useful
    $entry['mail']        = $p_email;

    // attributes givenName, displayName and description are optional in 
    // objectClass=inetOrgPerson but highly useful
    $entry['givenName']   = $first;
    $entry['displayName'] = $last.", ".$first;
    $middle = "";
    for ( $i = 1; $i < sizeof($names)-1; $i++ ) {
        $middle = $middle.' '.$names[$i];
    }
    $entry['description'] = $first.$middle.' '.$last;
    
    if ( 'heimdal' == $t_krb_vendor ) {
        // attribute krb5PrincipalName is mandatory in objectClass=krb5Principal
        $t_krb_domain = config_get( 'krb_domain', ldap_default_kerberos_domain( ) );
        $entry['krb5PrincipalName'] = $p_username.'@'.$t_krb_domain;

        // attribute krb5VersionNumber is mandatory in objectClass=krb5KDCEntry
        $entry['krb5KeyVersionNumber'] = 0;
        
        // optional attributes in objectClass=krb5KDCEntry
        $entry['krb5KDCFlags'] =    126;
        $entry['krb5MaxLife']  =  86400;
        $entry['krb5MaxRenew'] = 604800;
        
        // optional krb5Key is the initial password in objectClass=krb5KDCEntry
        $entry['krb5Key'] = 'cleartext';
        
        // attribute userPassword is mandatory in objectClass=simpleSecurityObject
        $entry['userPassword'] = '{K5KEY}';
    } else {
        // attribute userPassword is mandatory in objectClass=simpleSecurityObject
        $entry['userPassword'] = 'cleartext';
    }

    return $entry;
}


The call is something like this:


    $t_user_dn = $t_ldap_uid_field.'='.$p_username.','.$t_ldap_people_dn;
    // example: "uid=jsmith,ou=People,dc=jquantlib,dc=org"
    $t_added = ldap_add( $t_ds, $t_user_dn, $entry );
    if ( !$t_added ) {
        trigger_error( "Failed to add user $t_user_dn", ERROR );
    }


These are my configuration parameters retrieved by config_get(...):


        $g_login_method          = LDAP;
        $g_passwd_method         = 'clear'; // one of: 'clear', 'crypt', 'md5', 'sha'. default: 'sha'
        $g_ldap_protocol_version = 3;
        $g_ldap_server           = 'ldap://localhost';
        $g_ldap_port             = '389';
        $g_ldap_base_dn          = 'dc=jquantlib,dc=org';
        $g_ldap_root_dn          = "ou=People,dc=jquantlib,dc=org"; // DEPRECATED: for backward compatibility only
        $g_ldap_people_dn        = "ou=People,dc=jquantlib,dc=org"; // default: "ou=people,$ldap_base_dn"
        $g_ldap_group_dn         = "ou=Group,dc=jquantlib,dc=org";  // default: "ou=group,$ldap_base_dn"
        $g_ldap_uid_field        = 'uid';         // default: 'uid'
        $g_ldap_cn_field         = 'cn';          // default: 'cn'
        $g_ldap_auto_sync        = ON;            // default: OFF
        $g_ldap_organization     = '(objectClass=inetOrgPerson)';
        $g_ldap_bind_dn          = 'cn=admin,dc=jquantlib,dc=org';
        $g_ldap_bind_passwd      = 'secret';
        // $g_ldap_writer_dn        = 'cn=admin,dc=jquantlib,dc=org'; // default: $g_ldap_bind_dn
        // $g_ldap_writer_passwd    = 'secret';                       // default: $g_ldap_bind_passwd
        $g_use_ldap_email        = ON;

        $g_krb_vendor            = 'heimdal'; // default: 'none' (only heimdal is supported at the moment)
        // $g_krb_domain         = 'JQUANTLIB.ORG'; // default: strtoupper(str_replace(array('dc=',','), array('','.'), $p_ldap_base_dn))


Notes

  • objectClasses being used:

I'm adding objectClasses krb5Principal and krb5KDCEntry which are needed in order to support single-sign-on onto OpenLdap/Heimdal. If you dont know what it is about, define:

        $g_krb_vendor            = 'none';
  • Password change and password synchronization with Kerberos and Samba

I'm taking the approach to first insert the userDN and then change the new created user's password in 2 separate steps. I do it this way because I'm using smbk5pwd overlay on OpenLDAP, in order to synchronize LDAP, Kerberos and Samba passwords. You can simply forget Kerberos (specially if you dont know what it is about) and insert the password hash in one go.

  • What about Micro$oft AD?

You can try to change attributes which are different in M$AD. Below you see one example. You will have to reasearch yourself.

        $g_ldap_uid_field        = 'sAMAccountName';


Hope it helps


See also: http://www.jquantlib.org/


RichardGomes 12:06, 11 December 2008 (UTC)