Overview

Packages

  • Gollem
  • None

Classes

  • Gollem
  • Gollem_Ajax_Application
  • Gollem_Api
  • Gollem_Auth
  • Gollem_Exception
  • Gollem_Factory_Vfs
  • Gollem_Factory_VfsDefault
  • Gollem_LoginTasks_SystemTask_Upgrade
  • Gollem_Test
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Gollem_Auth class provides authentication for Gollem.
  4:  *
  5:  * Copyright 2004-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * See the enclosed file COPYING for license information (LGPL). If you
  8:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
  9:  *
 10:  * @author  Michael Slusarz <slusarz@horde.org>
 11:  * @author  Jan Schneider <jan@horde.org>
 12:  * @package Gollem
 13:  */
 14: class Gollem_Auth
 15: {
 16:     /**
 17:      * Authenticate to the backend.
 18:      *
 19:      * @param array $credentials  An array of login credentials. If empty,
 20:      *                            attempts to login to the cached session.
 21:      * <pre>
 22:      * 'password' - (string) The user password.
 23:      * 'backend' - (string) The backend key to use (from backends.php).
 24:      * 'userId' - (string) The username.
 25:      * </pre>
 26:      *
 27:      * @return mixed  If authentication was successful, and no session
 28:      *                exists, an array of data to add to the session.
 29:      *                Otherwise returns false.
 30:      * @throws Horde_Auth_Exception
 31:      */
 32:     static public function authenticate($credentials = array())
 33:     {
 34:         $result = false;
 35: 
 36:         // Do 'horde' authentication.
 37:         $gollem_app = $GLOBALS['registry']->getApiInstance('gollem', 'application');
 38:         if (!empty($gollem_app->initParams['authentication']) &&
 39:             ($gollem_app->initParams['authentication'] == 'horde')) {
 40:             if ($registry->getAuth()) {
 41:                 return $result;
 42:             }
 43:             throw new Horde_Auth_Exception('', Horde_Auth::REASON_FAILED);
 44:         }
 45: 
 46:         // Load backend.
 47:         if (!isset($credentials['backend_key'])) {
 48:             $credentials['backend_key'] = self::getPreferredBackend();
 49:         }
 50:         $backend = self::getBackend($credentials['backend_key']);
 51: 
 52:         // Check for hordeauth.
 53:         if ((!isset($credentials['userId']) ||
 54:              !isset($credentials['password'])) &&
 55:             !$GLOBALS['session']->exists('gollem', 'backend_key') &&
 56:             self::canAutoLogin()) {
 57:             if (!empty($backend['hordeauth'])) {
 58:                 $credentials['userId'] = self::getAutologinID($credentials['backend_key']);
 59:                 $credentials['password'] = $GLOBALS['registry']->getAuthCredential('password');
 60: 
 61:             }
 62:         }
 63: 
 64:         // Check for hardcoded backend credentials.
 65:         if (!isset($credentials['userId']) &&
 66:             !empty($backend['params']['username'])) {
 67:             $credentials['userId'] = $backend['params']['username'];
 68:         }
 69:         if (!isset($credentials['password']) &&
 70:             !empty($backend['params']['password'])) {
 71:             $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
 72:             $credentials['password'] = $secret->read(
 73:                 $secret->getKey('gollem'),
 74:                 $backend['params']['password']);
 75:         }
 76: 
 77:         if (!isset($credentials['userId']) ||
 78:             !isset($credentials['password'])) {
 79:             throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN);
 80:         }
 81: 
 82:         try {
 83:             $vfs = $GLOBALS['injector']
 84:                 ->getInstance('Gollem_Factory_Vfs')
 85:                 ->create($credentials['backend_key']);
 86:             $vfs->setParams(array('username' => $credentials['userId'],
 87:                                   'password' => $credentials['password']));
 88:             $vfs->checkCredentials();
 89:         } catch (Horde_Exception $e) {
 90:             throw new Horde_Auth_Exception($e->getMessage(), Horde_Auth::REASON_MESSAGE);
 91:         }
 92: 
 93:         // Set current backend.
 94:         Gollem::$backend = &$backend;
 95: 
 96:         // Mark backend as authenticated.
 97:         $backend['auth'] = true;
 98: 
 99:         // Save username in backend configuration.
100:         if (!isset($backend['params']['username'])) {
101:             $backend['params']['username'] = $credentials['userId'];
102:         }
103:         if (!isset($backend['params']['password'])) {
104:             $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
105:             $backend['params']['password'] = $secret->write($secret->getKey('gollem'), $credentials['password']);
106:         }
107: 
108:         // Make sure we have a 'root' parameter.
109:         if (empty($backend['root'])) {
110:             $backend['root'] = '/';
111:         }
112:         $backend['root'] = Horde_Util::realPath($backend['root']);
113: 
114:         // Make sure we have a 'home' parameter.
115:         if (empty($backend['home'])) {
116:             $backend['home'] = empty($backend['params']['home'])
117:                 ? $vfs->getCurrentDirectory()
118:                 : $backend['params']['home'];
119:             if (empty($backend['home'])) {
120:                 $backend['home'] = $backend['root'];
121:             }
122:         }
123: 
124:         // Make sure the home parameter lives under root if it is a relative
125:         // directory.
126:         if (strpos($backend['home'], '/') !== 0) {
127:             $backend['home'] = $backend['root'] . '/' . $backend['home'];
128:         }
129:         $backend['home'] = Horde_Util::realPath($backend['home']);
130:         $backend['dir'] = $backend['home'];
131: 
132:         // Verify that home is below root.
133:         if (!Gollem::verifyDir($backend['home'])) {
134:             throw new Horde_Auth_Exception('Backend Configuration Error: Home directory not below root.', Horde_Auth::REASON_MESSAGE);
135:         }
136: 
137:         // Create the home directory if it doesn't already exist.
138:         if ($backend['home'] != '/' && !empty($backend['createhome'])) {
139:             $pos = strrpos($backend['home'], '/');
140:             $cr_dir = substr($backend['home'], 0, $pos);
141:             $cr_file = substr($backend['home'], $pos + 1);
142:             if (!$vfs->exists($cr_dir, $cr_file)) {
143:                 try {
144:                     $res = Gollem::createFolder($cr_dir, $cr_file, $vfs);
145:                 } catch (Gollem_Exception $e) {
146:                     throw new Horde_Auth_Exception('Backend Configuration Error: Could not create home directory ' . $backend['home'] . ': ' . $e->getMessage(), Horde_Auth::REASON_MESSAGE);
147:                 }
148:             }
149:         }
150: 
151:         // Write the backend to the session.
152:         $backends = $GLOBALS['session']->get('gollem', 'backends');
153:         $backends[$credentials['backend_key']] = $backend;
154:         $GLOBALS['session']->set('gollem', 'backends', $backends);
155: 
156:         return array('backend_key' => $credentials['backend_key']);
157:     }
158: 
159:     /**
160:      * Perform transparent authentication.
161:      *
162:      * @param Horde_Auth_Application $auth_ob  The authentication object.
163:      *
164:      * @return mixed  If authentication was successful, and no session
165:      *                exists, an array of data to add to the session.
166:      *                Otherwise returns false.
167:      */
168:     static public function transparent($auth_ob)
169:     {
170:         $credentials = $auth_ob->getCredential('credentials');
171: 
172:         if (empty($credentials['transparent'])) {
173:             /* Attempt hordeauth authentication. */
174:             $credentials = self::canAutoLogin();
175:             if ($credentials === false) {
176:                 return false;
177:             }
178:         } else {
179:             /* It is possible that preauthenticate() set the credentials.
180:              * If so, use that information instead of hordeauth. */
181:             $credentials['userId'] = $auth_ob->getCredential('userId');
182:         }
183: 
184:         try {
185:             return self::authenticate($credentials);
186:         } catch (Horde_Auth_Exception $e) {
187:             return false;
188:         }
189:     }
190: 
191:     /**
192:      * Loads the Gollem backend configuration from backends.php.
193:      *
194:      * @param string $backend  Returns this labeled entry only.
195:      *
196:      * @return mixed  If $backend is set return this entry; else, return the
197:      *                entire backends array. Returns false on error.
198:      */
199:     static public function getBackend($backend = null)
200:     {
201:         if (!($backends = $GLOBALS['session']->get('gollem', 'backends'))) {
202:             try {
203:                 $backends = Horde::loadConfiguration('backends.php', 'backends', 'gollem');
204:                 if (is_null($backends)) {
205:                     return false;
206:                 }
207:             } catch (Horde_Exception $e) {
208:                 Horde::logMessage($e, 'ERR');
209:                 return false;
210:             }
211: 
212:             foreach (array_keys($backends) as $key) {
213:                 if (!empty($backends[$key]['disabled']) ||
214:                     !Gollem::checkPermissions('backend', Horde_Perms::SHOW, $key)) {
215:                     unset($backends[$key]);
216:                 }
217:                 if (isset($backends[$key]['params']['password'])) {
218:                     $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
219:                     $backends[$key]['params']['password'] = $secret->write($secret->getKey('gollem'), $backends[$key]['params']['password']);
220:                 }
221:             }
222:             $GLOBALS['session']->set('gollem', 'backends', $backends);
223:         }
224: 
225:         if (is_null($backend)) {
226:             return $backends;
227:         }
228: 
229:         /* Check for the existence of the backend in the config file. */
230:         if (empty($backends[$backend]) || !is_array($backends[$backend])) {
231:             $entry = sprintf('Invalid backend key "%s" from client [%s]',
232:                              $backend, $_SERVER['REMOTE_ADDR']);
233:             Horde::logMessage($entry, 'ERR');
234:             return false;
235:         }
236: 
237:         return $backends[$backend];
238:     }
239: 
240:     /**
241:      * Get the current preferred backend key.
242:      *
243:      * @return string  The preferred backend key.
244:      */
245:     static public function getPreferredBackend()
246:     {
247:         if ($backend_key = $GLOBALS['session']->get('gollem', 'backend_key')) {
248:             return $backend_key;
249:         }
250: 
251:         /* Determine the preferred backend. */
252:         foreach (self::getBackend() as $key => $backend) {
253:             if (empty($backend_key) && (substr($key, 0, 1) != '_')) {
254:                 $backend_key = $key;
255:             }
256:             if (empty($backend['preferred'])) {
257:                 continue;
258:             }
259:             $preferred = is_array($backend['preferred'])
260:                 ? $backend['preferred']
261:                 : array($backend['preferred']);
262:             if (in_array($_SERVER['SERVER_NAME'], $preferred) ||
263:                 in_array($_SERVER['HTTP_HOST'], $preferred)) {
264:                 $backend_key = $key;
265:             }
266:         }
267: 
268:         return $backend_key;
269:     }
270: 
271:     /**
272:      * Get the authentication ID to use for autologins based on the value of
273:      * the 'hordeauth' parameter.
274:      *
275:      * @param string $backend  The backend to login to.
276:      *
277:      * @return string  The ID string to use for logins.
278:      */
279:     static public function getAutologinID($backend)
280:     {
281:         $config = self::getBackend($backend);
282:         return (!empty($config['hordeauth']) &&
283:                 strcasecmp($config['hordeauth'], 'full') === 0)
284:             ? $GLOBALS['registry']->getAuth()
285:             : $GLOBALS['registry']->getAuth('bare');
286:     }
287: 
288:     /**
289:      * Can we log in without a login screen for the requested backend key?
290:      *
291:      * @param string $key     The backend key to check. Defaults to
292:      *                        self::getPreferredBackend().
293:      * @param boolean $force  If true, check the backend key even if there is
294:      *                        more than one backend.
295:      *
296:      * @return array  The credentials needed to login ('userId', 'password',
297:      *                'backend') or false if autologin not available.
298:      */
299:     static public function canAutoLogin($key = null, $force = false)
300:     {
301:         $auto_server = self::getPreferredBackend();
302:         if ($key === null) {
303:             $key = $auto_server;
304:         }
305: 
306:         if ((count($auto_server) == 1 || $force) &&
307:             $GLOBALS['registry']->getAuth() &&
308:             ($config = self::getBackend($key)) &&
309:             empty($config['loginparams']) &&
310:             !empty($config['hordeauth'])) {
311:             return array(
312:                 'userId' => self::getAutologinID($key),
313:                 'password' => $GLOBALS['registry']->getAuthCredential('password'),
314:                 'backend_key' => $key
315:             );
316:         }
317: 
318:         return false;
319:     }
320: 
321:     /**
322:      * Change the currently active backend.
323:      *
324:      * @param string $key  The ID of the backend to set as active.
325:      */
326:     static public function changeBackend($key)
327:     {
328:         $GLOBALS['session']->set('gollem', 'backend_key', $key);
329:         Gollem::$backend = self::getBackend($key);
330:     }
331: 
332: }
333: 
API documentation generated by ApiGen