From 78e3cc170099b5fa34ae51813780cca83b2f435f Mon Sep 17 00:00:00 2001 From: Ben Klang Date: Thu, 31 Dec 2009 21:22:29 -0500 Subject: [PATCH] Get Add and Edit Extension forms working with LDAP --- shout/extensions.php | 56 ++++------ shout/lib/Driver.php | 19 ++++ shout/lib/Driver/Ldap.php | 226 ++++++++++++++------------------------ shout/lib/Driver/Sql.php | 12 +- shout/lib/Forms/ExtensionForm.php | 30 ++--- shout/lib/Shout.php | 3 +- 6 files changed, 146 insertions(+), 200 deletions(-) diff --git a/shout/extensions.php b/shout/extensions.php index 27e4e9573..da4a4d1c1 100644 --- a/shout/extensions.php +++ b/shout/extensions.php @@ -13,10 +13,6 @@ require_once SHOUT_BASE . '/lib/Forms/ExtensionForm.php'; //require_once SHOUT_BASE . '/lib/Shout.php'; $action = Horde_Util::getFormData('action'); -$extension = Horde_Util::getFormData('extension'); -$extensions = $shout_extensions->getExtensions($context); - -$vars = Horde_Variables::getDefaultVariables(); //$tabs = Shout::getTabs($context, $vars); @@ -26,46 +22,37 @@ $section = 'extensions'; $title = _("Extensions: "); switch ($action) { -case 'save': - $title .= sprintf(_("Save Extension %s"), $extension); - $FormName = $vars->get('formname'); - - $Form = &Horde_Form::singleton($FormName, $vars); +case 'add': +case 'edit': + $vars = Horde_Variables::getDefaultVariables(); + $Form = new ExtensionDetailsForm($vars); $FormValid = $Form->validate($vars, true); if ($Form->isSubmitted() && $FormValid) { // Form is Valid and Submitted try { - $Form->execute(); + $Form->execute($context); + $notification->push(_("User information updated."), + 'horde.success'); + $action = 'list'; } catch (Exception $e) { $notification->push($e); } - $notification->push(_("User information updated."), - 'horde.success'); - break; - } else { - $action = 'edit'; - // Fall-through to the "edit" action - } - -case 'add': -case 'edit': - if ($action == 'add') { - $title .= _("New Extension"); - // Treat adds just like an empty edit - $action = 'edit'; } else { - $title .= sprintf(_("Edit Extension %s"), $extension); - + // Create a new add/edit form + $extension = Horde_Util::getFormData('extension'); + $extensions = $shout_extensions->getExtensions($context); + $vars = new Horde_Variables($extensions[$extension]); + if ($action == 'edit') { + $vars->set('oldextension', $extension); + } + $vars->set('action', $action); + $Form = new ExtensionDetailsForm($vars); + $Form->open($RENDERER, $vars, Horde::applicationUrl('extensions.php'), 'post'); + // Make sure we get the right template below. + $action = 'edit'; } - - $FormName = 'ExtensionDetailsForm'; - $vars = new Horde_Variables($extensions[$extension]); - $Form = &Horde_Form::singleton($FormName, $vars); - - $Form->open($RENDERER, $vars, Horde::applicationUrl('extensions.php'), 'post'); - break; case 'delete': @@ -87,6 +74,9 @@ default: $title .= _("List Users"); } +// Fetch the (possibly updated) list of extensions +$extensions = $shout_extensions->getExtensions($context); + require SHOUT_TEMPLATES . '/common-header.inc'; require SHOUT_TEMPLATES . '/menu.inc'; diff --git a/shout/lib/Driver.php b/shout/lib/Driver.php index acb9c41e5..b343bb729 100644 --- a/shout/lib/Driver.php +++ b/shout/lib/Driver.php @@ -114,6 +114,25 @@ class Shout_Driver { } /** + * Save an extension to the LDAP tree + * + * @param string $context Context to which the user should be added + * + * @param string $extension Extension to be saved + * + * @param array $details Phone numbers, PIN, options, etc to be saved + * + * @return TRUE on success, PEAR::Error object on error + * @throws Shout_Exception + */ + public function saveExtension($context, $extension, $details) + { + if (!Shout::checkRights("shout:contexts:$context:extensions", PERMS_EDIT, 1)) { + throw new Shout_Exception(_("Permission denied to save extensions in this context.")); + } + } + + /** * Attempts to return a concrete Shout_Driver instance based on * $driver. * diff --git a/shout/lib/Driver/Ldap.php b/shout/lib/Driver/Ldap.php index ee0358fde..b65475903 100644 --- a/shout/lib/Driver/Ldap.php +++ b/shout/lib/Driver/Ldap.php @@ -91,7 +91,7 @@ class Shout_Driver_Ldap extends Shout_Driver $attributes = array( 'cn', - 'mail', + 'AstVoicemailEmail', 'AstVoicemailMailbox', 'AstVoicemailPassword', 'AstVoicemailOptions', @@ -138,7 +138,7 @@ class Shout_Driver_Ldap extends Shout_Driver $res[$i]['cn'][0]; $entries[$context][$extension]['email'] = - $res[$i]['mail'][0]; + $res[$i]['astvoicemailemail'][0]; $entries[$context][$extension]['pageremail'] = $res[$i]['astvoicemailpager'][0]; @@ -492,162 +492,96 @@ class Shout_Driver_Ldap extends Shout_Driver * @param array $details Phone numbers, PIN, options, etc to be saved * * @return TRUE on success, PEAR::Error object on error + * @throws Shout_Exception */ public function saveExtension($context, $extension, $details) { - $ldapKey = &$this->_ldapKey; - $appKey = &$this->_appKey; - # FIXME Access Control/Authorization - if (!Shout::checkRights("shout:contexts:$context:extensions", PERMS_EDIT, 1)) { - // FIXME: Allow users to edit themselves - //&& !($details[$appKey] == Auth::getAuth())) { - throw new Shout_Exception(_("Permission denied to save extensions in this context.")); - } - - $contexts = &$this->getContexts(); -// $domain = $contexts[$context]['domain']; - - # Check to ensure the extension is unique within this context - $filter = "(&(objectClass=AstVoicemailMailbox)(context=$context))"; - $reqattrs = array('dn', $ldapKey); - $res = @ldap_search($this->_LDAP, - SHOUT_USERS_BRANCH . ',' . $this->_params['basedn'], - $filter, $reqattrs); - if (!$res) { - return PEAR::raiseError('Unable to check directory for duplicate extension: ' . - ldap_error($this->_LDAP)); - } - if (($res['count'] > 1) || - ($res['count'] != 0 && - !in_array($res[0][$ldapKey], $details[$appKey]))) { - return PEAR::raiseError('Duplicate extension found. Not saving changes.'); - } - + parent::saveExtension($context, $extension, $details); + + // FIXME: Fix and uncomment the below +// // Check to ensure the extension is unique within this context +// $filter = "(&(objectClass=AstVoicemailMailbox)(context=$context))"; +// $reqattrs = array('dn', $ldapKey); +// $res = @ldap_search($this->_LDAP, $this->_params['basedn'], +// $filter, $reqattrs); +// if ($res === false) { +// $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP), +// ldap_error($this->_LDAP)); +// Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR); +// throw new Shout_Exception(_("Error while searching the directory. Details have been logged for the administrator.")); +// } +// if (($res['count'] != 1) || +// ($res['count'] != 0 && +// !in_array($res[0][$ldapKey], $details[$appKey]))) { +// throw new Shout_Exception(_("Duplicate extension found. Not saving changes.")); +// } + // FIXME: Quote these strings + $uid = $extension . '@' . $context; $entry = array( + 'objectClass' => array('top', 'account', 'AsteriskVoicemail'), + 'uid' => $uid, 'cn' => $details['name'], - 'sn' => $details['name'], - 'mail' => $details['email'], - 'uid' => $details['email'], - 'voiceMailbox' => $details['newextension'], - 'voiceMailboxPin' => $details['mailboxpin'], - 'context' => $context, - 'asteriskUserDialOptions' => $details['dialopts'], + 'AstVoicemailEmail' => $details['email'], + 'AstVoicemailMailbox' => $extension, + 'AstVoicemailPassword' => $details['mailboxpin'], + 'AstContext' => $context, ); - - if (!empty ($details['telephonenumber'])) { - $entry['telephoneNumber'] = $details['telephonenumber']; - } - - $validusers = &$this->getUsers($context); - if (!isset($validusers[$extension])) { - # Test to see if we're modifying an existing user that has - # no telephone system objectClasses and update that object/user - $rdn = $ldapKey.'='.$details[$appKey].','; - $branch = SHOUT_USERS_BRANCH.','.$this->_params['basedn']; - - # This test is something of a hack. I want a cheap way to check - # for the existance of an object. I don't want to do a full search - # so instead I compare that the dn equals the dn. If the object - # exists then it'll return true. If the object doesn't exist, - # it'll return error. If it ever returns false something wierd - # is going on. - $res = @ldap_compare($this->_LDAP, $rdn.$branch, - $ldapKey, $details[$appKey]); + $rdn = 'uid=' . $uid; + $dn = $rdn . ',' . $this->_params['basedn']; + + if (!empty($details['oldextension'])) { + // This is a change to an existing extension + // First, identify the DN to modify + // FIXME: Quote these strings + $filter = '(&(AstVoicemailMailbox=%s)(AstContext=%s))'; + $filter = sprintf($filter, $details['oldextension'], $context); + $attributes = array('dn'); + + $res = ldap_search($this->_LDAP, $this->_params['basedn'], + $filter, $attributes); if ($res === false) { - # We should never get here: a DN should ALWAYS match itself - return PEAR::raiseError("Internal Error: " . __FILE__ . " at " . - __LINE__); - } elseif ($res === true) { - # The object/user exists but doesn't have the Asterisk - # objectClasses - $extension = $details['newextension']; - - # $tmp is the minimal information required to establish - # an account in LDAP as required by the objectClasses. - # The entry will be fully populated below. - $tmp = array(); - $tmp['objectClass'] = array( - 'asteriskUser', - 'asteriskVoiceMailbox' - ); - $tmp['voiceMailbox'] = $extension; - $tmp['context'] = $context; - $res = @ldap_mod_replace($this->_LDAP, $rdn.$branch, $tmp); - if (!$res) { - return PEAR::raiseError("Unable to modify the user: " . - ldap_error($this->_LDAP)); - } + $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP), + ldap_error($this->_LDAP)); + Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Shout_Exception(_("Error while searching the directory. Details have been logged for the administrator.")); + } - # Populate the $validusers array to make the edit go smoothly - # below - $validusers[$extension] = array(); - $validusers[$extension][$appKey] = $details[$appKey]; - - # The remainder of the work is done at the outside of the - # parent if() like a normal edit. - - } elseif ($res === -1) { - # We must be adding a new user. - $entry['objectClass'] = array( - 'top', - 'person', - 'organizationalPerson', - 'inetOrgPerson', - 'hordePerson', - 'asteriskUser', - 'asteriskVoiceMailbox' - ); - - # Check to see if the maximum number of users for this context - # has been reached - $limits = $this->getLimits($context); - if (is_a($limits, "PEAR_Error")) { - return $limits; - } - if (count($validusers) >= $limits['asteriskusersmax']) { - return PEAR::raiseError('Maximum number of users reached.'); - } + // If the extension has changed we need to perform an object rename + if ($extension != $details['oldextension']) { + $res = ldap_rename($this->_LDAP, $res['dn'], $rdn, + $this->_params['basedn'], true); - $res = @ldap_add($this->_LDAP, $rdn.$branch, $entry); - if (!$res) { - return PEAR::raiseError('LDAP Add failed: ' . - ldap_error($this->_LDAP)); + if ($res === false) { + $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP), + ldap_error($this->_LDAP)); + Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Shout_Exception(_("Error while modifying the directory. Details have been logged for the administrator.")); } - - return true; - } elseif (is_a($res, 'PEAR_Error')) { - # Some kind of internal error; not even sure if this is a - # possible outcome or not but I'll play it safe. - return $res; } - } - # Anything after this point is an edit. - - # Check to see if the object needs to be renamed (DN changed) - if ($validusers[$extension][$appKey] != $entry[$ldapKey]) { - $oldrdn = $ldapKey.'='.$validusers[$extension][$appKey]; - $oldparent = SHOUT_USERS_BRANCH.','.$this->_params['basedn']; - $newrdn = $ldapKey.'='.$entry[$ldapKey]; - $res = @ldap_rename($this->_LDAP, "$oldrdn,$oldparent", - $newrdn, $oldparent, true); - if (!$res) { - return PEAR::raiseError('LDAP Rename failed: ' . - ldap_error($this->_LDAP)); + // Now apply the changes + $res = ldap_modify($this->_LDAP, $dn, $entry); + if ($res === false) { + $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP), + ldap_error($this->_LDAP)); + Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Shout_Exception(_("Error while modifying the directory. Details have been logged for the administrator.")); } - } - # Update the object/user - $dn = $ldapKey.'='.$entry[$ldapKey]; - $dn .= ','.SHOUT_USERS_BRANCH.','.$this->_params['basedn']; - $res = @ldap_modify($this->_LDAP, $dn, $entry); - if (!$res) { - return PEAR::raiseError('LDAP Modify failed: ' . - ldap_error($this->_LDAP)); + return true; + } else { + // This is an add of a new extension + $res = ldap_add($this->_LDAP, $dn, $entry); + if ($res === false) { + $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP), + ldap_error($this->_LDAP)); + Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Shout_Exception(_("Error while modifying the directory. Details have been logged for the administrator.")); + } + return true; } - # We must have been successful - return true; + throw new Shout_Exception(_("Unspecified error.")); } /** @@ -709,7 +643,7 @@ class Shout_Driver_Ldap extends Shout_Driver } if (!Horde_Util::extensionExists('ldap')) { - throw new Horde_Exception('Required LDAP extension not found.'); + throw new Shout_Exception('Required LDAP extension not found.'); } Horde::assertDriverConfig($this->_params, $this->_params['class'], @@ -722,7 +656,7 @@ class Shout_Driver_Ldap extends Shout_Driver sprintf('Failed to open an LDAP connection to %s.', $this->_params['hostspec']), __FILE__, __LINE__, PEAR_LOG_ERR); - throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.'); + throw new Shout_Exception('Internal LDAP error. Details have been logged for the administrator.'); } /* Set hte LDAP protocol version. */ @@ -736,7 +670,7 @@ class Shout_Driver_Ldap extends Shout_Driver ldap_errno($conn), ldap_error($conn)), __FILE__, __LINE__, PEAR_LOG_WARNING); - throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn)); + throw new Shout_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn)); } } @@ -765,7 +699,7 @@ class Shout_Driver_Ldap extends Shout_Driver @ldap_errno($conn), @ldap_error($conn)), __FILE__, __LINE__, PEAR_LOG_ERR); - throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn)); + throw new Shout_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn)); } } diff --git a/shout/lib/Driver/Sql.php b/shout/lib/Driver/Sql.php index 8eaac441b..63583663a 100644 --- a/shout/lib/Driver/Sql.php +++ b/shout/lib/Driver/Sql.php @@ -69,8 +69,9 @@ class Shout_Driver_Sql extends Shout_Driver */ public function getDevices($context) { - $sql = 'SELECT id, name, alias, callerid, context, mailbox, host, permit, ' . - 'nat, secret, disallow, allow FROM %s WHERE accountcode = ?'; + $sql = 'SELECT id, name, alias, callerid, context, mailbox, host, ' . + 'permit, nat, secret, disallow, allow ' . + 'FROM %s WHERE accountcode = ?'; $sql = sprintf($sql, $this->_params['table']); $args = array($context); $result = $this->_db->query($sql, $args); @@ -163,6 +164,7 @@ class Shout_Driver_Sql extends Shout_Driver */ public function saveExtension($context, $extension, $userdetails) { + parent::saveExtension($context, $extension, $details); throw new Shout_Exception("Not implemented."); } @@ -182,7 +184,7 @@ class Shout_Driver_Sql extends Shout_Driver /** * Attempts to open a persistent connection to the SQL server. * - * @throws Horde_Exception + * @throws Shout_Exception */ protected function _connect() { @@ -207,7 +209,7 @@ class Shout_Driver_Sql extends Shout_Driver $this->_write_db = DB::connect($this->_params, array('persistent' => !empty($this->_params['persistent']))); if ($this->_write_db instanceof PEAR_Error) { - throw Horde_Exception($this->_write_db); + throw Shout_Exception($this->_write_db); } // Set DB portability options. @@ -226,7 +228,7 @@ class Shout_Driver_Sql extends Shout_Driver $this->_db = DB::connect($params, array('persistent' => !empty($params['persistent']))); if ($this->_db instanceof PEAR_Error) { - throw Horde_Exception($this->_db); + throw Shout_Exception($this->_db); } // Set DB portability options. diff --git a/shout/lib/Forms/ExtensionForm.php b/shout/lib/Forms/ExtensionForm.php index 0b23911b2..3acb4d7a9 100644 --- a/shout/lib/Forms/ExtensionForm.php +++ b/shout/lib/Forms/ExtensionForm.php @@ -23,22 +23,23 @@ class ExtensionDetailsForm extends Horde_Form { { global $shout_extensions; $context = $_SESSION['shout']['context']; - if ($vars->exists('extension')) { + $action = $vars->get('action'); + if ($action == 'edit') { $formtitle = "Edit User"; - $extension = $vars->get('extension'); } else { $formtitle = "Add User"; } + $extension = $vars->get('extension'); + parent::__construct($vars, _("$formtitle - Context: $context")); + $this->addHidden('', 'action', 'text', true); - $vars->set('action', 'save'); - $this->addHidden('', 'extension', 'int', true); - $vars->set('newextension', $extension); + $this->addHidden('', 'oldextension', 'text', false); $this->addVariable(_("Full Name"), 'name', 'text', true); - $this->addVariable(_("Extension"), 'newextension', 'int', true); + $this->addVariable(_("Extension"), 'extension', 'int', true); $this->addVariable(_("E-Mail Address"), 'email', 'email', true); - $this->addVariable(_("Pager E-Mail Address"), 'pageremail', 'email', false); + //$this->addVariable(_("Pager E-Mail Address"), 'pageremail', 'email', false); $this->addVariable(_("PIN"), 'mailboxpin', 'int', true); return true; @@ -54,15 +55,16 @@ class ExtensionDetailsForm extends Horde_Form { { global $shout_extensions; - $extension = $this->vars->get('extension'); + $extension = $this->_vars->get('extension'); - # FIXME: Input Validation (Text::??) + // FIXME: Input Validation (Text::??) $details = array( - 'newextension' => $vars->get('newextension'), - 'name' => $vars->get('name'), - 'mailboxpin' => $vars->get('mailboxpin'), - 'email' => $vars->get('email'), - ); + 'name' => $this->_vars->get('name'), + 'oldextension' => $this->_vars->get('oldextension'), + 'email' => $this->_vars->get('email'), + //'pager' => $this->_vars->get('pageremail') + 'mailboxpin' => $this->_vars->get('mailboxpin'), + ); $res = $shout_extensions->saveExtension($context, $extension, $details); } diff --git a/shout/lib/Shout.php b/shout/lib/Shout.php index 8eed4aa8a..2dc4ebbaa 100644 --- a/shout/lib/Shout.php +++ b/shout/lib/Shout.php @@ -129,8 +129,7 @@ class Shout $numparents--; } $test = $superadmin | $user; -$ret = ($test & $permmask) == $permmask; -print "Shout::checkRights() returning $ret"; + return ($test & $permmask) == $permmask; } } -- 2.11.0