Looking to get a sense of what various co-maintainers are looking to contribute. As an API, this will need to be very stable, have well thought out public functions, and good unit testing. As an API it will also need to have modules that leverage it, even if they are proof of concept modules. As it will be leveraged by authentication and authorization modules it should be fairly well tested for security.

So what roles are people intereted in playing?

- writing simple tests
- specing out the api itself. I already have an alpha but it needs a good look
- documentation
- getting other ldap modules to leverage it.
- exportables and patterns support
- ...oh and coding the api module itself

Late next week I'd like to skype or irc with whomever is interested in contributing or being co-maintainers to get things going. I have a deadline coming up middle of this week, but may get code cleaned up and posted before then.

Please be sure to take a look at the scope of the api module itself on the project page (6 points). I'm flexible on this, but am not interested in large amounts of philosophical/scope discussion. That is I would like to have a good discussion about the functionality and architecture of the module, then get to work on the unit tests and write the module.

Comments

retsamedoc’s picture

I'm up for coding\specing out the API. Probably something that needs to be done aside the documentation. Otherwise, I am perfectly happy writing some additional modules to leverage the LDAP API (I'm currently working on LDAP Content Profile to fill in a gap the previous LDAP Integration module is lacking).

I would really like to see what functions have already been written for the API and what remains to be written. I feel that there are plenty of good OSS examples of LDAP<->PHP interaction that we can leverage. No reason to reinvent the wheel.

johnbarclay’s picture

I paged through the adLDAP.php library for a lot of functions. Please add and comment on them. I don't do much with writing to the LDAP so am unclear on the utility of those functions. I think a wiki would be better for hashing out the functions and methods of the api, but am not sure where on drupal to put one. I'll look into that. I committed the code I had. I haven't really looked at in 6 months, so not sure what state its in.

I see 2 sets of functions:

1. ones that were about configuring or querying ldap instances. These I put in the .module file: (first code set below)
2. ones that only make sense in the context of a particular ldap connection. I made these methods and properties on an ldap class which would be instantiated based on an ldap configuration. (second code set below)

I'm generally looking at a stored ldap configuration as a given server and service account such that a single LDAP server might be used in different ldap configurations for different purposes.


/**
 * get one or more ldap_api_server objects
 *
 * @param $server
 *   - integer representing server id,
 *   - or name => value array of server parameters,
 *   - or instantiated server object
 *   - or NULL signifying find all servers configured
 *   
 * @param $module
 *   if present, only return servers which a module has enabled.
 *
 * @param $reset
 *   clear any cached servers
 *   
 * @return
 *   Array of ldap_server objects
 *   or single server object if server id passed in
 */

function ldap_api_get_server_objects($server = NULL, $module = NULL, $reset = FALSE) {
  require_once('ldap_api.functions.inc');
  return _ldap_api_get_server_objects($server, $module, $reset);
}


/**
 * update cache
 *
 */
function ldap_api_config_update_cache() {
  $ldap_api_config = ldap_api_config_get($reset = TRUE); 
}
/**
 * get configuration array from cache or db
 *   http://www.lullabot.com/articles/a_beginners_guide_to_caching_data
 *   http://dc2009.drupalcon.org/session/inside-drupal-caching-static-variables-memcache
 *
 * @param $reset
 *   true signifies override cache or static variable and get from db
 *   
 * @param $sid
 *   if present, only return a single server's configuration
 *
 * @return
 *  ldap configuration as array or single ldap server configuration
 */
 
function ldap_api_config_get($reset = FALSE, $sid = FALSE) {
  require_once('ldap_api.functions.inc');
  return _ldap_api_config_get($reset, $sid);
}

function ldap_api_module_server_config_get($sid, $module) {
  require_once('ldap_api.functions.inc');
  $ldap_server_config = _ldap_api_config_get(FALSE, $sid);
  return $ldap_server_config['module_data'][$module];
}

function ldap_api_module_server_config_set($sid, $module, $data, $merge = FALSE) { // merge means merge arrays, if not will overwrite
  require_once('ldap_api.functions.inc');
 // return _ldap_api_module_server_config_set($sid, $module, $data, $merge);  // needs to be written.  
}


/**
 * get single ldap server attribute
 *
 * @param $sid
 *   ldap server id
 *   
 * @param $attr
 *   attribute name
 *
 * @module
 *    module name.  if given, attribute is returned from module_data array
 *
 * @return
 *  ldap configuration as array or single ldap server configuration
 */
 function ldap_api_server_get_attribute($sid, $attr, $module) {
  require_once('ldap_api.functions.inc');
  return _ldap_api_server_get_attribute($sid, $attr, $module);
 }
 
function ldap_api_encrypt($text) {
  require_once('ldap_api.functions.inc');
  return _ldap_api_encrypt($text);
}

function ldap_api_decrypt($encrypted, $encryption) {
  require_once('ldap_api.functions.inc');
  return _ldap_api_decrypt($encrypted, $encryption);
}

function ldap_api_ldap_extension_loaded() {
  require_once('ldap_api.functions.inc');
  return _ldap_api_ldap_extension_loaded();
}



/**
 * Class to encapsulate a single LDAP Server configuration
 *
 */

class ldap_api_server {

  public $connection = NULL;
  public $server_addr = NULL;
  public $name;
  public $port = 389;
  public $tls = FALSE;
  public $sid;
  public $pwd_encryption;
  public $binddn;
  public $bindpw;
  public $basedns;  // array of basedns
  public $basedn; // set of basedns separated by returns
  public $user_attr;
  public $mail_attr = "mail";
  public $ldap_to_drupal_user;
  public $testing_drupal_username;
  public $module_data;
  
  /**
 * Constructor Method
 *
 * @param $params
 *   Can be:
 *     - an associative array of property-name => property-values
 *     - the id (sid) of an ldap server configuration stored by ldap_server module
 */
  function __construct($params = NULL) {
    $constructor_properties = array('server_addr','name','port','tls','pwd_encryption','binddn','bindpw','basedn','user_attr','mail_attr','ldap_to_drupal_user','testing_drupal_username','module_data');
    if (is_array($params)) {
      foreach (array_intersect($params,$constructor_properties) as $prop) {
        if (isset($params[$prop])) {
          $this->$prop = $params[$prop];
        }
      }  
    }
    elseif (is_numeric($params)) {
      $this->sid = $params;
      $record = db_fetch_object(db_query("SELECT * FROM {ldap_api_servers} WHERE sid = %d", $this->sid));
      foreach ($constructor_properties as $prop) {
        if (isset($record->$prop)) {
          $this->$prop = $record->$prop;
        }
      }  
    }
    
    if ($this->basedn) {
    // dpm('explode');  dpm(explode("\r\n", $this->basedn));
      $this->basedns = serialize(explode("\r\n", $this->basedn));
    }
  }

  function __destruct() {
    // should break any connection or binding
  }


  function connect($dn = NULL, $pass = NULL) {
    $this->disconnect();
    $dn = ($dn != NULL) ? $dn : $this->binddn;
    $pass = ($pass != NULL) ? $pass :  ldap_api_decrypt($this->bindpw, $this->pwd_encryption);
    return ($this->connectAndBind($dn, $pass));
  }

  function initConnection() {
    if (!$con = ldap_connect($this->server_addr, $this->port)) {
      watchdog('user', 'LDAP Connect failure to '. $this->server_addr .':'. $this->port);
      return;
    }

    ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($con, LDAP_OPT_REFERRALS, 0);
    if ($this->tls) {
      ldap_get_option($con, LDAP_OPT_PROTOCOL_VERSION, $vers);
      if ($vers == -1) {
        watchdog('user', 'Could not get LDAP protocol version.');
        return;
      }
      if ($vers != 3) {
        watchdog('user', 'Could not start TLS, only supported by LDAP v3.');
        return;
      }
      else if (!function_exists('ldap_start_tls')) {
        watchdog('user', 'Could not start TLS. It does not seem to be supported by this PHP setup.');
        return;
      }
      else if (!ldap_start_tls($con)) {
        watchdog('user', t("Could not start TLS. (Error %errno: %error).", array('%errno' => ldap_errno($con), '%error' => ldap_error($con))));
        return;
      }
    }
    $this->connection = $con;
  }

  function connectAndBind($dn, $pass) {
    $this->initConnection();
    $con = $this->connection;
    if (!$this->bind($dn, $pass)) {
      watchdog('user', 'LDAP Bind failure for user %user. Error %errno: %error', array('%user' => $dn, '%errno' => ldap_errno($con), '%error' => ldap_error($con)));
      return NULL;
    }

    return $con;
  }

  function bind($dn, $pass) {
    ob_start();
    set_error_handler(array('LDAPInterface', 'void_error_handler'));
    $ret = ldap_bind($this->connection, $dn, $pass);
    restore_error_handler();

    ob_end_clean();

    return $ret;
  }

  function disconnect() {
    if ($this->connection) {
      ldap_unbind($this->connection);
      $this->connection = NULL;
    }
  }

  /**
 * get_ldap_user_entry_from_drupal_username
 *
 * @param $drupal_username
 *
 * @return
 *   If no matching user found in LDAP: FALSE 
 *   If match found: an associative array of LDAP User object properties
 */
  
  public function get_ldap_user_entry_from_drupal_username($drupal_username) {
  
    if ($ldap_server->ldap_to_drupal_user) {
      $name = $drupal_username;
      drupal_eval($ldap_server->ldap_to_drupal_user);
      $drupal_username = $name;
    }
    
    foreach ($this->basedns as $base_dn) {
     $filter = $this->user_attr .'='. $drupal_username;
     $result = $this->search($base_dn, $filter);
     if (!$result)
       continue;
     
     // Must find exactly one user for authentication to.
     if ($result['count'] != 1) {
       watchdog('ldapauth', "Error: %num_matches users found with $%filter under %base_dn.", array('%num_matches' => $result['count'], '%filter' => $filter, '%base_dn' => $base_dn), WATCHDOG_ERROR);
       continue;
     }
     $match = $result[0];
 
     // These lines serve to fix the attribute name in case a
     // naughty server (i.e.: MS Active Directory) is messing the
     // characters' case.
     // This was contributed by Dan "Gribnif" Wilga, and described
     // here: http://drupal.org/node/87833
     if (!isset($match[$this->user_attr][0])) {
       $username_attr = drupal_strtolower($this->user_attr);
       if (!isset($match[$username_attr][0]))
         continue;
     }
     // Finally, we must filter out results with spaces added before
     // or after, which are considered OK by LDAP but are no good for us
     // We allow lettercase independence, as requested by Marc Galera
     // on http://drupal.org/node/97728
     //
     // Some setups have multiple $name_attr per entry, as pointed out by
     // Clarence "sparr" Risher on http://drupal.org/node/102008, so we
     // loop through all possible options.
     foreach ($match[$username_attr] as $value) {
       if (drupal_strtolower(trim($value)) == drupal_strtolower($drupal_username))
         return $match;
     }
     
    }
  

  }
  
  function search($base_dn, $filter, $attributes = array()) {
    $ret = array();

    // For the AD the '\,' should be replaced by the '\\,' in the search filter.
    $filter = preg_replace('/\\\,/', '\\\\\,', $filter);

    set_error_handler(array('ldap_server', 'void_error_handler'));
    $x = @ldap_search($this->connection, $base_dn, $filter, $attributes);
    restore_error_handler();

    if ($x && ldap_count_entries($this->connection, $x)) {
      $ret = ldap_get_entries($this->connection, $x);
    }
    return $ret;
  }

  // WARNING! WARNING! WARNING!
  // This function returns its entries with lowercase attribute names.
  // Don't blame me, blame PHP's own ldap_get_entries()
  function retrieveAttributes($dn) {
    set_error_handler(array('ldap_server', 'void_error_handler'));
    $result = ldap_read($this->connection, $dn, 'objectClass=*');
    $entries = ldap_get_entries($this->connection, $result);
    restore_error_handler();

    return call_user_func($this->attr_filter, $this->sid, $entries[0]);
  }

  function retrieveAttribute($dn, $attrname) {
    $entries = $this->retrieveAttributes($dn);
    return isset($entries[strtolower($attrname)]) ? $entries[strtolower($attrname)][0] : NULL;
  }

  function retrieveMultiAttribute($dn, $attrname) {
    $entries = $this->retrieveAttributes($dn);

    $result = array();
    $retrieved = $entries[strtolower($attrname)];
    $retrieved = $retrieved ? $retrieved : array();
    foreach ($retrieved as $key => $value) {
      if ($key !== 'count') {
        $result[] = $value;
      }
    }
    return $result;
  }

  function writeAttributes($dn, $attributes) {
    foreach ($attributes as $key => $cur_val) {
      if ($cur_val == '') {
        unset($attributes[$key]);
        $old_value = $this->retrieveAttribute($dn, $key);
        if (isset($old_value)) {
          ldap_mod_del($this->connection, $dn, array($key => $old_value));
        }
      }
      if (is_array ($cur_val)) {
        foreach ($cur_val as $mv_key => $mv_cur_val) {
          if ($mv_cur_val == '') {
            unset($attributes[$key][$mv_key]);
          }
          else {
            $attributes[$key][$mv_key] = $mv_cur_val;
          }
        }
      }
    }

    ldap_modify($this->connection, $dn, $attributes);
  }

  function create_entry($dn, $attributes) {
    set_error_handler(array('ldap_server', 'void_error_handler'));
    $ret = ldap_add($this->connection, $dn, $attributes);
    restore_error_handler();

    return $ret;
  }

  function rename_entry($dn, $newrdn, $newparent, $deleteoldrdn) {
    set_error_handler(array('ldap_server', 'void_error_handler'));
    $ret = ldap_rename($this->connection, $dn, $newrdn, $newparent, $deleteoldrdn);
    restore_error_handler();

    return $ret;
  }

  function delete_entry($dn) {
    set_error_handler(array('ldap_server', 'void_error_handler'));
    $ret = ldap_delete($this->connection, $dn);
    restore_error_handler();

    return $ret;
  }

  // This function is used by other modules to delete attributes once they are
  // moved to profiles cause ldap_mod_del does not delete facsimileTelephoneNumber if
  // attribute value to delete is passed to the function.
  // OpenLDAP as per RFC 2252 doesn't have equality matching for facsimileTelephoneNumber
  // http://bugs.php.net/bug.php?id=7168
  function deleteAttribute($dn, $attribute) {
    ldap_mod_del($this->connection, $dn, array($attribute => array()));
  }

  static function void_error_handler($p1, $p2, $p3, $p4, $p5) {
  }
  
}

retsamedoc’s picture

Overall I think we are on the same page. No reason to rebuild the wheel. The only concerns I have are:

  1. Keep the API stuff separate from the other functions (Authentication/Authorization/User/Role/Profile/etc). I know that this means the LDAP API is mostly a middleware library providing a light abstraction from PHP's LDAP library, but it should keep things modular enough to give everyone exactly what they want and will keep features from stepping on or otherwise breaking each other.
  2. Inherit functionality from LDAP Integration. No reason to reinvent the wheel, just re-engineer it to be more sturdy.
  3. The appropriate coding standards are followed (Drupal Coding, no PHP4 support, doxygen)

I think this is generally what @johnbarclay had in mind. I've been working on a reformat and standardization of the above code that I should have ready in another day or so (including a skeleton module to build upon). I hope I'm not over stepping, I just want to get a good start.

I fully agree about a wiki to further collaborate/solidify the API. If we can't get a wiki on drupal.org, perhaps we should create a Mediawiki on either your or my domain. I can get one going pretty quick if needed.

Just for openness, here is part of my ldap_server class:

// $Id$

/**
 * LDAP API
 *
 *   This file is the main module to provide a stable API for accessing LDAP
 * datasets within Drupal. The requirment is to remain standard complient.
 *
 *   In an attempt to make this API future-proof, it is being developed in
 * PHP 5.x and tested against both Drupal 6 and 7. It is our goal to have a
 * working LDAP module the day that Drupal 7 is released.
 *
 *
 * Additional Reading:
 *   RFC4510 - LDAP: Technical Specification Road Map
 *   RFC4511 - LDAP: The Protocol
 *   RFC4512 - LDAP: Directory Information Models
 *   RFC4513 - LDAP: Authentication Methods and Security Mechanisms
 *   RFC4514 - LDAP: String Representation of Distinguished Names
 *   RFC4515 - LDAP: String Representation of Search Filters
 *   RFC4516 - LDAP: Uniform Resource Locator
 *   RFC4517 - LDAP: Syntaxes and Matching Rules
 *   RFC4518 - LDAP: Internationalized String Preparation
 *   RFC4519 - LDAP: Schema for User Applications
 *
 */

/**
 * LDAP Server Class
 *
 *  This class is used to create, work with, and eventually destroy ldap_server
 * objects.
 */
class ldap_server {
  // LDAP Settings
  public $sid;
  public $name;
  public $address;
  public $port = 389;
  public $tls = FALSE;
  public $basedn;
  private $binddn = FALSE; // Default to an anonymous bind.
  private $bindpw = FALSE; // Default to an anonymous bind.
  protected $connection;
  const properties = array('sid','name','address','port','tls','base','binddn','bindpw');

  /**
   * Constructor Method
   */
  function __construct($sid = 1) {
    if (!is_numeric($params)) {
      return;
    }

    $this->sid = $sid;
    $record = db_fetch_object(db_query("SELECT * FROM {ldap_servers} WHERE sid = %d", $this->sid));
    foreach (properties as $property) {
      if (isset($record->$property)) {
        $this->$property = $record->$property;
      }
    }
  }

  /**
   * Destructor Method
   */
  function __destruct() {
    // Close the server connection to be sure.
    $this->disconnect();
  }


  /**
   * Invoke Method
   */
  function __invoke() {
    $this->connect();
    $this->bind();
  }

  /**
   * Error Handling Method
   *
   * @param int errno
   *   The level of the error raised.
   *
   * @param string errstr
   *   The error message.
   *
   * @param string errfile
   *   The filename that the error was raised in.
   *
   * @param int errline
   *   The line number the error was raised at.
   *
   * @param array errcontext
   *   An array of every variable that existed in the scope the error was 
   *   triggered in.
   *
   * @return bool
   *   Always return TRUE to avoid PHP's builtin handler.
   */
  function error_handler($errno,$errstr,$errfile,$errline,$errcontext){
    return TRUE;
  }


  /**
   * Connect Method
   */
  function connect() { 
    if (!$con = ldap_connect($this->server_addr, $this->port)) {
      watchdog('user', 'LDAP Connect failure to '. $this->server_addr .':'. $this->port);
      return;
    }
    
    ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($con, LDAP_OPT_REFERRALS, 0);
    
    // Use TLS if we are configured and able to.
    if ($this->tls) {
      ldap_get_option($con, LDAP_OPT_PROTOCOL_VERSION, $vers);
      if ($vers == -1) {
        watchdog('user', 'Could not get LDAP protocol version.');
        return; 
      }
      if ($vers != 3) {
        watchdog('user', 'Could not start TLS, only supported by LDAP v3.');
        return;
      } 
      else if (!function_exists('ldap_start_tls')) {
        watchdog('user', 'Could not start TLS. It does not seem to be supported by this PHP setup.');
        return;
      }
      else if (!ldap_start_tls($con)) {
        watchdog('user', t("Could not start TLS. (Error %errno: %error).", array('%errno' => ldap_errno($con), '%error' => ldap_error($con))));
        return;
      }
    }

  // Store the resulting resource
  $this->connection = $con;
  }

  /**
   * Bind (authenticate) against an active LDAP database.
   * 
   * @param $base
   *   The search base. If NULL, we use $this->basedn
   * @param $user
   *   The username or DN to bind against. If NULL, we use $this->binddn
   * @param $pass
   *   The password search base. If NULL, we use $this->bindpw 
   *
   */
  function bind($user = NULL, $pass = NULL) {
    $user = ($user != NULL) ? $user : $this->binddn;
    $pass = ($pass != NULL) ? $pass : $this->bindpw;

    // Ensure that we have an active server connection.
    if (!$this->connection) {
      watchdog('ldap', "LDAP bind failure for user %user. Not connected to LDAP server.", array('%user' => $dn));
      return;
    }

    if (!ldap_bind($this->connection, $userdn, $pass)) {
      watchdog('ldap', "LDAP bind failure for user %user. Error %errno: %error", array('%user' => $user, '$errno' => ldap_errno($this->connection), '%error' => ldap_error($this->connection)));
      return;
   }
  }

  /**
   * Disconnect (unbind) from an active LDAP server.
   */
  function disconnect(){
    if (!$this->connection) {
      watchdog('ldap', 'LDAP disconnect failure from '. $this->server_addr . ':' . $this->port);
    }

  ldap_unbind($this->connection);
  $this->connection = NULL;
  }

// vim:fenc=utf-8:ft=php:ai:si:ts=2:sw=2:et:
retsamedoc’s picture

Additional thoughts on what our final result should be is a series of modules and sub-modules that use LDAP API but remain separated in order to keep it maintainable. We do not want to fall in the trap that so many others have with monolithic codebases.

What I see/hope/wish is to someday see this in admin/build/modules:

The Lightweight Directory Access Protocol Package (and sub-modules)

  • LDAP API (Stable Middleware library; handles server configuration)
  • LDAP Authentication (LDAP<->User Synchronization; including password management)
  • LDAP Authorization (LDAP<->Role Synchronization)
  • LDAP Profile (LDAP<->Profile Syncronization)
  • LDAP Content Profile (LDAP<->Content_Profile Syncronization)
  • LDAP Views (Provides Views with the ability to access LDAP data)
  • etc...

I figure that LDAP Authentication and Authorization should remain as sub-modules to LDAP API (without them, LDAP API is not very useful on it's own). The others should be separate projects.

ebeyrent’s picture

Version: » 6.x-6.x-dev

I'll be happy to work on the Groups integration. The work I did on the extended_ldapgroups module is a good start, but I'd love to get it working as part of this effort. The interesting part of this is that the Authentication and Authorization are really tied together, and the challenge there is to do it in a decoupled way.

Any thoughts regarding how you think we should tackle this?

retsamedoc’s picture

I don't think it would be that difficult. The authentication would only touch the 'users' table while authorization would touch the 'roles' table. Both have been done before in LDAP Integration (LDAP Auth and LDAP Groups).

I'm currently reading up on how to properly handle external authentication (apparently you need to use hook_user, user_external_login, and a handful of other functions; using the builtin OpenID module as an example). I suppose it would be worthwhile for you to open a new issue involving the authorization and post some code. It would be useful to know which functions you need and what each one does so that we can determine if they make sense to include in the API. Does that sound good?

ebeyrent’s picture

I guess what I am getting at is that if Authentication handles sync of users, part of that is the user's groups/roles. When the user authenticates, we need to make sure that no new groups have been added to the user account in LDAP. If they have, we need to grant the matching role in Drupal. I think that all of that functionality, as you mentioned in #4, should happen in the Authorization module. I can pull a list of ldap functions that I use in the ldap_extendedgroups module so that we can include them in the API, but might it be a good idea to include all of the ldap functions in the API?

If you want to look at another example of remote authentication, you can take a look at the Crowd SSO module (http://drupal.org/project/crowd).

retsamedoc’s picture

Not entirely true. Both modules can tie in to Drupal's login system and run when appropriate. The point would be to allow for somebody to use LDAP for roles but have another method handle login (like using Kerberos 5 with HTTPAuth + mod_krb5 + SPNEGO). That is my classic example since plenty of site use a combination of Kerberos and LDAP. I'm sure there are plenty of other examples that make me seem a little less crazy.

Thanks for the heads up about Crowd SSO, I'll definitely take a look.

retsamedoc’s picture

I've committed all my work done thus far. It is mostly a skeleton but I really wanted to get some code somewhere. I was attempting to make the whole API very object oriented, using the phpLDAPadmin project as an example. I will continue to hash out how the different object should interact, but in general: 'servers'->array('server'->array('entry'->array('attribute'($key=>$value))))

This along with a few generic helper functions for each object type should provide the bulk of the API. I've even gone so far as to extend the attribute classes for special types. The hope is to be able to provide some input sanitation and syntax handling BEFORE we attempt to modify LDAP. Should also provide enough abstraction that our API can handle any particulars between OpenLDAP, Netscape Directory, Active Directory, etc without any future Drupal modules having to care.

johnbarclay’s picture

My initial code is in head. I'm converting it to D7 also. I'm definately on board with focus on the api. I tried to even separate out the server from the api, but no luck. Do you both agree on these points:

- the ldap server configuration interface should be in the ldap api module
- an ldap server instance should be represented as an object/class in our code
- authentication, authorization, etc. should be in sub or other modules
- a functional requirement of the api is for authorization and authentication to be separateable.

Are you also in agreement on these design principles?

  • accessible ui
  • Simpletest Coverage
  • Patterns and Features Support
  • Internationalization
  • Provide Adequate Hooks
  • PDO in D7; no SQL
  • Drupal Coding
  • no PHP4 support
  • doxygen

I think a wiki is in order since its time to flush out functions and structure. I'm going to create a wiki page in the ldap integration group on gdo. I just found the group and joined it. (http://groups.drupal.org/ldap-integration-development-and-modules)

johnbarclay’s picture

Not my favorite wiki ui, but I think its good that its on the drupal site. http://groups.drupal.org/node/68688

ebeyrent’s picture

I agree with all your points. I would definitely like to spend more time flushing out the functions and structure before doing too much coding.

johnbarclay’s picture

There is a middle ground between authorization and authentication. There are often feature requests in ldapauth for the ability to filter which ous can authenticate, or some other filter disallowing authentication by valid ldap user, who just don't have the correct characteristics.

Thus an ldap authn and an ldap authz module could use some of the same functions, but would end up with different mapping/filtering interfaces.

This will sort itself out when we have the ldap authn and an ldap authz modules.

myxelf’s picture

Subscribing...

johnbarclay’s picture

Status: Active » Closed (duplicate)

this module moved to the project/ldap namespace. closing issue.