From 85fe3f4f724b0379d90bd8ac3ee9b55753558226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Mon, 6 Mar 2017 22:30:01 +0100 Subject: [PATCH 1/7] Corrections on Spanish translation --- messages/es/back.php | 58 +++++++++++++++++++++---------------------- messages/es/front.php | 32 ++++++++++++------------ 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/messages/es/back.php b/messages/es/back.php index c254af93..0884bbe3 100644 --- a/messages/es/back.php +++ b/messages/es/back.php @@ -18,14 +18,14 @@ */ return [ 'Active' => 'Activo', - 'Are you sure you want to delete this user?' => '¿Está seguro que desea eliminar este usuario?', + 'Are you sure you want to delete this user?' => '¿Seguro que desea borrar este usuario?', 'Banned' => 'Bloqueado', - 'Bind to IP' => 'Casar a IP', + 'Bind to IP' => 'Asociar a la IP', 'Browser' => 'Navegador', - 'Change own password' => 'Cambiar propia contraseña', - 'Change password' => 'Cambiar contraseña de usuario', - 'Changing password' => 'Cambiando contraseña', - 'Changing password for user: ' => 'Cambiando contraseña para usuario: ', + 'Change own password' => 'Cambiar la contraseña propia', + 'Change password' => 'Cambiar la contraseña', + 'Changing password' => 'Cambio de la contraseña', + 'Changing password for user: ' => 'Cambiando la contraseña del usuario: ', 'Child permissions' => 'Permisos hijos', 'Child roles' => 'Roles hijos', 'Code' => 'Código', @@ -33,16 +33,16 @@ 'Create' => 'Crear', 'Created' => 'Creado', 'Creating permission group' => 'Creación de grupo de permisos', - 'Current password' => 'Actual contraseña', + 'Current password' => 'Contraseña actual', 'Data' => 'Dato', - 'Delete' => 'Eliminar', + 'Delete' => 'Borrar', 'Description' => 'Descripción', 'E-mail' => 'Correo electrónico', 'E-mail confirmed' => 'Correo confirmado', - 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => 'Un correo electrónico con un enlace de activación ha sido enviado a {email}. El enlace expirara en {minutes} minutos.', + 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => 'Se ha enviado un correo electrónico con un enlace de activación a {email}. El enlace expirará en {minutes} minutos.', 'Edit' => 'Editar', - 'Editing' => 'Editando', - 'Editing permission group' => 'Editando grupo de permiso', + 'Editing' => 'Edición', + 'Editing permission group' => 'Edición de grupo de permisos', 'Editing permission: ' => 'Editando permiso:', 'Editing role: ' => 'Editando rol:', 'Editing user: ' => 'Editando usuario:', @@ -52,46 +52,46 @@ 'Inactive' => 'Inactivo', 'IP' => 'IP', 'Language' => 'Idioma', - 'Login' => 'Inicio de sesión', + 'Login' => 'Iniciar sesión', 'Name' => 'Nombre', 'OS' => 'Sistema Operativo', 'Password' => 'Contraseña', - 'Password has been changed' => 'Contraseña ha sido cambiada', + 'Password has been changed' => 'Se ha cambiado la contraseña', 'Permission creation' => 'Creación de permisos', 'Permission groups' => 'Grupos de permisos', 'Permissions' => 'Permisos', - 'Permissions for role:' => 'Permisos de role:', - 'Refresh routes' => 'Refrescar rutas', - 'Refresh routes (and delete unused)' => 'Refrescar rutas (y eliminar sin uso)', - 'Registration IP' => 'IP Registrada', - 'Repeat password' => 'Repetir contraseña', - 'Reset' => 'Reestablecer', - 'Role creation' => 'Creación de Rol', + 'Permissions for role:' => 'Permisos del rol:', + 'Refresh routes' => 'Refrescar las rutas', + 'Refresh routes (and delete unused)' => 'Refrescar las rutas (y borrar las que no se usan)', + 'Registration IP' => 'IP de registro', + 'Repeat password' => 'Repita la contraseña', + 'Reset' => 'Restablecer', + 'Role creation' => 'Creación de rol', 'Roles' => 'Roles', 'Roles and permissions' => 'Roles y permisos', - 'Roles and permissions for user:' => 'Roles y permisos para el usuario', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => 'Se eliminarán rutas que no existan en esta aplicación. No se recomienda para aplicaciones con estructura de "avanzada", porque frontend y backend tienen que propio conjunto de rutas.', + 'Roles and permissions for user:' => 'Roles y permisos para el usuario:', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => 'Se eliminarán rutas que no existan en esta aplicación. No se recomienda para aplicaciones con estructura «avanzada», porque frontend y backend tienen su propio conjunto de rutas.', 'Rule' => 'Regla', 'Save' => 'Guardar', 'Saved' => 'Guardado', 'Search' => 'Buscar', - 'Search route' => 'Buscar ruta', + 'Search route' => 'Buscar una ruta', 'Settings for permission' => 'Configuración de permiso', 'Show all' => 'Mostrar todos', - 'Show only selected' => 'Mostrar solo seleccionados', - 'Status' => 'Estatus', - 'Superadmin' => 'Super admin', + 'Show only selected' => 'Mostrar sólo los seleccionados', + 'Status' => 'Estado', + 'Superadmin' => 'Superadmin', 'Token' => 'Código Token', 'Too many attempts' => 'Demasiados intentos', 'Type' => 'Tipo', 'Updated' => 'Actualizado', 'User' => 'Usuario', - 'User agent' => 'Agente de Usuario', - 'User creation' => 'Creación de Usuario', + 'User agent' => 'Agente de usuario', + 'User creation' => 'Creación de usuario', 'Users' => 'Usuarios', 'Visit Time' => 'Fecha de visita', 'Visit log' => 'Registro de visita', - 'Wrong format. Enter valid IPs separated by comma' => 'Formato incorrecto. Ingrese IPs valida separada por coma', + 'Wrong format. Enter valid IPs separated by comma' => 'Formato incorrecto. Introduzca IPs válidas separadas por comas', 'Wrong password' => 'Contraseña incorrecta', 'You can not change own permissions' => 'Usted no puede cambiar sus propios permisos', ]; diff --git a/messages/es/front.php b/messages/es/front.php index 45c34b9c..4a8ed502 100644 --- a/messages/es/front.php +++ b/messages/es/front.php @@ -20,33 +20,33 @@ 'Username' => 'Nombre de usuario', 'Authorization' => 'Autorización', 'Captcha' => 'Código Captcha', - 'Check your E-mail for further instructions' => 'Verifique su correo electrónico para futura instrucciones', - 'Check your e-mail {email} for instructions to activate account' => 'Verifique su correo electrónico {mail} para obtener las instrucciones para activar la cuenta', + 'Check your E-mail for further instructions' => 'Verifique su correo electrónico para más instrucciones', + 'Check your e-mail {email} for instructions to activate account' => 'Verifique su correo electrónico {email} para obtener las instrucciones para activar la cuenta', 'Confirm' => 'Confirmar', 'Confirm E-mail' => 'Confirmar correo electrónico', 'Continue' => 'Continuar', - 'Could not send confirmation email' => 'No fue posible enviar correo electrónico de confirmación', + 'Could not send confirmation email' => 'No fue posible enviar el correo electrónico de confirmación', 'E-mail' => 'Correo electrónico', - 'E-mail confirmation for' => 'Correo electrónico para confirmación', + 'E-mail confirmation for' => 'Confirmación del correo electrónico de', 'E-mail confirmed' => 'Correo electrónico confirmado', - 'E-mail is invalid' => 'Correo electrónico inválido', - 'Forgot password ?' => '¿Olvido la contraseña?', + 'E-mail is invalid' => 'Correo electrónico no válido', + 'Forgot password ?' => '¿Olvidó la contraseña?', 'Incorrect username or password.' => 'Nombre de usuario o contraseña incorrecta.', - 'Login' => 'Inicio de sesión', - 'Login has been taken' => 'Este login ya existe', + 'Login' => 'Usuario', + 'Login has been taken' => 'Este usuario ya existe', 'Password' => 'Contraseña', - 'Password recovery' => 'Recuperación de contraseña', - 'Password reset for' => 'Contraseña a definir de nuevo', + 'Password recovery' => 'Recuperación de la contraseña', + 'Password reset for' => 'Restablecer la contraseña de', 'Recover' => 'Recuperar', 'Register' => 'Registrar', 'Registration' => 'Registro', - 'Registration - confirm your e-mail' => 'Registro - Confirmar su correo electrónico', + 'Registration - confirm your e-mail' => 'Registro - Confirme su correo electrónico', 'Remember me' => 'Recordarme', - 'Repeat password' => 'Repita a contraseña', + 'Repeat password' => 'Repita la contraseña', 'This E-mail already exists' => 'Este correo electrónico ya existe', - 'Token not found. It may be expired' => 'Token no encontrado. Pode haber expirado', - 'Token not found. It may be expired. Try reset password once more' => 'Token no encontrado. Pode haber expirado. Trate de redefinir a contraseña una vez mas', + 'Token not found. It may be expired' => 'Token no encontrado. Puede haber expirado', + 'Token not found. It may be expired. Try reset password once more' => 'Token no encontrado. Puede haber expirado. Trate de restablecer la contraseña una vez más', 'Too many attempts' => 'Demasiados intentos', - 'Unable to send message for email provided' => 'Deshabilitado para enviar mensaje por correo electrónico proveído', - 'You could not login from this IP' => 'Usted no puede iniciar sesión desde esta dirección IP', + 'Unable to send message for email provided' => 'No fue posible enviar mensaje al correo electrónico indicado', + 'You could not login from this IP' => 'No pudo iniciar sesión desde esta dirección IP', ]; From 525006daea9fbf43dcb5f904eefea573bae0a9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Tue, 7 Mar 2017 11:19:33 +0100 Subject: [PATCH 2/7] Fix email maximum length: an entire email address can be up to 254 characters long. See RFC 3696 erratum 1690: https://www.rfc-editor.org/errata_search.php?eid=1690 There is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands of 254 characters. Since addresses that do not fit in those fields are not normally useful, the upper limit on address lengths should normally be considered to be 254. --- .../m170307_100221_update_email_type.php | 29 +++++++++++++++++++ migrations/mysql.schema.sql | 2 +- views/auth/confirmEmail.php | 2 +- views/auth/passwordRecovery.php | 2 +- views/user/_form.php | 4 +-- 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 migrations/m170307_100221_update_email_type.php diff --git a/migrations/m170307_100221_update_email_type.php b/migrations/m170307_100221_update_email_type.php new file mode 100644 index 00000000..9acbab96 --- /dev/null +++ b/migrations/m170307_100221_update_email_type.php @@ -0,0 +1,29 @@ +alterColumn('user', 'email', 'varchar(254)'); + } + + public function down() + { + echo "m170307_100221_update_email_type cannot be reverted.\n"; + + return false; + } + + /* + // Use safeUp/safeDown to run migration code within a transaction + public function safeUp() + { + } + + public function safeDown() + { + } + */ +} diff --git a/migrations/mysql.schema.sql b/migrations/mysql.schema.sql index 1e83df31..98b5ee1f 100644 --- a/migrations/mysql.schema.sql +++ b/migrations/mysql.schema.sql @@ -280,7 +280,7 @@ CREATE TABLE IF NOT EXISTS `user` ( `updated_at` int(11) NOT NULL, `registration_ip` varchar(15) DEFAULT NULL, `bind_to_ip` varchar(255) DEFAULT NULL, - `email` varchar(128) DEFAULT NULL, + `email` varchar(254) DEFAULT NULL, `email_confirmed` smallint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; diff --git a/views/auth/confirmEmail.php b/views/auth/confirmEmail.php index c21d1978..42d1a23d 100644 --- a/views/auth/confirmEmail.php +++ b/views/auth/confirmEmail.php @@ -34,7 +34,7 @@ 'validateOnBlur'=>false, ]); ?> - field($model, 'email')->textInput(['maxlength' => 255, 'autofocus'=>true]) ?> + field($model, 'email')->textInput(['maxlength' => 254, 'autofocus'=>true]) ?>
diff --git a/views/auth/passwordRecovery.php b/views/auth/passwordRecovery.php index b834c6d0..c68b7818 100644 --- a/views/auth/passwordRecovery.php +++ b/views/auth/passwordRecovery.php @@ -30,7 +30,7 @@ 'validateOnBlur'=>false, ]); ?> - field($model, 'email')->textInput(['maxlength' => 255, 'autofocus'=>true]) ?> + field($model, 'email')->textInput(['maxlength' => 254, 'autofocus'=>true]) ?> field($model, 'captcha')->widget(Captcha::className(), [ 'template' => '
{image}
{input}
', diff --git a/views/user/_form.php b/views/user/_form.php index e828d60f..4736ff75 100644 --- a/views/user/_form.php +++ b/views/user/_form.php @@ -44,7 +44,7 @@ - field($model, 'email')->textInput(['maxlength' => 255]) ?> + field($model, 'email')->textInput(['maxlength' => 254]) ?> field($model, 'email_confirmed')->checkbox() ?> @@ -70,4 +70,4 @@
- \ No newline at end of file + From be791299931a7a290b6f5046988a8c7076b960bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Tue, 7 Mar 2017 13:45:29 +0100 Subject: [PATCH 3/7] Fix ambiguous string The term `Login' was used to mean two different things: * username * to log in In order to be translatable to Spanish and other languages, each of these concepts should use a different word. --- messages/es/front.php | 2 +- models/User.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/messages/es/front.php b/messages/es/front.php index 4a8ed502..b60f88ab 100644 --- a/messages/es/front.php +++ b/messages/es/front.php @@ -32,7 +32,7 @@ 'E-mail is invalid' => 'Correo electrónico no válido', 'Forgot password ?' => '¿Olvidó la contraseña?', 'Incorrect username or password.' => 'Nombre de usuario o contraseña incorrecta.', - 'Login' => 'Usuario', + 'Login' => 'Iniciar sesión', 'Login has been taken' => 'Este usuario ya existe', 'Password' => 'Contraseña', 'Password recovery' => 'Recuperación de la contraseña', diff --git a/models/User.php b/models/User.php index 51002567..d00dcd35 100644 --- a/models/User.php +++ b/models/User.php @@ -316,7 +316,7 @@ public function attributeLabels() { return [ 'id' => 'ID', - 'username' => UserManagementModule::t('back', 'Login'), + 'username' => UserManagementModule::t('back', 'User'), 'superadmin' => UserManagementModule::t('back', 'Superadmin'), 'confirmation_token' => UserManagementModule::t('back', 'Confirmation Token'), 'registration_ip' => UserManagementModule::t('back', 'Registration IP'), From d3b35b034de66c923834ae2c41d3a44b8d793d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Tue, 14 Mar 2017 11:16:05 +0100 Subject: [PATCH 4/7] Update README --- README.md | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b1be3183..dddebff9 100644 --- a/README.md +++ b/README.md @@ -11,26 +11,31 @@ Perks * Optimised (zero DB queries during usual user workflow) * Nice widgets like GhostMenu or GhostHtml::a where elements are visible only if user has access to route where they point +Features of this fork +~~~ + +* Correct maximum length of an email address +* Improved Spanish translation + Installation ------------ The preferred way to install this extension is through [composer](http://getcomposer.org/download/). -Either run - -``` -composer require webvimark/module-user-management -``` - -or add - +Add the following lines to your `composer.json` file: ``` -"webvimark/module-user-management": "^1" +"repositories": [ + { + "type": "vcs", + "url": "https://github.com/quique/user-management" + } +], +"require": { + "webvimark/module-user-management": "dev-dev", +}, ``` -to the require section of your `composer.json` file. - Configuration --- @@ -65,7 +70,7 @@ Configuration // $: anchored to the end of the string //'passwordRegexp' => '^\S*(?=\S{8,})(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$', - + // Here you can set your handler to change layout for any controller or action // Tip: you can use this event in any module From 8aa1a4fc169ad69b26a785bd7c0304b7e8edd034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Wed, 15 Mar 2017 11:39:29 +0100 Subject: [PATCH 5/7] style: Honor PSR-2 coding style guidelines --- components/UserConfig.php | 98 +++-- components/UserIdentity.php | 333 ++++++++-------- models/User.php | 757 +++++++++++++++++------------------- models/forms/LoginForm.php | 198 +++++----- 4 files changed, 674 insertions(+), 712 deletions(-) diff --git a/components/UserConfig.php b/components/UserConfig.php index 54de6e75..594e2f17 100644 --- a/components/UserConfig.php +++ b/components/UserConfig.php @@ -6,57 +6,55 @@ use Yii; /** - * Class UserConfig - * @package webvimark\modules\UserManagement\components + * Class UserConfig. */ class UserConfig extends User { - /** - * @inheritdoc - */ - public $identityClass = 'webvimark\modules\UserManagement\models\User'; - - /** - * @inheritdoc - */ - public $enableAutoLogin = true; - - /** - * @inheritdoc - */ - public $cookieLifetime = 2592000; - - /** - * @inheritdoc - */ - public $loginUrl = ['/user-management/auth/login']; - - /** - * Allows to call Yii::$app->user->isSuperadmin - * - * @return bool - */ - public function getIsSuperadmin() - { - return @Yii::$app->user->identity->superadmin == 1; - } - - /** - * @return string - */ - public function getUsername() - { - return @Yii::$app->user->identity->username; - } - - /** - * @inheritdoc - */ - protected function afterLogin($identity, $cookieBased, $duration) - { - AuthHelper::updatePermissions($identity); - - parent::afterLogin($identity, $cookieBased, $duration); - } - + /** + * {@inheritdoc} + */ + public $identityClass = 'webvimark\modules\UserManagement\models\User'; + + /** + * {@inheritdoc} + */ + public $enableAutoLogin = true; + + /** + * {@inheritdoc} + */ + public $cookieLifetime = 2592000; + + /** + * {@inheritdoc} + */ + public $loginUrl = ['/user-management/auth/login']; + + /** + * Allows to call Yii::$app->user->isSuperadmin. + * + * @return bool + */ + public function getIsSuperadmin() + { + return @Yii::$app->user->identity->superadmin == 1; + } + + /** + * @return string + */ + public function getUsername() + { + return @Yii::$app->user->identity->username; + } + + /** + * {@inheritdoc} + */ + protected function afterLogin($identity, $cookieBased, $duration) + { + AuthHelper::updatePermissions($identity); + + parent::afterLogin($identity, $cookieBased, $duration); + } } diff --git a/components/UserIdentity.php b/components/UserIdentity.php index 75fd6583..ec2a7880 100644 --- a/components/UserIdentity.php +++ b/components/UserIdentity.php @@ -1,4 +1,5 @@ $token, 'status' => User::STATUS_ACTIVE]); - } - - /** - * Finds user by username - * - * @param string $username - * @return static|null - */ - public static function findByUsername($username) - { - return static::findOne(['username' => $username, 'status' => User::STATUS_ACTIVE]); - } - - /** - * Finds user by confirmation token - * - * @param string $token confirmation token - * @return static|null|User - */ - public static function findByConfirmationToken($token) - { - $expire = Yii::$app->getModule('user-management')->confirmationTokenExpire; - - $parts = explode('_', $token); - $timestamp = (int)end($parts); - - if ( $timestamp + $expire < time() ) - { - // token expired - return null; - } - - return static::findOne([ - 'confirmation_token' => $token, - 'status' => User::STATUS_ACTIVE, - ]); - } - - /** - * Finds user by confirmation token - * - * @param string $token confirmation token - * @return static|null|User - */ - public static function findInactiveByConfirmationToken($token) - { - $expire = Yii::$app->getModule('user-management')->confirmationTokenExpire; - - $parts = explode('_', $token); - $timestamp = (int)end($parts); - - if ( $timestamp + $expire < time() ) - { - // token expired - return null; - } - - return static::findOne([ - 'confirmation_token' => $token, - 'status' => User::STATUS_INACTIVE, - ]); - } - - /** - * @inheritdoc - */ - public function getId() - { - return $this->getPrimaryKey(); - } - - /** - * @inheritdoc - */ - public function getAuthKey() - { - return $this->auth_key; - } - - /** - * @inheritdoc - */ - public function validateAuthKey($authKey) - { - return $this->getAuthKey() === $authKey; - } - - /** - * Validates password - * - * @param string $password password to validate - * @return boolean if password provided is valid for current user - */ - public function validatePassword($password) - { - return Yii::$app->security->validatePassword($password, $this->password_hash); - } - - /** - * Generates password hash from password and sets it to the model - * - * @param string $password - */ - public function setPassword($password) - { - if ( php_sapi_name() == 'cli' ) - { - $security = new Security(); - $this->password_hash = $security->generatePasswordHash($password); - } - else - { - $this->password_hash = Yii::$app->security->generatePasswordHash($password); - } - } - - /** - * Generates "remember me" authentication key - */ - public function generateAuthKey() - { - if ( php_sapi_name() == 'cli' ) - { - $security = new Security(); - $this->auth_key = $security->generateRandomString(); - } - else - { - $this->auth_key = Yii::$app->security->generateRandomString(); - } - } - - /** - * Generates new confirmation token - */ - public function generateConfirmationToken() - { - $this->confirmation_token = Yii::$app->security->generateRandomString() . '_' . time(); - } - - /** - * Removes confirmation token - */ - public function removeConfirmationToken() - { - $this->confirmation_token = null; - } -} \ No newline at end of file + /** + * {@inheritdoc} + */ + public static function findIdentity($id) + { + return static::findOne($id); + } + + /** + * {@inheritdoc} + */ + public static function findIdentityByAccessToken($token, $type = null) + { + return static::findOne(['auth_key' => $token, 'status' => User::STATUS_ACTIVE]); + } + + /** + * Finds user by username. + * + * @param string $username + * + * @return static|null + */ + public static function findByUsername($username) + { + return static::findOne(['username' => $username, 'status' => User::STATUS_ACTIVE]); + } + + /** + * Finds user by confirmation token. + * + * @param string $token confirmation token + * + * @return static|null|User + */ + public static function findByConfirmationToken($token) + { + $expire = Yii::$app->getModule('user-management')->confirmationTokenExpire; + + $parts = explode('_', $token); + $timestamp = (int) end($parts); + + if ($timestamp + $expire < time()) { + // token expired + return null; + } + + return static::findOne([ + 'confirmation_token' => $token, + 'status' => User::STATUS_ACTIVE, + ]); + } + + /** + * Finds user by confirmation token. + * + * @param string $token confirmation token + * + * @return static|null|User + */ + public static function findInactiveByConfirmationToken($token) + { + $expire = Yii::$app->getModule('user-management')->confirmationTokenExpire; + + $parts = explode('_', $token); + $timestamp = (int) end($parts); + + if ($timestamp + $expire < time()) { + // token expired + return null; + } + + return static::findOne([ + 'confirmation_token' => $token, + 'status' => User::STATUS_INACTIVE, + ]); + } + + /** + * {@inheritdoc} + */ + public function getId() + { + return $this->getPrimaryKey(); + } + + /** + * {@inheritdoc} + */ + public function getAuthKey() + { + return $this->auth_key; + } + + /** + * {@inheritdoc} + */ + public function validateAuthKey($authKey) + { + return $this->getAuthKey() === $authKey; + } + + /** + * Validates password. + * + * @param string $password password to validate + * + * @return bool if password provided is valid for current user + */ + public function validatePassword($password) + { + return Yii::$app->security->validatePassword($password, $this->password_hash); + } + + /** + * Generates password hash from password and sets it to the model. + * + * @param string $password + */ + public function setPassword($password) + { + if (php_sapi_name() == 'cli') { + $security = new Security(); + $this->password_hash = $security->generatePasswordHash($password); + } else { + $this->password_hash = Yii::$app->security->generatePasswordHash($password); + } + } + + /** + * Generates "remember me" authentication key. + */ + public function generateAuthKey() + { + if (php_sapi_name() == 'cli') { + $security = new Security(); + $this->auth_key = $security->generateRandomString(); + } else { + $this->auth_key = Yii::$app->security->generateRandomString(); + } + } + + /** + * Generates new confirmation token. + */ + public function generateConfirmationToken() + { + $this->confirmation_token = Yii::$app->security->generateRandomString().'_'.time(); + } + + /** + * Removes confirmation token. + */ + public function removeConfirmationToken() + { + $this->confirmation_token = null; + } +} diff --git a/models/User.php b/models/User.php index 51002567..e2de8730 100644 --- a/models/User.php +++ b/models/User.php @@ -15,406 +15,379 @@ /** * This is the model class for table "user". * - * @property integer $id + * @property int $id * @property string $username * @property string $email - * @property integer $email_confirmed + * @property int $email_confirmed * @property string $auth_key * @property string $password_hash * @property string $confirmation_token * @property string $bind_to_ip * @property string $registration_ip - * @property integer $status - * @property integer $superadmin - * @property integer $created_at - * @property integer $updated_at + * @property int $status + * @property int $superadmin + * @property int $created_at + * @property int $updated_at */ class User extends UserIdentity { - const STATUS_ACTIVE = 1; - const STATUS_INACTIVE = 0; - const STATUS_BANNED = -1; - - /** - * @var string - */ - public $gridRoleSearch; - - /** - * @var string - */ - public $password; - - /** - * @var string - */ - public $repeat_password; - - /** - * Store result in singleton to prevent multiple db requests with multiple calls - * - * @param bool $fromSingleton - * - * @return static - */ - public static function getCurrentUser($fromSingleton = true) - { - if ( !$fromSingleton ) - { - return static::findOne(Yii::$app->user->id); - } - - $user = Singleton::getData('__currentUser'); - - if ( !$user ) - { - $user = static::findOne(Yii::$app->user->id); - - Singleton::setData('__currentUser', $user); - } - - return $user; - } - - /** - * Assign role to user - * - * @param int $userId - * @param string $roleName - * - * @return bool - */ - public static function assignRole($userId, $roleName) - { - try - { - Yii::$app->db->createCommand() - ->insert(Yii::$app->getModule('user-management')->auth_assignment_table, [ - 'user_id' => $userId, - 'item_name' => $roleName, - 'created_at' => time(), - ])->execute(); - - AuthHelper::invalidatePermissions(); - - return true; - } - catch (\Exception $e) - { - return false; - } - } - - /** - * Revoke role from user - * - * @param int $userId - * @param string $roleName - * - * @return bool - */ - public static function revokeRole($userId, $roleName) - { - $result = Yii::$app->db->createCommand() - ->delete(Yii::$app->getModule('user-management')->auth_assignment_table, ['user_id' => $userId, 'item_name' => $roleName]) - ->execute() > 0; - - if ( $result ) - { - AuthHelper::invalidatePermissions(); - } - - return $result; - } - - /** - * @param string|array $roles - * @param bool $superAdminAllowed - * - * @return bool - */ - public static function hasRole($roles, $superAdminAllowed = true) - { - if ( $superAdminAllowed AND Yii::$app->user->isSuperadmin ) - { - return true; - } - $roles = (array)$roles; - - AuthHelper::ensurePermissionsUpToDate(); - - return array_intersect($roles, Yii::$app->session->get(AuthHelper::SESSION_PREFIX_ROLES,[])) !== []; - } - - /** - * @param string $permission - * @param bool $superAdminAllowed - * - * @return bool - */ - public static function hasPermission($permission, $superAdminAllowed = true) - { - if ( $superAdminAllowed AND Yii::$app->user->isSuperadmin ) - { - return true; - } - - AuthHelper::ensurePermissionsUpToDate(); - - return in_array($permission, Yii::$app->session->get(AuthHelper::SESSION_PREFIX_PERMISSIONS,[])); - } - - /** - * Useful for Menu widget - * - * - * ... - * [ 'label'=>'Some label', 'url'=>['/site/index'], 'visible'=>User::canRoute(['/site/index']) ] - * ... - * - * - * @param string|array $route - * @param bool $superAdminAllowed - * - * @return bool - */ - public static function canRoute($route, $superAdminAllowed = true) - { - if ( $superAdminAllowed AND Yii::$app->user->isSuperadmin ) - { - return true; - } - - $baseRoute = AuthHelper::unifyRoute($route); - - if ( Route::isFreeAccess($baseRoute) ) - { - return true; - } - - AuthHelper::ensurePermissionsUpToDate(); - - return Route::isRouteAllowed($baseRoute, Yii::$app->session->get(AuthHelper::SESSION_PREFIX_ROUTES,[])); - } - - /** - * getStatusList - * @return array - */ - public static function getStatusList() - { - return array( - self::STATUS_ACTIVE => UserManagementModule::t('back', 'Active'), - self::STATUS_INACTIVE => UserManagementModule::t('back', 'Inactive'), - self::STATUS_BANNED => UserManagementModule::t('back', 'Banned'), - ); - } - - /** - * getStatusValue - * - * @param string $val - * - * @return string - */ - public static function getStatusValue($val) - { - $ar = self::getStatusList(); - - return isset( $ar[$val] ) ? $ar[$val] : $val; - } - - /** - * @inheritdoc - */ - public static function tableName() - { - return Yii::$app->getModule('user-management')->user_table; - } - - /** - * @inheritdoc - */ - public function behaviors() - { - return [ - TimestampBehavior::className(), - ]; - } - - /** - * @inheritdoc - */ - public function rules() - { - return [ - ['username', 'required'], - ['username', 'unique'], - ['username', 'trim'], - - [['status', 'email_confirmed'], 'integer'], - - ['email', 'email'], - ['email', 'validateEmailConfirmedUnique'], - - ['bind_to_ip', 'validateBindToIp'], - ['bind_to_ip', 'trim'], - ['bind_to_ip', 'string', 'max' => 255], - - ['password', 'required', 'on'=>['newUser', 'changePassword']], - ['password', 'string', 'max' => 255, 'on'=>['newUser', 'changePassword']], - ['password', 'trim', 'on'=>['newUser', 'changePassword']], - ['password', 'match', 'pattern' => Yii::$app->getModule('user-management')->passwordRegexp], - - ['repeat_password', 'required', 'on'=>['newUser', 'changePassword']], - ['repeat_password', 'compare', 'compareAttribute'=>'password'], - ]; - } - - /** - * Check that there is no such confirmed E-mail in the system - */ - public function validateEmailConfirmedUnique() - { - if ( $this->email ) - { - $exists = User::findOne([ - 'email' => $this->email, - 'email_confirmed' => 1, - ]); - - if ( $exists AND $exists->id != $this->id ) - { - $this->addError('email', UserManagementModule::t('front', 'This E-mail already exists')); - } - } - } - - /** - * Validate bind_to_ip attr to be in correct format - */ - public function validateBindToIp() - { - if ( $this->bind_to_ip ) - { - $ips = explode(',', $this->bind_to_ip); - - foreach ($ips as $ip) - { - if ( !filter_var(trim($ip), FILTER_VALIDATE_IP) ) - { - $this->addError('bind_to_ip', UserManagementModule::t('back', "Wrong format. Enter valid IPs separated by comma")); - } - } - } - } - - /** - * @return array - */ - public function attributeLabels() - { - return [ - 'id' => 'ID', - 'username' => UserManagementModule::t('back', 'Login'), - 'superadmin' => UserManagementModule::t('back', 'Superadmin'), - 'confirmation_token' => UserManagementModule::t('back', 'Confirmation Token'), - 'registration_ip' => UserManagementModule::t('back', 'Registration IP'), - 'bind_to_ip' => UserManagementModule::t('back', 'Bind to IP'), - 'status' => UserManagementModule::t('back', 'Status'), - 'gridRoleSearch' => UserManagementModule::t('back', 'Roles'), - 'created_at' => UserManagementModule::t('back', 'Created'), - 'updated_at' => UserManagementModule::t('back', 'Updated'), - 'password' => UserManagementModule::t('back', 'Password'), - 'repeat_password' => UserManagementModule::t('back', 'Repeat password'), - 'email_confirmed' => UserManagementModule::t('back', 'E-mail confirmed'), - 'email' => UserManagementModule::t('back', 'E-mail'), - ]; - } - - /** - * @return \yii\db\ActiveQuery - */ - public function getRoles() - { - return $this->hasMany(Role::className(), ['name' => 'item_name']) - ->viaTable(Yii::$app->getModule('user-management')->auth_assignment_table, ['user_id'=>'id']); - } - - - /** - * Make sure user will not deactivate himself and superadmin could not demote himself - * Also don't let non-superadmin edit superadmin - * - * @inheritdoc - */ - public function beforeSave($insert) - { - if ( $insert ) - { - if ( php_sapi_name() != 'cli' ) - { - $this->registration_ip = LittleBigHelper::getRealIp(); - } - $this->generateAuthKey(); - } - else - { - // Console doesn't have Yii::$app->user, so we skip it for console - if ( php_sapi_name() != 'cli' ) - { - if ( Yii::$app->user->id == $this->id ) - { - // Make sure user will not deactivate himself - $this->status = static::STATUS_ACTIVE; - - // Superadmin could not demote himself - if ( Yii::$app->user->isSuperadmin AND $this->superadmin != 1 ) - { - $this->superadmin = 1; - } - } - - // Don't let non-superadmin edit superadmin - if ( isset($this->oldAttributes['superadmin']) && !Yii::$app->user->isSuperadmin && $this->oldAttributes['superadmin'] == 1 ) - { - return false; - } - } - } - - // If password has been set, than create password hash - if ( $this->password ) - { - $this->setPassword($this->password); - } - - return parent::beforeSave($insert); - } - - /** - * Don't let delete yourself and don't let non-superadmin delete superadmin - * - * @inheritdoc - */ - public function beforeDelete() - { - // Console doesn't have Yii::$app->user, so we skip it for console - if ( php_sapi_name() != 'cli' ) - { - // Don't let delete yourself - if ( Yii::$app->user->id == $this->id ) - { - return false; - } - - // Don't let non-superadmin delete superadmin - if ( !Yii::$app->user->isSuperadmin AND $this->superadmin == 1 ) - { - return false; - } - } - - return parent::beforeDelete(); - } + const STATUS_ACTIVE = 1; + const STATUS_INACTIVE = 0; + const STATUS_BANNED = -1; + + /** + * @var string + */ + public $gridRoleSearch; + + /** + * @var string + */ + public $password; + + /** + * @var string + */ + public $repeat_password; + + /** + * Store result in singleton to prevent multiple db requests with multiple calls. + * + * @param bool $fromSingleton + * + * @return static + */ + public static function getCurrentUser($fromSingleton = true) + { + if (!$fromSingleton) { + return static::findOne(Yii::$app->user->id); + } + + $user = Singleton::getData('__currentUser'); + + if (!$user) { + $user = static::findOne(Yii::$app->user->id); + + Singleton::setData('__currentUser', $user); + } + + return $user; + } + + /** + * Assign role to user. + * + * @param int $userId + * @param string $roleName + * + * @return bool + */ + public static function assignRole($userId, $roleName) + { + try { + Yii::$app->db->createCommand() + ->insert(Yii::$app->getModule('user-management')->auth_assignment_table, [ + 'user_id' => $userId, + 'item_name' => $roleName, + 'created_at' => time(), + ])->execute(); + + AuthHelper::invalidatePermissions(); + + return true; + } catch (\Exception $e) { + return false; + } + } + + /** + * Revoke role from user. + * + * @param int $userId + * @param string $roleName + * + * @return bool + */ + public static function revokeRole($userId, $roleName) + { + $result = Yii::$app->db->createCommand() + ->delete(Yii::$app->getModule('user-management')->auth_assignment_table, ['user_id' => $userId, 'item_name' => $roleName]) + ->execute() > 0; + + if ($result) { + AuthHelper::invalidatePermissions(); + } + + return $result; + } + + /** + * @param string|array $roles + * @param bool $superAdminAllowed + * + * @return bool + */ + public static function hasRole($roles, $superAdminAllowed = true) + { + if ($superAdminAllowed and Yii::$app->user->isSuperadmin) { + return true; + } + $roles = (array) $roles; + + AuthHelper::ensurePermissionsUpToDate(); + + return array_intersect($roles, Yii::$app->session->get(AuthHelper::SESSION_PREFIX_ROLES, [])) !== []; + } + + /** + * @param string $permission + * @param bool $superAdminAllowed + * + * @return bool + */ + public static function hasPermission($permission, $superAdminAllowed = true) + { + if ($superAdminAllowed and Yii::$app->user->isSuperadmin) { + return true; + } + + AuthHelper::ensurePermissionsUpToDate(); + + return in_array($permission, Yii::$app->session->get(AuthHelper::SESSION_PREFIX_PERMISSIONS, [])); + } + + /** + * Useful for Menu widget. + * + * + * ... + * [ 'label'=>'Some label', 'url'=>['/site/index'], 'visible'=>User::canRoute(['/site/index']) ] + * ... + * + * + * @param string|array $route + * @param bool $superAdminAllowed + * + * @return bool + */ + public static function canRoute($route, $superAdminAllowed = true) + { + if ($superAdminAllowed and Yii::$app->user->isSuperadmin) { + return true; + } + + $baseRoute = AuthHelper::unifyRoute($route); + + if (Route::isFreeAccess($baseRoute)) { + return true; + } + + AuthHelper::ensurePermissionsUpToDate(); + + return Route::isRouteAllowed($baseRoute, Yii::$app->session->get(AuthHelper::SESSION_PREFIX_ROUTES, [])); + } + + /** + * getStatusList. + * + * @return array + */ + public static function getStatusList() + { + return array( + self::STATUS_ACTIVE => UserManagementModule::t('back', 'Active'), + self::STATUS_INACTIVE => UserManagementModule::t('back', 'Inactive'), + self::STATUS_BANNED => UserManagementModule::t('back', 'Banned'), + ); + } + + /** + * getStatusValue. + * + * @param string $val + * + * @return string + */ + public static function getStatusValue($val) + { + $ar = self::getStatusList(); + + return isset($ar[$val]) ? $ar[$val] : $val; + } + + /** + * {@inheritdoc} + */ + public static function tableName() + { + return Yii::$app->getModule('user-management')->user_table; + } + + /** + * {@inheritdoc} + */ + public function behaviors() + { + return [ + TimestampBehavior::className(), + ]; + } + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + ['username', 'required'], + ['username', 'unique'], + ['username', 'trim'], + + [['status', 'email_confirmed'], 'integer'], + + ['email', 'email'], + ['email', 'validateEmailConfirmedUnique'], + + ['bind_to_ip', 'validateBindToIp'], + ['bind_to_ip', 'trim'], + ['bind_to_ip', 'string', 'max' => 255], + + ['password', 'required', 'on' => ['newUser', 'changePassword']], + ['password', 'string', 'max' => 255, 'on' => ['newUser', 'changePassword']], + ['password', 'trim', 'on' => ['newUser', 'changePassword']], + ['password', 'match', 'pattern' => Yii::$app->getModule('user-management')->passwordRegexp], + + ['repeat_password', 'required', 'on' => ['newUser', 'changePassword']], + ['repeat_password', 'compare', 'compareAttribute' => 'password'], + ]; + } + + /** + * Check that there is no such confirmed E-mail in the system. + */ + public function validateEmailConfirmedUnique() + { + if ($this->email) { + $exists = self::findOne([ + 'email' => $this->email, + 'email_confirmed' => 1, + ]); + + if ($exists and $exists->id != $this->id) { + $this->addError('email', UserManagementModule::t('front', 'This E-mail already exists')); + } + } + } + + /** + * Validate bind_to_ip attr to be in correct format. + */ + public function validateBindToIp() + { + if ($this->bind_to_ip) { + $ips = explode(',', $this->bind_to_ip); + + foreach ($ips as $ip) { + if (!filter_var(trim($ip), FILTER_VALIDATE_IP)) { + $this->addError('bind_to_ip', UserManagementModule::t('back', 'Wrong format. Enter valid IPs separated by comma')); + } + } + } + } + + /** + * @return array + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'username' => UserManagementModule::t('back', 'Login'), + 'superadmin' => UserManagementModule::t('back', 'Superadmin'), + 'confirmation_token' => UserManagementModule::t('back', 'Confirmation Token'), + 'registration_ip' => UserManagementModule::t('back', 'Registration IP'), + 'bind_to_ip' => UserManagementModule::t('back', 'Bind to IP'), + 'status' => UserManagementModule::t('back', 'Status'), + 'gridRoleSearch' => UserManagementModule::t('back', 'Roles'), + 'created_at' => UserManagementModule::t('back', 'Created'), + 'updated_at' => UserManagementModule::t('back', 'Updated'), + 'password' => UserManagementModule::t('back', 'Password'), + 'repeat_password' => UserManagementModule::t('back', 'Repeat password'), + 'email_confirmed' => UserManagementModule::t('back', 'E-mail confirmed'), + 'email' => UserManagementModule::t('back', 'E-mail'), + ]; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getRoles() + { + return $this->hasMany(Role::className(), ['name' => 'item_name']) + ->viaTable(Yii::$app->getModule('user-management')->auth_assignment_table, ['user_id' => 'id']); + } + + /** + * Make sure user will not deactivate himself and superadmin could not demote himself + * Also don't let non-superadmin edit superadmin. + * + * {@inheritdoc} + */ + public function beforeSave($insert) + { + if ($insert) { + if (php_sapi_name() != 'cli') { + $this->registration_ip = LittleBigHelper::getRealIp(); + } + $this->generateAuthKey(); + } else { + // Console doesn't have Yii::$app->user, so we skip it for console + if (php_sapi_name() != 'cli') { + if (Yii::$app->user->id == $this->id) { + // Make sure user will not deactivate himself + $this->status = static::STATUS_ACTIVE; + + // Superadmin could not demote himself + if (Yii::$app->user->isSuperadmin and $this->superadmin != 1) { + $this->superadmin = 1; + } + } + + // Don't let non-superadmin edit superadmin + if (isset($this->oldAttributes['superadmin']) && !Yii::$app->user->isSuperadmin && $this->oldAttributes['superadmin'] == 1) { + return false; + } + } + } + + // If password has been set, than create password hash + if ($this->password) { + $this->setPassword($this->password); + } + + return parent::beforeSave($insert); + } + + /** + * Don't let delete yourself and don't let non-superadmin delete superadmin. + * + * {@inheritdoc} + */ + public function beforeDelete() + { + // Console doesn't have Yii::$app->user, so we skip it for console + if (php_sapi_name() != 'cli') { + // Don't let delete yourself + if (Yii::$app->user->id == $this->id) { + return false; + } + + // Don't let non-superadmin delete superadmin + if (!Yii::$app->user->isSuperadmin and $this->superadmin == 1) { + return false; + } + } + + return parent::beforeDelete(); + } } diff --git a/models/forms/LoginForm.php b/models/forms/LoginForm.php index ee6cc9d2..d820fbb5 100644 --- a/models/forms/LoginForm.php +++ b/models/forms/LoginForm.php @@ -1,4 +1,5 @@ UserManagementModule::t('front', 'Username'), - 'password' => UserManagementModule::t('front', 'Password'), - 'rememberMe' => UserManagementModule::t('front', 'Remember me'), - ]; - } - - /** - * Validates the password. - * This method serves as the inline validation for password. - */ - public function validatePassword() - { - if ( !Yii::$app->getModule('user-management')->checkAttempts() ) - { - $this->addError('password', UserManagementModule::t('front', 'Too many attempts')); - - return false; - } - - if ( !$this->hasErrors() ) - { - $user = $this->getUser(); - if ( !$user || !$user->validatePassword($this->password) ) - { - $this->addError('password', UserManagementModule::t('front', 'Incorrect username or password.')); - } - } - } - - /** - * Check if user is binded to IP and compare it with his actual IP - */ - public function validateIP() - { - $user = $this->getUser(); - - if ( $user AND $user->bind_to_ip ) - { - $ips = explode(',', $user->bind_to_ip); - - $ips = array_map('trim', $ips); - - if ( !in_array(LittleBigHelper::getRealIp(), $ips) ) - { - $this->addError('password', UserManagementModule::t('front', "You could not login from this IP")); - } - } - } - - /** - * Logs in a user using the provided username and password. - * @return boolean whether the user is logged in successfully - */ - public function login() - { - if ( $this->validate() ) - { - return Yii::$app->user->login($this->getUser(), $this->rememberMe ? Yii::$app->user->cookieLifetime : 0); - } - else - { - return false; - } - } - - /** - * Finds user by [[username]] - * @return User|null - */ - public function getUser() - { - if ( $this->_user === false ) - { - $u = new \Yii::$app->user->identityClass; - $this->_user = ($u instanceof User ? $u->findByUsername($this->username) : User::findByUsername($this->username)); - } - - return $this->_user; - } + public $username; + public $password; + public $rememberMe = false; + + private $_user = false; + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + [['username', 'password'], 'required'], + ['rememberMe', 'boolean'], + ['password', 'validatePassword'], + + ['username', 'validateIP'], + ]; + } + + public function attributeLabels() + { + return [ + 'username' => UserManagementModule::t('front', 'Username'), + 'password' => UserManagementModule::t('front', 'Password'), + 'rememberMe' => UserManagementModule::t('front', 'Remember me'), + ]; + } + + /** + * Validates the password. + * This method serves as the inline validation for password. + */ + public function validatePassword() + { + if (!Yii::$app->getModule('user-management')->checkAttempts()) { + $this->addError('password', UserManagementModule::t('front', 'Too many attempts')); + + return false; + } + + if (!$this->hasErrors()) { + $user = $this->getUser(); + if (!$user || !$user->validatePassword($this->password)) { + $this->addError('password', UserManagementModule::t('front', 'Incorrect username or password.')); + } + } + } + + /** + * Check if user is binded to IP and compare it with his actual IP. + */ + public function validateIP() + { + $user = $this->getUser(); + + if ($user and $user->bind_to_ip) { + $ips = explode(',', $user->bind_to_ip); + + $ips = array_map('trim', $ips); + + if (!in_array(LittleBigHelper::getRealIp(), $ips)) { + $this->addError('password', UserManagementModule::t('front', 'You could not login from this IP')); + } + } + } + + /** + * Logs in a user using the provided username and password. + * + * @return bool whether the user is logged in successfully + */ + public function login() + { + if ($this->validate()) { + return Yii::$app->user->login($this->getUser(), $this->rememberMe ? Yii::$app->user->cookieLifetime : 0); + } else { + return false; + } + } + + /** + * Finds user by [[username]]. + * + * @return User|null + */ + public function getUser() + { + if ($this->_user === false) { + $u = new \Yii::$app->user->identityClass(); + $this->_user = ($u instanceof User ? $u->findByUsername($this->username) : User::findByUsername($this->username)); + } + + return $this->_user; + } } From 0f8d4f8990d9de7b031fecece5b5d557d300a844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Wed, 15 Mar 2017 13:19:23 +0100 Subject: [PATCH 6/7] style: Honor PSR-2 coding style guidelines --- views/user/view.php | 126 ++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/views/user/view.php b/views/user/view.php index 5623a29b..8e833c94 100644 --- a/views/user/view.php +++ b/views/user/view.php @@ -8,7 +8,7 @@ use yii\helpers\Html; use yii\widgets\DetailView; -/** +/* * @var yii\web\View $this * @var webvimark\modules\UserManagement\models\User $model */ @@ -19,71 +19,71 @@ ?>
-

title ?>

+

title ?>

-
-
+
+
-

- $model->id], ['class' => 'btn btn-sm btn-primary']) ?> - 'btn btn-sm btn-success']) ?> - $model->id], - ['class' => 'btn btn-sm btn-default'] - ) ?> +

+ $model->id], ['class' => 'btn btn-sm btn-primary']) ?> + 'btn btn-sm btn-success']) ?> + $model->id], + ['class' => 'btn btn-sm btn-default'] + ) ?> - $model->id], [ - 'class' => 'btn btn-sm btn-danger pull-right', - 'data' => [ - 'confirm' => UserManagementModule::t('back', 'Are you sure you want to delete this user?'), - 'method' => 'post', - ], - ]) ?> -

+ $model->id], [ + 'class' => 'btn btn-sm btn-danger pull-right', + 'data' => [ + 'confirm' => UserManagementModule::t('back', 'Are you sure you want to delete this user?'), + 'method' => 'post', + ], + ]) ?> +

- $model, - 'attributes' => [ - 'id', - [ - 'attribute'=>'status', - 'value'=>User::getStatusValue($model->status), - ], - 'username', - [ - 'attribute'=>'email', - 'value'=>$model->email, - 'format'=>'email', - 'visible'=>User::hasPermission('viewUserEmail'), - ], - [ - 'attribute'=>'email_confirmed', - 'value'=>$model->email_confirmed, - 'format'=>'boolean', - 'visible'=>User::hasPermission('viewUserEmail'), - ], - [ - 'label'=>UserManagementModule::t('back', 'Roles'), - 'value'=>implode('
', ArrayHelper::map(Role::getUserRoles($model->id), 'name', 'description')), - 'visible'=>User::hasPermission('viewUserRoles'), - 'format'=>'raw', - ], - [ - 'attribute'=>'bind_to_ip', - 'visible'=>User::hasPermission('bindUserToIp'), - ], - array( - 'attribute'=>'registration_ip', - 'value'=>Html::a($model->registration_ip, "http://ipinfo.io/" . $model->registration_ip, ["target"=>"_blank"]), - 'format'=>'raw', - 'visible'=>User::hasPermission('viewRegistrationIp'), - ), - 'created_at:datetime', - 'updated_at:datetime', - ], - ]) ?> + $model, + 'attributes' => [ + 'id', + [ + 'attribute' => 'status', + 'value' => User::getStatusValue($model->status), + ], + 'username', + [ + 'attribute' => 'email', + 'value' => $model->email, + 'format' => 'email', + 'visible' => User::hasPermission('viewUserEmail'), + ], + [ + 'attribute' => 'email_confirmed', + 'value' => $model->email_confirmed, + 'format' => 'boolean', + 'visible' => User::hasPermission('viewUserEmail'), + ], + [ + 'label' => UserManagementModule::t('back', 'Roles'), + 'value' => implode('
', ArrayHelper::map(Role::getUserRoles($model->id), 'name', 'description')), + 'visible' => User::hasPermission('viewUserRoles'), + 'format' => 'raw', + ], + [ + 'attribute' => 'bind_to_ip', + 'visible' => User::hasPermission('bindUserToIp'), + ], + array( + 'attribute' => 'registration_ip', + 'value' => Html::a($model->registration_ip, 'http://ipinfo.io/'.$model->registration_ip, ['target' => '_blank']), + 'format' => 'raw', + 'visible' => User::hasPermission('viewRegistrationIp'), + ), + 'created_at:datetime', + 'updated_at:datetime', + ], + ]) ?> -
-
+
+
From 23c5603cfca12b1ee776c66190e2e70cc837b1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Mat=C3=ADas=20S=C3=A1nchez=20=28Quique=29?= Date: Wed, 15 Mar 2017 13:51:03 +0100 Subject: [PATCH 7/7] LDAP support --- README.md | 28 ++++++ components/UserConfig.php | 5 + components/UserIdentity.php | 99 ++++++++++++++++++- messages/cs/back.php | 10 +- messages/de/back.php | 40 ++++---- messages/es/back.php | 63 ++++++------ messages/fr/back.php | 10 +- messages/ko-KR/back.php | 30 +++--- messages/pl/back.php | 36 ++++--- messages/pt-BR/back.php | 6 +- messages/pt-PT/back.php | 32 +++--- messages/ru/back.php | 30 +++--- ...029_add_auth_type_column_to_user_table.php | 25 +++++ models/User.php | 3 +- models/forms/LoginForm.php | 11 +++ views/user/view.php | 1 + 16 files changed, 315 insertions(+), 114 deletions(-) create mode 100644 migrations/m170315_110029_add_auth_type_column_to_user_table.php diff --git a/README.md b/README.md index b1be3183..19c87656 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Perks * Visit log * Optimised (zero DB queries during usual user workflow) * Nice widgets like GhostMenu or GhostHtml::a where elements are visible only if user has access to route where they point +* LDAP support Installation @@ -40,6 +41,8 @@ Configuration 'components'=>[ 'user' => [ + // 'identityClass' => 'app\models\User', + 'enableLdap' => false, // Change it to true to enable LDAP authentication 'class' => 'webvimark\modules\UserManagement\components\UserConfig', // Comment this if you don't want to record user logins @@ -80,6 +83,22 @@ Configuration ``` +If needed, you can extend the base User class in app/models/User.php +(change the identityClass in the configuration accordingly): +```php + [ + 'host' => 'ldapserver.domain.net', + 'port' => 389, + 'base_dn' => 'ou=unit, dc=domain, dc=net', // Base Distinguished Name +], +``` + Where you can go ----- diff --git a/components/UserConfig.php b/components/UserConfig.php index 594e2f17..f814a5c5 100644 --- a/components/UserConfig.php +++ b/components/UserConfig.php @@ -20,6 +20,11 @@ class UserConfig extends User */ public $enableAutoLogin = true; + /** + * {@inheritdoc} + */ + public $enableLdap = false; + /** * {@inheritdoc} */ diff --git a/components/UserIdentity.php b/components/UserIdentity.php index ec2a7880..0006151f 100644 --- a/components/UserIdentity.php +++ b/components/UserIdentity.php @@ -3,9 +3,11 @@ namespace webvimark\modules\UserManagement\components; use webvimark\modules\UserManagement\models\User; +use webvimark\modules\UserManagement\UserManagementModule; use yii\base\Security; use yii\db\ActiveRecord; use yii\web\IdentityInterface; +use yii\web\ServerErrorHttpException; use Yii; /** @@ -126,7 +128,7 @@ public function validateAuthKey($authKey) } /** - * Validates password. + * Validates password, locally or via LDAP. * * @param string $password password to validate * @@ -134,7 +136,100 @@ public function validateAuthKey($authKey) */ public function validatePassword($password) { - return Yii::$app->security->validatePassword($password, $this->password_hash); + // Local user + if ($this->auth_type === 'local') { + return Yii::$app->security->validatePassword($password, $this->password_hash); + } + + // LDAP user + if ($this->auth_type === 'ldap') { + $user = $this->username; + $ldap_host = Yii::$app->params['ldap']['host']; + $ldap_port = Yii::$app->params['ldap']['port']; + $base_dn = Yii::$app->params['ldap']['base_dn']; // Active Directory base DN + $dn = "uid=$user, $base_dn"; // Distinguised Name + + // Connecting to LDAP server + // The "@" will silence any php errors and warnings the function could raise. + // See http://php.net/manual/en/language.operators.errorcontrol.php + if (!$ds = @ldap_connect($ldap_host, $ldap_port)) { + throw new ServerErrorHttpException(UserManagementModule::t('back', 'The provided LDAP parameters are syntactically wrong.')); + } + ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); + + // ldap_connect() does not actually test the connection to the + // specified LDAP server, it is just a syntactic check. + // The only way to test the connection is to actually call + // ldap_bind($ds, $username, $password). + // But if that fails, is it because credentials were wrong, + // or is it because the app could not reach the LDAP server? + // + // One possible workaround is to try an anonymous bind first. + // Note that this workaround relies on anonymous login being enabled. + // TODO: Explore ldap_error($ds) and LDAP_OPT_DIAGNOSTIC_MESSAGE. + if (!($anon = @ldap_bind($ds))) { + throw new ServerErrorHttpException(UserManagementModule::t('back', 'Could not bind to the LDAP server.')); + } else { + // Test passed. Unbind anonymous. + ldap_unbind($ds); + } + + // Reconnect and try a real login. + if (!$ldapconn = @ldap_connect($ldap_host, $ldap_port)) { + throw new ServerErrorHttpException(UserManagementModule::t('back', 'The provided LDAP parameters are syntactically wrong.')); + } + ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3); + ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0); // We need this for doing an LDAP search on Windows 2003 Server Active Directory. + if (!($bind = @ldap_bind($ldapconn, $dn, $password))) { + // Authentication failed + ldap_unbind($ldapconn); + + return false; + } + + // Successfully authenticated! + // If it is the first the user logs in, let's add it to the database. + if (!$this->id) { + $this->getUserAttributes($ldapconn, $base_dn); + $this->save(); + } + + ldap_unbind($ldapconn); + + return true; + } + + throw new ServerErrorHttpException(UserManagementModule::t('back', 'Unknown auth type.')); + } + + /** + * Search user attributes in the LDAP server, and add them to the User object. + * + * You may want to override this function in your custom User class. + * This is just a placeholder and example. + * + * @param resource $ldapconn An LDAP link identifier, returned by ldap_connect() + * @param string $base_dn The base DN for the directory + */ + protected function getUserAttributes($ldapconn, $base_dn) + { + /* + $filter = "(uid=$this->username)"; + // RFC specifications define many standard LDAP attributes, including + // RFC 2256: cn (Common Name) + // RFC 2798: mail (primary e-mail address) + // RFC 2307: uidNumber (user's integer identification number) + $attributes = ['mail']; + $results = @ldap_search($ldapconn, $base_dn, $filter, $attributes); + if (!$results) { + throw new ServerErrorHttpException(Yii::t('app', 'Unable to search LDAP server')); + } + // $number_returned = ldap_count_entries($ldapconn, $results); + $entries = ldap_get_entries($ldapconn, $results); + $mail = $entries[0]['mail'][0]; + + $this->email = $mail; + */ } /** diff --git a/messages/cs/back.php b/messages/cs/back.php index dd7fd4b7..4fe3857d 100644 --- a/messages/cs/back.php +++ b/messages/cs/back.php @@ -2,7 +2,7 @@ /** * Message translations. * - * This file is automatically generated by 'yii message' command. + * This file is automatically generated by 'yii message/extract' command. * It contains the localizable messages extracted from source code. * You may modify this file by translating the extracted messages. * @@ -19,6 +19,7 @@ return [ 'Active' => '', 'Are you sure you want to delete this user?' => '', + 'Authentication type' => '', 'Banned' => '', 'Bind to IP' => '', 'Browser' => '', @@ -30,6 +31,7 @@ 'Child roles' => '', 'Code' => '', 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', 'Create' => '', 'Created' => '', 'Creating permission group' => '', @@ -49,10 +51,9 @@ 'For example: 123.34.56.78, 168.111.192.12' => '', 'Group' => '', 'ID' => '', - 'Inactive' => '', 'IP' => '', + 'Inactive' => '', 'Language' => '', - 'Login' => '', 'Name' => '', 'OS' => '', 'Password' => '', @@ -81,9 +82,11 @@ 'Show only selected' => '', 'Status' => '', 'Superadmin' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', 'Token' => '', 'Too many attempts' => '', 'Type' => '', + 'Unknown auth type.' => '', 'Updated' => '', 'User' => '', 'User agent' => '', @@ -94,4 +97,5 @@ 'Wrong format. Enter valid IPs separated by comma' => '', 'Wrong password' => '', 'You can not change own permissions' => '', + 'Login' => '@@@@', ]; diff --git a/messages/de/back.php b/messages/de/back.php index 16965e3f..25d3d4d5 100644 --- a/messages/de/back.php +++ b/messages/de/back.php @@ -17,19 +17,37 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', + 'Banned' => '', + 'Browser' => '', + 'Code' => '', + 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', + 'E-mail' => '', + 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => '', + 'ID' => '', + 'IP' => '', + 'Name' => '', + 'Refresh routes' => '', + 'Refresh routes (and delete unused)' => '', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', + 'Search route' => '', + 'Show all' => '', + 'Show only selected' => '', + 'Status' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', + 'Token' => '', + 'Unknown auth type.' => '', + 'Login' => '@@@@', 'Active' => 'Aktiv', 'Are you sure you want to delete this user?' => 'Wollen Sie diesen Benutzer wirklich löschen?', - 'Banned' => '', 'Bind to IP' => 'An IP binden', - 'Browser' => '', 'Change own password' => 'Eigenes Passwort ändern', 'Change password' => 'Passwort ändern', 'Changing password' => 'Ändere Passwort', 'Changing password for user: ' => 'Ändere Passwort von Benutzer: ', 'Child permissions' => 'Kind-Berechtigungen', 'Child roles' => 'Kind-Rollen', - 'Code' => '', - 'Confirmation Token' => '', 'Create' => 'Erstellen', 'Created' => 'Erstellt', 'Creating permission group' => 'Erstelle Berechtigungs-Gruppe', @@ -37,9 +55,7 @@ 'Data' => 'Daten', 'Delete' => 'Löschen', 'Description' => 'Beschreibung', - 'E-mail' => '', 'E-mail confirmed' => 'E-Mail bestätigt', - 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => '', 'Edit' => 'Bearbeiten', 'Editing' => 'Bearbeite', 'Editing permission group' => 'Bearbeite Berechtigungs-Gruppe', @@ -48,12 +64,8 @@ 'Editing user: ' => 'Bearbeite Benutzer', 'For example: 123.34.56.78, 168.111.192.12' => 'Zum Beispiel: 123.34.56.78, 168.111.192.12', 'Group' => 'Gruppe', - 'ID' => '', 'Inactive' => 'Inaktiv', - 'IP' => '', 'Language' => 'Sprache', - 'Login' => '', - 'Name' => '', 'OS' => 'Betriebssystem', 'Password' => 'Passwort', 'Password has been changed' => 'Passwort wurde geändert', @@ -61,8 +73,6 @@ 'Permission groups' => 'Berechtigungs-Gruppen', 'Permissions' => 'Berechtigungen', 'Permissions for role:' => 'Berechtigungen für Rolle', - 'Refresh routes' => '', - 'Refresh routes (and delete unused)' => '', 'Registration IP' => 'Registrierung IP', 'Repeat password' => 'Passwort wiederholen', 'Reset' => 'Zurücksetzen', @@ -70,18 +80,12 @@ 'Roles' => 'Rollen', 'Roles and permissions' => 'Rollen und Berechtigungen', 'Roles and permissions for user:' => 'Rollen und Berechtigungen von Benutzer:', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', 'Rule' => 'Rolle', 'Save' => 'Speichern', 'Saved' => 'Gespeichert', 'Search' => 'Suchen', - 'Search route' => '', 'Settings for permission' => 'Einstellungen für Berechtigung', - 'Show all' => '', - 'Show only selected' => '', - 'Status' => '', 'Superadmin' => 'Super-Administrator', - 'Token' => '', 'Too many attempts' => 'Zu viele Versuche', 'Type' => 'Typ', 'Updated' => 'Aktualisiert', diff --git a/messages/es/back.php b/messages/es/back.php index c254af93..3ef3d942 100644 --- a/messages/es/back.php +++ b/messages/es/back.php @@ -17,15 +17,19 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => 'Tipo de autenticación', + 'Could not bind to the LDAP server.' => 'No fue posible conectarse al servidor LDAP', + 'The provided LDAP parameters are syntactically wrong.' => 'Los parámetros de LDAP proporcionados no son sintácticamente correctos.', + 'Unknown auth type.' => 'Tipo de autenticación desconocido', 'Active' => 'Activo', - 'Are you sure you want to delete this user?' => '¿Está seguro que desea eliminar este usuario?', + 'Are you sure you want to delete this user?' => '¿Seguro que desea borrar este usuario?', 'Banned' => 'Bloqueado', - 'Bind to IP' => 'Casar a IP', + 'Bind to IP' => 'Asociar a la IP', 'Browser' => 'Navegador', - 'Change own password' => 'Cambiar propia contraseña', - 'Change password' => 'Cambiar contraseña de usuario', - 'Changing password' => 'Cambiando contraseña', - 'Changing password for user: ' => 'Cambiando contraseña para usuario: ', + 'Change own password' => 'Cambiar la contraseña propia', + 'Change password' => 'Cambiar la contraseña', + 'Changing password' => 'Cambio de la contraseña', + 'Changing password for user: ' => 'Cambiando la contraseña del usuario: ', 'Child permissions' => 'Permisos hijos', 'Child roles' => 'Roles hijos', 'Code' => 'Código', @@ -33,65 +37,64 @@ 'Create' => 'Crear', 'Created' => 'Creado', 'Creating permission group' => 'Creación de grupo de permisos', - 'Current password' => 'Actual contraseña', + 'Current password' => 'Contraseña actual', 'Data' => 'Dato', - 'Delete' => 'Eliminar', + 'Delete' => 'Borrar', 'Description' => 'Descripción', 'E-mail' => 'Correo electrónico', 'E-mail confirmed' => 'Correo confirmado', - 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => 'Un correo electrónico con un enlace de activación ha sido enviado a {email}. El enlace expirara en {minutes} minutos.', + 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => 'Se ha enviado un correo electrónico con un enlace de activación a {email}. El enlace expirará en {minutes} minutos.', 'Edit' => 'Editar', - 'Editing' => 'Editando', - 'Editing permission group' => 'Editando grupo de permiso', + 'Editing' => 'Edición', + 'Editing permission group' => 'Edición de grupo de permisos', 'Editing permission: ' => 'Editando permiso:', 'Editing role: ' => 'Editando rol:', 'Editing user: ' => 'Editando usuario:', 'For example: 123.34.56.78, 168.111.192.12' => 'Por ejemplo: 123.34.56.78, 168.111.192.12', 'Group' => 'Grupo', 'ID' => 'Id', - 'Inactive' => 'Inactivo', 'IP' => 'IP', + 'Inactive' => 'Inactivo', 'Language' => 'Idioma', - 'Login' => 'Inicio de sesión', 'Name' => 'Nombre', 'OS' => 'Sistema Operativo', 'Password' => 'Contraseña', - 'Password has been changed' => 'Contraseña ha sido cambiada', + 'Password has been changed' => 'Se ha cambiado la contraseña', 'Permission creation' => 'Creación de permisos', 'Permission groups' => 'Grupos de permisos', 'Permissions' => 'Permisos', - 'Permissions for role:' => 'Permisos de role:', - 'Refresh routes' => 'Refrescar rutas', - 'Refresh routes (and delete unused)' => 'Refrescar rutas (y eliminar sin uso)', - 'Registration IP' => 'IP Registrada', - 'Repeat password' => 'Repetir contraseña', - 'Reset' => 'Reestablecer', - 'Role creation' => 'Creación de Rol', + 'Permissions for role:' => 'Permisos del rol:', + 'Refresh routes' => 'Refrescar las rutas', + 'Refresh routes (and delete unused)' => 'Refrescar las rutas (y borrar las que no se usan)', + 'Registration IP' => 'IP de registro', + 'Repeat password' => 'Repita la contraseña', + 'Reset' => 'Restablecer', + 'Role creation' => 'Creación de rol', 'Roles' => 'Roles', 'Roles and permissions' => 'Roles y permisos', - 'Roles and permissions for user:' => 'Roles y permisos para el usuario', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => 'Se eliminarán rutas que no existan en esta aplicación. No se recomienda para aplicaciones con estructura de "avanzada", porque frontend y backend tienen que propio conjunto de rutas.', + 'Roles and permissions for user:' => 'Roles y permisos para el usuario:', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => 'Se eliminarán rutas que no existan en esta aplicación. No se recomienda para aplicaciones con estructura «avanzada», porque frontend y backend tienen su propio conjunto de rutas.', 'Rule' => 'Regla', 'Save' => 'Guardar', 'Saved' => 'Guardado', 'Search' => 'Buscar', - 'Search route' => 'Buscar ruta', + 'Search route' => 'Buscar una ruta', 'Settings for permission' => 'Configuración de permiso', 'Show all' => 'Mostrar todos', - 'Show only selected' => 'Mostrar solo seleccionados', - 'Status' => 'Estatus', - 'Superadmin' => 'Super admin', + 'Show only selected' => 'Mostrar sólo los seleccionados', + 'Status' => 'Estado', + 'Superadmin' => 'Superadmin', 'Token' => 'Código Token', 'Too many attempts' => 'Demasiados intentos', 'Type' => 'Tipo', 'Updated' => 'Actualizado', 'User' => 'Usuario', - 'User agent' => 'Agente de Usuario', - 'User creation' => 'Creación de Usuario', + 'User agent' => 'Agente de usuario', + 'User creation' => 'Creación de usuario', 'Users' => 'Usuarios', 'Visit Time' => 'Fecha de visita', 'Visit log' => 'Registro de visita', - 'Wrong format. Enter valid IPs separated by comma' => 'Formato incorrecto. Ingrese IPs valida separada por coma', + 'Wrong format. Enter valid IPs separated by comma' => 'Formato incorrecto. Introduzca IPs válidas separadas por comas', 'Wrong password' => 'Contraseña incorrecta', 'You can not change own permissions' => 'Usted no puede cambiar sus propios permisos', ]; diff --git a/messages/fr/back.php b/messages/fr/back.php index 27a4be20..767ed67a 100644 --- a/messages/fr/back.php +++ b/messages/fr/back.php @@ -17,6 +17,12 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', + 'Could not bind to the LDAP server.' => '', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', + 'Unknown auth type.' => '', + 'Login' => '@@Identifiant@@', 'Active' => 'Actif', 'Are you sure you want to delete this user?' => 'Etes-vous sûre de vouloir supprimer cet utilisateur ?', 'Banned' => 'Banni', @@ -49,10 +55,9 @@ 'For example: 123.34.56.78, 168.111.192.12' => 'Par exemple: 123.34.56.78, 168.111.192.12', 'Group' => 'Groupe', 'ID' => 'ID', - 'Inactive' => 'Inactif', 'IP' => 'Adresse IP', + 'Inactive' => 'Inactif', 'Language' => 'Langage', - 'Login' => 'Identifiant', 'Name' => 'Nom', 'OS' => 'OS', 'Password' => 'Mot de passe', @@ -70,7 +75,6 @@ 'Roles' => 'Rôles', 'Roles and permissions' => 'Rôles et permissions', 'Roles and permissions for user:' => 'Rôles et permissions pour l\'utilisateur:', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', 'Rule' => 'Rêgle', 'Save' => 'Enregistrer', 'Saved' => 'Enregistrement', diff --git a/messages/ko-KR/back.php b/messages/ko-KR/back.php index 22aa9fdb..1fc32a98 100644 --- a/messages/ko-KR/back.php +++ b/messages/ko-KR/back.php @@ -17,9 +17,25 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', + 'Banned' => '', + 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', + 'E-mail' => '', + 'ID' => '', + 'IP' => '', + 'Refresh routes' => '', + 'Refresh routes (and delete unused)' => '', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', + 'Search route' => '', + 'Show all' => '', + 'Show only selected' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', + 'Token' => '', + 'Unknown auth type.' => '', + 'Login' => '@@로그인@@', 'Active' => '활성', 'Are you sure you want to delete this user?' => '이 사용자를 삭제하시겠습니까?', - 'Banned' => '', 'Bind to IP' => '아이피에 바인드', 'Browser' => '브라우져', 'Change own password' => '자신의 암호를 변경', @@ -29,7 +45,6 @@ 'Child permissions' => '자식 권한', 'Child roles' => '자식 역할', 'Code' => '코드', - 'Confirmation Token' => '', 'Create' => '생성', 'Created' => '성됨', 'Creating permission group' => '권한 그룹 생성중', @@ -37,7 +52,6 @@ 'Data' => '데이터', 'Delete' => '삭제', 'Description' => '설명', - 'E-mail' => '', 'E-mail confirmed' => 'E-Mail 승인됨', 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => '{email} 로 계정 활성화 링크를 보냈습니다. 이 메일은 {minutes}분 동안 유효합니다', 'Edit' => '편집', @@ -48,11 +62,8 @@ 'Editing user: ' => '사용자 편집중', 'For example: 123.34.56.78, 168.111.192.12' => '예시 : 123.34.56.78, 168.111.192.12', 'Group' => '그룹', - 'ID' => '', 'Inactive' => '비활성화', - 'IP' => '', 'Language' => '언어', - 'Login' => '로그인', 'Name' => '이름', 'OS' => '운영체제', 'Password' => '암호', @@ -61,8 +72,6 @@ 'Permission groups' => '권한 그룹들', 'Permissions' => '권한들', 'Permissions for role:' => '역할을 위한 권한', - 'Refresh routes' => '', - 'Refresh routes (and delete unused)' => '', 'Registration IP' => '등록 IP', 'Repeat password' => '암호 반복', 'Reset' => '재설정', @@ -70,18 +79,13 @@ 'Roles' => '역할들', 'Roles and permissions' => '역할과 권한', 'Roles and permissions for user:' => '사용자를 위한역할과 권한:', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', 'Rule' => '규칙', 'Save' => '저장', 'Saved' => '저장됨', 'Search' => '검색', - 'Search route' => '', 'Settings for permission' => '권한을 위한설정', - 'Show all' => '', - 'Show only selected' => '', 'Status' => '상태', 'Superadmin' => '슈퍼 관리자', - 'Token' => '', 'Too many attempts' => '너무 많은 시도들', 'Type' => '유형', 'Updated' => '수정됨', diff --git a/messages/pl/back.php b/messages/pl/back.php index 884e9d34..4c0feefb 100644 --- a/messages/pl/back.php +++ b/messages/pl/back.php @@ -17,6 +17,26 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', + 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', + 'E-mail' => '', + 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => '', + 'ID' => '', + 'IP' => '', + 'Permission creation' => '', + 'Refresh routes' => '', + 'Refresh routes (and delete unused)' => '', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', + 'Search route' => '', + 'Show all' => '', + 'Show only selected' => '', + 'Status' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', + 'Token' => '', + 'Unknown auth type.' => '', + 'User agent' => '', + 'Login' => '@@Login@@', 'Active' => 'Aktywny', 'Are you sure you want to delete this user?' => 'Czy na pewno chcesz usunąć tego użytkownika?', 'Banned' => 'Zbanowany', @@ -29,7 +49,6 @@ 'Child permissions' => 'Podrzędne uprawnienia', 'Child roles' => 'Podrzędne role', 'Code' => 'Kod', - 'Confirmation Token' => '', 'Create' => 'Utwórz', 'Created' => 'Utworzone', 'Creating permission group' => 'Tworzenie grupy uprawnień', @@ -37,9 +56,7 @@ 'Data' => 'Dane', 'Delete' => 'Usuń', 'Description' => 'Opis', - 'E-mail' => '', 'E-mail confirmed' => 'E-mail potwierdzony', - 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => '', 'Edit' => 'Edytuj', 'Editing' => 'Edytowanie', 'Editing permission group' => 'Edytowanie grupy uprawnień: ', @@ -48,21 +65,15 @@ 'Editing user: ' => 'Edycja użytkownika: ', 'For example: 123.34.56.78, 168.111.192.12' => 'Przykładowo: 123.34.56.78, 168.111.192.12', 'Group' => 'Grupa', - 'ID' => '', 'Inactive' => 'Nieaktywny', - 'IP' => '', 'Language' => 'Język', - 'Login' => 'Login', 'Name' => 'Nazwa', 'OS' => 'System', 'Password' => 'Hasło', 'Password has been changed' => 'Hasło zostało zmienione', - 'Permission creation' => '', 'Permission groups' => 'Grupy uprawnień', 'Permissions' => 'Uprawnienia', 'Permissions for role:' => 'Uprawnienia roli: ', - 'Refresh routes' => '', - 'Refresh routes (and delete unused)' => '', 'Registration IP' => 'Adres IP rejestracji', 'Repeat password' => 'Powtórz hasło', 'Reset' => 'Resetuj', @@ -70,23 +81,16 @@ 'Roles' => 'Role', 'Roles and permissions' => 'Role i uprawnienia', 'Roles and permissions for user:' => 'Role i uprawnienia użytkownika: ', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', 'Rule' => 'Reguła', 'Save' => 'Zapisz', 'Saved' => 'Zapisano', 'Search' => 'Szukaj', - 'Search route' => '', 'Settings for permission' => 'Ustawienia uprawnień', - 'Show all' => '', - 'Show only selected' => '', - 'Status' => '', 'Superadmin' => 'Superadministrator', - 'Token' => '', 'Too many attempts' => 'Zbyt wiele prób', 'Type' => 'Typ', 'Updated' => 'Zaktualizowano', 'User' => 'Użytkownik', - 'User agent' => '', 'User creation' => 'Dodawanie użytkownika', 'Users' => 'Użytkownicy', 'Visit Time' => 'Ostatnia wizyta', diff --git a/messages/pt-BR/back.php b/messages/pt-BR/back.php index a4fd7689..da2ded6e 100644 --- a/messages/pt-BR/back.php +++ b/messages/pt-BR/back.php @@ -17,7 +17,9 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', 'E-mail' => '', 'ID' => '', 'IP' => '', @@ -28,7 +30,10 @@ 'Show all' => '', 'Show only selected' => '', 'Superadmin' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', 'Token' => '', + 'Unknown auth type.' => '', + 'Login' => '@@Login@@', 'Permissions for role - "{role}"' => '@@Permissões da função - "{role}"@@', 'Active' => 'Ativo', 'Are you sure you want to delete this user?' => 'Você tem certeza de que deseja excluir este usuário?', @@ -61,7 +66,6 @@ 'Group' => 'Grupo', 'Inactive' => 'Inativo', 'Language' => 'Idioma', - 'Login' => 'Login', 'Name' => 'Nome', 'OS' => 'Sistema operacional', 'Password' => 'Senha', diff --git a/messages/pt-PT/back.php b/messages/pt-PT/back.php index 467d5711..49199426 100644 --- a/messages/pt-PT/back.php +++ b/messages/pt-PT/back.php @@ -17,9 +17,25 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', + 'Banned' => '', + 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', + 'E-mail' => '', + 'ID' => '', + 'IP' => '', + 'Refresh routes' => '', + 'Refresh routes (and delete unused)' => '', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', + 'Search route' => '', + 'Show all' => '', + 'Show only selected' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', + 'Token' => '', + 'Unknown auth type.' => '', + 'Login' => '@@Nome de utilizador@@', 'Active' => 'Ativo', 'Are you sure you want to delete this user?' => 'Você tem certeza de que deseja excluir este utilizador?', - 'Banned' => '', 'Bind to IP' => 'Víncular ao IP', 'Browser' => 'Navegador', 'Change own password' => 'Alterar a própria senha', @@ -29,7 +45,6 @@ 'Child permissions' => 'Permissões filhas', 'Child roles' => 'Regras filhas', 'Code' => 'Código', - 'Confirmation Token' => '', 'Create' => 'Criar', 'Created' => 'Criado', 'Creating permission group' => 'Criando grupo de permissões', @@ -37,9 +52,8 @@ 'Data' => 'Dados', 'Delete' => 'Excluir', 'Description' => 'Descrição', - 'E-mail' => '', 'E-mail confirmed' => 'E-mail confirmado', - 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' =>'Um e-mail com o link de ativação foi enviado para {email}. Este link irá expirar dentro de {minutes} minutos.', + 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => 'Um e-mail com o link de ativação foi enviado para {email}. Este link irá expirar dentro de {minutes} minutos.', 'Edit' => 'Editar', 'Editing' => 'Editando', 'Editing permission group' => 'Editando grupo de permissões', @@ -48,11 +62,8 @@ 'Editing user: ' => 'Editando utilizador: ', 'For example: 123.34.56.78, 168.111.192.12' => 'Por exemplo: 123.34.56.78, 168.111.192.12', 'Group' => 'Grupo', - 'ID' => '', 'Inactive' => 'Inativo', - 'IP' => '', 'Language' => 'Idioma', - 'Login' => 'Nome de utilizador', 'Name' => 'Nome', 'OS' => 'SO', 'Password' => 'Senha', @@ -61,8 +72,6 @@ 'Permission groups' => 'Grupos de permissão', 'Permissions' => 'Permissões', 'Permissions for role:' => 'Permissões da função:', - 'Refresh routes' => '', - 'Refresh routes (and delete unused)' => '', 'Registration IP' => 'Registo do IP', 'Repeat password' => 'Repetir senha', 'Reset' => 'Redefinir', @@ -70,18 +79,13 @@ 'Roles' => 'Funções', 'Roles and permissions' => 'Funções e permissões', 'Roles and permissions for user:' => 'Funções e permissões do utilizador:', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', 'Rule' => 'Regra', 'Save' => 'Salvar', 'Saved' => 'Salvo', 'Search' => 'Buscar', - 'Search route' => '', 'Settings for permission' => 'Configurações de permissões', - 'Show all' => '', - 'Show only selected' => '', 'Status' => 'Estado', 'Superadmin' => 'Superadmin', - 'Token' => '', 'Too many attempts' => 'Demasiadas tentativas', 'Type' => 'Tipo', 'Updated' => 'Atualizado', diff --git a/messages/ru/back.php b/messages/ru/back.php index 42e083ea..2675f72b 100644 --- a/messages/ru/back.php +++ b/messages/ru/back.php @@ -17,9 +17,25 @@ * NOTE: this file must be saved in UTF-8 encoding. */ return [ + 'Authentication type' => '', + 'Banned' => '', + 'Confirmation Token' => '', + 'Could not bind to the LDAP server.' => '', + 'E-mail' => '', + 'ID' => '', + 'IP' => '', + 'Refresh routes' => '', + 'Refresh routes (and delete unused)' => '', + 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', + 'Search route' => '', + 'Show all' => '', + 'Show only selected' => '', + 'The provided LDAP parameters are syntactically wrong.' => '', + 'Token' => '', + 'Unknown auth type.' => '', + 'Login' => '@@Логин@@', 'Active' => 'Активен', 'Are you sure you want to delete this user?' => 'Вы уверены, что хотите удалить этого пользователя ?', - 'Banned' => '', 'Bind to IP' => 'Привязать к IP', 'Browser' => 'Браузер', 'Change own password' => 'Смена пароля', @@ -29,7 +45,6 @@ 'Child permissions' => 'Дочерние права', 'Child roles' => 'Дочерние роли', 'Code' => 'Код', - 'Confirmation Token' => '', 'Create' => 'Создать', 'Created' => 'Создано', 'Creating permission group' => 'Создание группы прав', @@ -37,7 +52,6 @@ 'Data' => 'Данные', 'Delete' => 'Удалить', 'Description' => 'Описание', - 'E-mail' => '', 'E-mail confirmed' => 'E-mail подтверждён', 'E-mail with activation link has been sent to {email}. This link will expire in {minutes} min.' => 'Ссылка активации была отправлена на {email}>. Срок действия ссылки {minutes} мин.', 'Edit' => 'Редактировать', @@ -48,11 +62,8 @@ 'Editing user: ' => 'Редактирование пользователя: ', 'For example: 123.34.56.78, 168.111.192.12' => 'Напрмиер: 123.34.56.78, 168.111.192.12', 'Group' => 'Группа', - 'ID' => '', 'Inactive' => 'Неактивен', - 'IP' => '', 'Language' => 'Язык', - 'Login' => 'Логин', 'Name' => 'Название', 'OS' => 'ОС', 'Password' => 'Пароль', @@ -61,8 +72,6 @@ 'Permission groups' => 'Группы прав', 'Permissions' => 'Права', 'Permissions for role:' => 'Права для роли:', - 'Refresh routes' => '', - 'Refresh routes (and delete unused)' => '', 'Registration IP' => 'IP регистрации', 'Repeat password' => 'Повторите пароль', 'Reset' => 'Сбросить', @@ -70,18 +79,13 @@ 'Roles' => 'Роли', 'Roles and permissions' => 'Роли и права', 'Roles and permissions for user:' => 'Роли и права для пользователя', - 'Routes that are not exists in this application will be deleted. Do not recommended for application with "advanced" structure, because frontend and backend have they own set of routes.' => '', 'Rule' => 'Правило', 'Save' => 'Сохранить', 'Saved' => 'Сохранено', 'Search' => 'Поиск', - 'Search route' => '', 'Settings for permission' => 'Настройки для права', - 'Show all' => '', - 'Show only selected' => '', 'Status' => 'Статус', 'Superadmin' => 'Суперадмин', - 'Token' => '', 'Too many attempts' => 'Лимит попыток превышен', 'Type' => 'Тип', 'Updated' => 'Обновлено', diff --git a/migrations/m170315_110029_add_auth_type_column_to_user_table.php b/migrations/m170315_110029_add_auth_type_column_to_user_table.php new file mode 100644 index 00000000..0b757232 --- /dev/null +++ b/migrations/m170315_110029_add_auth_type_column_to_user_table.php @@ -0,0 +1,25 @@ +addColumn('user', 'auth_type', $this->string(15)->defaultValue('local')); + } + + /** + * {@inheritdoc} + */ + public function down() + { + $this->dropColumn('user', 'auth_type'); + } +} diff --git a/models/User.php b/models/User.php index e2de8730..3e0b8361 100644 --- a/models/User.php +++ b/models/User.php @@ -302,7 +302,7 @@ public function attributeLabels() { return [ 'id' => 'ID', - 'username' => UserManagementModule::t('back', 'Login'), + 'username' => UserManagementModule::t('back', 'User'), 'superadmin' => UserManagementModule::t('back', 'Superadmin'), 'confirmation_token' => UserManagementModule::t('back', 'Confirmation Token'), 'registration_ip' => UserManagementModule::t('back', 'Registration IP'), @@ -315,6 +315,7 @@ public function attributeLabels() 'repeat_password' => UserManagementModule::t('back', 'Repeat password'), 'email_confirmed' => UserManagementModule::t('back', 'E-mail confirmed'), 'email' => UserManagementModule::t('back', 'E-mail'), + 'auth_type' => UserManagementModule::t('back', 'Authentication type'), ]; } diff --git a/models/forms/LoginForm.php b/models/forms/LoginForm.php index d820fbb5..a4589995 100644 --- a/models/forms/LoginForm.php +++ b/models/forms/LoginForm.php @@ -103,6 +103,17 @@ public function getUser() $this->_user = ($u instanceof User ? $u->findByUsername($this->username) : User::findByUsername($this->username)); } + if (!$this->_user and Yii::$app->user->enableLdap) { + // If the user doesn't exist in the database, + // it might be the first login of a LDAP user. + $new_user = new \Yii::$app->user->identityClass(); + $new_user->id = null; + $new_user->username = $this->username; + $new_user->password_hash = Yii::$app->getSecurity()->generatePasswordHash(Yii::$app->getSecurity()->generateRandomString()); + $new_user->auth_type = 'ldap'; + $this->_user = $new_user; + } + return $this->_user; } } diff --git a/views/user/view.php b/views/user/view.php index 8e833c94..86211054 100644 --- a/views/user/view.php +++ b/views/user/view.php @@ -63,6 +63,7 @@ 'format' => 'boolean', 'visible' => User::hasPermission('viewUserEmail'), ], + 'auth_type', [ 'label' => UserManagementModule::t('back', 'Roles'), 'value' => implode('
', ArrayHelper::map(Role::getUserRoles($model->id), 'name', 'description')),