From 17f89c3768f6cb6b4001a0bf93d8dca436621acf Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Sun, 14 Sep 2014 11:18:59 +0300 Subject: [PATCH] rework auth app --- ipf/admin/forms/login.php | 5 +- ipf/admin/views.php | 8 +- ipf/auth/admin.php | 120 +++++++------------ ipf/auth/app.php | 42 ++++++- ipf/auth/commands/createsuperuser.php | 4 +- ipf/auth/middleware.php | 4 +- ipf/auth/models.php | 158 +++++++++++++++++++++----- ipf/form/objectform.php | 35 ++++++ 8 files changed, 252 insertions(+), 124 deletions(-) create mode 100644 ipf/form/objectform.php diff --git a/ipf/admin/forms/login.php b/ipf/admin/forms/login.php index ef950e4..b05b32f 100644 --- a/ipf/admin/forms/login.php +++ b/ipf/admin/forms/login.php @@ -16,10 +16,11 @@ class IPF_Admin_Forms_Login extends IPF_Form { $data = parent::clean(); - $this->user = User::checkCreditentials($data['username'], $data['password']); - if (!$this->user) + $user = \PFF\Container::auth()->findUserByUsername($data['username']); + if (!$user || !$user->checkPassword($data['password'])) throw new IPF_Exception_Form(__('The login or the password is not valid. The login and the password are case sensitive.')); + $this->user = $user; return $data; } diff --git a/ipf/admin/views.php b/ipf/admin/views.php index b23a561..d1bb7c8 100644 --- a/ipf/admin/views.php +++ b/ipf/admin/views.php @@ -87,7 +87,7 @@ function IPF_Admin_Views_Login($request, $match) if ($request->method == 'POST') { $form = new IPF_Admin_Forms_Login($request->POST); if ($form->isValid()) { - IPF_Auth_App::login($request, $form->user); + \PFF\Container::auth()->login($request, $form->user); return new IPF_HTTP_Response_Redirect($success_url); } } else { @@ -104,7 +104,7 @@ function IPF_Admin_Views_Login($request, $match) function IPF_Admin_Views_Logout($request, $match) { - IPF_Auth_App::logout($request); + \PFF\Container::auth()->logout($request); $context = array( 'page_title' => IPF::get('admin_title'), ); @@ -120,10 +120,10 @@ function IPF_Admin_Views_Impersonate($request, $match) $success_url = IPF_HTTP_URL::urlForView('IPF_Admin_Views_Index'); if (!$request->user->isAnonymous() && $request->user->is_superuser) { - $user = User::find($match[1]); + $user = \PFF\Container::auth()->findUser($match[1]); if (!$user) return new IPF_HTTP_Response_NotFound($request); - IPF_Auth_App::login($request, $user); + \PFF\Container::auth()->login($request, $user); } return new IPF_HTTP_Response_Redirect($success_url); diff --git a/ipf/auth/admin.php b/ipf/auth/admin.php index b80e984..e45bb74 100644 --- a/ipf/auth/admin.php +++ b/ipf/auth/admin.php @@ -1,5 +1,7 @@ auth_app = \PFF\Container::auth(); + } + public function getItems($searchValue, $filters, $page, $pageSize) { - return User::query() + return $this->auth_app->userQuery() ->limit($pageSize) ->offset(($page - 1) * $pageSize) ->fetchAll('id'); @@ -121,7 +130,7 @@ class AdminUser extends IPF_Admin_Component public function itemsCount($searchValue, $filters) { - return User::query() + return $this->auth_app->userQuery() ->select(null)->select('COUNT(1)') ->fetchColumn(); } @@ -168,7 +177,7 @@ class AdminUser extends IPF_Admin_Component public function getObjectByID($id) { - return User::query()->where('id', $id)->fetch(); + return \PFF\Container::auth()->findUser($id); } protected function _getForm($user, $data) @@ -176,11 +185,6 @@ class AdminUser extends IPF_Admin_Component $extra = array(); if ($user) { $extra['initial'] = array( - 'username' => $user->username, - 'email' => $user->email, - 'is_active' => $user->is_active, - 'is_staff' => $user->is_staff, - 'is_superuser' => $user->is_superuser, 'permissions' => \PFF\Arr::create($user->permissions())->pluck('id')->arr(), 'roles' => \PFF\Arr::create($user->roles())->pluck('id')->arr(), ); @@ -188,49 +192,27 @@ class AdminUser extends IPF_Admin_Component } else { $extra['is_add'] = true; } - return new IPFAuthAdminUserForm($data, $extra); + return new IPFAuthAdminUserForm($data, $user, $extra); } public function saveObject($form, $user) { if (!$user) - $user = new User; - - if ($user->id) { - } else { - } - -/* - -// $this->cleaned_data['password'] = User::SetPassword2($this->cleaned_data['password1']); - - - - \PFF\Container::databaseQuery() - ->deleteFrom('auth_user_permission') - ->where('user_id', $user->id) - ->execute(); - - $query = \PFF\Container::databaseQuery() - ->insertInto('auth_user_permission'); - foreach ($this->cleaned_data['permissions'] as $pid) - $query->values(array('user_id' => $user->id, 'permission_id' => $pid)); - $query->execute(); + $user = $this->auth_app->createUser(); + $form->toObject($user); + if ($form->cleaned_data['password1']) + $user->setPassword($form->cleaned_data['password1']); + $user->save(); - \PFF\Container::databaseQuery() - ->deleteFrom('auth_user_group') - ->where('user_id', $user->id) - ->execute(); + Permission::revokeAll($user); + $permissions = Permission::query()->where('id', $form->cleaned_data['permissions'])->fetchAll(); + Permission::grantAll($permissions, $user); - $query = \PFF\Container::databaseQuery() - ->insertInto('auth_user_role'); - foreach ($this->cleaned_data['roles'] as $pid) - $query->values(array('user_id' => $user->id, 'role_id' => $pid)); - $query->execute(); + Role::leaveAll($user); + foreach (Role::query()->where('id', $form->cleaned_data['roles']) as $role) + $role->join($user); - - */ return array($user->id, $user); } @@ -249,10 +231,10 @@ class AdminUser extends IPF_Admin_Component ); } - public function verbose_name() { return 'User'; } + public function verbose_name() { return __('User'); } } -class IPFAdminRoleForm extends IPF_Form +class IPFAdminRoleForm extends IPF_ObjectForm { function initFields($extra=array()) { @@ -316,14 +298,12 @@ class AdminRole extends IPF_Admin_Component protected function _getForm($role, $data) { - $extra = array(); - if ($role) { - $extra['initial'] = array( - 'name' => $role->name, + if ($role) + return new IPFAdminRoleForm($data, $role, array('initial' => array( 'permissions' => \PFF\Arr::create($role->permissions())->pluck('id')->arr(), - ); - } - return new IPFAdminRoleForm($data, $extra); + ))); + else + return new IPFAdminRoleForm($data, null); } public function saveObject($form, $role) @@ -331,34 +311,12 @@ class AdminRole extends IPF_Admin_Component if (!$role) $role = new Role; - $role->name = $form->cleaned_data['name']; - if ($role->id) { - \PFF\Container::databaseQuery() - ->update('auth_role') - ->set('name', $role->name) - ->where('id', $role->id) - ->execute(); - - \PFF\Container::databaseQuery() - ->deleteFrom('auth_role_permission') - ->where('role_id', $role->id) - ->execute(); - } else { - $role->id = \PFF\Container::databaseQuery() - ->insertInto('auth_role') - ->values(array('name' => $role->name)) - ->execute(); - } - - if ($form->cleaned_data['permissions']) { - $data = array_map(function($pid) use($role) { return array('role_id' => $role->id, 'permission_id' => $pid); }, - $form->cleaned_data['permissions']); + $form->toObject($role); + $role->save(); - \PFF\Container::databaseQuery() - ->insertInto('auth_role_permission') - ->values($data) - ->execute(); - } + Permission::revokeAll($role); + foreach (Permission::query()->where('id', $form->cleaned_data['permissions']) as $permission) + $permission->grant($role); return array($role->id, $role); } @@ -371,8 +329,8 @@ class AdminRole extends IPF_Admin_Component ->execute(); } - public function page_title() { return 'Group'; } - public function verbose_name() { return 'Group'; } + public function page_title() { return __('Role'); } + public function verbose_name() { return __('Role'); } } if (IPF_Auth_App::ArePermissionsEnabled()) { diff --git a/ipf/auth/app.php b/ipf/auth/app.php index f7134df..3e3049e 100644 --- a/ipf/auth/app.php +++ b/ipf/auth/app.php @@ -2,12 +2,44 @@ class IPF_Auth_App extends IPF_Application { - public function getTitle() + public $userModel; + + function configure($settings) + { + $this->userModel = \PFF\Arr::get($settings, 'auth_user_model', 'User'); + \PFF\Container::set('auth', $this); + } + + function getTitle() + { + return __('User Accounts'); + } + + function userQuery() + { + return \PFF\Container::databaseQuery() + ->from('auth_user') + ->orderBy('username') + ->asObject($this->userModel); + } + + function findUser($id) + { + return $this->userQuery()->where('id', $id)->fetch(); + } + + function findUserByUsername($username) + { + return $this->userQuery()->where('username', $username)->fetch(); + } + + function createUser() { - return 'User Accounts'; + $className = $this->userModel; + return new $className; } - static function login($request, $user) + function login($request, $user) { $request->user = $user; $request->session->data = array( @@ -15,9 +47,9 @@ class IPF_Auth_App extends IPF_Application ); } - static function logout($request) + function logout($request) { - $request->user = new User; + $request->user = new AnonymousUser; $request->session->data = array( 'login_time' => gmdate('Y-m-d H:i:s') ); diff --git a/ipf/auth/commands/createsuperuser.php b/ipf/auth/commands/createsuperuser.php index 19a76fd..696b897 100644 --- a/ipf/auth/commands/createsuperuser.php +++ b/ipf/auth/commands/createsuperuser.php @@ -13,9 +13,7 @@ class IPF_Auth_Command_CreateSuperUser $password = IPF_Shell::ask(' Password: '); $email = IPF_Shell::ask(' E-mail: '); - $project = IPF_Project::getInstance(); - - $su = new User; + $su = \PFF\Container::auth()->createUser(); $su->username = $username; $su->email = $email; $su->is_staff = true; diff --git a/ipf/auth/middleware.php b/ipf/auth/middleware.php index 0cf563a..90c6d15 100644 --- a/ipf/auth/middleware.php +++ b/ipf/auth/middleware.php @@ -10,7 +10,7 @@ class IPF_Auth_Middleware $user_id = \PFF\Arr::get($request->session->data, self::SessionKey, 0); if ($user_id > 0) { - $request->user = User::find($user_id); + $request->user = \PFF\Container::auth()->findUser($user_id); if ($request->user && 43200 < IPF_Utils::dateCompare($request->user->last_login)) { $request->user->last_login = gmdate('Y-m-d H:i:s'); $request->user->save(); @@ -18,7 +18,7 @@ class IPF_Auth_Middleware } if (!$request->user) - $request->user = new User; + $request->user = new AnonymousUser; return false; } diff --git a/ipf/auth/models.php b/ipf/auth/models.php index 933cdcb..a2e75c7 100644 --- a/ipf/auth/models.php +++ b/ipf/auth/models.php @@ -1,8 +1,58 @@ getProperties(ReflectionProperty::IS_PUBLIC) as $p) { + $name = $p->getName(); + if ($name === 'id' || $name[0] === '_') + continue; + $values[$name] = $p->getValue($this); + } + + if ($this->id) { + \PFF\Container::databaseQuery() + ->update($this->table, $values, $this->id) + ->execute(); + } else { + $this->id = \PFF\Container::databaseQuery() + ->insertInto($this->table, $values) + ->execute(); + } + } +} + +class AnonymousUser +{ + public $id = 0; + + public function __toString() + { + return 'Anonymous'; + } + + function isAnonymous() + { + return true; + } + + public function can(/* $permission ... */) + { + return false; + } +} + +class User extends DBObject +{ + protected $table = 'auth_user'; + public $username, $password, $email, $is_active, $is_staff, $is_superuser, $last_login; public function __toString() { @@ -20,31 +70,14 @@ class User $this->password = ''; } - function isAnonymous() - { - return 0 === (int)$this->id; - } - - public static function find($id) - { - return self::query()->where('id', $id)->fetch(); - } - - public static function checkCreditentials($username, $password) + function checkPassword($raw_password) { - $user = self::query()->where('username', $username)->fetch(); - if ($user && $user->is_active && IPF_Crypto::checkPassword($password, $user->password)) - return $user; - else - return false; + return $this->is_active && IPF_Crypto::checkPassword($raw_password, $this->password); } - public static function query() + function isAnonymous() { - return \PFF\Container::databaseQuery() - ->from('auth_user') - ->orderBy('username') - ->asObject('User'); + return false; } public function permissions() @@ -103,9 +136,10 @@ class User } } -class Role +class Role extends DBObject { - public $id, $name; + protected $table = 'auth_role'; + public $name; public function __toString() { @@ -127,11 +161,37 @@ class Role ->where('role_id', $this->id) ->fetchAll(); } + + public function join($user) + { + \PFF\Container::databaseQuery() + ->insertInto('auth_user_role') + ->values(array('user_id' => $user->id, 'role_id' => $this->id)) + ->execute(); + } + + public function leave($user) + { + if ($this->id) + self::leaveAll($user, $this->id); + } + + public static function leaveAll($user, $only=null) + { + $cond = array('user_id' => $user->id); + if ($only) + $cond['role_id'] = $only; + \PFF\Container::databaseQuery() + ->deleteFrom('auth_user_role') + ->where($cond) + ->execute(); + } } -class Permission +class Permission extends DBObject { - public $id, $name, $title; + protected $table = 'auth_permission'; + public $name; public static function query() { @@ -140,5 +200,49 @@ class Permission ->asObject('Permission') ->orderBy('name'); } + + public function grant($obj) + { + list($table, $data) = self::link($obj); + $data['permission_id'] = $this->id; + \PFF\Container::databaseQuery()->insertInto($table, $data)->execute(); + } + + public static function grantAll($permissions, $obj) + { + if (!$permissions) + return; + + list($table, $data) = self::link($obj); + $values = array(); + foreach ($permissions as $p) + $values[] = array_merge($data, array('permission_id' => $p->id)); + \PFF\Container::databaseQuery()->insertInto($table, $values)->execute(); + } + + public function revoke($obj) + { + if ($this->id) + self::revokeAll($obj, $this->id); + } + + public static function revokeAll($obj, $only=null) + { + list($table, $cond) = self::link($obj); + if ($only) + $cond['permission_id'] = $only; + \PFF\Container::databaseQuery()->deleteFrom($table)->where($cond)->execute(); + } + + private static function link($obj) + { + if ($obj instanceof User) { + return array('auth_user_permission', array('user_id' => $obj->id)); + } elseif ($obj instanceof Role) { + return array('auth_role_permission', array('role_id' => $obj->id)); + } else { + throw new IPF_Exception('Bad argument.'); + } + } } diff --git a/ipf/form/objectform.php b/ipf/form/objectform.php new file mode 100644 index 0000000..7732d83 --- /dev/null +++ b/ipf/form/objectform.php @@ -0,0 +1,35 @@ +fields as $name => $field) { + if (array_key_exists($name, $this->initial)) + continue; + + if (property_exists($object, $name)) { + $this->initial[$name] = $object->$name; + } elseif (method_exists($object, $name)) { + $this->initial[$name] = $object->$name(); + } + } + } + } + + public function toObject($object) + { + foreach ($this->fields as $name => $field) { + if (property_exists($object, $name)) { + $object->$name = $this->cleaned_data[$name]; + } elseif (method_exists($object, 'set'.ucfirst($name))) { + $m = 'set'.ucfirst($name); + $object->$m($this->cleaned_data[$name]); + } + } + } +} + -- 2.49.0