]> git.mjollnir.org Git - moodle.git/commitdiff
Enrol/LDAP - initial commit, a bit rough around the edges.
authormartinlanghoff <martinlanghoff>
Mon, 22 Nov 2004 02:41:41 +0000 (02:41 +0000)
committermartinlanghoff <martinlanghoff>
Mon, 22 Nov 2004 02:41:41 +0000 (02:41 +0000)
This code is in production in a high-volume environment, so it has already proven to be reliable and scalable. Configuration is still tricky, and some corner cases may or may not be handled elegantly.

Please test!

enrol/ldap/config.html [new file with mode: 0755]
enrol/ldap/enrol.php [new file with mode: 0755]
enrol/ldap/enrol_ldap_sync.php [new file with mode: 0755]
lang/en/enrol_ldap.php [new file with mode: 0755]

diff --git a/enrol/ldap/config.html b/enrol/ldap/config.html
new file mode 100755 (executable)
index 0000000..dfc2815
--- /dev/null
@@ -0,0 +1,295 @@
+<?php // initialize variables
+
+global $THEME;
+
+// general
+optional_variable($frm->enrol_ldap_host_url, '');
+optional_variable($frm->enrol_ldap_version, '');
+optional_variable($frm->enrol_ldap_bind_dn, '');
+optional_variable($frm->ldap_bind_pw, '');
+// student & teacher enrol
+optional_variable($frm->enrol_ldap_student_contexts, '');
+optional_variable($frm->enrol_ldap_student_memberattribute, '');
+optional_variable($frm->enrol_ldap_teacher_contexts, '');
+optional_variable($frm->enrol_ldap_teacher_memberattribute, '');
+optional_variable($frm->enrol_ldap_objectclass, '');
+optional_variable($frm->enrol_ldap_course_idnumber_updatelocal, '');
+// fields
+optional_variable($frm->enrol_ldap_course_idnumber, '');
+optional_variable($frm->enrol_ldap_course_idnumber_updatelocal, false);
+optional_variable($frm->enrol_ldap_course_idnumber_editlock,    false);
+optional_variable($frm->enrol_ldap_course_fullname, '');
+optional_variable($frm->enrol_ldap_course_fullname_updatelocal, false);
+optional_variable($frm->enrol_ldap_course_fullname_editlock,    false);
+optional_variable($frm->enrol_ldap_course_shortname, '');
+optional_variable($frm->enrol_ldap_course_shortname_updatelocal, false);
+optional_variable($frm->enrol_ldap_course_shortname_editlock,    false);
+optional_variable($frm->enrol_ldap_course_summary, '');
+optional_variable($frm->enrol_ldap_course_summary_updatelocal, false);
+optional_variable($frm->enrol_ldap_course_summary_editlock,    false);
+// autocreate
+optional_variable($frm->enrol_ldap_autocreate, false);
+optional_variable($frm->enrol_ldap_category, 1);
+optional_variable($frm->enrol_ldap_template, '');
+
+?>
+
+<table cellspacing="0" cellpadding="5" border="0" align="center">
+<tr>
+   <td colspan="2">
+        <h4><?php print_string("enrol_ldap_server_settings", "enrol_ldap") ?> </h4>
+   </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+       <td align="right"><P>enrol_ldap_host_url:</td>
+       <td>
+        <input name="enrol_ldap_host_url" TYPE="text" SIZE="30" value="<?php echo $frm->enrol_ldap_host_url?>">
+       <?php  if (isset($err["enrol_ldap_host_url"])) formerr($err["enrol_ldap_host_url"]); ?>
+       </td>
+    <td>
+    <?php  print_string("enrol_ldap_host_url","enrol_ldap") ?>
+    </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+       <td align="right"><P>enrol_ldap_version:</td>
+       <td>
+    <?php
+       $versions[2] = "2";
+       $versions[3] = "3";
+       choose_from_menu($versions, "enrol_ldap_version", $frm->enrol_ldap_version, "");
+          if (isset($err["enrol_ldap_version"])) formerr($err["enrol_ldap_version"]); 
+    ?>
+       </td>
+    <td>
+    <?php  print_string("enrol_ldap_version","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+    <td align="right"><P>enrol_ldap_bind_dn:</td>
+    <td>
+    <input name="enrol_ldap_bind_dn" type="text" size="30" value="<?php echo $frm->enrol_ldap_bind_dn?>">
+    <?php  if (isset($err["enrol_ldap_bind_dn"])) formerr($err["ldap_bind_dn"]); ?>
+    </td><td>
+    <?php  print_string("enrol_ldap_bind_dn","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+    <td align="right"><P>ldap_bind_pw:</td>
+    <td>
+    <input name="enrol_ldap_bind_pw" type="text" size="30" value="<?php echo $frm->enrol_ldap_bind_pw?>">
+    <?php  if (isset($err["enrol_ldap_bind_pw"])) formerr($err["enrol_ldap_bind_pw"]); ?>
+    </td><td>
+    <?php  print_string("enrol_ldap_bind_pw","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr>
+   <td colspan="2">
+        <h4><?php print_string("enrol_ldap_student_settings", "enrol_ldap") ?> </h4>
+   </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+       <td align="right"><P>enrol_ldap_student_contexts:</td>
+       <td>
+    <input name="enrol_ldap_student_contexts" TYPE="text" SIZE="30 "value="<?php echo $frm->enrol_ldap_student_contexts?>">
+    <?php  if (isset($err["enrol_ldap_student_contexts"])) formerr($err["enrol_ldap_student_contexts"]); ?>
+    </td>
+    <td>
+    <?php  print_string("enrol_ldap_student_contexts","enrol_ldap") ?>
+    </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_student_memberattribute:</td>
+        <td>
+    <input name="enrol_ldap_student_memberattribute" type="text" size="30" value="<?php echo $frm->enrol_ldap_student_memberattribute?>">
+    <?php  if (isset($err["enrol_ldap_student_memberattribute"])) formerr($err["enrol_ldap_student_memberattribute"]); ?>
+    </td><td>
+    <?php  print_string("enrol_ldap_student_memberattribute","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr>
+   <td colspan="2">
+        <h4><?php print_string("enrol_ldap_teacher_settings", "enrol_ldap") ?> </h4>
+   </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+       <td align="right"><P>enrol_ldap_teacher_contexts:</td>
+       <td>
+    <input name="enrol_ldap_teacher_contexts" TYPE="text" SIZE="30 "value="<?php echo $frm->enrol_ldap_teacher_contexts?>">
+    <?php  if (isset($err["enrol_ldap_teacher_contexts"])) formerr($err["enrol_ldap_teacher_contexts"]); ?>
+    </td>
+    <td>
+    <?php  print_string("enrol_ldap_teacher_contexts","enrol_ldap") ?>
+    </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_teacher_memberattribute:</td>
+        <td>
+    <input name="enrol_ldap_teacher_memberattribute" type="text" size="30" value="<?php echo $frm->enrol_ldap_teacher_memberattribute?>">
+    <?php  if (isset($err["enrol_ldap_teacher_memberattribute"])) formerr($err["enrol_ldap_teacher_memberattribute"]); ?>
+    </td><td>
+    <?php  print_string("enrol_ldap_teacher_memberattribute","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr>
+   <td colspan="2">
+        <h4><?php print_string("enrol_ldap_course_settings", "enrol_ldap") ?> </h4>
+   </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+    <td align="right"><P>enrol_ldap_objectclass:</td>
+    <td>
+    <input name=enrol_ldap_objectclass type="text" size="30" value="<?php echo $frm->enrol_ldap_objectclass?>">
+    <?php  if (isset($err["enrol_ldap_objectclass"])) formerr($err["enrol_ldap_objectclass"]); ?>
+    </td>
+    <td>
+    <?php  print_string("enrol_ldap_objectclass","enrol_ldap") ?>
+    </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_course_idnumber:</td>
+        <td>
+    <input name="enrol_ldap_course_idnumber" type="text" size="30" value="<?php echo $frm->enrol_ldap_course_idnumber?>">
+    <?php  if (isset($err["enrol_ldap_course_idnumber"])) formerr($err["enrol_ldap_course_idnumber"]); ?>
+    <div align="right">
+    <?php  print_string("enrol_ldap_updatelocal", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_idnumber_updatelocal">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_idnumber_updatelocal ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_idnumber_updatelocal ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select><BR>
+    <?php  print_string("enrol_ldap_editlock", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_idnumber_editlock">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_idnumber_editlock ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_idnumber_editlock ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select></div>  
+    </td><td>
+    <?php  print_string("enrol_ldap_course_idnumber","enrol_ldap") ?>
+    </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_course_shortname:</td>
+        <td>
+    <input name="enrol_ldap_course_shortname" type="text" size="30" value="<?php echo $frm->enrol_ldap_course_shortname?>">
+    <?php  if (isset($err["enrol_ldap_course_shortname"])) formerr($err["enrol_ldap_course_shortname"]); ?>
+    <div align="right">
+    <?php  print_string("enrol_ldap_updatelocal", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_shortname_updatelocal">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_shortname_updatelocal ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_shortname_updatelocal ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select><BR>
+    <?php  print_string("enrol_ldap_editlock", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_shortname_editlock">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_shortname_editlock ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_shortname_editlock ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select></div>
+    </td><td>
+    <?php  print_string("enrol_ldap_course_shortname","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_course_fullname:</td>
+        <td>
+    <input name="enrol_ldap_course_fullname" type="text" size="30" value="<?php echo $frm->enrol_ldap_course_fullname ?>">
+    <?php  if (isset($err["enrol_ldap_course_fullname"])) formerr($err["enrol_ldap_course_fullname"]); ?>
+    <div align="right">
+    <?php  print_string("enrol_ldap_updatelocal", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_fullname_updatelocal">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_fullname_updatelocal ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_fullname_updatelocal ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select><BR>
+    <?php  print_string("enrol_ldap_editlock", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_idnumber_editlock">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_fullname_editlock ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_fullname_editlock ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select></div>
+    </td><td>
+    <?php  print_string("enrol_ldap_course_fullname","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_course_summary:</td>
+        <td>
+    <input name="enrol_ldap_course_summary" type="text" size="30" value="<?php echo $frm->enrol_ldap_course_summary?>">    
+    <?php  if (isset($err["enrol_ldap_course_summary"])) formerr($err["enrol_ldap_course_summary"]); ?>
+    <div align="right">
+    <?php  print_string("enrol_ldap_updatelocal", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_summary_updatelocal">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_summary_updatelocal ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_summary_updatelocal ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select><BR>
+    <?php  print_string("enrol_ldap_editlock", "enrol_ldap") ?>
+    <select name="enrol_ldap_course_summary_editlock">
+        <option value="0" <?php echo ($frm->enrol_ldap_course_summary_editlock ? '' : 'selected="yes"') ?> >
+            <?php  print_string("no")  ?></option>
+        <option value="1" <?php echo ($frm->enrol_ldap_course_summary_editlock ? 'selected="yes"' : '') ?> >
+            <?php  print_string("yes") ?></option>
+    </select></div>
+    </td><td>
+    <?php  print_string("enrol_ldap_course_summary","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr>
+   <td colspan="2">
+        <h4><?php print_string("enrol_ldap_autocreation_settings", "enrol_ldap") ?> </h4>
+   </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+       <td align="right"><P>enrol_ldap_autocreate:</td>
+       <td>
+    <?php
+       choose_from_menu(array('0'=>'no','1'=>'yes'), "enrol_ldap_autocreate", $frm->enrol_ldap_autocreate, "");
+          if (isset($err["enrol_ldap_autocreate"])) formerr($err["enrol_ldap_autocreate"]); 
+    ?>
+       </td>
+    <td>
+    <?php  print_string("enrol_ldap_autocreate","enrol_ldap") ?>
+    </td>
+</tr>
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_category:</td>
+        <td>
+    <?php
+           $displaylist = array();
+           $parentlist = array();
+           make_categories_list($displaylist, $parentlist);
+           choose_from_menu($displaylist, "enrol_ldap_category", $frm->enrol_ldap_category, "");
+           
+    ?>
+    <?php  if (isset($err["enrol_ldap_category"])) formerr($err["enrol_ldap_category"]); ?>
+    </td><td>
+    <?php  print_string("enrol_ldap_category","enrol_ldap") ?>
+    </td>
+</tr>
+
+<tr valign="top" bgcolor="<?php echo $THEME->cellheading2 ?>">
+        <td align="right"><P>enrol_ldap_template:</td>
+        <td>
+    <input name=enrol_ldap_template type="text" size="30" value="<?php echo $frm->enrol_ldap_template?>">
+    <?php  if (isset($err["enrol_ldap_template"])) formerr($err["enrol_ldap_template"]); ?>
+    </td><td>
+    <?php  print_string("enrol_ldap_template","enrol_ldap") ?>
+    </td>
+</tr>
+
+</table>
diff --git a/enrol/ldap/enrol.php b/enrol/ldap/enrol.php
new file mode 100755 (executable)
index 0000000..85519d0
--- /dev/null
@@ -0,0 +1,624 @@
+<?php  // $Id$
+
+require_once("$CFG->dirroot/enrol/enrol.class.php");
+require_once("$CFG->dirroot/course/lib.php");
+require_once("$CFG->dirroot/lib/blocklib.php");
+
+$CFG->enrol_localcoursefield = 'idnumber';
+
+class enrolment_plugin extends enrolment_base {
+
+    var $log;    
+
+/// Leave get_teacher_courses() function unchanged for the time being
+
+
+/// Leave cron() function unchanged
+
+
+/// Overide the base get_student_courses() function
+function get_student_courses(&$user) {
+    global $CFG;
+    parent::get_student_courses($user); // populate known enrolments
+    $this->get_user_courses($user, 'student');
+    return parent::get_student_courses($user);    
+}
+
+/// Overide the base get_teacher_courses() function
+function get_teacher_courses(&$user) {
+    global $CFG;
+    parent::get_teacher_courses($user); // populate known enrolments
+    $this->get_user_courses($user, 'teacher');
+    return parent::get_teacher_courses($user);
+}
+
+/// Overide the base get_student_courses() function
+function get_user_courses(&$user, $type) {
+    global $CFG;
+
+    if(!isset($type) || !($type =='student' || $type =='teacher' )){
+        error("Bad call to get_user_courses()!");
+    }
+    
+
+    // Connect to the external database
+    $ldap_connection = $this->enrol_ldap_connect();
+    if (!$ldap_connection) {
+        @ldap_close($ldap_connection);
+        error("LDAP-module cannot connect to server: $CFG->ldap_host_url");
+        return false;
+    }
+    
+    // we are connected OK, continue...
+
+    /// Find a record in the external database that matches the local course field and local user field
+    /// to the respective remote fields
+    $enrolments = $this->find_ext_enrolments( $ldap_connection, 
+                                    $user->idnumber , 
+                                    $type);
+    
+    foreach ($enrolments as $enrol){
+    
+        $course_ext_id = $enrol[$CFG->enrol_ldap_course_idnumber][0];
+        if(empty($course_ext_id)){
+            error_log("The course external id is invalid!\n");
+            continue; // next; skip this one!
+        }
+        
+        // create the course  ir required
+        $course_obj = get_record( 'course',
+                                  $CFG->enrol_localcoursefield,
+                                  $course_ext_id );
+
+        if (empty($course_obj)){ // course doesn't exist
+            if($CFG->enrol_ldap_autocreate){ // autocreate
+                error_log("CREATE User $user->username enrolled to a nonexistant course $course_ext_id \n");
+                $newcourseid = $this->create_course($enrol);
+                $course_obj = get_record( 'course',
+                                  $CFG->enrol_localcoursefield,
+                                   $newcourseid);
+            } else {
+                error_log("User $user->username enrolled to a nonexistant course $course_ext_id \n");
+            }
+        } else { // the course object exists before we call...
+            if ($courseobj->visible==0) {
+                // non-visible courses don't show up in the enrolled 
+                // array, so we should skip them -- 
+                unset($user->{$type}[$course_obj->id]);
+                continue;
+            }
+        }
+        
+        // deal with enrolment in the moodle db
+        if (!empty($course_obj)) { // does course exist now?     
+            if(isset($user->{$type}[$course_obj->id])){
+                unset($user->{$type}[$course_obj->id]); // remove from old list
+            } else {
+                $CFG->debug=10;
+                if ($type === 'student') { // enrol
+                   error_log("Enrolling student $user->id ($user->username) in course $course_obj->id ($course_obj->shortname) ");
+                   if (!  enrol_student($user->id, $course_obj->id, NULL,NULL, 'ldap')){
+                        error_log("Failed to enrol student $user->id ($user->username) into course $course_obj->id ($course_obj->shortname)");
+                   }
+                } else if ($type === 'teacher') {
+                      error_log("Enrolling teacher $user->id ($user->username) in course $course_obj->id ($course_obj->shortname)");
+                    add_teacher($user->id, $course_obj->id, NULL,NULL,NULL, NULL,'ldap');
+                }
+                $CFG->debug=0;
+            }
+        }
+    }
+
+    // ok, if there's any thing still left in the $user->student or $user->teacher
+    // array, those are old enrolments that we want to remove (or are they?)
+    if(!empty($user->{$type})){
+        $courses = array_keys($user->{$type});
+        foreach ($courses as $courseid){
+            // get the record if it's ldap
+            $rec = get_record('user_' . $type . 's', 'userid', $user->id, 'course', $courseid, 'enrol', 'ldap');
+            if(!empty($rec)){ // this was a legacy 
+                if ($type === 'student') { // enrol
+                    unenrol_student($user->id, $courseid);
+                } else if ($type === 'teacher') {
+                    remove_teacher($user->id, $courseid);
+                }
+                unset($user->{$type}[$course_obj->id]);
+            }
+
+        }
+    }
+
+    @ldap_close($ldap_connection);
+    return true;
+}
+
+/// sync enrolments with ldap, create courses if required.
+function sync_enrolments($type, $enrol) {
+    global $CFG;
+
+    if(!isset($type) || !($type =='student' || $type =='teacher' )){
+        error("Bad call to get_all_courses()!");
+    }
+    $table = array( 'teacher' => 'user_teachers',
+                    'student' => 'user_students');
+    
+    if(!isset($enrol)){
+        $enrol=false;
+    }
+
+    // Connect to the external database
+    $ldap_connection = $this->enrol_ldap_connect();
+    if (!$ldap_connection) {
+        @ldap_close($ldap_connection);
+        error("LDAP-module cannot connect to server: $CFG->ldap_host_url");
+        return false;
+    }
+    
+    // we are connected OK, continue...
+    $this->enrol_ldap_bind($ldap_connection);
+
+    //get all contexts and look for first matching user
+    $ldap_contexts = explode(";",$CFG->{'enrol_ldap_'.$type.'_contexts'});
+
+    // get all the fields we will want for the potential course creation
+    // as they are light. don't get membership -- potentially a lot of data. 
+    $ldap_fields_wanted = array( 'dn', $CFG->enrol_ldap_course_idnumber);
+    if (!empty($CFG->enrol_ldap_course_fullname)){
+        array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_fullname);
+    }
+    if (!empty($CFG->enrol_ldap_course_shortname)){
+        array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_shortname);
+    }
+    if (!empty($CFG->enrol_ldap_course_summary)){
+        array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_summary);
+    }
+    if($enrol){
+        array_push($ldap_fields_wanted, $CFG->{'enrol_ldap_'.$type.'_memberattribute'});
+    }
+
+    // define the search pattern
+    if (!empty($CFG->enrol_ldap_objectclass)){ 
+        $ldap_search_pattern='(objectclass='.$CFG->enrol_ldap_objectclass.')';
+    } else {
+       $ldap_search_pattern="(objectclass='*')";
+        
+    }
+
+    // first, pack the sortorder...
+    fix_course_sortorder();
+
+    foreach ($ldap_contexts as $context) {
+
+        $context == trim($context);
+        if ($CFG->enrol_ldap_search_sub){
+            //use ldap_search to find first user from subtree
+            $ldap_result = ldap_search($ldap_connection, 
+                                        $context, 
+                                        $ldap_search_pattern,
+                                        $ldap_fields_wanted);
+
+        } else {
+            //search only in this context
+            $ldap_result = ldap_list($ldap_connection, 
+                                        $context, 
+                                        $ldap_search_pattern,
+                                        $ldap_fields_wanted,0,0);
+        }
+        // check and push results
+        $records = ldap_get_entries($ldap_connection,$ldap_result);        
+
+        // ldap libraries return an odd array, really. fix it:
+        $flat_records=array();
+        for ($c=0;$c<$records['count'];$c++) {
+            array_push($flat_records, $records["$c"]); 
+        }
+        // free mem -- is there a leak? 
+        $records=0; $ldap_result=0;
+
+        if (count($flat_records)) {
+
+
+            foreach($flat_records as $course){
+                $idnumber = $course{$CFG->enrol_ldap_course_idnumber}[0];
+                print "== Synching $idnumber\n";
+                // does the course exist in moodle already? 
+                $course_obj = false;
+                $course_obj = get_record( 'course',
+                                          $CFG->enrol_localcoursefield,
+                                          $idnumber );
+                if (!is_object($course_obj)) {
+                    // ok, now then let's create it!
+                    print "Creating Course $idnumber...";
+                    $newcourseid = $this->create_course($course, true); // we are skipping fix_course_sortorder()
+                    $course_obj = get_record( 'course', 'id', $newcourseid);
+                    if (is_object($course_obj)) {
+                        print "OK!\n";
+                    } else {
+                        print "failed\n";
+                    }
+                }
+
+                // enrol&unenrol if required
+                if($enrol && is_object($course_obj)){
+                    // pull the ldap membership into a nice array
+                    // this is an odd array -- mix of hash and array -- 
+                    $ldapmembers=array();
+                    if(!empty($course{ strtolower($CFG->{'enrol_ldap_'.$type.'_memberattribute'} ) })){ // may have no membership!
+
+                        $ldapmembers = $course{ strtolower($CFG->{'enrol_ldap_'.$type.'_memberattribute'} ) }; 
+                        unset($ldapmembers{'count'}); // remove oddity ;)
+                    }
+                    
+                    // prune old ldap enrolments
+                    // hopefully they'll fit in the max buffer size for the RDBMS
+                    $sql = ' SELECT enr.userid AS user, 1
+                             FROM ' . $CFG->prefix . $table{$type} . ' enr ' .
+                           ' JOIN ' . $CFG->prefix . 'user  usr ON usr.id=enr.userid ' .
+                           " WHERE course=$course_obj->id 
+                                  AND enrol='ldap' ";
+                    if (!empty($ldapmembers)) {
+                        $sql .= 'AND usr.idnumber NOT IN (\''. join('\',\'', $ldapmembers).'\')';
+                    } else {
+                        print ("Empty enrolment for $course_obj->shortname \n");
+                    }
+                    $todelete = get_records_sql($sql);
+                    if(!empty($todelete)){
+                        foreach ($todelete as $member) {
+                            $member = $member->{'user'};
+                            if($type==='student'){
+                                if (unenrol_student($member, $course_obj->id)){
+                                    print "Unenrolled $type $member into course $course_obj->id ($course_obj->shortname)\n";
+                                } else {
+                                    print "Failed to unenrol $type $member into course $course_obj->id ($course_obj->shortname)\n";
+                                }
+                            } else {
+                                if (remove_teacher($member, $course_obj->id)){
+                                    print "Unenrolled $type $member into course $course_obj->id ($course_obj->shortname)\n";
+                                } else {
+                                    print "Failed to unenrol $type $member into course $course_obj->id ($course_obj->shortname)\n";
+                                }
+                            }
+                        }
+                    }
+                    
+                    // insert current enrolments 
+                    // bad we can't do INSERT IGNORE with postgres...
+                    foreach ($ldapmembers as $ldapmember) {
+                        $sql = 'SELECT id,1 FROM '.$CFG->prefix.'user '
+                                ." WHERE idnumber='$ldapmember'";
+                        $member = get_record_sql($sql); 
+//                        print "sql: $sql \nidnumber = $ldapmember \n" . var_dump($member); 
+                        $member = $member->id;
+                        if(empty($member)){
+                            print "Could not find user $ldapmember, skipping\n";
+                            continue;
+                        }
+                        if (!get_record($table{$type}, 'course', $course_obj->id, 
+                                        'userid', $member, 'enrol', 'ldap')){
+                            if($type === 'student'){
+                                if (enrol_student($member, $course_obj->id, NULL,NULL, 'ldap')){
+                                    print "Enrolled $type $member ($ldapmember) into course $course_obj->id ($course_obj->shortname)\n";
+                                } else {
+                                    print "Failed to enrol $type $member ($ldapmember) into course $course_obj->id ($course_obj->shortname)\n";
+                                }
+                            } else { // teacher
+                                if (add_teacher($member, $course_obj->id, NULL,NULL,NULL, NULL,'ldap')){
+                                    print "Enrolled $type $member ($ldapmember) into course $course_obj->id ($course_obj->shortname)\n";
+                                } else {
+                                    print "Failed to enrol $type $member ($ldapmember) into course $course_obj->id ($course_obj->shortname)\n";
+                                }
+                            }
+                        }                        
+                    }
+                        
+                     
+                }
+            }
+        }
+    }
+    
+    // we are done now, a bit of housekeeping
+    fix_course_sortorder();
+    
+    @ldap_close($ldap_connection);
+    return true;
+}
+
+
+/// Override the base print_entry() function
+function print_entry($course) {
+    global $CFG;
+
+    if (! empty($CFG->enrol_allowinternal) ) {
+        parent::print_entry($course);
+    } else {
+        print_header();
+        notice(get_string("enrolmentnointernal"), $CFG->wwwroot);
+    }
+}
+
+/// Override the base check_entry() function
+function check_entry($form, $course) {
+    global $CFG;
+
+    if (! empty($CFG->enrol_allowinternal) ) {
+        parent::check_entry($form, $course);
+    }
+}
+
+
+/// Overide the get_access_icons() function
+function get_access_icons($course) {
+}
+
+
+/// Overrise the base config_form() function
+function config_form($frm) {
+    global $CFG;
+    include("$CFG->dirroot/enrol/ldap/config.html");
+}
+
+/// Override the base process_config() function
+function process_config($config) {
+
+    optional_variable($config->enrol_ldap_host_url, '');
+    set_config('enrol_ldap_host_url', $config->enrol_ldap_host_url);
+
+    optional_variable($config->enrol_ldap_version, '');
+    set_config('enrol_ldap_version', $config->enrol_ldap_version);
+    
+    optional_variable($config->enrol_ldap_bind_dn, '');
+    set_config('enrol_ldap_bind_dn', $config->enrol_ldap_bind_dn);
+    
+    optional_variable($config->enrol_ldap_bind_pw, '');
+    set_config('enrol_ldap_bind_pw', $config->enrol_ldap_bind_pw);    
+    
+    optional_variable($config->enrol_ldap_student_contexts, '');
+    set_config('enrol_ldap_student_contexts', $config->enrol_ldap_student_contexts);    
+    
+    optional_variable($config->enrol_ldap_student_memberattribute, '');
+    set_config('enrol_ldap_student_memberattribute', $config->enrol_ldap_student_memberattribute);    
+    
+    optional_variable($config->enrol_ldap_teacher_contexts, '');
+    set_config('enrol_ldap_teacher_contexts', $config->enrol_ldap_teacher_contexts);   
+    
+    optional_variable($config->enrol_ldap_teacher_memberattribute, '');
+    set_config('enrol_ldap_teacher_memberattribute', $config->enrol_ldap_teacher_memberattribute);    
+    
+    optional_variable($config->enrol_ldap_objectclass, '');
+    set_config('enrol_ldap_objectclass', $config->enrol_ldap_objectclass);    
+    
+    optional_variable($config->enrol_ldap_category, '');
+    set_config('enrol_ldap_category', $config->enrol_ldap_category);    
+    
+    optional_variable($config->enrol_ldap_template, '');
+    set_config('enrol_ldap_template', $config->enrol_ldap_template);    
+    
+    optional_variable($config->enrol_ldap_course_fullname, '');
+    set_config('enrol_ldap_course_fullname', $config->enrol_ldap_course_fullname);    
+
+    optional_variable($config->enrol_ldap_course_shortname, '');
+    set_config('enrol_ldap_course_shortname', $config->enrol_ldap_course_shortname);    
+        
+    optional_variable($config->enrol_ldap_course_summary, '');
+    set_config('enrol_ldap_course_summary', $config->enrol_ldap_course_summary);    
+    
+    optional_variable($config->enrol_ldap_course_idnumber, '');
+    set_config('enrol_ldap_course_idnumber', $config->enrol_ldap_course_idnumber); 
+    
+    optional_variable($config->enrol_localcoursefield, '');
+    set_config('enrol_localcoursefield', $config->enrol_localcoursefield);
+    
+    optional_variable($config->enrol_ldap_user_memberfield, '');
+    set_config('enrol_ldap_user_memberfield', $config->enrol_ldap_user_memberfield); 
+    
+    optional_variable($config->enrol_ldap_search_sub, '0');
+    set_config('enrol_ldap_search_sub', $config->enrol_ldap_search_sub); 
+    
+    optional_variable($config->enrol_ldap_autocreate, '0');
+    set_config('enrol_ldap_autocreate', $config->enrol_ldap_autocreate);                 
+    
+    
+
+    if (!isset($config->enrol_allowinternal)) {
+        $config->enrol_allowinternal = '';
+    }
+    set_config('enrol_allowinternal', $config->enrol_allowinternal);
+    
+    return true;
+
+}
+
+function enrol_ldap_connect(){
+/// connects to ldap-server
+    global $CFG;
+
+    $result = ldap_connect($CFG->enrol_ldap_host_url);
+
+    if ($result) {
+        if (!empty($CFG->enrol_ldap_version)) {
+            ldap_set_option($result, LDAP_OPT_PROTOCOL_VERSION, $CFG->enrol_ldap_version);
+        }
+
+        return $result;
+
+    } else {
+        error("LDAP-module cannot connect to server: $CFG->enrol_ldap_host_url");
+        return false;
+    }
+}
+
+function enrol_ldap_bind($ldap_connection){
+/// makes bind to ldap for searching users
+/// uses ldap_bind_dn or anonymous bind
+
+    global $CFG;
+
+    if ( ! empty($CFG->enrol_ldap_bind_dn) ){
+        //bind with search-user
+        if (!ldap_bind($ldap_connection, $CFG->enrol_ldap_bind_dn,$CFG->enrol_ldap_bind_dn)){
+            error("Error: could not bind ldap with ldap_bind_dn/pw");
+            return false;
+        }
+
+    } else {
+        //bind anonymously 
+        if ( !ldap_bind($ldap_connection)){
+            error("Error: could not bind ldap anonymously");
+            return false;
+        }  
+    }
+
+    return true;
+}
+
+function find_ext_enrolments ($ldap_connection, $memberuid, $type){
+/// type is teacher or student
+/// return multidimentional array array with of courses (at least dn and idnumber)
+/// 
+
+    global $CFG;
+
+    //default return value
+    $courses = array();
+    $this->enrol_ldap_bind($ldap_connection);
+
+    //get all contexts and look for first matching user
+    $ldap_contexts = explode(";",$CFG->{'enrol_ldap_'.$type.'_contexts'});
+
+    // get all the fields we will want for the potential course creation
+    // as they are light. don't get membership -- potentially a lot of data. 
+    $ldap_fields_wanted = array( 'dn', $CFG->enrol_ldap_course_idnumber);
+    if (!empty($CFG->enrol_ldap_course_fullname)){
+        array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_fullname);
+    }
+    if (!empty($CFG->enrol_ldap_course_shortname)){
+        array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_shortname);
+    }
+    if (!empty($CFG->enrol_ldap_course_summary)){
+        array_push($ldap_fields_wanted, $CFG->enrol_ldap_course_summary);
+    }
+
+    // define the search pattern
+    $ldap_search_pattern = "(".$CFG->{'enrol_ldap_'.$type.'_memberattribute'}."=".$memberuid.")";
+    if (!empty($CFG->enrol_ldap_objectclass)){ 
+        $ldap_search_pattern='(&(objectclass='.$CFG->enrol_ldap_objectclass.')'.$ldap_search_pattern.')';
+    }
+
+    foreach ($ldap_contexts as $context) {
+        $context == trim($context);
+        
+        if ($CFG->enrol_ldap_search_sub){
+            //use ldap_search to find first user from subtree
+            $ldap_result = ldap_search($ldap_connection, 
+                                        $context, 
+                                        $ldap_search_pattern,
+                                        $ldap_fields_wanted);
+
+        } else {
+            //search only in this context
+            $ldap_result = ldap_list($ldap_connection, 
+                                        $context, 
+                                        $ldap_search_pattern,
+                                        $ldap_fields_wanted);
+        }
+        // check and push results
+        $records = ldap_get_entries($ldap_connection,$ldap_result);        
+
+        // ldap libraries return an odd array, really. fix it:
+        $flat_records=array();
+        for ($c=0;$c<$records['count'];$c++) {
+            array_push($flat_records, $records["$c"]); 
+        }
+        
+        if (count($flat_records)) {
+            $courses = array_merge($courses, $flat_records);
+        }
+    }
+
+    return $courses;
+}
+
+// will create the moodle course from the template
+// course_ext is an array as obtained from ldap -- flattened somewhat
+// NOTE: if you pass true for $skip_fix_course_sortorder 
+// you will want to call fix_course_sortorder() after your are done
+// with course creation
+function create_course ($course_ext,$skip_fix_course_sortorder=0){
+    global $CFG;
+    
+    // set defaults
+    $course = NULL;
+    $course->student  = 'Student';
+    $course->students = 'Students';
+    $course->teacher  = 'Teacher';
+    $course->teachers = 'Teachers';
+    $course->format = 'topics';
+    $course->blockinfo = blocks_get_default_blocks();
+    
+    // override defaults with template course
+    if(!empty($CFG->enrol_ldap_template)){
+        $course = get_record("course", 'shortname', $CFG->enrol_ldap_template);
+        unset($course->id); // so we are clear to reinsert the record
+        unset($course->sortorder);
+    }
+
+    // override with required ext data
+    $course->idnumber  = $course_ext[$CFG->enrol_ldap_course_idnumber][0];
+    $course->fullname  = $course_ext[$CFG->enrol_ldap_course_fullname][0];
+    $course->shortname = $course_ext[$CFG->enrol_ldap_course_shortname][0];
+    if (   empty($course->idnumber)
+        || empty($course->fullname)
+        || empty($course->shortname) ) { 
+        // we are in trouble!
+        error_log("Cannot create course: missing required data from the LDAP record!");
+         error_log(var_export($course, true));
+        return false;
+    }
+
+    if(!empty($CFG->enrol_ldap_course_summary)){ // optional
+        $course->summary   = $course_ext->{$CFG->enrol_ldap_course_summary}[0];
+    }
+    if(!empty($CFG->enrol_ldap_category)){ // optional ... but ensure it is set!
+        $course->category   = $CFG->enrol_ldap_category;
+    } 
+    if ($course->category == 0){ // must be avoided as it'll break moodle
+        $course->category = 1; // the misc 'catch-all' category
+    }
+
+    // define the sortorder (yuck)
+    $sort = get_record_sql('SELECT MAX(sortorder) AS max, 1 FROM ' . $CFG->prefix . 'course WHERE category=' . $course->category);
+    $sort = $sort->max;
+    $sort++;
+    $course->sortorder = $sort; 
+
+    // override with local data
+    $course->startdate = time();
+    $course->timecreated = time();
+    $course->visible     = 1;
+    
+    // store it and log
+    if ($newcourseid = insert_record("course", $course)) {  // Set up new course
+        $section = NULL;
+        $section->course = $newcourseid;   // Create a default section.
+        $section->section = 0;
+        $section->id = insert_record("course_sections", $section);
+
+        if(!$skip_fix_course_sortorder){ 
+            fix_course_sortorder(); 
+        }
+        add_to_log($newcourseid, "course", "new", "view.php?id=$newcourseid", "enrol/ldap auto-creation");
+    } else {
+        error_log("Could not create new course from LDAP from DN:" . $course_ext['dn']);
+        error("Serious Error! Could not create the new course!");
+        return false;
+    }
+    
+    return $newcourseid;
+}
+
+} // end of class
+
+?>
diff --git a/enrol/ldap/enrol_ldap_sync.php b/enrol/ldap/enrol_ldap_sync.php
new file mode 100755 (executable)
index 0000000..31d0a5a
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+    if(!empty($_SERVER['GATEWAY_INTERFACE'])){
+        error_log("should not be called from apache!");
+        exit;
+    }
+    error_reporting(E_ALL);
+    
+    require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); // global moodle config file.
+
+    require_once($CFG->dirroot . '/course/lib.php');
+    require_once($CFG->dirroot . '/lib/moodlelib.php');
+    require_once($CFG->dirroot . '/lib/datalib.php');
+    require_once($CFG->dirroot . "/enrol/" . $CFG->enrol . "/enrol.php");
+
+    // ensure errors are well explained
+    $CFG->debug=10;
+    // update enrolments -- these handlers should autocreate courses if required
+    $enrol = new enrolment_plugin();
+    $enrol->enrol_ldap_connect();    
+    $enrol->sync_enrolments('student', true);
+    $enrol->sync_enrolments('teacher', true);
+    
+    // sync metacourses
+    if (function_exists('sync_metacourses')) {
+        sync_metacourses();
+    }
+    
+?>
diff --git a/lang/en/enrol_ldap.php b/lang/en/enrol_ldap.php
new file mode 100755 (executable)
index 0000000..daeb3aa
--- /dev/null
@@ -0,0 +1,69 @@
+<?php // $Id$ 
+
+$string['enrolname'] = 'LDAP';
+$string['description'] = '<p>You can use an LDAP server to control your enrolments.  
+                          It is assumed your LDAP tree contains groups that map to 
+                          the courses, and that each of thouse groups/courses will 
+                          have membership entries to map to students.</p>
+                          <p>It is assumed that courses are defined as groups in 
+                          LDAP, with each group having multiple membership fields 
+                          (<em>member</em> or <em>memberUid</em>) that contain a unique
+                          identification of the user.</p>
+                          <p>To use LDAP enrolment, your users <strong>must</strong> 
+                          to have a valid  idnumber field. The LDAP groups must have 
+                          that idnumber in the member fields for a user to be enrolled 
+                          in the course.
+                          This will usually work well if you are already using LDAP 
+                          Authentication.</p>
+                          <p>Enrolments will be updated when the user logs in. You
+                           can also run a script to keep enrolments in synch. Look in 
+                          <em>enrol/ldap/enrol_ldap_sync.php</em>.<p>
+                          <p>This plugin can also be set to automatically create new 
+                          courses when new groups appear in LDAP.</p>';
+$string['enrol_ldap_server_settings'] = 'LDAP Server Settings';
+$string['enrol_ldap_host_url'] = 'Specify LDAP host in URL-form like 
+                                  \'ldap://ldap.myorg.com/\' 
+                                  or \'ldaps://ldap.myorg.com/\'';
+$string['enrol_ldap_version'] = 'The version of the LDAP protocol your server is using.';
+$string['enrol_ldap_bind_dn'] = 'If you want to use bind-user to search users, 
+                                 specify it here. Someting like 
+                                 \'cn=ldapuser,ou=public,o=org\'';
+$string['enrol_ldap_bind_pw'] = 'Password for bind-user.';
+$string['enrol_ldap_student_settings'] = 'Student enrolment settings';
+$string['enrol_ldap_teacher_settings'] = 'Teacher enrolment settings';
+$string['enrol_ldap_course_settings'] = 'Course enrolment settings';
+$string['enrol_ldap_student_contexts'] = 'List of contexts where groups with student
+                                          enrolments are located. Separate different 
+                                          contexts with \';\'. For example: 
+                                          \'ou=courses,o=org; ou=others,o=org\'';
+$string['enrol_ldap_student_memberattribute'] = 'Member attribute, when users belongs
+                                          (is enrolled) to a group. Usually \'member\'
+                                          or \'memberUid\'.';
+$string['enrol_ldap_teacher_contexts'] = 'List of contexts where groups with teacher
+                                          enrolments are located. Separate different 
+                                          contexts with \';\'. For example: 
+                                          \'ou=courses,o=org; ou=others,o=org\'';
+$string['enrol_ldap_teacher_memberattribute'] = 'Member attribute, when users belongs
+                                          (is enrolled) to a group. Usually \'member\'
+                                          or \'memberUid\'.';
+$string['enrol_ldap_autocreation_settings'] = 'Automatic course creation settings';
+$string['enrol_ldap_autocreate'] = 'Courses can be created automatically if there are
+                                    enrolments to a course  that doesn\'t yet exist 
+                                    in Moodle.';
+$string['enrol_ldap_objectclass'] = 'objectClass used to search courses. Usually
+                                     \'posixGroup\'.';
+$string['enrol_ldap_category'] = 'The category for auto-created courses.';
+$string['enrol_ldap_template'] = 'Optional: auto-created courses can copy 
+                                  their settings from a template course.';
+$string['enrol_ldap_updatelocal'] = 'Update local data';
+$string['enrol_ldap_editlock']    = 'Lock value';
+
+$string['enrol_ldap_course_idnumber'] = 'Map to the unique identifier in LDAP, usually
+                                         <em>cn</em> or <em>uid</em>. It is 
+                                         ecommended to lock the value if you are using 
+                                         automatic course creation.';
+$string['enrol_ldap_course_shortname'] = 'Optional: LDAP field to get the shortname from.';
+$string['enrol_ldap_course_fullname']  = 'Optional: LDAP field to get the full name from.';
+$string['enrol_ldap_course_summary']   = 'Optional: LDAP field to get the summary from.';                                                                                                                                                
+                                    
+?>