Horde_Auth improvements
authorMichael M Slusarz <slusarz@curecanti.org>
Thu, 23 Jul 2009 16:49:24 +0000 (10:49 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Thu, 23 Jul 2009 16:56:34 +0000 (10:56 -0600)
Standardize pre/post-authenticate hooks and ensure they are called for
all authentication events.
Use transparent() authentication to authenticate to applications that
don't require any additional authentication.

framework/Auth/lib/Horde/Auth.php
framework/Auth/lib/Horde/Auth/Application.php
framework/Auth/lib/Horde/Auth/Base.php

index f9c9b4a..f5e9eaf 100644 (file)
@@ -378,17 +378,10 @@ class Horde_Auth
             return self::checkExistingAuth();
         }
 
-        if (empty($options['app'])) {
-            $auth = self::singleton($driver);
-        } else {
-            $auth = self::singleton('application', array('app' => $driver));
-
-            /* If we have a horde session, and the app doesn't need additional
-             * auth, mark that in the session and return. */
-            if ($is_auth && !$auth->hasCapability('authenticate')) {
-                return self::setAuth($is_auth, self::getCredential(), array('app' => $driver));
-            }
-        }
+        /* Try transparent authentication. */
+        $auth = empty($options['app'])
+            ? self::singleton($driver)
+            : self::singleton('application', array('app' => $driver));
 
         return $auth->transparent();
     }
@@ -639,13 +632,10 @@ class Horde_Auth
         $app = empty($options['app']) ? 'horde' : $options['app'];
         $userId = self::addHook(trim($userId));
 
-        if (!empty($GLOBALS['conf']['hooks']['postauthenticate'])) {
-            if (Horde::callHook('_horde_hook_postauthenticate', array($userId, $credentials, $app), 'horde') === false) {
-                if (self::getAuthError() != self::REASON_MESSAGE) {
-                    self::setAuthError(self::REASON_FAILED);
-                }
-                return false;
-            }
+        try {
+            list($userId, $credentials) = self::runHook($userId, $credentials, $app, 'postauthenticate');
+        } catch (Horde_Auth_Exception $e) {
+            return false;
         }
 
         $app_array = array();
@@ -818,6 +808,45 @@ class Horde_Auth
     }
 
     /**
+     * Runs the pre/post-authenticate hook and parses the result.
+     *
+     * @param string $userId      The userId who has been authorized.
+     * @param array $credentials  The credentials of the user.
+     * @param string $app         The app currently being authenticated.
+     * @param string $type        Either 'preauthenticate' or
+     *                            'postauthenticate'.
+     *
+     * @return array  Two element array, $userId and $credentials.
+     * @throws Horde_Auth_Exception
+     */
+    static public function runHook($userId, $credentials, $app, $type)
+    {
+        $ret_array = array($userId, $credentials);
+
+        if (!empty($GLOBALS['conf']['hooks'][$type])) {
+            $result = Horde::callHook('_horde_hook_' . $type, array($userId, $credentials, $app), 'horde');
+            if ($result === false) {
+                if (self::getAuthError() != self::REASON_MESSAGE) {
+                    self::setAuthError(self::REASON_FAILED);
+                }
+                throw new Horde_Auth_Exception($type . ' hook failed');
+            }
+
+            if (is_array($result)) {
+                if (isset($result['userId'])) {
+                    $ret_array[0] = $result['userId'];
+                }
+
+                if (isset($result['credentials'])) {
+                    $ret_array[1] = $result['credentials'];
+                }
+            }
+        }
+
+        return $ret_array;
+    }
+
+    /**
      * Returns the name of the authentication provider.
      *
      * @return string  The name of the driver currently providing
index 6df6e19..d3549ee 100644 (file)
@@ -47,11 +47,13 @@ class Horde_Auth_Application extends Horde_Auth_Base
      * Constructor.
      *
      * @param array $params  A hash containing connection parameters.
+     * @throws Horde_Exception
      */
     public function __construct($params = array())
     {
         Horde::assertDriverConfig($params, 'auth', array('app'), 'authentication application');
 
+        $this->_app = $params['app'];
         parent::__construct($params);
     }
 
@@ -70,7 +72,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
         if (!in_array($capability, $this->_loaded) &&
             isset($this->_apiMethods[$capability])) {
             $registry = Horde_Registry::singleton();
-            $this->_capabilities[$capability] = $registry->hasMethod($this->_apiMethods[$capability], $this->_params['app']);
+            $this->_capabilities[$capability] = $registry->hasMethod($this->_apiMethods[$capability], $this->_app);
             $this->_loaded[] = $capability;
         }
 
@@ -112,7 +114,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     protected function _authenticate($userId, $credentials)
     {
         if (!$this->hasCapability('authenticate')) {
-            throw new Horde_Auth_Exception($this->_params['app'] . ' does not provide an authenticate() method.');
+            throw new Horde_Auth_Exception($this->_app . ' does not provide an authenticate() method.');
         }
 
         $registry = Horde_Registry::singleton();
@@ -120,8 +122,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
         $credentials['auth_ob'] = $this;
 
         try {
-            $result = $registry->callByPackage($this->_params['app'], $this->_apiMethods['authenticate'], array($userId, $credentials));
-            $this->_credentials['params']['app'] = $this->_params['app'];
+            $result = $registry->callByPackage($this->_app, $this->_apiMethods['authenticate'], array($userId, $credentials));
         } catch (Horde_Auth_Exception $e) {
             throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN);
         }
@@ -137,7 +138,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     {
         if ($this->hasCapability('list')) {
             $registry = Horde_Registry::singleton();
-            return $registry->callByPackage($this->_params['app'], $this->_apiMethods['list']);
+            return $registry->callByPackage($this->_app, $this->_apiMethods['list']);
         } else {
             return parent::listUsers();
         }
@@ -154,7 +155,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     {
         if ($this->hasCapability('exists')) {
             $registry = Horde_Registry::singleton();
-            return $registry->callByPackage($this->_params['app'], $this->_apiMethods['exists'], array($userId));
+            return $registry->callByPackage($this->_app, $this->_apiMethods['exists'], array($userId));
         } else {
             return parent::exists($userId);
         }
@@ -172,7 +173,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     {
         if ($this->hasCapability('add')) {
             $registry = Horde_Registry::singleton();
-            $registry->callByPackage($this->_params['app'], $this->_apiMethods['exists'], array($userId, $credentials));
+            $registry->callByPackage($this->_app, $this->_apiMethods['exists'], array($userId, $credentials));
         } else {
             parent::addUser($userId, $credentials);
         }
@@ -191,7 +192,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     {
         if ($this->hasCapability('update')) {
             $registry = Horde_Registry::singleton();
-            $registry->callByPackage($this->_params['app'], $this->_apiMethods['update'], array($oldID, $newID, $credentials));
+            $registry->callByPackage($this->_app, $this->_apiMethods['update'], array($oldID, $newID, $credentials));
         } else {
             parent::updateUser($userId, $credentials);
         }
@@ -208,7 +209,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     {
         if ($this->hasCapability('remove')) {
             $registry = Horde_Registry::singleton();
-            $registry->callByPackage($this->_params['app'], $this->_apiMethods['remove'], array($userId));
+            $registry->callByPackage($this->_app, $this->_apiMethods['remove'], array($userId));
             Horde_Auth::removeUserData($userId);
         } else {
             parent::removeUser($userId);
@@ -241,16 +242,15 @@ class Horde_Auth_Application extends Horde_Auth_Base
     protected function _transparent()
     {
         if (!$this->hasCapability('transparent')) {
-            return false;
+            /* If this application contains neither transparent nor
+             * authenticate capabilities, it does not require any
+             * authentication if already authenticated to Horde. */
+            return (Horde_Auth::getAuth() &&
+                    !$this->hasCapability('authenticate'));
         }
 
         $registry = Horde_Registry::singleton();
-        if (!$registry->callByPackage($this->_params['app'], $this->_apiMethods['transparent'])) {
-            return false;
-        }
-
-        $this->_credentials['params']['app'] = $this->_params['app'];
-        return true;
+        return $registry->callByPackage($this->_app, $this->_apiMethods['transparent']);
     }
 
     /**
@@ -269,7 +269,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
         }
 
         $registry = Horde_Registry::singleton();
-        return $registry->callByPackage($this->_params['app'], $this->_apiMethods['loginparams']);
+        return $registry->callByPackage($this->_app, $this->_apiMethods['loginparams']);
     }
 
     /**
@@ -307,7 +307,7 @@ class Horde_Auth_Application extends Horde_Auth_Base
     {
         if ($this->hasCapability('authenticatecallback')) {
             $registry = Horde_Registry::singleton();
-            $registry->callByPackage($this->_params['app'], $this->_apiMethods['authenticatecallback']);
+            $registry->callByPackage($this->_app, $this->_apiMethods['authenticatecallback']);
         }
     }
 
index 974da44..9e8a547 100644 (file)
@@ -50,6 +50,13 @@ abstract class Horde_Auth_Base
     );
 
     /**
+     * Current application for authentication.
+     *
+     * @param string
+     */
+    protected $_app = 'horde';
+
+    /**
      * Constructor.
      *
      * @param array $params  A hash containing parameters.
@@ -76,19 +83,17 @@ abstract class Horde_Auth_Base
         $auth = false;
         $userId = trim($userId);
 
-        if (!empty($GLOBALS['conf']['hooks']['preauthenticate'])) {
-            if (!Horde::callHook('_horde_hook_preauthenticate', array($userId, $credentials), 'horde')) {
-                if (Horde_Auth::getAuthError() != Horde_Auth::REASON_MESSAGE) {
-                    Horde_Auth::setAuthError(Horde_Auth::REASON_FAILED);
-                }
-                return $auth;
-            }
+        try {
+            list($userId, $credentials) = Horde_Auth::runHook($userId, $credentials, $this->_app, 'preauthenticate');
+         } catch (Horde_Auth_Exception $e) {
+            return false;
         }
 
         /* Store the credentials being checked so that subclasses can modify
          * them if necessary. */
         $this->_credentials['credentials'] = $credentials;
         $this->_credentials['userId'] = $userId;
+        $this->_credentials['params']['app'] = $this->_app;
 
         try {
             $this->_authenticate($userId, $credentials);
@@ -202,10 +207,20 @@ abstract class Horde_Auth_Base
      */
     public function transparent()
     {
+        $userId = empty($this->_credentials['userId'])
+            ? Horde_Auth::getAuth()
+            : $this->_credentials['userId'];
+        $credentials = empty($this->_credentials['credentials'])
+            ? Horde_Auth::getCredential()
+            : $this->_credentials['credentials'];
+
+        list($this->_credentials['userId'], $this->_credentials['credentials']) = Horde_Auth::runHook($userId, $credentials, $this->_app, 'preauthenticate');
+        $this->_credentials['params']['app'] = $this->_app;
+
         if ($this->_transparent()) {
             return Horde_Auth::setAuth(
-                empty($this->_credentials['userId']) ? Horde_Auth::getAuth() : $this->_credentials['userId'],
-                empty($this->_credentials['credentials']) ? Horde_Auth::getCredential() : $this->_credentials['credentials'],
+                $this->_credentials['userId'],
+                $this->_credentials['credentials'],
                 $this->_credentials['params']
             );
         }