This is a general discussion thread for ldap provisioning functionality in LDAP 7.x-2.x . The goal is use cases being articulated and covered. Bugs and clearly distinct feature requests should be separate issues.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

johnbarclay’s picture

I committed the current user interface changes to ldap_user. I'm looking for feedback on if the ldap user interface appears to meet people's use cases. The code behind it for provisioning is not finished yet. If you don't want to install it, you can the UI in the following video. Keep in mind I haven't used any of the drupal to ldap provisioning in the past, so feedback will be very helpful.

http://screencast.com/t/SjcoeScigUqM

Design Decisions and Feedback Needed:
- does it look like it meets your use cases based on the user interface options?
- can a single drupal user property, field, etc be limited to synching in only one direction? e.g. mail, name, first name, etc. I believe this is useful for keeping it simple and avoiding synch order issues; but does it not meet your use cases?
- should fields like puid that are controlled by an ldap module alone be visible in the UI at all? I think they are illustrative, but add an element of confusion.

These 2 files may be illustrative also:

http://drupalcode.org/project/ldap.git/blob/refs/heads/7.x-2.x:/ldap_use...
http://drupalcode.org/project/ldap.git/blob/refs/heads/7.x-2.x:/ldap_use...

johnbarclay’s picture

Making progress on this:
- simpletests are working again in 2.x branch except for authorization. Fixed some small 2.x bugs along the way.

My next steps are to implement the api functions for provisioning to ldap and do test coverage of the api. These are the LdapUserConf methods analogous to:

  • ldapUserConf->synchToDrupalAccount()
  • ldapUserConf->deleteDrupalAccount()
  • ldapUserConf->provisionDrupalAccount()
  • ldapUserConf->entryToUserEdit()

which I guess will be:

  • ldapUserConf->synchToLdapEntry()
  • ldapUserConf->deleteLdapEntry()
  • ldapUserConf->provisionLdapEntry()
  • ldapUserConf->drupalUserToLdapEntry()
johnbarclay’s picture

The following is all in 7.x-2.x-dev. Still in a rough state.

I roughed these functions out over the last few days:

provision to drupal (seehttp://www.gliffy.com/go/publish/3664260/ )

  • $ldapUserConf->synchToDrupalAccount($account, &$user_edit, $synch_context, $ldap_user = NULL, $save = FALSE)
  • $ldapUserConf->entryToUserEdit($ldap_user, $ldap_server, &$edit, $synch_context, $op)
  • $ldapUserConf->deleteDrupalAccount($username, $synch_context)
  • $ldapUserConf->provisionDrupalAccount($account = FALSE, &$user_edit, $synch_context = LDAP_USER_SYNCH_CONTEXT_INSERT_DRUPAL_USER, $ldap_user = NULL, $save = TRUE)

provision to ldap: (see http://www.gliffy.com/go/publish/3664796/ )

  • $ldapUserConf->synchToLdapEntry($account, $synch_context, $ldap_user_entry = array())
  • $ldapUserConf->deleteCorrespondingLdapEntry($account)
  • provisionLdapEntry
  • $ldapUserConf->drupalUserToLdapEntry($account, $ldap_server, $ldap_user_entry = array(), $synch_context, $op)
  • $ldapUserConf->provisionLdapEntry($account = FALSE, $synch_context = LDAP_USER_SYNCH_CONTEXT_INSERT_DRUPAL_USER, $ldap_user = NULL)

And tied them into the following hooks:

  • hook_user_insert()
  • hook_user_update()
  • hook_user_delete()
  • hook_user_login()

My next steps are vaguely:

  • write mock server behavior to emulate writing to ldap
  • write api test calls for the new functions above that aren't already covered
  • fix synch mapping function so ldap_user module configured fields behave like other module provided fields
  • clean up drupal user provision method. its a bit of a mess
  • get writeable ldap test server up to test provisioning to ldap
  • implement functions to resolve puid conflicts and cname changes.
Renee S’s picture

I'd love to help test, if there's something testable :)

johnbarclay’s picture

Shouldn't be too long. I had to alter a bunch of code for the UI to deal with provisioning to LDAP. I have 4 days free this week to work on this.

Its coming together nicely, but not useable. So if you want to schedule some testing time Monday, that would be ideal. If you have specific use cases and can articulate them, that is always helpful also.

The last commit may be functional for provisioning/synching to from ldap to drupal.

taquil’s picture

I also would like to participate in this. We have a D6 site currently for our Intranet that authenticates against an AD for our employees. We are looking at migrating that to a D7 installation that would function as intranet as well as a new public website.

We currently have the live employee AD and the test client LDAP running and the D7 install works for authenticating either employees or clients pre-loaded in that LDAP.

Employees are not be able to edit their info in Drupal at all, any changes to name, email, or password would have to be handled internally, and in all cases employees are created in their AD first before hire, so they'd never have to request an account through Drupal. Basically, for employees, AD is the authority and any changes are made by the AD admins.

For the public side, our clients would authenticate against a new LDAP. Ideally, clients would request a new account through Drupal, and, when the status changes from Blocked to Active, would create their record in the client LDAP. Clients should be able to change their basic info, like email address, as well as update their password in Drupal, and that would then be transmitted to LDAP. The only other thing that might require synching is the Drupal role, which would map to a LDAP group. We currently have 2 different tiers of client access to our current non-Drupal website and that would be carried over in the form of Drupal roles. It's rare, but if a client was to move from one group to the other, it would be nice to be able to have that happen in Drupal and then the change be reflected by mapping that Drupal role to a LDAP group. At least, that's the basic premise.

I will download the latest 7.x.2 instance and see where I get with it.

Edit: actually, I won't yet. It looks like there are some dependencies and obstacles to doing that at this moment. But I will be watching this thread to see if there's any feedback/guidance.

johnbarclay’s picture

FileSize
153.5 KB

In working on the drupal to ldap direction, I noticed a clear need for being able to use a string of tokens to generate the ldap attribute. For example "[user.field.firstname] [user.field.lastiname]" might map to the ldap attribute "displayName". I implemented this and am still working through some of the UI.

What I'm looking for is feedback on if the user interface options for provisioing to LDAP make sense and will meet your use cases.

Here is a screenshot and video of the UI. The video is quite dramatic ;)

http://screencast.com/t/FH14Mu9Jg

taquil’s picture

That looks pretty good. The concatting of different fields into a string I think is essential. If possible, some sort of explicit text added would also be good. For instance, we'd like to have our clients be put into groups, so adding a mapping of something like naming a group to put them in that would be derived from a drupal role. Then you can state something like the LDAP attribute "gidNumber" would be set to "10000" or "members" or something that is not included in the user profile (that I'm aware of).

Another idea could be performing some sort of operation on the value once created, like pack({this value}), or trimming a value down to a certain number of characters, or deriving a name from an email address. This is probably far beyond the scope of what you want to do, but it's the sort of thing that occurs to me looking at the way we can manipulate data we get from LDAP/AD going the other way.

johnbarclay’s picture

Yeah. These all make sense. Essentially we need the feature set of feeds and feeds tamper. I wanted to make feeds a requirement for this, but a 7 version is far off. I wonder if there is a way of leveraging feeds tamper in some way?

johnbarclay’s picture

FileSize
118.31 KB

I committed the latest round of ldap user mapping interface. Though the synching/provisioning to ldap isn't functional, the UI is. Attached is an image attempting to illustrate some use cases by taquil such as constants being mapped.

The work in #1543382: LDAP Profile: Not syncing ldap fields to user profile fields is sort of broken until some code is added to account for the tokens (http://drupal.org/node/1245736) that should be used in the ldap attribute column now. e.g. using "[lname]" instead of "lname". This change is to allow for literals and concatenation of multiple ldap attributes per #8. My next task is to deal with the token syntax change.

The feeds tamper plugins could be integrated into the ui in some way; but the feeds tamper UI itself would be hard to mangle into a useful UI. If we got feeds tamper integration working, we could write a feeds tamper plugin for dealing with binary attribute conversion and this would help with ldap feeds also.

I'm putting the following on the "later" list.

  • add validation
  • add some CSS to make sections clearer and generally improve usability
  • allow for feeds tamper plugins be configured and act on mappings
  • add some js to disable disallowed directions for selected user attributes
johnbarclay’s picture

FileSize
101.83 KB

I finished with the token changes in ldap attributes and committed this. Wanted to alert those using 2.x-dev of the following changes:

1. ldap attribute column in servers mappings table now require token format for non literals. Values should be of form [dn], [dept:0], [jpegPhoto;toBase64], etc. with brackets around them. This is to allow for contants/literals to be mapped to user fields. It also allows for ldap token functionality http://drupal.org/node/1245736.

2. To do this, I got rid of
ldap_server->getAttributeValue() method and replaced the call with it to a call to ldap_servers_token_replace(). I think if we use ldap_servers_token_replace() consistently, the ldap token syntax will be easier to support and our implementation of modifiers such as ;toBase64 can be dealt with in 1 place. There is some room for performance/caching work in ldap_servers_token_tokenize_entry() though.

Here's the gist of the change in ldapuserconf.class.php:

        if (!ldap_servers_token_is_token($field_detail['ldap_attr'])) {
          $value = $field_detail['ldap_attr']; // literal value
        }
        else {
          // And that we have a value for this attribute in the ldap entry.
          $value = ldap_servers_token_replace($ldap_user, $field_detail['ldap_attr']);
          if ($value === FALSE) {
            continue; // if attribute value doesn't exist, do not evaluate.
          }
        }

the modifiers such as ;toBase64 still need to be implemented in ldap_servers_token_tokenize_entry();

johnbarclay’s picture

Made some progress getting the simpletest coverage for ldap 7.x-2.x working again. In the process fixed a recursion problem where user_save() calls within ldap user could trigger additional user_save() calls depending on which ldap user event handlers were enabled. Should have solid test coverage of ldap to drupal provisioning and ldap user UI in the next day or two.

The code for drupal to ldap provisioning is there, but has no test coverage so is still likely not functional.

All in all, its 2.0 is finanlly starting to come together instead of spiralling outward.

johnbarclay’s picture

Had a good week on ldap_user working on test coverage and bugs. Finished test coverage of ldap to drupal provisioning. Moving on to drupal to ldap provisioning next since they fit in the same part of the test framework. Will cover UI tests later.

Summary

Here are some of the bugs that were found and fixed.

  • token strings like "[cn]@mycompany.com" were not being evaluated correctly
  • token strings with multiple tokens like "[givenname] [sn]" were not being evaluated correctly
  • some ldap_servers_attributes_needed and ldap_user_conf caching issues which likely would only come up in simpletests
  • some fixes for what attributes are needed by ldap user in different synching and provisioning contexts
  • broken ldap_servers_token_tokenize_entry() function fixed
  • bug where email field was cleared out in some synch contexts

Here are the last 3 committs. They are kinda messy since the simpltest debugging requires alot of debug() statements.

johnbarclay’s picture

Synching to drupal is now functional and has simpletest coverage. The synch contexts part needs some documentation and maybe simplification yet. I also added some validation to the mapping table/form.

Tests 1-8 of http://drupalcode.org/project/ldap.git/blob_plain/refs/heads/7.x-2.x:/ld... illustrate how to test manually.

The testFunctionsAndInstall() method in http://drupalcode.org/project/ldap.git/blob_plain/refs/heads/7.x-2.x:/ld... is where the automated tests are, which also illustrate the functionality.

I'm continuing on with the drupal to ldap provisioning and synching next, but wanted to check in.

@Reinette, testing of that functionality would be great. And if you want to write some documentation or suggestions for the UI wording, that would also be very welcome.

@boran, let me know if I broke anything in your synching commit.

@taquil, would love to tie feeds tamper into this for some of the functionality you suggest, but need a way to do so without overwhelming an already complex ui. And feeds tamper requires feeds so I think another approach may be better.

johnbarclay’s picture

Had a good run the last 4 days. Here are some results:

Provisioning to ldap is pretty far along, but needs some testing in real environments.

johnbarclay’s picture

In provision ldap entries from drupal accounts, there's the possibility of 0 to many ldap entries per drupal user; though I don't think there are many use cases for it.

So for the event delete ldap entry when drupal account is deleted to function, I added a "ldap_user_prov_entries" field that takes multiple values to the user entity. Each time an ldap entry is provisioned from a drupal account, server id|dn is stored in this field.

Then when the deleteProvisionedLdapEntries() method is called, it just loops through this field and deletes the entries.

In practicality there would likely only be 1 entry in the field.

This is in the most recent commit and requires an update.

johnbarclay’s picture

Provisioning to LDAP is ready for testing. A rough outline of manual tests are at: http://drupalcode.org/project/ldap.git/blob_plain/refs/heads/7.x-2.x:/ld...

Patches or comments on UI, validation, errors, and documentation are also desired as this is a not the easiest thing to configure.

There are still some bugs and features needed for the 2.0 branch, but provisioning to ldap is largely done and in need of more eyes. The full list is: http://drupal.org/project/issues/search/ldap?text=&assigned=&submitted=&...

Below are the mappings for provisioning to ldap for an active directory LDAP as an example with an attached image. The form at admin/config/people/ldap/user/test is also useful for testing.

  'ldapUserSynchMappings' => array(
      2 => array(
        'uiuc_prov_ad' => array(
          '[dn]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[dn]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'cn=ed-drupal-[property.name],ou=test,ou=webs,ou=people,dc=ad,dc=mycompany,dc=com',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[cn]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[cn]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'ed-drupal-[property.name]',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[sn]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[sn]',
            'user_attr' => '[field.field_user_lname]',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'Doe',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[givenname]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[givenname]',
            'user_attr' => '[field.field_user_fname]',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'Jane 345435',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[displayname]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[displayname]',
            'user_attr' => '[field.field_display_name]',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'ed-drupal-[property.name] Test User',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[samaccountname]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[samaccountname]',
            'user_attr' => '[property.name]',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'fdgdfsgdfsgdsfgdfgdfsg',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[objectclass:0]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[objectclass:0]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'top',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[objectclass:1]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[objectclass:1]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'person',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[objectclass:2]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[objectclass:2]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'organizationalPerson',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[objectclass:3]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[objectclass:3]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'user',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[description]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[description]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'Drupal Provisioned LDAP Account',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[mail]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[mail]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'ed-drupal-[property.name]@illinois.edu',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[distinguishedName]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[distinguishedName]',
            'user_attr' => 'user_tokens',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => 'cn=ed-drupal-[property.username],ou=test,ou=webs,ou=people,dc=ad,dc=mycompany,dc=com',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
          '[userpassword]' => array(
            'sid' => 'uiuc_prov_ad',
            'ldap_attr' => '[userpassword]',
            'user_attr' => '[password.user-none]',
            'convert' => 0,
            'direction' => 2,
            'user_tokens' => '',
            'config_module' => 'ldap_user',
            'synch_module' => 'ldap_user',
            'enabled' => 1,
            'contexts' => array(
              0 => 1,
              1 => 2,
            ),
          ),
Anonymous’s picture

johnbarclay,
First, thank you so much for all the work on this very important module. I am just now implementing v7.x-1.x and realized it was only a READ from the directory (AD, in my case.) I would really like to have our HR dept create the user in a nice Drupal form that would then create the user in AD. I see that is precisely what you are writing for the 2.x version.

I will need to implement v1.x first so we can at least have all AD users have an account in Drupal. Will this be a problem when implementing v2.x later? I assume the links between Drupal and AD will be fine when upgrading?

I would be happy to test v2.x for you in an Active Directory environment. I assume it is NOT ready to be used in a LIVE environment, right?

Thanks!

johnbarclay’s picture

I'm committed to an upgrade path between 7.x-1.x Release Candidate and 7.x-2.x Release Candidate, but don't have a commitment to a timeline on the updgrade code.

7.x-2.x is not ready for a live environment and I would argue 7.x-1.x isn't either. 7.x-2.x may be done first though because I have funding for some progress on it and active, articulate testers on it. It really depends on your timeline and what functionality you need which to go with. I have four days set aside for 2.x this and next week, so may be easier to make a call in the next week on which to go with.

Anonymous’s picture

Thank you for your response. In your opinion, would you say that 2.x is just as reliable as 1.x, then? Since they are both actually in RC state, it might make sense for me to go straight to the 2.x version.

Again, I'd be glad to be a tester for you.

Thanks!

johnbarclay’s picture

Neither is in RC state. I would say 1.x is more reliable. In a week it will likely be 2.x

Anonymous’s picture

Oh, OK. I will hold off until the next major 2.x release and update to that when it is ready.

Thanks!

Anonymous’s picture

Just wanted to touch base with you and see if you had an expected release date, yet? Thanks!

johnbarclay’s picture

No. I have more time the next couple weeks and some other developers are pitching in also. I expect it will be useable in 3 weeks. But it won't be a release candidate, just and alpha or beta depending on how much testing people do.

Anonymous’s picture

Thank you for the update. I REALLY appreciate it!

johnbarclay’s picture

Some recent commits in 7.x-2.x-dev are related to provisioning to ldap. Any help testing these would be useful.

ocran’s picture

Hi John,

I am currently working with 7.x-2.0-beta3+52-dev attempting to have accounts which are created by an administrator in drupal to automatically create the associated ldap entry.

Note that I have verified that I can bind and search with with my service account.

The first issue that I have came across is the following, found on the administrator's "add user" page"

[_]Create corresponding LDAP entry.
To enable this an LDAP server must be selected for provisioning to Drupal in admin/config/people/ldap/user and manual creation of LDAP accounts must be enabled also.

I can't seem to enable this option, regardless of settings Administration » Configuration » People » LDAP Configuration » USER.

With that being said I am not sure if it should even be provided(as an option), considering I have the following selected in "BASIC PROVISIONING TO LDAP SETTINGS":

[X]Create or Synch to LDAP entry when a Drupal account is created or updated. Only applied to accounts with a status of approved.
[_]Create or Synch to LDAP entry when a user authenticates.
[X]Delete LDAP entry when the corresponding Drupal Account is deleted. This only applies when the LDAP entry was provisioned by Drupal by the LDAP User module.

With the above settings, when I create a user account in Drupal I don't even get any activity on the ldap server (slapd -d 1).

If I select the radio button: "Make this an LDAP Associated account. If a related LDAP account can not be found, a validation error will appear and the account will not be created."

I am provided with the error(with activity on the ldap server):

User my_username does not have a corresponding LDAP Entry (dn). Under LDAP options, you may NOT select "Make this an LDAP Associated Account"

Which then brings me full circle back to the original problem.

Rather than filling this reply with even more information I am going to wait for further direction.

For the sake of completeness, I do not have my ldap server selected in "BASIC PROVISIONING TO DRUPAL ACCOUNT SETTINGS"

Also, please see the attachment Test_LDAP_UserConfiguration.txt

Thanks!

johnbarclay’s picture

Thanks. Please post issues as appropriate to a different thread. There are some directions when creating a new issue. But some of this may relate to existing issues.

grahl’s picture

Issue summary: View changes
Status: Active » Closed (outdated)

Please open separate tickets for regressions or new feature requests in regards to provisioning.