[ingo] Requesting comment on a patch to enable "proxy" authentication in Ingo

Etienne Goyer etienne.goyer at linuxquebec.com
Mon Jul 21 12:14:59 PDT 2003


Hi list,

I have a patch here that implement so-called "proxy" authentication with
Ingo.  For those unfamiliar with the concept, protocol that use SASL for
authentication and authorization have the possibility (not necessarily
implemented) to allow one user to proxy for another.  This could be used,
for example, by an administrative user to perform routine maintenance on
behalf of a user, etc.

Protocol that can use various SASL method, such as IMAP and
Managesieve, can pass both an authentication id (shortened to authcid)
and an authorization id (shortened to authzid) to the SASL mechanism.
If the authcid and the authzid differ, the mechanism is supposed to
verify the authcid and the password to authenticate.  If authcid is
permitted to act on behalf of authzid, authorization is granted. I am 
not an expert on SASL myself so I may have gotten some of the lingo
wrong, but this is basically how it work. 

To implement this feature, change had to be made to the Net_Sieve
module.  I submit a patch to the maintainer of this module this morning;
hopefully, it will be accepted.

One of the change made to Ingo to make this work is quite intrusive.
Since not every backend type support "proxy" authentication, I had to
move the credentials fetching from lib/Ingo.php to the specific backend
drivers (lib/Driver/*).  This make more sense to me, but create some
code duplication for adding realm to the username.  Overall, I think it
is worth it since future backend driver may have different requirement
in this regard.

My patch include change to both the timsieved and vfs driver, but I
tested only the timsieved driver.  I cannot foresee any problem vfs, but
this will have to be tested eventually.

Here is included my patchs for both Ingo and Net_Sieve.  Since
integration of the required part in Net_Sieve is not yet complete, it's
too soon to integrate my changes in Ingo but I would like feedback about
suitability of them.  These change are critical to me and I would be 
willing to do more work if they are not acceptable for some reason in
their current state. I am eagerly awaiting comment from those wielding 
the mighty commit bit  :) 

Regards,

-- 
Etienne Goyer                    Linux Québec Technologies Inc.
http://www.LinuxQuebec.com       etienne.goyer at linuxquebec.com
-------------- next part --------------
diff -ur ingo.orig/config/backends.php.dist ingo/config/backends.php.dist
--- ingo.orig/config/backends.php.dist	Mon Jul 21 10:40:58 2003
+++ ingo/config/backends.php.dist	Mon Jul 21 10:46:12 2003
@@ -44,6 +44,10 @@
         'hostspec' => 'mail.example.com',
         // Login type of the server
         'logintype' => 'PLAIN',
+        // Authentication id (username by default)
+        //'authcid' => 'cyrus',
+        // Password for authcid (if different than user's)
+        //'password' = '',
         // Port number of the timsieved server
         'port' => 2000,
         // Name of the sieve script
diff -ur ingo.orig/lib/Driver/timsieved.php ingo/lib/Driver/timsieved.php
--- ingo.orig/lib/Driver/timsieved.php	Mon Jul 21 10:01:32 2003
+++ ingo/lib/Driver/timsieved.php	Mon Jul 21 10:57:38 2003
@@ -38,19 +38,42 @@
      * Sets a script running on the backend.
      *
      * @param string $script    The sieve script.
-     * @param string $username  The backend username.
-     * @param string $password  The backend password.
      *
      * @return mixed  True on success.
      *                Returns PEAR_Error on error.
      */
-    function setScriptActive($script, $username, $password)
+    function setScriptActive($script)
     {
-        $sieve = &new Net_Sieve($username,
+	$authzid = Auth::getAuth();
+        $backend = Ingo::getBackend();
+        if (is_a($backend, 'PEAR_Error')) {
+            $notification->push($backend->getMessage(), 'horde.error');
+            return false;
+        } else {
+            if (($backend['hordeauth'] == 'user') &&
+                (($pos = strpos($authzid, '@')) !== false)) {
+                $authzid = substr($authzid, 0, $pos);
+            }
+        }
+
+	if (isset($this->_params['authcid'])) {
+            if (isset($this->_params['password'])) {
+                $authcid = $this->_params['authcid'];
+                $password = $this->_params['password'];
+            } else {
+                return PEAR::raiseError(_(sprintf("No password for authentication id had been specified.")));
+            }
+	} else {
+            $authcid = $authzid;
+	    $password = Auth::getCredential('password');
+	}
+
+        $sieve = &new Net_Sieve($authzid,
                                 $password,
                                 $this->_params['hostspec'],
                                 $this->_params['port'],
-                                $this->_params['logintype']);
+                                $this->_params['logintype'],
+				$authcid);
 
         if (is_a($sieve, 'PEAR_Error')) {
             return $sieve;
diff -ur ingo.orig/lib/Driver/vfs.php ingo/lib/Driver/vfs.php
--- ingo.orig/lib/Driver/vfs.php	Mon Jul 21 10:30:35 2003
+++ ingo/lib/Driver/vfs.php	Mon Jul 21 10:55:26 2003
@@ -41,13 +41,24 @@
      *
      * @return mixed  True on success, or PEAR_Error on failure.
      */
-    function setScriptActive($script, $username, $password)
+    function setScriptActive($script)
     {
         if ($this->_params['vfstype'] != 'ftp') {
             return PEAR::raiseError(_(sprintf("VFS type '%s' not yet implemented.", $this->_params['vfstype'])));
         }
-        $this->_params['username'] = $username;
-        $this->_params['password'] = $password;
+
+        $this->_params['username'] = Auth::getAuth;
+        $this->_params['password'] = Auth::getCredentials('password');
+        $backend = Ingo::getBackend();
+        if (is_a($backend, 'PEAR_Error')) {
+            $notification->push($backend->getMessage(), 'horde.error');
+            return false;
+        } else {        
+            if (($backend['hordeauth'] == 'user') &&
+                (($pos = strpos($this->_params['username'], '@')) !== false)) {
+                $this->_params['username'] = substr($this->_params['username'], 0, $pos);
+            }
+        }
 
         require_once HORDE_BASE . '/lib/VFS.php';
         $vfs = &VFS::singleton($this->_params['vfstype'], $this->_params);
diff -ur ingo.orig/lib/Ingo.php ingo/lib/Ingo.php
--- ingo.orig/lib/Ingo.php	Mon Jul 21 10:39:20 2003
+++ ingo/lib/Ingo.php	Mon Jul 21 10:40:03 2003
@@ -75,18 +75,12 @@
             return false;
         }
 
-        $uid = Auth::getAuth();
-        if (($backend['hordeauth'] == 'user') &&
-            (($pos = strpos($uid, '@')) !== false)) {
-            $uid = substr($uid, 0, $pos);
-        }
-
         require_once INGO_BASE . '/lib/Driver.php';
         if (empty($backend['driver'])) {
             $notification->push(sprintf(_("No '%s' element found in backend configuration."), 'driver'), 'horde.error');
         } else {
             $driver = &Ingo_Driver::singleton($backend['driver'], $backend['params']);
-            $res = $driver->setScriptActive($script, $uid, Auth::getCredential('password'));
+            $res = $driver->setScriptActive($script);
             if (is_a($res, 'PEAR_Error')) {
                 $notification->push(sprintf(_("There was an error activating this script. The driver said: %s"), $res->getMessage()), 'horde.error');
             } elseif ($res === true) {
-------------- next part --------------
--- Sieve.php.orig	Mon Jul 21 09:26:01 2003
+++ Sieve.php	Mon Jul 21 11:20:46 2003
@@ -104,20 +104,24 @@
     * using the getError() method.
     *
     * @access public
-    * @param  string $user      Login username
-    * @param  string $pass      Login password
+    * @param  string $authzid   Authorization id
+    * @param  string $pass      Password
     * @param  string $host      Hostname of server
     * @param  string $port      Port of server
     * @param  string $logintype Type of login to perform
+    * @param  string $authcid   Authentication id (if any, default to authzid)
     */
-    function Net_Sieve($user, $pass, $host = 'localhost', $port = 2000, $logintype = 'PLAIN')
+    function Net_Sieve($authzid, $pass, $host = 'localhost', $port = 2000, $logintype = 'PLAIN', $authcid)
     {
         $this->_state = NET_SIEVE_STATE_DISCONNECTED;
 
-        $this->_data['user'] = $user;
-        $this->_data['pass'] = $pass;
-        $this->_data['host'] = $host;
-        $this->_data['port'] = $port;
+        if (!isset($authcid)) { $authcid = $authzid; }
+
+        $this->_data['authzid'] = $authzid;
+        $this->_data['pass']    = $pass;
+        $this->_data['host']    = $host;
+        $this->_data['port']    = $port;
+        $this->_data['authcid'] = $authcid;
         $this->_sock = &new Net_Socket();
 
         if (PEAR::isError($res = $this->_connect($host, $port))) {
@@ -125,7 +129,7 @@
             return;
         }
 
-        if (PEAR::isError($res = $this->_login($user, $pass, $logintype))) {
+        if (PEAR::isError($res = $this->_login($authzid, $pass, $logintype, $authcid))) {
             $this->_error = $res;
         }
     }
@@ -266,17 +270,18 @@
     * Logs into server.
     *
     * @access private
-    * @param  string $user      Login username
-    * @param  string $pass      Login password
+    * @param  string $authzid   Authorization id
+    * @param  string $pass      Password
     * @param  string $logintype Type of login method to use
+    * @param  string $authcid   Authentication id (if any)
     * @return mixed             True on success, PEAR_Error otherwise
     */
-    function _login($user, $pass, $logintype = 'PLAIN')
+    function _login($authzid, $pass, $logintype = 'PLAIN', $authcid)
     {
         if (NET_SIEVE_STATE_AUTHORISATION == $this->_state) {
 
             if ($logintype == 'PLAIN' AND in_array('PLAIN', $this->_capability['sasl'])) {
-                $this->_sendCmd(sprintf('AUTHENTICATE "PLAIN" "%s"', base64_encode(chr(0) . $user . chr(0) . $pass)));
+                $this->_sendCmd(sprintf('AUTHENTICATE "PLAIN" "%s"', base64_encode($authzid . chr(0) . $authcid . chr(0) . $pass)));
 
             } elseif ($logintype == 'PLAIN' AND in_array('LOGIN', $this->_capability['sasl'])) {
                 $this->_sendCmd('AUTHENTICATE "LOGIN"');
@@ -532,4 +537,4 @@
         }
     }
 }
-?>
\ No newline at end of file
+?>


More information about the ingo mailing list