Dotclear

source: inc/core/class.dc.auth.php @ 2159:d709a73eb75b

Revision 2159:d709a73eb75b, 14.7 KB checked in by Nicolas <nikrou77@…>, 12 years ago (diff)

blog_count was only set when getPermissions was called.
Add a new method (getBlogCount()) that used blog_count param or retrieved it from database.
close 1545

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14/**
15* @ingroup DC_CORE
16* @nosubgrouping
17* @brief Authentication and user credentials management
18*
19* dcAuth is a class used to handle everything related to user authentication
20* and credentials. Object is provided by dcCore $auth property.
21*/
22class dcAuth
23{
24     /** @var dcCore dcCore instance */
25     protected $core;
26     /** @var connection Database connection object */
27     protected $con;
28     
29     /** @var string User table name */
30     protected $user_table;
31     /** @var string Perm table name */
32     protected $perm_table;
33     
34     /** @var string Current user ID */
35     protected $user_id;
36     /** @var array Array with user information */
37     protected $user_info = array();
38     /** @var array Array with user options */
39     protected $user_options = array();
40     /** @var boolean User must change his password after login */
41     protected $user_change_pwd;
42     /** @var boolean User is super admin */
43     protected $user_admin;
44     /** @var array Permissions for each blog */
45     protected $permissions = array();
46     /** @var boolean User can change its password */
47     protected $allow_pass_change = true;
48     /** @var array List of blogs on which the user has permissions */
49     protected $blogs = array();
50     /** @var integer Count of user blogs */
51     public $blog_count = null;
52     
53     /** @var array Permission types */
54     protected $perm_types;
55     
56     /** @var dcPrefs dcPrefs object */
57     public $user_prefs;
58     
59     /**
60     * Class constructor. Takes dcCore object as single argument.
61     *
62     * @param dcCore     $core          dcCore object
63     */
64     public function __construct($core)
65     {
66          $this->core =& $core;
67          $this->con =& $core->con;
68          $this->blog_table = $core->prefix.'blog';
69          $this->user_table = $core->prefix.'user';
70          $this->perm_table = $core->prefix.'permissions';
71         
72          $this->perm_types = array(
73               'admin' => __('administrator'),
74               'usage' => __('manage their own entries and comments'),
75               'publish' => __('publish entries and comments'),
76               'delete' => __('delete entries and comments'),
77               'contentadmin' => __('manage all entries and comments'),
78               'categories' => __('manage categories'),
79               'media' => __('manage their own media items'),
80               'media_admin' => __('manage all media items')
81          );
82     }
83     
84     /// @name Credentials and user permissions
85     //@{
86     /**
87     * Checks if user exists and can log in. <var>$pwd</var> argument is optionnal
88     * while you may need to check user without password. This method will create
89     * credentials and populate all needed object properties.
90     *
91     * @param string     $user_id       User ID
92     * @param string     $pwd           User password
93     * @param string     $user_key      User key check
94     * @param boolean    $check_blog    checks if user is associated to a blog or not.
95     * @return boolean
96     */
97     public function checkUser($user_id, $pwd=null, $user_key=null, $check_blog=true)
98     {
99          # Check user and password
100          $strReq = 'SELECT user_id, user_super, user_pwd, user_change_pwd, '.
101                    'user_name, user_firstname, user_displayname, user_email, '.
102                    'user_url, user_default_blog, user_options, '.
103                    'user_lang, user_tz, user_post_status, user_creadt, user_upddt '.
104                    'FROM '.$this->con->escapeSystem($this->user_table).' '.
105                    "WHERE user_id = '".$this->con->escape($user_id)."' ";
106         
107          try {
108               $rs = $this->con->select($strReq);
109          } catch (Exception $e) {
110               $err = $e->getMessage();
111               return false;
112          }         
113         
114          if ($rs->isEmpty()) {
115               return false;
116          }
117         
118          $rs->extend('rsExtUser');
119         
120          if ($pwd != '')
121          {
122               if (crypt::hmac(DC_MASTER_KEY,$pwd) != $rs->user_pwd) {
123                    sleep(rand(2,5));
124                    return false;
125               }
126          }
127          elseif ($user_key != '')
128          {
129               if (http::browserUID(DC_MASTER_KEY.$rs->user_id.$rs->user_pwd) != $user_key) {
130                    return false;
131               }
132          }
133         
134          $this->user_id = $rs->user_id;
135          $this->user_change_pwd = (boolean) $rs->user_change_pwd;
136          $this->user_admin = (boolean) $rs->user_super;
137         
138          $this->user_info['user_pwd'] = $rs->user_pwd;
139          $this->user_info['user_name'] = $rs->user_name;
140          $this->user_info['user_firstname'] = $rs->user_firstname;
141          $this->user_info['user_displayname'] = $rs->user_displayname;
142          $this->user_info['user_email'] = $rs->user_email;
143          $this->user_info['user_url'] = $rs->user_url;
144          $this->user_info['user_default_blog'] = $rs->user_default_blog;
145          $this->user_info['user_lang'] = $rs->user_lang;
146          $this->user_info['user_tz'] = $rs->user_tz;
147          $this->user_info['user_post_status'] = $rs->user_post_status;
148          $this->user_info['user_creadt'] = $rs->user_creadt;
149          $this->user_info['user_upddt'] = $rs->user_upddt;
150         
151          $this->user_info['user_cn'] = dcUtils::getUserCN($rs->user_id, $rs->user_name,
152          $rs->user_firstname, $rs->user_displayname);
153         
154          $this->user_options = array_merge($this->core->userDefaults(),$rs->options());
155         
156          $this->user_prefs = new dcPrefs($this->core,$this->user_id);
157         
158          # Get permissions on blogs
159          if ($check_blog && ($this->findUserBlog() === false)) {
160               return false;
161          }
162          return true;
163     }
164     
165     /**
166     * This method only check current user password.
167     *
168     * @param string     $pwd           User password
169     * @return boolean
170     */
171     public function checkPassword($pwd)
172     {
173          if (!empty($this->user_info['user_pwd'])) {
174               return $pwd == $this->user_info['user_pwd'];
175          }
176         
177          return false;
178     }
179     
180     /**
181     * This method checks if user session cookie exists
182     *
183     * @return boolean
184     */
185     public function sessionExists()
186     {
187          return isset($_COOKIE[DC_SESSION_NAME]);
188     }
189     
190     /**
191     * This method checks user session validity.
192     *
193     * @return boolean
194     */
195     public function checkSession($uid=null)
196     {
197          $this->core->session->start();
198         
199          # If session does not exist, logout.
200          if (!isset($_SESSION['sess_user_id'])) {
201               $this->core->session->destroy();
202               return false;
203          }
204         
205          # Check here for user and IP address
206          $this->checkUser($_SESSION['sess_user_id']);
207          $uid = $uid ? $uid : http::browserUID(DC_MASTER_KEY);
208         
209          $user_can_log = $this->userID() !== null && $uid == $_SESSION['sess_browser_uid'];
210         
211          if (!$user_can_log) {
212               $this->core->session->destroy();
213               return false;
214          }
215         
216          return true;
217     }
218     
219     /**
220     * Checks if user must change his password in order to login.
221     *
222     * @return boolean
223     */
224     public function mustChangePassword()
225     {
226          return $this->user_change_pwd;
227     }
228     
229     /**
230     * Checks if user is super admin
231     *
232     * @return boolean
233     */
234     public function isSuperAdmin()
235     {
236          return $this->user_admin;
237     }
238     
239     /**
240     * Checks if user has permissions given in <var>$permissions</var> for blog
241     * <var>$blog_id</var>. <var>$permissions</var> is a coma separated list of
242     * permissions.
243     *
244     * @param string     $permissions   Permissions list
245     * @param string     $blog_id       Blog ID
246     * @return boolean
247     */
248     public function check($permissions,$blog_id)
249     {
250          if ($this->user_admin) {
251               return true;
252          }
253         
254          $p = explode(',',$permissions);
255          $b = $this->getPermissions($blog_id);
256         
257          if ($b != false)
258          {
259               if (isset($b['admin'])) {
260                    return true;
261               }
262               
263               foreach ($p as $v)
264               {
265                    if (isset($b[$v])) {
266                         return true;
267                    }
268               }
269          }
270         
271          return false;
272     }
273     
274     /**
275     * Returns true if user is allowed to change its password.
276     *
277     * @return boolean
278     */
279     public function allowPassChange()
280     {
281          return $this->allow_pass_change;
282     }
283     //@}
284     
285     /// @name User code handlers
286     //@{
287     public function getUserCode()
288     {
289          $code =
290          pack('a32',$this->userID()).
291          pack('H*',crypt::hmac(DC_MASTER_KEY,$this->getInfo('user_pwd')));
292          return bin2hex($code);
293     }
294     
295     public function checkUserCode($code)
296     {
297          $code = @pack('H*',$code);
298         
299          $user_id = trim(@pack('a32',substr($code,0,32)));
300          $pwd = @unpack('H40hex',substr($code,32,40));
301         
302          if ($user_id === false || $pwd === false) {
303               return false;
304          }
305         
306          $pwd = $pwd['hex'];
307         
308          $strReq = 'SELECT user_id, user_pwd '.
309                    'FROM '.$this->user_table.' '.
310                    "WHERE user_id = '".$this->con->escape($user_id)."' ";
311         
312          $rs = $this->con->select($strReq);
313         
314          if ($rs->isEmpty()) {
315               return false;
316          }
317         
318          if (crypt::hmac(DC_MASTER_KEY,$rs->user_pwd) != $pwd) {
319               return false;
320          }
321         
322          return $rs->user_id;
323     }
324     //@}
325     
326     
327     /// @name Sudo
328     //@{
329     /**
330     * Calls $f function with super admin rights.
331     * Returns the function result.
332     *
333     * @param callback   $f             Callback function
334     * @return mixed
335     */
336     public function sudo($f)
337     {
338          if (!is_callable($f)) {
339               throw new Exception($f.' function doest not exist');
340          }
341         
342          $args = func_get_args();
343          array_shift($args);
344         
345          if ($this->user_admin) {
346               $res = call_user_func_array($f,$args);
347          } else {
348               $this->user_admin = true;
349               try {
350                    $res = call_user_func_array($f,$args);
351                    $this->user_admin = false;
352               } catch (Exception $e) {
353                    $this->user_admin = false;
354                    throw $e;
355               }
356          }
357         
358          return $res;
359     }
360     //@}
361     
362     /// @name User information and options
363     //@{
364     /**
365     * Returns user permissions for a blog as an array which looks like:
366     *
367     *  - [blog_id]
368     *    - [permission] => true
369     *    - ...
370     *
371     * @param string     $blog_id       Blog ID
372     * @return array
373     */
374     public function getPermissions($blog_id)
375     {
376          if (isset($this->blogs[$blog_id])) {
377               return $this->blogs[$blog_id];
378          }
379
380          if ($this->user_admin) {
381               $strReq = 'SELECT blog_id '.
382                    'from '.$this->blog_table.' '.
383                    "WHERE blog_id = '".$this->con->escape($blog_id)."' ";
384               $rs = $this->con->select($strReq);
385               
386               $this->blogs[$blog_id] = $rs->isEmpty() ? false : array('admin' => true);
387               
388               return $this->blogs[$blog_id];
389          }
390         
391          $strReq = 'SELECT permissions '.
392                    'FROM '.$this->perm_table.' '.
393                    "WHERE user_id = '".$this->con->escape($this->user_id)."' ".
394                    "AND blog_id = '".$this->con->escape($blog_id)."' ".
395                    "AND (permissions LIKE '%|usage|%' OR permissions LIKE '%|admin|%' OR permissions LIKE '%|contentadmin|%') ";
396          $rs = $this->con->select($strReq);
397         
398          $this->blogs[$blog_id] = $rs->isEmpty() ? false : $this->parsePermissions($rs->permissions);
399         
400          return $this->blogs[$blog_id];
401     }
402
403    public function getBlogCount() {
404          if ($this->blog_count === null) {
405               $this->blog_count = $this->core->getBlogs(array(),true)->f(0);
406          }
407
408        return $this->blog_count;
409    }
410     
411     public function findUserBlog($blog_id=null)
412     {
413          if ($blog_id && $this->getPermissions($blog_id) !== false)
414          {
415               return $blog_id;
416          }
417          else
418          {
419               if ($this->user_admin)
420               {
421                    $strReq = 'SELECT blog_id '.
422                              'FROM '.$this->blog_table.' '.
423                              'ORDER BY blog_id ASC '.
424                              $this->con->limit(1);
425               }
426               else
427               {
428                    $strReq = 'SELECT blog_id '.
429                              'FROM '.$this->perm_table.' '.
430                              "WHERE user_id = '".$this->con->escape($this->user_id)."' ".
431                              "AND (permissions LIKE '%|usage|%' OR permissions LIKE '%|admin|%' OR permissions LIKE '%|contentadmin|%') ".
432                              'ORDER BY blog_id ASC '.
433                              $this->con->limit(1);
434               }
435               
436               $rs = $this->con->select($strReq);
437               if (!$rs->isEmpty()) {
438                    return $rs->blog_id;
439               }
440          }
441         
442          return false;
443     }
444     
445     /**
446     * Returns current user ID
447     *
448     * @return string
449     */
450     public function userID()
451     {
452          return $this->user_id;
453     }
454     
455     /**
456     * Returns information about a user .
457     *
458     * @param string     $n             Information name
459     * @return string
460     */
461     public function getInfo($n)
462     {
463          if (isset($this->user_info[$n])) {
464               return $this->user_info[$n];
465          }
466         
467          return null;
468     }
469     
470     /**
471     * Returns a specific user option
472     *
473     * @param string     $n             Option name
474     * @return string
475     */
476     public function getOption($n)
477     {
478          if (isset($this->user_options[$n])) {
479               return $this->user_options[$n];
480          }
481          return null;
482     }
483     
484     /**
485     * Returns all user options in an associative array.
486     *
487     * @return array
488     */
489     public function getOptions()
490     {
491          return $this->user_options;
492     }
493     //@}
494     
495     /// @name Permissions
496     //@{
497     /**
498     * Returns an array with permissions parsed from the string <var>$level</var>
499     *
500     * @param string     $level         Permissions string
501     * @return array
502     */
503     public function parsePermissions($level)
504     {
505          $level = preg_replace('/^\|/','',$level);
506          $level = preg_replace('/\|$/','',$level);
507         
508          $res = array();
509          foreach (explode('|',$level) as $v) {
510               $res[$v] = true;
511          }
512          return $res;
513     }
514     
515     /**
516     * Returns <var>perm_types</var> property content.
517     *
518     * @return array
519     */
520     public function getPermissionsTypes()
521     {
522          return $this->perm_types;
523     }
524     
525     /**
526     * Adds a new permission type.
527     *
528     * @param string     $name          Permission name
529     * @param string     $title         Permission title
530     */
531     public function setPermissionType($name,$title)
532     {
533          $this->perm_types[$name] = $title;
534     }
535     //@}
536     
537     /// @name Password recovery
538     //@{
539     /**
540     * Add a recover key to a specific user identified by its email and
541     * password.
542     *
543     * @param string     $user_id       User ID
544     * @param string     $user_email    User Email
545     * @return string
546     */
547     public function setRecoverKey($user_id,$user_email)
548     {
549          $strReq = 'SELECT user_id '.
550                    'FROM '.$this->user_table.' '.
551                    "WHERE user_id = '".$this->con->escape($user_id)."' ".
552                    "AND user_email = '".$this->con->escape($user_email)."' ";
553         
554          $rs = $this->con->select($strReq);
555         
556          if ($rs->isEmpty()) {
557               throw new Exception(__('That user does not exist in the database.'));
558          }
559         
560          $key = md5(uniqid());
561         
562          $cur = $this->con->openCursor($this->user_table);
563          $cur->user_recover_key = $key;
564         
565          $cur->update("WHERE user_id = '".$this->con->escape($user_id)."'");
566         
567          return $key;
568     }
569     
570     /**
571     * Creates a new user password using recovery key. Returns an array:
572     *
573     * - user_email
574     * - user_id
575     * - new_pass
576     *
577     * @param string     $recover_key   Recovery key
578     * @return array
579     */
580     public function recoverUserPassword($recover_key)
581     {
582          $strReq = 'SELECT user_id, user_email '.
583                    'FROM '.$this->user_table.' '.
584                    "WHERE user_recover_key = '".$this->con->escape($recover_key)."' ";
585         
586          $rs = $this->con->select($strReq);
587         
588          if ($rs->isEmpty()) {
589               throw new Exception(__('That key does not exist in the database.'));
590          }
591         
592          $new_pass = crypt::createPassword();
593         
594          $cur = $this->con->openCursor($this->user_table);
595          $cur->user_pwd = crypt::hmac(DC_MASTER_KEY,$new_pass);
596          $cur->user_recover_key = null;
597         
598          $cur->update("WHERE user_recover_key = '".$this->con->escape($recover_key)."'");
599         
600          return array('user_email' => $rs->user_email, 'user_id' => $rs->user_id, 'new_pass' => $new_pass);
601     }
602     //@}
603     
604     /** @name User management callbacks
605     This 3 functions only matter if you extend this class and use
606     DC_AUTH_CLASS constant.
607     These are called after core user management functions.
608     Could be useful if you need to add/update/remove stuff in your
609     LDAP directory or other third party authentication database.
610     */
611     //@{
612     
613     /**
614     * Called after core->addUser
615     * @see dcCore::addUser
616     * @param cursor     $cur           User cursor
617     */
618     public function afterAddUser($cur) {}
619     
620     /**
621     * Called after core->updUser
622     * @see dcCore::updUser
623     * @param string     $id            User ID
624     * @param cursor     $cur           User cursor
625     */
626     public function afterUpdUser($id,$cur) {}
627     
628     /**
629     * Called after core->delUser
630     * @see dcCore::delUser
631     * @param string     $id            User ID
632     */
633     public function afterDelUser($id) {}
634     //@}
635}
636?>
Note: See TracBrowser for help on using the repository browser.

Sites map