Hi, I'm desiging a scripting language binding for interfacing with AD (and other LDAP services). Currentlyy the target language is PHP but I will likey be doing Python as well as possibly others. Anyway I thought I would consult the community before writing this up so if you have the time (this is somewhat lengthy) I would apprecitate your feedback.
The only requirements for the binding is that it have full coverage WRT getting, modifying, adding, deleting, and searching and that it be as simple as possible but no simpler as one would expect when using a scripting language. The simplest "getting" case is easy. You create an associative array with the names of the attributes you're interested in and call a function that returns an associative array of attributes with values. Consider the following script: $attrs = array("userPrincipalName", "userAccountControl"); $acct = account_get(NULL, "[EMAIL PROTECTED]", $attrs); echo "userPrincipalName: " . $acct['userPrincipalName'] . "\n"; echo "userAccountControl: " . $acct['userAccountControl'] . "\n"; This might print: userPrincipalName: [EMAIL PROTECTED] userAccountControl: 544 This doesn't address data type issues however. How do I specify that an attribute is a string, binary and/or multivalued? It seems there are three solutions to this. 1) Create a local database of metadata indicating that an attribute is multivalued or not and string or binary. This is pretty much what Java's JNDI does (albeit somewhat clumsey IMO). 2) Provide functions to query the context object such as account_get_str or account_get_binary, account_get_multivalued_str, .. etc. This is pretty much what the Microsoft ADSI providers do. 3) Provide attribute modifiers with the attribute names array to tell the binding to construct arrays for multivalued attributes, convert strings, etc. The first option is a reasonable solution. The second option seems like it's not "as simple as possible but not simpler" as it is tantamount to explicit type casting and the scriptor is required to repeatedly assert the type by using the approriate function. The third option is nice because the objects are automatically typed correctly. If we explore the 3rd option, consider the following code that prints all memberOf attributes: $attrs = array("multivalued(memberOf)"); $acct = account_get(NULL, "[EMAIL PROTECTED]", $attrs); $mos = $acct['memberOf']; foreach ($mos as $mo) { echo "memberOf: $mo\n"; } The key part above is the "multivalued(...)" function-like modifier which indicates that $acct['memberOf'] should be an array of strings. A function-like modifier is used to clearly separate it from existing attribute modifiers like 'jpegPhoto;binary' that are passed through to the raw LDAP api. If no attribute modifiers or function-like modifers are specified the attribute is assumed to be a string and will be converted from UTF-8 to the locale encoding. To specify a multivalued binary array is desired one would use "multivalued(name;binary)". This method is also extensible. There could be function-like modfiers for converting values to base64 or converting a binary sid to a sid string (this would not be reasonable with the first option). Consider the following example: $attrs = array("userPrincipalName", "base64(objectGUID;binary)", "sidstr(objectSid;binary)", "multivalued(memberOf)"); $acct = account_get(NULL, "[EMAIL PROTECTED]", $attrs); foreach ($acct as $name => $value) { if (!is_array($value)) { echo "$name: $value\n"; } else { foreach ($value as $v) { echo "$name: $v\n"; } } } This might print the following: userPrincipalName: [EMAIL PROTECTED] objectGUID: Szm2n2e8M0SA1Hz0QGgOnw== objectSid: S-1-5-21-4133388447-792352518-2001609813-1159 memberOf: CN=Managers,CN=Users,DC=example,DC=com memberOf: CN=CMS Admin,CN=Users,DC=example,DC=com To modify an entry the $attrs array is reused like: $attrs = array("distingushedName", "displayName"); $acct = account_get(NULL, "[EMAIL PROTECTED]", $attrs); $acct['displayName'] = "James T. Kirk"; account_modify(NULL, $acct, $attrs); Searching might look like the following: $attrs = array("userPrincipalName", "multivalued(memberOf)"); $accts = account_search(NULL, "DC=example,DC=com", "sub", $attrs, "(objectClass=user)"); foreach ($accts as $acct) { echo "userPrincipalName: " . $acct['userPrincipalName'] . "\n"; $mos = $acct['memberOf']; foreach ($mos as $mo) { echo " memberOf: $mo\n"; } } So what do you think? Does anyone see any problem with any of this? Does anyone have any ideas for improvments? Thanks for your time, Mike -- Michael B Allen PHP Active Directory SSO http://www.ioplex.com/ List info : http://www.activedir.org/List.aspx List FAQ : http://www.activedir.org/ListFAQ.aspx List archive: http://www.mail-archive.com/activedir@mail.activedir.org/