phpScheduleIt
June 19, 2013, 05:45:17 PM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News: phpScheduleIt 2.4.2 has been released!
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: Some LDAP tweaking  (Read 6770 times)
pixor
Newbie
*

Karma: 0
Posts: 14


« on: April 20, 2006, 06:59:27 AM »

Hi Nick,

Firstly, thanks for phpScheduleIt - I have it successfully in use at my University, and look forward to applying it to a few more scheduling systems we have here.

I had a few issues with the LDAP support (vital here), and made a few tweaks. I think these are generally applicable, and wondered if you might be interested in rolling these changes back into the project?

The problem I had was that the LDAP module has hard-coded assumptions in it regarding the LDAP attributes that map onto phpScheduleIt's field names. I started by hacking the code to use the appropriate attributes in our LDAP db, but realised I would have to keep applying these changes whenever I updated the code from the main project, so I have tried to remove these hard-coded assumptions and put the mapping of LDAP attributes->phpScheduleIt field names in the configuration file, so that the source code can be upgraded without having to re-apply any changes.

I have updated the LDAP settings section in config.php as follows:-

---

// LDAP Settings
// Should we use LDAP for authentication and enable transparent user registration.
//  User registration data(mail, phone, etc.) is pulled from LDAP.
//  If true the user will have to login with their LDAP uid instead of email address.
//$conf['ldap']['authentication'] = false;
//$conf['ldap']['host'] = 'ldap.host.com';
//$conf['ldap']['port'] = 389;

// LDAP people search base. Set this to where people in your organization are stored in LDAP,
// typically ou=people,o=domain.com.
//$conf['ldap']['basedn'] = "ou=people,o=domain.com";

// MSB - additions start here...

// Logon name - the key field you will be searching for this user within LDAP for
$conf['ldap']['logon'] = "cn";

// The following are mappings of LDAP attributes to phpScheduleIt database columns...
// The configuration name is the phpScheduleIt column name and the string it is set to
// is the LDAP attribute name that will be queried for the equivalent information.

// First name
$conf['ldap']['fname'] = "givenname";
// Last name
$conf['ldap']['lname'] = "sn";
// Email
$conf['ldap']['email'] = "mail";
// Phone
$conf['ldap']['phone'] = "telephonenumber";
Logged

ike
pixor
Newbie
*

Karma: 0
Posts: 14


« Reply #1 on: April 20, 2006, 07:02:17 AM »

I have modified the code in lib/LDAPEngine.class.php to use these variables instead of the hard-coded attribute names. The code changes are enclosd by comments with my initials (MSB):-

---

<?php
/**
* LDAPEngine class
* @author David Poole <David.Poole@fccc.edu>
* @version 04-19-05
* @package LDAPEngine
*
* Copyright (C) 2004 phpScheduleIt
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* CmnFns class
*/
include_once('CmnFns.class.php');


class LDAPEngine {

   var $host;
   var $port;
   var $basedn;

   var $binddn;
    var $ldap;
    var $connected;

    var $uid;
    var $fname;
    var $lname;
    var $mail;
    var $phone;
   var $password;

   /**
   * LDAPEngine constructor to initialize object
   * @param string $uid user id
   * @param string $password password associated with uid
   */
   function LDAPEngine( $uid, $password ) {
      global $conf;

      $this->connected = false;

      if( strlen( $uid ) == 0 || strlen( $password ) == 0 ) {
           return;
      }

      $this->host = $conf['ldap']['host'];
      $this->port = $conf['ldap']['port'];
      $this->basedn = $conf['ldap']['basedn'];

      $this->ldap = ldap_connect( $this->host, $this->port ) or die( "Could not connect to LDAP server." );
      $this->uid = $uid;
// msb - start
//      $uid = "uid=$uid,". $this->basedn;
      $uid = $conf['ldap']['logon']."=$uid,". $this->basedn;
// msb - end
      if( $this->ldap ) {
          $bind = @ldap_bind( $this->ldap, $uid, $password );

          if( $bind ) {
              // authenication was a success, try to load user information
              $this->binddn = $uid;

              if( $this->loadUserData() ) {
                  $this->connected = true;
                  $this->password = $password;
              } else {
                  ldap_close( $this->ldap );
              }

            } else {
                ldap_close( $this->ldap );
            }
        }

    }

    /**
   * Disconnects from the LDAP server
   * @param none
   */
    function disconnect() {
        if( $this->connected ) {
            ldap_close( $this->ldap );
            $this->connected = false;
        }
    }

   /**
   * Queries LDAP for user information
   * @return boolean indicating success or failure
   */
   function loadUserData() {
// msb - start
    global $conf;

//      $attributes = array( "sn", "givenname", "mail", "telephonenumber" );
      $attributes = array( $conf['ldap']['lname'], $conf['ldap']['fname'], $conf['ldap']['email'], $conf['ldap']['phone'] );

//        $result = ldap_search( $this->ldap, $this->binddn, "uid=". $this->uid, $attributes );
        $result = ldap_search( $this->ldap, $this->binddn, $conf['ldap']['logon']."=". $this->uid, $attributes );
// msb - end

        $entries = ldap_get_entries( $this->ldap, $result );

        if( $result and ( $entries["count"] == 1 ) ) {
// msb - start
//            $this->fname = $entries[0]['givenname'][0];
//            $this->lname = $entries[0]['sn'][0];
//            $this->mail = strtolower( $entries[0]['mail'][0] );
//            $this->phone = $entries[0]['telephonenumber'][0];
            $this->fname = $entries[0][$conf['ldap']['fname']][0];
            $this->lname = $entries[0][$conf['ldap']['lname']][0];
            $this->mail = strtolower( $entries[0][$conf['ldap']['email']][0] );
            $this->phone = $entries[0][$conf['ldap']['phone']][0];
// msb - end
        } else {
            return false;
        }

      return true;

   }

    /**
   * Returns user information
   * @return array containing user information
   */
    function getUserData() {

        $return = array(
            'fname' => $this->fname,
            'lname' => $this->lname,
            'emailaddress' => $this->mail,
            'phone' => $this->phone,
            'logon_name' => $this->uid,
            'password' => $this->password,
            'password2' => $this->password
        );

        return $return;

    }

    /**
   * Gets user's mail attribute.
   * @return string user's email address
   */
   function getUserEmail( ) {
        return $this->mail;
    }

    /**
   * See if the user was authenticated.
   * @return boolean authenication success of failure
   */
   function connected( ) {
        return $this->connected;
    }

}

?>
Logged

ike
pixor
Newbie
*

Karma: 0
Posts: 14


« Reply #2 on: April 20, 2006, 07:06:17 AM »

Creating users via LDAP showed up a minor data validation issue in lib/Auth.class.php . I made a couple of fixes, again surrounded with comments with MSB in them...

---

<?php
/**
* Authorization and login functionality
* @author Nick Korbel <lqqkout13@users.sourceforge.net>
* @author David Poole <David.Poole@fccc.edu>
* @version 04-26-05
* @package phpScheduleIt
*
* Copyright (C) 2003 - 2006 phpScheduleIt
* License: GPL, see LICENSE
*/
/**
* Base directory of application
*/
@define('BASE_DIR', dirname(__FILE__) . '/..');
/**
* Include AuthDB class
*/
include_once('db/AuthDB.class.php');
/**
* Include User class
*/
include_once('User.class.php');
/**
* PHPMailer
*/
include_once('PHPMailer.class.php');
/**
* Include Auth template functions
*/
include_once(BASE_DIR . '/templates/auth.template.php');

/**
* This class provides all authoritiative and verification
*  functionality, including login/logout, registration,
*  and user verification
*/
class Auth {
   var $is_loggedin = false;
   var   $login_msg = '';
   var $is_attempt = false;
   var $db;
   var $success;

   /**
   * Create a reference to the database class
   *  and start the session
   * @param none
   */
   function Auth() {
      $this->db = new AuthDB();
   }

   /**
   * Check if user is the administrator
   * This function checks to see if the currently
   *  logged in user is the administrator, granting
   *  them special permissions
   * @param none
   * @return boolean whether the user is the admin
   */
   function isAdmin() {
      return isset($_SESSION['sessionAdmin']);
   }

   /**
   * Check user login
   * This function checks to see if the user has
   * a valid session set (if they are logged in)
   * @param none
   * @return boolean whether the user is logged in
   */
   function is_logged_in() {
      return isset($_SESSION['sessionID']);
   }

   /**
   * Returns the currently logged in user's userid
   * @param none
   * @return the userid, or null if the user is not logged in
   */
   function getCurrentID() {
      return isset($_SESSION['sessionID']) ? $_SESSION['sessionID'] : null;
   }

   /**
   * Logs the user in
   * @param string $uname username
   * @param string $pass password
   * @param string $cookieVal y or n if we are using cookie
   * @param string $isCookie id value of user stored in the cookie
   * @param string $resume page to forward the user to after a login
   * @param string $lang language code to set
   * @return any error message that occured during login
   */
   function doLogin($uname, $pass, $cookieVal = null, $isCookie = false, $resume = '', $lang = '') {
      global $conf;
      $msg = '';

      if (empty($resume)) $resume = 'ctrlpnl.php';      // Go to control panel by default

      $_SESSION['sessionID'] = null;
      $_SESSION['sessionName'] = null;
      $_SESSION['sessionAdmin'] = null;

      $uname = stripslashes($uname);
      $pass = stripslashes($pass);
      $ok_user = $ok_pass = false;
      $use_logonname = (bool)$conf['app']['useLogonName'];

      $adminemail = strtolower($conf['app']['adminEmail']);

      if ($isCookie !== false) {      // Cookie is set
         $id = $isCookie;
         if ($this->db->verifyID($id))
            $ok_user = $ok_pass = true;
         else {
            $ok_user = $ok_pass = false;
            setcookie('ID', '', time()-3600, '/');   // Clear out all cookies
            $msg .= translate('That cookie seems to be invalid') . '<br/>';
         }
      }
      else {

        if( $conf['ldap']['authentication'] ) {

          // Include LDAPEngine class
            include_once('LDAPEngine.class.php');

            $ldap = new LDAPEngine($uname, $pass);

           if( $ldap->connected() ) {

                $mail = $ldap->getUserEmail();

                if( $mail ) {

                    $id = $this->db->userExists( $mail );

                    if( $id ) {
                        // check if LDAP and local DB are in consistancy.
                        $updates = $ldap->getUserData();

                        if( $this->db->check_updates( $id, $updates ) ) {
                            $this->db->update_user( $id, $updates );
                        }

                    } else {
                        $data = $ldap->getUserData();
                        $id = $this->do_register_user( $data );
                    }

                    $ok_user = true; $ok_pass = true;

                }
            else {
                    $msg .= translate('This system requires that you have an email address.');
               }
            }
         else {
                $msg .= translate('Invalid User Name/Password.');
            }

            $ldap->disconnect();

        }
        else {
         // If we cant find email, set message and flag
         if ( !$id = $this->db->userExists($uname, $use_logonname) ) {
            $msg .= translate('We could not find that logon in our database.') . '<br/>';
            $ok_user = false;
         }
         else
            $ok_user = true;

         // If password is incorrect, set message and flag
         if ($ok_user && !$this->db->isPassword($uname, $pass, $use_logonname)) {
            $msg .= translate('That password did not match the one in our database.') . '<br/>';
            $ok_pass = false;
         }
         else
            $ok_pass = true;
        }
        }


      // If the login failed, notify the user and quit the app
      if (!$ok_user || !$ok_pass) {
         $msg .= translate('You can try');
         return $msg;
      }
      else {

         $this->is_loggedin = true;
         $user = new User($id);   // Get user info

         // If the user wants to set a cookie, set it
         // for their ID and fname.  Expires in 30 days (2592000 seconds)
         if (!empty($cookieVal)) {
            //die ('Setting cookie');
            setcookie('ID', $user->get_id(), time() + 2592000, '/');
         }

          // If it is the admin, set session variable
         if ($user->get_email() == $adminemail || $user->get_isadmin()) {
            $_SESSION['sessionAdmin'] = $user->get_email();
         }

         // Set other session variables
         $_SESSION['sessionID'] = $user->get_id();
         $_SESSION['sessionName'] = $user->get_fname();

         if ($lang != '') {
            set_language($lang);
         }

         // Send them to the control panel
         CmnFns::redirect(urldecode($resume));
      }
   }

   /**
   * Log the user out of the system
   * @param none
   */
   function doLogout() {
      // Check for valid session
      if (!$this->is_logged_in()) {
         $this->print_login_msg();
         die;
      }
      else {
         // Destroy all session variables
         unset($_SESSION['sessionID']);
         unset($_SESSION['sessionName']);
         if (isset($_SESSION['sessionAdmin'])) unset($_SESSION['sessionAdmin']);
         session_destroy();

         // Clear out all cookies
         setcookie('ID', '', time()-3600, '/');

         // Refresh page
         CmnFns::redirect($_SERVER['PHP_SELF']);
      }
   }

   /**
   * Register a new user
   * This function will allow a new user to register.
   * It checks to make sure the email does not already
   * exist and then stores all user data in the login table.
   * It will also set a cookie if the user wants
   * @param array $data array of user data
   */
   function do_register_user($data) {
      global $conf;
      // Verify user data
      $msg = $this->check_all_values($data, false);
      if (!empty($msg)) {
         return $msg;
      }

      $adminemail = strtolower($conf['app']['adminEmail']);
      $techEmail  = empty($conf['app']['techEmail']) ? translate('N/A') : $conf['app']['techEmail'];
      $url        = CmnFns::getScriptURL();

      // Register the new member
      $id = $this->db->insertMember($data);

      $this->db->auto_assign($id);      // Give permission on auto-assigned resources

      $mailer = new PHPMailer();
      $mailer->IsHTML(false);

      // Email user informing about successful registration
      $subject = $conf['ui']['welcome'];
      $msg = translate_email('register',
                        $data['fname'], $conf['ui']['welcome'],
                        $data['fname'], $data['lname'],
                        (isset($data['logon_name']) ? $data['logon_name'] : $data['emailaddress']),
                        $data['phone'],
// msb - start
                        isset($data['institution']) ? $data['institution'] : null,
                        isset($data['position']) ? $data['position'] : null,
//                        $data['institution'],
//                        $data['position'],
// msb - end
                        $url,
                        $adminemail);

      $mailer->AddAddress($data['emailaddress'], $data['fname'] . ' ' . $data['lname']);
      $mailer->From = $adminemail;
      $mailer->FromName = $conf['app']['title'];
      $mailer->Subject = $subject;
      $mailer->Body = $msg;
      $mailer->Send();

      // Email the admin informing about new user
      if ($conf['app']['emailAdmin']) {
         $subject = translate('A new user has been added');
         $msg = translate_email('register_admin',
                        $data['emailaddress'],
                        $data['fname'], $data['lname'],
                        $data['phone'],
                        $data['institution'],
                        $data['position']);

         $mailer->ClearAllRecipients();
         $mailer->AddAddress($adminemail);
         $mailer->Subject = $subject;
         $mailer->Body = $msg;
         $mailer->Send();
      }

      // If the user wants to set a cookie, set it
      // for their ID and fname.  Expires in 30 days (2592000 seconds)
      if (isset($data['setCookie'])) {
         setcookie('ID', $id, time() + 2592000, '/');
      }

      // If it is the admin, set session variable
      if ($data['emailaddress'] == $adminemail) {
         $_SESSION['sessionAdmin'] = $adminemail;
      }

      // Set other session variables
      $_SESSION['sessionID'] = $id;
      $_SESSION['sessionName'] = $data['fname'];

      // Write log file
// msb - start
//      CmnFns::write_log('New user registered. Data provided: fname- ' . $data['fname'] . ' lname- ' . $data['lname']
//                  . ' email- '. $data['emailaddress'] . ' phone- ' . $data['phone'] . ' institution- ' . $data['institution']
//                  . ' position- ' . $data['position'], $id);
      CmnFns::write_log('New user registered. Data provided: fname- ' . $data['fname'] . ' lname- ' . $data['lname']
                  . ' email- '. $data['emailaddress'] . ' phone- ' . $data['phone'] . ' institution- ' . (isset($data['institution']) ? $data['institution'] : null)
                  . ' position- ' . (isset($data['position']) ? $data['position'] : null), $id);
// msb - end
      if( !$conf['ldap']['authentication'] ) {

        CmnFns::redirect('ctrlpnl.php', 1, false);
        $link = CmnFns::getNewLink();

        $this->success = translate('You have successfully registered') . '<br/>' . $link->getLink('ctrlpnl.php', translate('Continue'));
      } else {
          // return DB id from entry created if using LDAP
          return $id;
      }

   }

   /**
   * Edits user data
   * @param array $data array of user data
   */
   function do_edit_user($data) {
      global $conf;

      // Verify user data
      $msg = $this->check_all_values($data, true);
      if (!empty($msg)) {
         return $msg;
      }

      $this->db->update_user($_SESSION['sessionID'], $data);

      $adminemail = strtolower($conf['app']['adminEmail']);
      // If it is the admin, set session variable
      if ($data['emailaddress'] == $adminemail) {
         $_SESSION['sessionAdmin'] = $adminemail;
      }

      // Set other session variables
      $_SESSION['sessionName'] = $data['fname'];

      // Write log file
      CmnFns::write_log('User data modified. Data provided: fname- ' . $data['fname'] . ' lname- ' . $data['lname']
                  . ' email- '. $data['emailaddress'] . ' phone- ' . $data['phone'] . ' institution- ' . $data['institution']
                  . ' position- ' . $data['position'], $_SESSION['sessionID']);

      $link = CmnFns::getNewLink();

        $this->success = translate('Your profile has been successfully updated!') . '<br/>'
            . $link->getLink('ctrlpnl.php', translate('Please return to My Control Panel'));

   }


   /**
   * Verify that the user entered all data properly
   * @param array $data array of data to check
   * @param boolean $is_edit whether this is an edit or not
   */
   function check_all_values(&$data, $is_edit) {
      global $conf;
      $use_logonname = (bool)$conf['app']['useLogonName'];

      $msg = '';

      if ($use_logonname && empty($data['logon_name'])) {
         $msg .= translate('Valid username is required') . '<br/>';
      }
      else if ($use_logonname) {
         $data['logon_name'] = htmlspecialchars($data['logon_name']);
      }
      if (empty($data['emailaddress']) || !preg_match("/^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/", $data['emailaddress']))
         $msg .= translate('Valid email address is required.') . '<br/>';
      if (empty($data['fname'])) {
         $msg .= translate('First name is required.') . '<br/>';
      }
      else {
         $data['fname'] = htmlspecialchars($data['fname']);
      }
      if (empty($data['lname'])) {
         $msg .= translate('Last name is required.') . '<br/>';
      }
      else {
         $data['lname'] = htmlspecialchars($data['lname']);
      }
      if(!empty($data['phone'])) {
         $data['phone'] = htmlspecialchars($data['phone']);
      }
      if (!empty($data['institution'])) {
         $data['institution'] = htmlspecialchars($data['institution']);
      }
      if (!empty($data['position'])) {
         $data['position'] = htmlspecialchars($data['position']);
      }


        if( !$conf['ldap']['authentication'] ) {

            // Make sure email isnt in database (and is not current users email)
            if ($is_edit) {
                $user = new User($_SESSION['sessionID']);
                if (!$use_logonname) {
               if ($this->db->userExists($data['emailaddress']) && ($data['emailaddress'] != $user->get_email()) ) {
                  $msg .= translate('That email is taken already.') . '<br/>';
               }
            }
            else {
               if ( $this->db->userExists($data['logon_name'], true) && ($data['logon_name'] != $user->get_logon_name()) ) {
                  $msg .= translate('That logon name is taken already.') . '<br/>';
               }
            }

                if (!empty($data['password'])) {
                    if (strlen($data['password']) < $conf['app']['minPasswordLength'])
                        $msg .= translate('Min 6 character password is required.', array($conf['app']['minPasswordLength'])) . '<br/>';
                    if ($data['password'] != $data['password2'])
                        $msg .= translate('Passwords do not match.') . '<br/>';
                }

                unset($user);
            }
            else {
                if (empty($data['password']) || strlen($data['password']) < $conf['app']['minPasswordLength']) {
                     $msg .= translate('Min 6 character password is required.', array($conf['app']['minPasswordLength'])) . '<br/>';
            }
                if ($data['password'] != $data['password2']) {
                    $msg .= translate('Passwords do not match.') . '<br/>';
            }
                if ($this->db->userExists($data['emailaddress'])) {
                    $msg .= translate('That email is taken already.') . '<br/>';
                }
            if ($use_logonname && $this->db->userExists($data['logon_name'], true)) {
               $msg .= translate('That logon name is taken already.') . '<br/>';
            }
            }
        }

      return $msg;
   }
   /**
   * Returns whether the user is attempting to log in
   * @param none
   * @return whether the user is attempting to log in
   */
   function isAttempting() {
      return $this->is_attempt;
   }

   /**
   * Kills app
   * @param none
   */
   function kill() {
      die;
   }

   /**
   * Destroy any lingering sessions
   * @param none
   */
   function clean() {
      // Destroy all session variables
      unset($_SESSION['sessionID']);
      unset($_SESSION['sessionName']);
      if (isset($_SESSION['sessionAdmin'])) unset($_SESSION['sessionAdmin']);
      session_destroy();
   }

   /**
   * Wrapper function to call template 'print_register_form' function
   * @param boolean $edit whether this is an edit or a new register
   * @param array $data values to auto fill
   */
   function print_register_form($edit, $data, $msg = '') {
      print_register_form($edit, $data, $msg);      // Function in auth.template.php
   }


   /**
   * Wrapper function to call template 'printLoginForm' function
   * @param string $msg error messages to display for user
   * @param string $resume page to resume after a login
   */
   function printLoginForm($msg = '', $resume = '') {
      printLoginForm($msg, $resume);
   }

   /**
   * Prints a message telling the user to log in
   * @param boolean $kill whether to end the program or not
   */
   function print_login_msg($kill = true) {
      CmnFns::redirect(CmnFns::getScriptURL() . '/index.php?auth=no&resume=' . urlencode($_SERVER['PHP_SELF']) . '?' . urlencode($_SERVER['QUERY_STRING']));
   }

   /**
   * Prints out the latest success box
   * @param none
   */
   function print_success_box() {
      CmnFns::do_message_box($this->success);
   }
}
?>
Logged

ike
pixor
Newbie
*

Karma: 0
Posts: 14


« Reply #3 on: April 20, 2006, 07:08:01 AM »

If you do end up putting this back into the project, I am happy to test things still work as expected.

Thanks,

Mike.
Logged

ike
Nick
Administrator
Hero Member
*****

Karma: 15
Posts: 5506


WWW
« Reply #4 on: April 20, 2006, 09:51:42 AM »

Absolutely this will be included in the code.  I don't know anything about LDAP really, so the help is very much appreciated.  If you want to send me an email with your full name and email address, or the adjusted LDAP file, I'll make sure you get the credit you deserve.
Logged
rmunsch
Newbie
*

Karma: 0
Posts: 8


WWW
« Reply #5 on: November 09, 2006, 12:20:38 PM »

So is all the above functionality now in 1.2.4, and my going in and trashi^H^H^H^H changing the source code is no longer necessary?  Cheesy
Logged

ttp://www.solutionsforprogress.com/
http://www.thebenefitbank.com/
victaru
Newbie
*

Karma: 0
Posts: 4


« Reply #6 on: July 14, 2010, 10:32:21 PM »

hi there,

i do not see the edited version in the latest build. 1.2.12, would this be implemented in?

at the moment i made the changes based on your file, and i noticed that I am able to create a new account even if the email already exists in the database.
Logged
Nick
Administrator
Hero Member
*****

Karma: 15
Posts: 5506


WWW
« Reply #7 on: July 19, 2010, 01:37:20 PM »

This has not made it into the code base yet.
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2006-2007, Simple Machines Valid XHTML 1.0! Valid CSS!