Overview

Classes

  • Ws_logged_inModel
  • Ws_permissionsModel
  • Ws_role_permModel
  • Ws_rolesModel
  • Ws_user_roleModel
  • Ws_userModel
  • WsAuth
  • WsauthController
  • WsChart
  • WsConfig
  • WsController
  • WsDatabase
  • WsForm
  • WsImage
  • WsLocalize
  • WsModel
  • WsModelForm
  • WsModelGridView
  • WsUrl

Functions

  • __autoload
  • callHook
  • WsErrorHandler
  • Overview
  • Class
  1: <?php
  2: /**
  3:  * WsAuth
  4:  * Base class for user authentication.
  5:  *
  6:  * Example usage:
  7:  *
  8:  * <code>
  9:  * $auth = new WsAuth();
 10:  *
 11:  * //check if any user is logged in
 12:  * if ($auth->checkSessioun()) {
 13:  * .
 14:  * .
 15:  * .
 16:  * }
 17:  *
 18:  * // check if logged in user has specific permission
 19:  * if ($auth->hasPermission('perm_name')) {
 20:  * .
 21:  * .
 22:  * .
 23:  * }
 24:  * </code>
 25:  *
 26:  */
 27: class WsAuth
 28: {
 29:     /**
 30:      * checks if database object is available. Database is needed for WsAuth
 31:      * module.
 32:      */
 33:     public $isUsable;
 34:     private $_db;
 35: 
 36: 
 37:     public function __construct()
 38:     {
 39:         // connect to database
 40:         $this->_db = new WsDatabase();
 41: 
 42:         if (!$this->_db->isConnected) {
 43:             $this->isUsable = false;
 44:             return false; // cant't use WsAuth if there is no db connection
 45:         } else {
 46:             $this->isUsable = true;
 47:         }
 48: 
 49:         // auth database tables for PostgreSQL server
 50:         if (WsConfig::get('db_driver') === 'pgsql') {
 51:             $create_table = '
 52: CREATE TABLE IF NOT EXISTS ws_user (
 53:     id SERIAL PRIMARY KEY,
 54:     email VARCHAR(128) NOT NULL,
 55:     password VARCHAR(128) NOT NULL,
 56:     user_salt VARCHAR(50) NOT NULL,
 57:     is_verified BOOLEAN NOT NULL,
 58:     is_active BOOLEAN NOT NULL,
 59:     verification_code VARCHAR(65) NOT NULL
 60: );
 61: ';
 62:             $this->_db->execute($create_table);
 63:             $create_table = '
 64: CREATE TABLE IF NOT EXISTS ws_logged_in (
 65:     id SERIAL PRIMARY KEY,
 66:     user_id INTEGER NOT NULL REFERENCES ws_user(id),
 67:     session_id CHAR(32) NOT NULL,
 68:     token CHAR(128) NOT NULL
 69: );
 70: ';
 71:             $this->_db->execute($create_table);
 72:             $create_table = '
 73: CREATE TABLE IF NOT EXISTS ws_roles (
 74:     id SERIAL PRIMARY KEY,
 75:     name VARCHAR(25) NOT NULL,
 76:     description VARCHAR(50)
 77: );
 78: ';
 79:             $this->_db->execute($create_table);
 80:             $create_table = '
 81: CREATE TABLE IF NOT EXISTS ws_permissions (
 82:     id SERIAL PRIMARY KEY,
 83:     name VARCHAR(25) NOT NULL,
 84:     description VARCHAR(50)
 85: );
 86: ';
 87:             $this->_db->execute($create_table);
 88:             $create_table = '
 89: CREATE TABLE IF NOT EXISTS ws_role_perm (
 90:     role_id INTEGER NOT NULL REFERENCES ws_roles(id),
 91:     permissions_id INTEGER NOT NULL REFERENCES ws_permissions(id)
 92: );
 93: ';
 94:             $this->_db->execute($create_table);
 95:             $create_table = '
 96: CREATE TABLE IF NOT EXISTS ws_user_role (
 97:     user_id INTEGER NOT NULL REFERENCES ws_user(id),
 98:     role_id INTEGER NOT NULL REFERENCES ws_roles(id)
 99: );
100: ';
101:             $this->_db->execute($create_table);
102: 
103:         // auth tables for MariaDB/MySql database server
104:         } else if (WsConfig::get('db_driver') === 'mysql') {
105:             $create_table = '
106: CREATE TABLE IF NOT EXISTS ws_user (
107:     id INTEGER PRIMARY KEY AUTO_INCREMENT,
108:     email VARCHAR(128) NOT NULL,
109:     password VARCHAR(128) NOT NULL,
110:     user_salt VARCHAR(50) NOT NULL,
111:     is_verified BOOLEAN NOT NULL,
112:     is_active BOOLEAN NOT NULL,
113:     verification_code VARCHAR(65) NOT NULL
114: );
115: ';
116:             $this->_db->execute($create_table);
117:             $create_table = '
118: CREATE TABLE IF NOT EXISTS ws_logged_in (
119:     id INTEGER PRIMARY KEY AUTO_INCREMENT,
120:     user_id INTEGER NOT NULL,
121:     session_id CHAR(32) NOT NULL,
122:     token CHAR(128) NOT NULL,
123: 
124:     FOREIGN KEY (user_id) REFERENCES ws_user(id)
125: );
126: ';
127:             $this->_db->execute($create_table);
128:             $create_table = '
129: CREATE TABLE IF NOT EXISTS ws_roles (
130:     id INTEGER PRIMARY KEY AUTO_INCREMENT,
131:     name VARCHAR(25) NOT NULL,
132:     description VARCHAR(50)
133: );
134: ';
135:             $this->_db->execute($create_table);
136:             $create_table = '
137: CREATE TABLE IF NOT EXISTS ws_permissions (
138:     id INTEGER PRIMARY KEY AUTO_INCREMENT,
139:     name VARCHAR(25) NOT NULL,
140:     description VARCHAR(50)
141: );
142: ';
143:             $this->_db->execute($create_table);
144:             $create_table = '
145: CREATE TABLE IF NOT EXISTS ws_role_perm (
146:     role_id INTEGER NOT NULL,
147:     permissions_id INTEGER NOT NULL,
148: 
149:     FOREIGN KEY (role_id) REFERENCES ws_roles(id),
150:     FOREIGN KEY (permissions_id) REFERENCES ws_permissions(id)
151: );
152: ';
153:             $this->_db->execute($create_table);
154:             $create_table = '
155: CREATE TABLE IF NOT EXISTS ws_user_role (
156:     user_id INTEGER NOT NULL,
157:     role_id INTEGER NOT NULL,
158: 
159:     FOREIGN KEY (user_id) REFERENCES ws_user(id),
160:     FOREIGN KEY (role_id) REFERENCES ws_roles(id)
161: );
162: ';
163:             $this->_db->execute($create_table);
164: 
165:         // auth tables for sqlite database
166:         } else if (WsConfig::get('db_driver') === 'sqlite') {
167:             $create_table = '
168: CREATE TABLE IF NOT EXISTS ws_user (
169:     id INTEGER PRIMARY KEY AUTOINCREMENT,
170:     email VARCHAR(128) NOT NULL,
171:     password VARCHAR(128) NOT NULL,
172:     user_salt VARCHAR(50) NOT NULL,
173:     is_verified BOOLEAN NOT NULL,
174:     is_active BOOLEAN NOT NULL,
175:     verification_code VARCHAR(65) NOT NULL
176: );
177: ';
178:             $this->_db->execute($create_table);
179:             $create_table = '
180: CREATE TABLE IF NOT EXISTS ws_logged_in (
181:     id INTEGER PRIMARY KEY AUTOINCREMENT,
182:     user_id INTEGER NOT NULL,
183:     session_id CHAR(32) NOT NULL,
184:     token CHAR(128) NOT NULL,
185: 
186:     FOREIGN KEY (user_id) REFERENCES ws_user(id)
187: );
188: ';
189:             $this->_db->execute($create_table);
190:             $create_table = '
191: CREATE TABLE IF NOT EXISTS ws_roles (
192:     id INTEGER PRIMARY KEY AUTOINCREMENT,
193:     name VARCHAR(25) NOT NULL,
194:     description VARCHAR(50)
195: );
196: ';
197:             $this->_db->execute($create_table);
198:             $create_table = '
199: CREATE TABLE IF NOT EXISTS ws_permissions (
200:     id INTEGER PRIMARY KEY AUTOINCREMENT,
201:     name VARCHAR(25) NOT NULL,
202:     description VARCHAR(50)
203: );
204: ';
205:             $this->_db->execute($create_table);
206:             $create_table = '
207: CREATE TABLE IF NOT EXISTS ws_role_perm (
208:     role_id INTEGER NOT NULL,
209:     permissions_id INTEGER NOT NULL,
210: 
211:     FOREIGN KEY (role_id) REFERENCES ws_roles(id),
212:     FOREIGN KEY (permissions_id) REFERENCES ws_permissions(id)
213: );
214: ';
215:             $this->_db->execute($create_table);
216:             $create_table = '
217: CREATE TABLE IF NOT EXISTS ws_user_role (
218:     user_id INTEGER NOT NULL,
219:     role_id INTEGER NOT NULL,
220: 
221:     FOREIGN KEY (user_id) REFERENCES ws_user(id),
222:     FOREIGN KEY (role_id) REFERENCES ws_roles(id)
223: );
224: ';
225:             $this->_db->execute($create_table);
226:         }
227: 
228:         // create admin user account if it doesent exists
229:         $this->createAdminUser();
230: 
231:         unset($create_table);
232:     }
233: 
234: 
235:     /**
236:      * Create administrator user account if it doesent exist.
237:      * Default password is set to 'admin'
238:      *
239:      */
240:     private function createAdminUser()
241:     {
242:         if (!$this->isUsable) {
243:             return false;
244:         }
245: 
246:         // get administrato mail addres from config file
247:         $email = WsConfig::get('auth_admin');
248: 
249:         // add new user to database
250:         $user_model = new Ws_userModel();
251: 
252:         // check if administrator account is allready created
253:         $user_model->search("email='$email'");
254:         if ($user_model->nRows > 0) {
255:             return WS_AUTH_USER_EXISTS;
256:         }
257: 
258:         // add new user to database
259:         $user_model->email = $email;
260:         $user_model->is_verified = true;
261:         $user_model->is_active = true;
262:         $user_model->password = 'admin';
263:         $user_model->verification_code = $user_model->randomString(65);
264: 
265:         $user_model->save();
266: 
267:         return true;
268:     }
269: 
270: 
271:     /**
272:      * Create new user record.
273:      *
274:      * @param string $email User email
275:      * @param string $password User password
276:      * @return boolean
277:      *
278:      */
279:     public function createUser($email, $password)
280:     {
281:         if (!$this->isUsable) {
282:             return false;
283:         }
284: 
285:         // add new user to database
286:         $user_model = new Ws_userModel();
287: 
288:         // check if email allready exists
289:         $user_model->search("email='$email'");
290:         if ($user_model->nRows > 0) {
291:             return WS_AUTH_USER_EXISTS;
292:         }
293: 
294:         // add new user to database
295:         $user_model->email = $email;
296:         if (WsConfig::get('db_driver') == 'pgsql') {
297:             $user_model->is_verified = 'f';
298:             $user_model->is_active = 'f';
299:         } else {
300:             $user_model->is_verified = 0;
301:             $user_model->is_active = 0;
302:         }
303:         $user_model->password = $password;
304:         $verification_code = $user_model->randomString(65);
305:         $user_model->verification_code = $verification_code;
306: 
307:         if ($user_model->save()) {
308:             if (
309:                 filter_input(INPUT_SERVER, 'SERVER_NAME', FILTER_SANITIZE_STRING)
310:                     == 'localhost') {
311:                 $server = filter_input(INPUT_SERVER, 'SERVER_ADDR',
312:                     FILTER_SANITIZE_STRING);
313:             } else {
314:                 $server = filter_input(INPUT_SERVER, 'SERVER_NAME',
315:                     FILTER_SANITIZE_URL);
316:             }
317:             $link = 'http://'.$server
318:                 .WsUrl::link('Wsauth', 'verify', array(
319:                     'code'=>$verification_code
320:                 ));
321: 
322:             // send verification mail
323:             $to = $email;
324:             // subject
325:             $subject = WsConfig::get('app_name')
326:                 .WsLocalize::msg(' - Thank you for registering');
327:             // content
328:             $html = "
329:             <HTML>
330:                 <HEAD>
331:                     <TITLE>$subject</TITLE>
332:                 </HEAD>
333:                 <BODY>
334:                     Welcome,
335:                     <BR/>
336:                     <BR/>
337:             ";
338:             $html .= '<p>';
339:             $html .= WsLocalize::msg('We sent you this email to verify your email address.');
340:             $html .= WsLocalize::msg('To complete user registration, click on the following link');
341:             $html .= '</p>';
342:             $html .= '<p><a href="'.$link.'">';
343:             $html .= WsLocalize::msg('finish registration');
344:             $html .= '</a></p>'.$link;
345:             $html .= '<br/>';
346:             $html .= WsLocalize::msg('Thank you and welcome.');
347:             $html .= '</BODY></HTML>';
348:             // To send HTML mail, the Content-type header must be set
349:             $headers  = "MIME-Version: 1.0\r\n";
350:             $headers .= "Content-type: text/html; charset=utf-8\r\n";
351:             $headers .= 'From: <'
352:                 .WsConfig::get('auth_admin').'>'."\r\n";
353: 
354:             // send user verification mail
355:             mail($to, $subject, $html, $headers);
356:             return true;
357:         } else {
358:             return false;
359:         }
360:     }
361: 
362: 
363:     /**
364:      * Login existing user and star user session.
365:      *
366:      * @param string $email User email address
367:      * @param string $password User password
368:      * @return boolean
369:      *
370:      */
371:     public function login($email, $password)
372:     {
373:         // check for database connection
374:         if (!$this->isUsable) {
375:             return false;
376:         }
377: 
378:         $user_model = new Ws_userModel();
379:         $user_model->search("email='$email'");
380: 
381:         if ($user_model->nRows != 1) {
382:             return WS_AUTH_NO_MATCH;
383:         }
384: 
385:         // Salt and hash password for checking
386:         $password1 = $user_model->user_salt.$password;
387:         $password2 = $user_model->hashData($password1);
388: 
389:         // check for valid username(email)/password combination
390:         $user_model->search("email='$email' AND password='$password2'");
391: 
392:         if ($user_model->nRows != 1) {
393:             return WS_AUTH_NO_MATCH;
394:         }
395: 
396:         // check if user account is verified and actived.
397:         $is_active = (boolean)$user_model->is_active;
398:         $is_verified = (boolean)$user_model->is_verified;
399: 
400:         // account is not verified, send user verification email.
401:         if (!$is_verified) {
402:             // send verification mail
403:             return WS_AUTH_NOT_VERIFIED;
404:         }
405: 
406:         // account is not active/
407:         if (!$is_active) {
408:            return WS_AUTH_NOT_ACTIVE;
409:         }
410: 
411:         // all OK; login user
412:         $random = $user_model->randomString();
413:         // build the session token
414:         $token = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT',
415:             FILTER_SANITIZE_STRING).$random;
416:         $token = $user_model->hashData($token);
417:         // user id
418:         $user_id = $user_model->id;
419:         // session id
420:         $session_id = session_id();
421: 
422:         // set session variables
423:         $_SESSION['ws_auth_token'] = $token;
424:         $_SESSION['ws_auth_user_id'] = $user_id;
425:         $_SESSION['ws_auth_user_email'] = $user_model->email;
426:         $_SESSION['ws_auth_generated_time'] = time();
427:         $_SESSION['ws_auth_client_ip'] =
428:             filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING);
429:         $_SESSION['ws_auth_user_agent'] =
430:             filter_input(INPUT_SERVER,'HTTP_USER_AGENT',FILTER_SANITIZE_STRING);
431: 
432:         $logged_in_model = new Ws_logged_inModel();
433:         // delete old logged_in record from database
434:         $logged_in_model->search("user_id=$user_id");
435:         $logged_in_model->delete();
436: 
437:         // save new logged_in record to database
438:         $logged_in_model->user_id = $user_id;
439:         $logged_in_model->session_id = $session_id;
440:         $logged_in_model->token = $token;
441:         $logged_in_model->save();
442: 
443:         return WS_AUTH_LOGIN_OK;
444:     }
445: 
446: 
447:     /**
448:      * Checks current user session.
449:      *
450:      * @return boolean
451:      *
452:      */
453:     public function checkSession()
454:     {
455:         if (!isset($_SESSION['ws_auth_user_id'])) {
456:             return false;
457:         }
458: 
459:         // check if session is expired (1 hour)
460:         if(!isset($_SESSION['ws_auth_generated_time'])) {
461:             return false;
462:         }
463:         if (time() > ($_SESSION['ws_auth_generated_time'] + 3600)) {
464:             return false;
465:         }
466: 
467:         // validate ip address
468:         if(!isset($_SESSION['ws_auth_client_ip'])) {
469:             return false;
470:         }
471:         if ($_SESSION['ws_auth_client_ip'] !==
472:             filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING)) {
473:                 return false;
474:         }
475: 
476:         // validate user agent
477:         if(!isset($_SESSION['ws_auth_user_agent'])) {
478:             return false;
479:         }
480:         if ($_SESSION['ws_auth_user_agent'] !==
481:             filter_input(INPUT_SERVER, 'HTTP_USER_AGENT',
482:                 FILTER_SANITIZE_STRING)) {
483:                 return false;
484:         }
485: 
486:         // check is user is logged in
487:         $user_id = $_SESSION['ws_auth_user_id'];
488:         $logged_in_model = new Ws_logged_inModel();
489:         $logged_in_model->search("user_id=$user_id");
490: 
491:         // if user is logged in
492:         if ($logged_in_model->nRows >= 1) {
493:             // check session ID and Token
494:             if(session_id() == trim($logged_in_model->session_id)
495:                 && $_SESSION['ws_auth_token'] == trim($logged_in_model->token)){
496: 
497:                     // expand expiration time for 1 hour
498:                     $_SESSION['ws_auth_generated_time'] = time();
499: 
500:                     /** Id and token match, refresh the session
501:                      * for the next request
502:                      */
503:                     return true;
504:             }
505:         }
506: 
507:         return false;
508:     }
509: 
510: 
511:     /*
512:      * Logout current user from session
513:      *
514:      * @return boolean
515:      *
516:      */
517:     public function logout()
518:     {
519:         if (!$this->checkSession()) {
520:             return false;
521:         }
522: 
523:         $user_id = $_SESSION['ws_auth_user_id'];
524:         $logged_in_model = new Ws_logged_inModel();
525:         // delete logged_in record from database
526:         $logged_in_model->search("user_id=$user_id");
527:         $logged_in_model->delete();
528: 
529:         // delete session records
530:         $_SESSION = array();
531: 
532:         session_destroy();
533: 
534:         return true;
535:     }
536: 
537: 
538:     /**
539:      * check if user has specific permission
540:      *
541:      * @param string $perm Permission name
542:      * @return boolean
543:      *
544:      */
545:     public function hasPermission($perm)
546:     {
547:         // if no user is logged in then return false
548:         if (!$this->checkSession()) {
549:             return false;
550:         }
551: 
552:         // check if admin user is logged in
553:         if ($_SESSION['ws_auth_user_email'] === WsConfig::get('auth_admin')) {
554:             return true;
555:         } else if ($perm === 'admin' and (
556:             $_SESSION['ws_auth_user_email'] === WsConfig::get('auth_admin')
557:             )) {
558:             return true;
559:         }
560: 
561:         $db = new WsDatabase();
562:         $user_id = $_SESSION['ws_auth_user_id'];
563: 
564:         // check if user has permission
565:         $sql = '
566:             SELECT
567:                 wp.id
568:             FROM ws_permissions wp,
569:                 ws_role_perm rp,
570:                 ws_roles wr,
571:                 ws_user_role wur,
572:                 ws_user wu
573:             WHERE wp.id=rp.permissions_id
574:                 AND rp.role_id=wr.id
575:                 AND wr.id=wur.role_id
576:                 AND wur.user_id=wu.id
577:                 AND wu.id=:user_id
578:                 AND wp.name=:perm
579:             GROUP BY wp.id
580:         ';
581:         $db->query($sql, array(
582:             'user_id' => $user_id,
583:             'perm' => $perm
584:         ));
585: 
586:         if ($db->nRows >= 1) {
587:             return true;
588:         }
589: 
590:         return false;
591:     }
592: 
593: 
594:     /**
595:      * return email address of current logged in user
596:      *
597:      * @return string
598:      *
599:      */
600:     public function currentUser()
601:     {
602:         // if no user is logged in then return empty string
603:         if (!$this->checkSession()) {
604:             return '';
605:         }
606: 
607:         return($_SESSION['ws_auth_user_email']);
608:     }
609: 
610: 
611:     /**
612:      * return ID of current logged in user
613:      *
614:      * @return integer
615:      *
616:      */
617:     public function currentUserID()
618:     {
619:         // if no user is logged in then return empty string
620:         if (!$this->checkSession()) {
621:             return -1;
622:         }
623: 
624:         return($_SESSION['ws_auth_user_id']);
625:     }
626: }
627: 
628: 
API documentation generated by ApiGen