diff --git a/CHANGELOG.md b/CHANGELOG.md index 712bf18..a66252f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,4 @@ ## 1.2 (20th May 2015) - Bug fixes for LDAP plugin - - Improved UI - -## 1.3 (6th July 2017) - - - Add config to enable/disable strict password checking - - use encryptionstore to retrieve/store passwords - - move strict password checking to client side \ No newline at end of file + - Improved UI \ No newline at end of file diff --git a/LICENSE.md b/LICENSE similarity index 91% rename from LICENSE.md rename to LICENSE index 4d87ad5..a072de3 100644 --- a/LICENSE.md +++ b/LICENSE @@ -1,5 +1,5 @@ Zarafa Webapp Password Change Plugin -Copyright (C) 2013 - 2017 Saket Patel +Copyright (C) 2013 Saket Patel silentsakky@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by diff --git a/README.md b/README.md index 665167e..825fe92 100644 --- a/README.md +++ b/README.md @@ -7,46 +7,32 @@ This plugin is largely based on the Passwd plugin by Andreas Brodowski. For his original work check this [link](https://community.zarafa.com/pg/plugins/project/157/developer/dw2412/passwd-plugin) ## How to install -1. If you want to use this plugin with production / debug version of webapp then please download package from [release page](https://github.com/silentsakky/zarafa-webapp-passwd/releases) +1. If you want to use this plugin with production / debug version of webapp then please download package from [community](https://community.zarafa.com/pg/plugins/project/23147/developer/silentsakky/webapp-password-change) 2. If you want to use this plugin with source copy of webapp then you can just download this whole project -3. Extract contents of this plugin to /plugins directory, in Ubuntu 16 refers to /usr/share/kopano-webapp +3. Extract contents of this plugin to /plugins directory 4. Give read permissions to apache for /plugins/passwd directory 5. If you are using LDAP plugin then change PLUGIN_PASSWD_LDAP to true and also set proper values for PLUGIN_PASSWD_LDAP_BASEDN and PLUGIN_PASSWD_LDAP_URI configurations 6. If you are using DB plugin then no need to change anything, default configurations should be fine 5. Restart apache, reload webapp after clearing cache 6. If you want to enable this plugin by default for all users then edit config.php file and change PLUGIN_PASSWD_USER_DEFAULT_ENABLE setting to true - ## How to enable 1. Go to settings section 2. Go to Plugins tab 3. Enable password change plugin and reload webapp - +4. Go to Change Password tab of settings section +5. Provide current password and new password +6. Click on apply ## How to disable 1. Go to settings section 2. Go to Plugins tab 3. Disable password change plugin and reload webapp - -## How to use -1. Go to Change Password tab of settings section -2. Provide current password and new password -3. Click on apply - - ## Notes - Feedback/Bug Reports are welcome -- thanks to h44z for adding password meter and icon for the plugin +- If anyone is good at creating icons then please help me add a good icon to change password tab (credits will be given) - -## Dependencies: -- php ldap extension is required if you are using LDAP plugin -- if you have ubuntu 16 then follow below steps (this should ideally work with all distros) - 1) sudo apt-get install php-ldap - 2) sudo phpenmod ldap - 3) check if ldap extension is enabled using below command - php -i "(command-line 'phpinfo()')" | grep ldap - - -Initially releases of this plugin were maintained in [community](https://community.zarafa.com/pg/plugins/project/23147/developer/silentsakky/webapp-password-change), but now users can download latest builds from [github release page](https://github.com/silentsakky/zarafa-webapp-passwd/releases) \ No newline at end of file +## Todo +- Add password strength meter on client side, so user can create complex passwords +- Check on client side for empty fields \ No newline at end of file diff --git a/build.xml b/build.xml index 543e6fb..a5f4840 100644 --- a/build.xml +++ b/build.xml @@ -233,13 +233,5 @@ - - - - - - - - diff --git a/builds/passwd-1.0.zip b/builds/passwd-1.0.zip new file mode 100644 index 0000000..0235122 Binary files /dev/null and b/builds/passwd-1.0.zip differ diff --git a/builds/passwd-1.1.zip b/builds/passwd-1.1.zip new file mode 100644 index 0000000..6f28c72 Binary files /dev/null and b/builds/passwd-1.1.zip differ diff --git a/builds/passwd-1.2.zip b/builds/passwd-1.2.zip new file mode 100644 index 0000000..1706ae5 Binary files /dev/null and b/builds/passwd-1.2.zip differ diff --git a/config.php b/config.php index 5b55c11..0dcc16f 100644 --- a/config.php +++ b/config.php @@ -2,10 +2,7 @@ /** Enable the passwd plugin for all clients **/ define('PLUGIN_PASSWD_USER_DEFAULT_ENABLE', false); -/** Enable the passwd plugin for all clients **/ -define('PLUGIN_PASSWD_STRICT_CHECK_ENABLE', true); - -/** Define passwd plugin installation uses LDAP **/ +/** Define zarafa installtion uses LDAP **/ define('PLUGIN_PASSWD_LDAP', false); /** Base DN to access LDAP users **/ @@ -26,4 +23,4 @@ define('PLUGIN_PASSWD_LDAP_BIND_PW', ""); /** Set to true if you login with username@tenantname **/ define('PLUGIN_PASSWD_LOGIN_WITH_TENANT', false); -?> \ No newline at end of file +?> diff --git a/js/ABOUT.js b/js/ABOUT.js index 3cdb890..8381cbc 100644 --- a/js/ABOUT.js +++ b/js/ABOUT.js @@ -6,7 +6,7 @@ Ext.namespace('Zarafa.plugins.passwd'); * The copyright string holding the copyright notice for the Zarafa passwd Plugin. */ Zarafa.plugins.passwd.ABOUT = "" - + "

Copyright (C) 2013 - 2017 Saket Patel <silentsakky@gmail.com>

" + + "

Copyright (C) 2013 Saket Patel <silentsakky@gmail.com>

" + "

This program is free software: you can redistribute it and/or modify " + "it under the terms of the GNU Affero General Public License as " diff --git a/js/external/PasswordMeter.js b/js/external/PasswordMeter.js index 7afbf91..b8ce416 100644 --- a/js/external/PasswordMeter.js +++ b/js/external/PasswordMeter.js @@ -62,8 +62,7 @@ Ext.ux.form.field.PasswordMeter = Ext.extend(Ext.form.TextField, { var width = this.getEl().getWidth(); - var newID = Ext.id(); - this.strengthMeterID = newID; + this.strengthMeterID = newID = Ext.id(); this.scoreBarID = Ext.id(); var objMeter = Ext.DomHelper.insertAfter(this.getEl(), { tag: "div", diff --git a/js/settings/SettingsPasswdWidget.js b/js/settings/SettingsPasswdWidget.js index 7c7b77d..59a93b6 100644 --- a/js/settings/SettingsPasswdWidget.js +++ b/js/settings/SettingsPasswdWidget.js @@ -72,15 +72,14 @@ Zarafa.plugins.passwd.settings.SettingsPasswdWidget = Ext.extend(Zarafa.settings } else if(!this.passwdPanel.getForm().isValid()) { Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'One or more fields does contain errors.')); return false; - } else if (container.getSettingsModel().get("zarafa/v1/plugins/passwd/enable_strict_check")) { + } else { // do a quick score check: if(this.passwdPanel.new_password.getScore() < 70) { Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'Password is weak. Password should contain capital, non-capital letters and numbers. Password should have 8 to 20 characters.')); return false; } + return true; } - - return true; }, /** diff --git a/language/hu_HU.UTF-8/LC_MESSAGES/plugin_passwd.mo b/language/hu_HU.UTF-8/LC_MESSAGES/plugin_passwd.mo deleted file mode 100644 index e9141a1..0000000 Binary files a/language/hu_HU.UTF-8/LC_MESSAGES/plugin_passwd.mo and /dev/null differ diff --git a/language/hu_HU.UTF-8/LC_MESSAGES/plugin_passwd.po b/language/hu_HU.UTF-8/LC_MESSAGES/plugin_passwd.po deleted file mode 100644 index 4bc504e..0000000 --- a/language/hu_HU.UTF-8/LC_MESSAGES/plugin_passwd.po +++ /dev/null @@ -1,94 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: zarafa-webapp-plugin-passwd\n" -"POT-Creation-Date: 2014-03-04 13:53+0100\n" -"PO-Revision-Date: 2016-04-08 21:28+0200\n" -"Last-Translator: David Horvath \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: hu\n" -"X-Generator: Poedit 1.8.7.1\n" - -# php/class.passwdmodule.php:44: -msgid "No data received." -msgstr "Nem érkezett adat." - -# php/class.passwdmodule.php:48: -msgid "User name is empty." -msgstr "Felhasználónév mező üres." - -# php/class.passwdmodule.php:52: -msgid "Current password is empty." -msgstr "Jelenlegi jelszó mező üres." - -# php/class.passwdmodule.php:56: -msgid "New password is empty." -msgstr "Új jelszó mező üres." - -# php/class.passwdmodule.php:60: -msgid "New passwords do not match." -msgstr "Az új jelszavak nem egyeznek." - -# php/class.passwdmodule.php:137: -# php/class.passwdmodule.php:196: -# js/data/PasswdResponseHandler.js:44: -msgid "Password is changed successfully." -msgstr "A jelszót sikeresen módosította." - -# php/class.passwdmodule.php:141: -# php/class.passwdmodule.php:200: -msgid "Password is not changed." -msgstr "A jelszó nem módosult." - -# php/class.passwdmodule.php:144: -# php/class.passwdmodule.php:203: -msgid "" -"Password is weak. Password should contain capital, non-capital letters and " -"numbers. Password should have 8 to 20 characters." -msgstr "" -"A jelszó gyenge. Tartalmaznia kell számot, nagy- és kisbetűt. A jelszó " -"minimum 8, maximum 20 karakter legyen." - -# php/class.passwdmodule.php:147: -msgid "Current password does not match." -msgstr "A jelenlegi jelszó nem megfelelő." - -# js/data/PasswdResponseHandler.js:27: -msgid "An unknown error occurred while changing password." -msgstr "Ismeretlen hiba történt a jelszó megváltoztatásakor." - -# js/data/PasswdResponseHandler.js:33: -msgid "Error" -msgstr "Hiba" - -# js/data/PasswdResponseHandler.js:50: -msgid "Success" -msgstr "Sikeres" - -# js/settings/SettingsPasswdWidget.js:24: -# js/settings/SettingsPasswdCategory.js:20: -msgid "Change Password" -msgstr "Jelszó megváltoztatása" - -# js/PasswdPlugin.js:50: -msgid "Password Change Plugin" -msgstr "Jelszóváltoztatás kiegészítő" - -# js/settings/PasswdPanel.js:29: -msgid "User name" -msgstr "Felhasználónév" - -# js/settings/PasswdPanel.js:33: -msgid "Current password" -msgstr "Jelenlegi jelszó" - -# js/settings/PasswdPanel.js:42: -msgid "New password" -msgstr "Új jelszó" - -# js/settings/PasswdPanel.js:51: -msgid "Retype new password" -msgstr "Új jelszó mégegyszer" diff --git a/manifest.xml b/manifest.xml index 7479624..c9e6440 100644 --- a/manifest.xml +++ b/manifest.xml @@ -2,12 +2,12 @@ - 1.3 + 1.2 Passwd Password Change Plugin Saket Patel https://github.com/silentsakky - Change your password from webapp + Change your password from zarafa webapp config.php @@ -16,6 +16,7 @@ language + diff --git a/php/class.passwdmodule.php b/php/class.passwdmodule.php index 88d4fba..f2f4a02 100644 --- a/php/class.passwdmodule.php +++ b/php/class.passwdmodule.php @@ -83,9 +83,6 @@ class PasswdModule extends Module public function saveInLDAP($data) { $errorMessage = ''; - $userName = $data['username']; - $newPassword = $data['new_password']; - $sessionPass = ''; // connect to LDAP server $ldapconn = ldap_connect(PLUGIN_PASSWD_LDAP_URI); @@ -94,10 +91,10 @@ class PasswdModule extends Module if(ldap_errno($ldapconn) === 0) { // get the users uid, if we have a multi tenant installation then remove company name from user name if (PLUGIN_PASSWD_LOGIN_WITH_TENANT){ - $parts = explode('@', $userName); + $parts = explode('@', $data['username']); $uid = $parts[0]; } else { - $uid = $userName; + $uid = $data['username']; } // check if we should use tls! @@ -117,47 +114,55 @@ class PasswdModule extends Module $ldapconn, // connection-identify PLUGIN_PASSWD_LDAP_BASEDN, // basedn 'uid=' . $uid, // search filter - array('dn', 'objectClass') // needed attributes. we need dn and objectclass + array('dn') // needed attributes. we need the dn ); if ($userdn) { - $entries = ldap_get_entries($ldapconn, $userdn); - $userdn = $entries[0]['dn']; + $userdn = ldap_get_entries($ldapconn, $userdn); + $userdn = $userdn[0]['dn']; // bind to ldap directory // login with current password if that fails then current password is wrong ldap_bind($ldapconn, $userdn, $data['current_password']); if(ldap_errno($ldapconn) === 0) { - $password_hash = $this->sshaEncode($newPassword); - $entry = array('userPassword' => $password_hash); - if (in_array('sambaSamAccount', $entries[0]['objectclass'])) { - $nthash = strtoupper(bin2hex(mhash(MHASH_MD4, iconv("UTF-8", "UTF-16LE", $newPassword)))); - $entry['sambaNTPassword'] = $nthash; - $entry['sambaPwdLastSet'] = strval(time()); - } + $passwd = $data['new_password']; - ldap_modify($ldapconn, $userdn, $entry); - if (ldap_errno($ldapconn) === 0) { - // password changed successfully + if ($this->checkPasswordStrenth($passwd)) { + $password_hash = $this->sshaEncode($passwd); + $entry = array('userPassword' => $password_hash); + ldap_modify($ldapconn, $userdn, $entry); + if (ldap_errno($ldapconn) === 0) { + // password changed successfully - // send feedback to client - $this->sendFeedback(true, array( - 'info' => array( - 'display_message' => dgettext("plugin_passwd", 'Password is changed successfully.') - ) - )); + // write new password to session because we don't want user to re-authenticate + session_start(); + // if user has openssl module installed + if(function_exists("openssl_encrypt")) { + // In PHP 5.3.3 the iv parameter was added + if(version_compare(phpversion(), "5.3.3", "<")) { + $_SESSION['password'] = openssl_encrypt($passwd,"des-ede3-cbc",PASSWORD_KEY,0); + } else { + $_SESSION['password'] = openssl_encrypt($passwd,"des-ede3-cbc",PASSWORD_KEY,0,PASSWORD_IV); + } + } + else { + $_SESSION['password'] = $passwd; + } + session_write_close(); - // write new password to session because we don't want user to re-authenticate - session_start(); - $encryptionStore = EncryptionStore::getInstance(); - $encryptionStore->add('password', $newPassword); - session_write_close(); - - return true; + // send feedback to client + $this->sendFeedback(true, array( + 'info' => array( + 'display_message' => dgettext("plugin_passwd", 'Password is changed successfully.') + ) + )); + } else { + $errorMessage = dgettext("plugin_passwd", 'Password is not changed.'); + } } else { - $errorMessage = dgettext("plugin_passwd", 'Password is not changed.'); + $errorMessage = dgettext("plugin_passwd", 'Password is weak. Password should contain capital, non-capital letters and numbers. Password should have 8 to 20 characters.'); } } else { $errorMessage = dgettext("plugin_passwd", 'Current password does not match.'); @@ -187,47 +192,58 @@ class PasswdModule extends Module public function saveInDB($data) { $errorMessage = ''; - $userName = $data['username']; - $newPassword = $data['new_password']; - $sessionPass = ''; + $passwd = $data['new_password']; // get current session password - // if this plugin is used on a webapp version with EncryptionStore, - // $_SESSION['password'] is no longer available. User EncryptionStore - // in this case. - // EncryptionStore was introduced in webapp core somewhere after - // version 2.1.2, and with or before version 2.2.0.414. - // tested with Zarafa WebApp 2.2.1.43-199.1 running with - // Zarafa Server 7.2.4.29-99.1 - if(class_exists("EncryptionStore")) { - $encryptionStore = EncryptionStore::getInstance(); - $sessionPass = $encryptionStore->get("password"); + $sessionPass = $_SESSION['password']; + // if user has openssl module installed + if (function_exists("openssl_decrypt")) { + if (version_compare(phpversion(), "5.3.3", "<")) { + $sessionPass = openssl_decrypt($sessionPass, "des-ede3-cbc", PASSWORD_KEY, 0); + } else { + $sessionPass = openssl_decrypt($sessionPass, "des-ede3-cbc", PASSWORD_KEY, 0, PASSWORD_IV); + } + + if (!$sessionPass) { + $sessionPass = $_SESSION['password']; + } } if($data['current_password'] === $sessionPass) { - // all information correct, change password - $store = $GLOBALS['mapisession']->getDefaultMessageStore(); - $userinfo = mapi_zarafa_getuser_by_name($store, $userName); + if ($this->checkPasswordStrenth($passwd)) { + // all information correct, change password + $store = $GLOBALS['mapisession']->getDefaultMessageStore(); + $userinfo = mapi_zarafa_getuser_by_name($store, $data['username']); - if (mapi_zarafa_setuser($store, $userinfo['userid'], $userName, $userinfo['fullname'], $userinfo['emailaddress'], $newPassword, 0, $userinfo['admin'])) { - // password changed successfully + if (mapi_zarafa_setuser($store, $userinfo['userid'], $data['username'], $userinfo['fullname'], $userinfo['emailaddress'], $passwd, 0, $userinfo['admin'])) { + // password changed successfully - // send feedback to client - $this->sendFeedback(true, array( - 'info' => array( - 'display_message' => dgettext("plugin_passwd", 'Password is changed successfully.') - ) - )); + // write new password to session because we don't want user to re-authenticate + session_start(); + // if user has openssl module installed + if (function_exists("openssl_encrypt")) { + // In PHP 5.3.3 the iv parameter was added + if (version_compare(phpversion(), "5.3.3", "<")) { + $_SESSION['password'] = openssl_encrypt($passwd, "des-ede3-cbc", PASSWORD_KEY, 0); + } else { + $_SESSION['password'] = openssl_encrypt($passwd, "des-ede3-cbc", PASSWORD_KEY, 0, PASSWORD_IV); + } + } else { + $_SESSION['password'] = $passwd; + } + session_write_close(); - // write new password to session because we don't want user to re-authenticate - session_start(); - $encryptionStore = EncryptionStore::getInstance(); - $encryptionStore->add('password', $newPassword); - session_write_close(); - - return true; + // send feedback to client + $this->sendFeedback(true, array( + 'info' => array( + 'display_message' => dgettext("plugin_passwd", 'Password is changed successfully.') + ) + )); + } else { + $errorMessage = dgettext("plugin_passwd", 'Password is not changed.'); + } } else { - $errorMessage = dgettext("plugin_passwd", 'Password is not changed.'); + $errorMessage = dgettext("plugin_passwd", 'Password is weak. Password should contain capital, non-capital letters and numbers. Password should have 8 to 20 characters.'); } } else { $errorMessage = dgettext("plugin_passwd", 'Current password does not match.'); @@ -243,6 +259,25 @@ class PasswdModule extends Module } } + /** + * Function will check strength of the password and if it does not meet minimum requirements then + * will return false. + * Password should meet the following criteria: + * - min. 8 chars, max. 20 + * - contain caps and noncaps characters + * - contain numbers + * @param {String} $password password which should be checked. + * @return {Boolean} true if password passes the minimum requirement else false. + */ + public function checkPasswordStrenth($password) + { + if (preg_match("#.*^(?=.{8,20})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$#", $password)) { + return true; + } else { + return false; + } + } + /** * Function will generate SSHA hash to use to store user's password in LDAP. * @param {String} $text text based on which hash will be generated. diff --git a/php/plugin.passwd.php b/php/plugin.passwd.php index 85bd809..729815b 100644 --- a/php/plugin.passwd.php +++ b/php/plugin.passwd.php @@ -43,9 +43,9 @@ class Pluginpasswd extends Plugin { 'v1' => Array( 'plugins' => Array( 'passwd' => Array( - 'enable' => PLUGIN_PASSWD_USER_DEFAULT_ENABLE, - 'enable_strict_check' => PLUGIN_PASSWD_STRICT_CHECK_ENABLE, + 'enable' => PLUGIN_PASSWD_USER_DEFAULT_ENABLE, ) + ) ) )