Overview

Packages

  • Auth

Classes

  • Horde_Auth
  • Horde_Auth_Auto
  • Horde_Auth_Base
  • Horde_Auth_Composite
  • Horde_Auth_Customsql
  • Horde_Auth_Cyrsql
  • Horde_Auth_Exception
  • Horde_Auth_Ftp
  • Horde_Auth_Http
  • Horde_Auth_Http_Remote
  • Horde_Auth_Imap
  • Horde_Auth_Ipbasic
  • Horde_Auth_Kolab
  • Horde_Auth_Ldap
  • Horde_Auth_Login
  • Horde_Auth_Msad
  • Horde_Auth_Pam
  • Horde_Auth_Passwd
  • Horde_Auth_Peclsasl
  • Horde_Auth_Radius
  • Horde_Auth_Shibboleth
  • Horde_Auth_Smb
  • Horde_Auth_Smbclient
  • Horde_Auth_Sql
  • Horde_Auth_Translation
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Horde_Auth_Cyrsql class provides a SQL implementation of the Horde
  4:  * authentication system for the Cyrus IMAP server. Most of the functionality
  5:  * is the same as for the SQL class; only what is different overrides the
  6:  * parent class implementations.
  7:  *
  8:  * The table structure for the auth system is as follows:
  9:  * <pre>
 10:  * CREATE TABLE accountuser (
 11:  *     username    VARCHAR(255) BINARY NOT NULL DEFAULT '',
 12:  *     password    VARCHAR(32) BINARY NOT NULL DEFAULT '',
 13:  *     prefix      VARCHAR(50) NOT NULL DEFAULT '',
 14:  *     domain_name VARCHAR(255) NOT NULL DEFAULT '',
 15:  *     UNIQUE KEY username (username)
 16:  * );
 17:  *
 18:  * CREATE TABLE adminuser (
 19:  *     username    VARCHAR(50) BINARY NOT NULL DEFAULT '',
 20:  *     password    VARCHAR(50) BINARY NOT NULL DEFAULT '',
 21:  *     type        INT(11) NOT NULL DEFAULT '0',
 22:  *     SID         VARCHAR(255) NOT NULL DEFAULT '',
 23:  *     home        VARCHAR(255) NOT NULL DEFAULT '',
 24:  *     PRIMARY KEY (username)
 25:  * );
 26:  *
 27:  * CREATE TABLE alias (
 28:  *     alias       VARCHAR(255) NOT NULL DEFAULT '',
 29:  *     dest        LONGTEXT,
 30:  *     username    VARCHAR(50) NOT NULL DEFAULT '',
 31:  *     status      INT(11) NOT NULL DEFAULT '1',
 32:  *     PRIMARY KEY (alias)
 33:  * );
 34:  *
 35:  * CREATE TABLE domain (
 36:  *     domain_name VARCHAR(255) NOT NULL DEFAULT '',
 37:  *     prefix      VARCHAR(50) NOT NULL DEFAULT '',
 38:  *     maxaccounts INT(11) NOT NULL DEFAULT '20',
 39:  *     quota       INT(10) NOT NULL DEFAULT '20000',
 40:  *     transport   VARCHAR(255) NOT NULL DEFAULT 'cyrus',
 41:  *     freenames   ENUM('YES','NO') NOT NULL DEFAULT 'NO',
 42:  *     freeaddress ENUM('YES','NO') NOT NULL DEFAULT 'NO',
 43:  *     PRIMARY KEY (domain_name),
 44:  *     UNIQUE KEY prefix (prefix)
 45:  * );
 46:  *
 47:  * CREATE TABLE domainadmin (
 48:  *     domain_name VARCHAR(255) NOT NULL DEFAULT '',
 49:  *     adminuser   VARCHAR(255) NOT NULL DEFAULT ''
 50:  * );
 51:  *
 52:  * CREATE TABLE search (
 53:  *     search_id   VARCHAR(255) NOT NULL DEFAULT '',
 54:  *     search_sql  TEXT NOT NULL,
 55:  *     perpage     INT(11) NOT NULL DEFAULT '0',
 56:  *     timestamp   TIMESTAMP(14) NOT NULL,
 57:  *     PRIMARY KEY (search_id),
 58:  *     KEY search_id (search_id)
 59:  * );
 60:  *
 61:  * CREATE TABLE virtual (
 62:  *     alias       VARCHAR(255) NOT NULL DEFAULT '',
 63:  *     dest        LONGTEXT,
 64:  *     username    VARCHAR(50) NOT NULL DEFAULT '',
 65:  *     status      INT(11) NOT NULL DEFAULT '1',
 66:  *     KEY alias (alias)
 67:  * );
 68:  *
 69:  * CREATE TABLE log (
 70:  *     id          INT(11) NOT NULL AUTO_INCREMENT,
 71:  *     msg         TEXT NOT NULL,
 72:  *     user        VARCHAR(255) NOT NULL DEFAULT '',
 73:  *     host        VARCHAR(255) NOT NULL DEFAULT '',
 74:  *     time        DATETIME NOT NULL DEFAULT '2000-00-00 00:00:00',
 75:  *     pid         VARCHAR(255) NOT NULL DEFAULT '',
 76:  *     PRIMARY KEY (id)
 77:  * );
 78:  * </pre>
 79:  *
 80:  * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
 81:  *
 82:  * See the enclosed file COPYING for license information (LGPL). If you did
 83:  * not receive this file, http://www.horde.org/licenses/lgpl21
 84:  *
 85:  * @author   Ilya Krel <mail@krel.org>
 86:  * @author   Jan Schneider <jan@horde.org>
 87:  * @category Horde
 88:  * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
 89:  * @package  Auth
 90:  */
 91: class Horde_Auth_Cyrsql extends Horde_Auth_Sql
 92: {
 93:     /**
 94:      * An array of capabilities, so that the driver can report which
 95:      * operations it supports and which it doesn't.
 96:      *
 97:      * @var array
 98:      */
 99:     protected $_capabilities = array(
100:         'add'           => true,
101:         'list'          => true,
102:         'remove'        => true,
103:         'resetpassword' => false,
104:         'update'        => true,
105:         'authenticate'  => true,
106:     );
107: 
108:     /**
109:      * Horde_Imap_Client object.
110:      *
111:      * @var Horde_Imap_Client_Base
112:      */
113:     protected $_imap;
114: 
115:     /**
116:      * Constructor.
117:      *
118:      * @param array $params  Parameters:
119:      * <pre>
120:      * 'charset' - (string) Default charset.
121:      *             DEFAULT: NONE
122:      * 'domain_field' - (string) If set to anything other than 'none' this is
123:      *                  used as field name where domain is stored.
124:      *                  DEFAULT: 'domain_name'
125:      * 'folders' - (array) An array of folders to create under username.
126:      *             DEFAULT: NONE
127:      * 'hidden_accounts' - (array) An array of system accounts to hide from
128:      *                     the user interface.
129:      *                     DEFAULT: None.
130:      * 'imap' - (Horde_Imap_Client_Base) [REQUIRED] An IMAP client object.
131:      * 'quota' - (integer) The quota (in kilobytes) to grant on the mailbox.
132:      *           DEFAULT: NONE
133:      * 'userhierarchy' - (string) The user hierarchy prefix.
134:      *                   DEFAULT: 'user.'
135:      * </pre>
136:      *
137:      * @throws InvalidArgumentException
138:      */
139:     public function __construct(array $params = array())
140:     {
141:         if (!isset($params['imap']) ||
142:             !($params['imap'] instanceof Horde_Imap_Client_Base)) {
143:             throw new InvalidArgumentException('Missing imap parameter.');
144:         }
145:         $this->_imap = $params['imap'];
146:         unset($params['imap']);
147: 
148:         $params = array_merge(array(
149:             'charset' => null,
150:             'domain_field' => 'domain_name',
151:             'folders' => array(),
152:             'hidden_accounts' => array('cyrus'),
153:             'quota' => null,
154:             'userhierarchy' => 'user.'
155:         ), $params);
156: 
157:         parent::__construct($params);
158:     }
159: 
160:     /**
161:      * Find out if a set of login credentials are valid.
162:      *
163:      * @param string $userId      The userId to check.
164:      * @param array $credentials  The credentials to use.
165:      *
166:      * @throws Horde_Auth_Exception
167:      */
168:     protected function _authenticate($userId, $credentials)
169:     {
170:         if (!empty($this->_params['domain_field']) &&
171:             ($this->_params['domain_field'] != 'none')) {
172:             /* Build the SQL query with domain. */
173:             $query = sprintf('SELECT * FROM %s WHERE %s = ? AND %s = ?',
174:                              $this->_params['table'],
175:                              $this->_params['username_field'],
176:                              $this->_params['domain_field']);
177:             $values = explode('@', $userId);
178:         } else {
179:             /* Build the SQL query without domain. */
180:             $query = sprintf('SELECT * FROM %s WHERE %s = ?',
181:                              $this->_params['table'],
182:                              $this->_params['username_field']);
183:             $values = array($userId);
184:         }
185: 
186:         try {
187:             $row = $this->_db->selectOne($query, $values);
188:         } catch (Horde_Db_Exception $e) {
189:             throw new Horde_Auth_Exception('', Horde_Auth::REASON_FAILED);
190:         }
191: 
192:         if (!$row ||
193:             !$this->_comparePasswords($row[$this->_params['password_field']], $credentials['password'])) {
194:             throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN);
195:         }
196: 
197:         $now = time();
198:         if (!empty($this->_params['hard_expiration_field']) &&
199:             !empty($row[$this->_params['hard_expiration_field']]) &&
200:             ($now > $row[$this->_params['hard_expiration_field']])) {
201:             throw new Horde_Auth_Exception('', Horde_Auth::REASON_EXPIRED);
202:         }
203: 
204:         if (!empty($this->_params['soft_expiration_field']) &&
205:             !empty($row[$this->_params['soft_expiration_field']]) &&
206:             ($now > $row[$this->_params['soft_expiration_field']])) {
207:             $this->setCredential('change', true);
208:         }
209:     }
210: 
211:     /**
212:      * Add a set of authentication credentials.
213:      *
214:      * @param string $userId       The userId to add.
215:      * @param array  $credentials  The credentials to add.
216:      *
217:      * @throw Horde_Auth_Exception
218:      */
219:     public function addUser($userId, $credentials)
220:     {
221:         if (!empty($this->_params['domain_field']) &&
222:             ($this->_params['domain_field'] != 'none')) {
223:             list($name, $domain) = explode('@', $userId);
224: 
225:             $query = sprintf('INSERT INTO %s (%s, %s, %s) VALUES (?, ?, ?)',
226:                              $this->_params['table'],
227:                              $this->_params['username_field'],
228:                              $this->_params['domain_field'],
229:                              $this->_params['password_field']);
230:             $values = array(
231:                 $name,
232:                 $domain,
233:                 Horde_Auth::getCryptedPassword($credentials['password'],
234:                                                '',
235:                                                $this->_params['encryption'],
236:                                                $this->_params['show_encryption'])
237:             );
238: 
239:             $query2 = 'INSERT INTO virtual (alias, dest, username, status) VALUES (?, ?, ?, 1)';
240:             $values2 = array($userId, $userId, $name);
241: 
242:             try {
243:                 $this->_db->insert($query, $values);
244:                 $this->_db->insert($query2, $values2);
245:             } catch (Horde_Db_Exception $e) {
246:                 throw new Horde_Auth_Exception($e);
247:             }
248:         } else {
249:             parent::addUser($userId, $credentials);
250:         }
251: 
252:         $mailbox = Horde_String::convertCharset($this->_params['userhierarchy'] . $userId, $this->_params['charset'], 'utf7-imap');
253: 
254:         try {
255:             $this->_imap->createMailbox($mailbox);
256:             $this->_imap->setACL($mailbox, $this->_params['cyradmin'], 'lrswipcda');
257:             if (isset($this->_params['quota']) &&
258:                 ($this->_params['quota'] >= 0)) {
259:                 $this->_imap->setQuota($mailbox, array('storage' => $this->_params['quota']));
260:             }
261:         } catch (Horde_Imap_Client_Exception $e) {
262:             throw new Horde_Auth_Exception($e);
263:         }
264: 
265:         foreach ($this->_params['folders'] as $val) {
266:             try {
267:                 $this->_imap->createMailbox($val);
268:                 $this->_imap->setACL($val, $this->_params['cyradmin'], 'lrswipcda');
269:             } catch (Horde_Imap_Client_Exception $e) {}
270:         }
271:     }
272: 
273:     /**
274:      * Delete a set of authentication credentials.
275:      *
276:      * @param string $userId  The userId to delete.
277:      *
278:      * @throws Horde_Auth_Exception
279:      */
280:     public function removeUser($userId)
281:     {
282:         if (!empty($this->_params['domain_field']) &&
283:             ($this->_params['domain_field'] != 'none')) {
284:             list($name, $domain) = explode('@', $userId);
285: 
286:             /* Build the SQL query. */
287:             $query = sprintf('DELETE FROM %s WHERE %s = ? and %s = ?',
288:                              $this->_params['table'],
289:                              $this->_params['username_field'],
290:                              $this->_params['domain_field']);
291:             $values = array($name, $domain);
292: 
293:             $query2 = 'DELETE FROM virtual WHERE dest = ?';
294:             $values2 = array($userId);
295: 
296:             try {
297:                 $this->_db->delete($query, $values);
298:                 $this->_db->delete($query2, $values2);
299:             } catch (Horde_Db_Exception $e) {
300:                 throw new Horde_Auth_Exception($e);
301:             }
302:         } else {
303:             parent::removeUser($userId);
304:         }
305: 
306:         /* Set ACL for mailbox deletion. */
307:         list($admin) = explode('@', $this->_params['cyradmin']);
308: 
309:         $mailbox = Horde_String::convertCharset($this->_params['userhierarchy'] . $userId, $this->_params['charset'], 'utf7-imap');
310: 
311:         try {
312:             $this->_imap->setACL($mailbox, $admin, array('rights' => 'lrswipcda'));
313:             $this->_imap->deleteMailbox($mailbox);
314:         } catch (Horde_Imap_Client_Exception $e) {
315:             throw new Horde_Auth_Exception($e);
316:         }
317:     }
318: 
319:     /**
320:      * List all users in the system.
321:      *
322:      * @return mixed  The array of userIds.
323:      * @throws Horde_Auth_Exception
324:      */
325:     public function listUsers($sort = false)
326:     {
327:         if (!empty($this->_params['domain_field']) &&
328:             ($this->_params['domain_field'] != 'none')) {
329:             /* Build the SQL query with domain. */
330:             $query = sprintf('SELECT %s, %s FROM %s',
331:                              $this->_params['username_field'],
332:                              $this->_params['domain_field'],
333:                              $this->_params['table']);
334:         } else {
335:             /* Build the SQL query without domain. */
336:             $query = sprintf('SELECT %s FROM %s',
337:                              $this->_params['username_field'],
338:                              $this->_params['table']);
339:         }
340:         if ($sort) {
341:             $query .= sprintf(" ORDER BY %s", $this->_params['username_field']);
342:         }
343: 
344:         try {
345:             $result = $this->_db->selectAll($query);
346:         } catch (Horde_Db_Exception $e) {
347:             throw new Horde_Auth_Exception($e);
348:         }
349: 
350:         /* Loop through and build return array. */
351:         $users = array();
352:         if (!empty($this->_params['domain_field']) &&
353:             ($this->_params['domain_field'] != 'none')) {
354:             foreach ($result as $ar) {
355:                 if (!in_array($ar[$this->_params['username_field']], $this->_params['hidden_accounts'])) {
356:                     $users[] = $ar[$this->_params['username_field']] . '@' . $ar[$this->_params['domain_field']];
357:                 }
358:             }
359:         } else {
360:             foreach ($result as $ar) {
361:                 if (!in_array($ar[$this->_params['username_field']], $this->_params['hidden_accounts'])) {
362:                     $users[] = $ar[$this->_params['username_field']];
363:                 }
364:             }
365:         }
366:         return $users;
367:     }
368: 
369:     /**
370:      * Update a set of authentication credentials.
371:      *
372:      * @param string $oldID       The old userId.
373:      * @param string $newID       The new userId. [NOT SUPPORTED]
374:      * @param array $credentials  The new credentials
375:      *
376:      * @throws Horde_Auth_Exception
377:      */
378:     public function updateUser($oldID, $newID, $credentials)
379:     {
380:         if (!empty($this->_params['domain_field']) &&
381:             ($this->_params['domain_field'] != 'none')) {
382:             list($name, $domain) = explode('@', $oldID);
383:             /* Build the SQL query with domain. */
384:             $query = sprintf(
385:                 'UPDATE %s SET %s = ? WHERE %s = ? and %s = ?',
386:                 $this->_params['table'],
387:                 $this->_params['password_field'],
388:                 $this->_params['username_field'],
389:                 $this->_params['domain_field']
390:             );
391:             $values = array(
392:                 Horde_Auth::getCryptedPassword($credentials['password'], '', $this->_params['encryption'], $this->_params['show_encryption']),
393:                 $name,
394:                 $domain
395:             );
396:         } else {
397:             /* Build the SQL query. */
398:             $query = sprintf(
399:                 'UPDATE %s SET %s = ? WHERE %s = ?',
400:                 $this->_params['table'],
401:                 $this->_params['password_field'],
402:                 $this->_params['username_field']
403:             );
404:             $values = array(
405:                 Horde_Auth::getCryptedPassword($credentials['password'], '', $this->_params['encryption'], $this->_params['show_encryption']),
406:                 $oldID
407:             );
408:         }
409: 
410:         try {
411:             $this->_db->update($query, $values);
412:         } catch (Horde_Db_Exception $e) {
413:             throw new Horde_Auth_Exception($e);
414:         }
415:     }
416: 
417: }
418: 
API documentation generated by ApiGen