1
0
Fork 0
mirror of https://github.com/silentsakky/zarafa-webapp-passwd synced 2026-07-27 10:30:56 +02:00

added most of the basic functionalities

This commit is contained in:
Saket Patel 2013-07-04 03:22:31 +05:30
commit 5064cf5742
7 changed files with 365 additions and 57 deletions

View file

@ -185,6 +185,7 @@
<!-- copy files -->
<copy todir="${target-folder}/${plugin-folder}">
<fileset dir=".">
<include name="lib/**/*.*"/>
<include name="resources/**/*.*"/>
<include name="php/**/*.php"/>
<include name="config.php"/>

View file

@ -3,7 +3,7 @@
define('PLUGIN_PASSWD_USER_DEFAULT_ENABLE', true);
/** Define zarafa installtion uses LDAP **/
define('PLUGIN_PASSWD_LDAP', true);
define('PLUGIN_PASSWD_LDAP', false);
/** Base DN to access LDAP users **/
define('PLUGIN_PASSWD_LDAP_BASEDN', 'dc=example,dc=com');

View file

@ -10,6 +10,8 @@ Zarafa.plugins.passwd.PasswdPanel = Ext.extend(Ext.form.FormPanel, {
/**
* @property
* @type Ext.LoadMask
* Save mask that will be displayed when request has been sent to server for password change
* and waiting for the response.
*/
saveMask : undefined,
@ -63,6 +65,10 @@ Zarafa.plugins.passwd.PasswdPanel = Ext.extend(Ext.form.FormPanel, {
this.on('afterrender', this.initialize, this);
},
/**
* Function will initialize this dialog with some default values and will
* also create object of {@link #saveMask}.
*/
initialize : function()
{
this.userNameField.setValue(container.getUser().getUserName());
@ -72,24 +78,51 @@ Zarafa.plugins.passwd.PasswdPanel = Ext.extend(Ext.form.FormPanel, {
})
},
/**
* Handler function that will be called when user presses ok button
* to change password.
*/
onOk : function()
{
// send request
// show load mask
this.saveMask.show();
// send request
container.getRequest().singleRequest('passwdmodule', 'save', {
username : this.userNameField.getValue(),
current_password : this.oldPasswdField.getValue(),
new_password : this.newPasswdField.getValue(),
new_password_repeat : this.newPasswdRepeatField.getValue()
//}, new Zarafa.plugins.sugarcrm.data.SugarCRMResponseHandler());
});
}, new Zarafa.plugins.passwd.data.PasswdResponseHandler({
callbackFn : this.callbackFn,
scope : this
}));
},
/**
* Handler function that will be called when user presses cancel button
* to close the dialog.
*/
onCancel : function()
{
// close the dialog
this.dialog.close();
},
/**
* Callback function that will be executed after response is received from server.
* @param {Boolean} success boolean to indicate response contains success/failure data.
* @param {Object} response response sent by server.
*/
callbackFn : function(success, response)
{
// hide load mask
this.saveMask.hide();
// close the dialog
if(success) {
this.dialog.close();
}
}
});

View file

@ -0,0 +1,54 @@
Ext.namespace('Zarafa.plugins.passwd.data');
/**
* @class Zarafa.plugins.passwd.data.ResponseHandler
* @extends Zarafa.core.data.AbstractResponseHandler
*
* Passwd plugin specific response handler.
*/
Zarafa.plugins.passwd.data.PasswdResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, {
/**
* @cfg {Function} callbackFn The function which will be called after success/failure response.
*/
callbackFn : undefined,
/**
* @cfg {Object} scope The function scope that will be used when calling {@link #callbackFn}.
*/
scope : undefined,
/**
* In case exception happened on server, server will return exception response with the display message.
* @param {Object} response Object contained the response data.
*/
doError : function(response)
{
var displayMessage = _('An unknown error occurred while changing password.');
if(response.info) {
displayMessage = response.info.display_message;
}
Ext.MessageBox.alert(_('Error'), displayMessage);
this.callbackFn.apply(this.scope || this, [ false, response ]);
},
/**
* When password change is successfull server will send a success response including display message.
* @param {Object} response Object contained the response data.
*/
doSuccess : function(response)
{
var displayMessage = _('Password is changed successfully.');
if(response.info) {
displayMessage = response.info.display_message;
}
Ext.MessageBox.alert(_('Success'), displayMessage);
this.callbackFn.apply(this.scope || this, [ true, response ]);
}
});

158
lib/PasswordMeter.js Normal file
View file

@ -0,0 +1,158 @@
// Create user extensions namespace (Ext.ux)
Ext.namespace('Ext.ux');
/**
* Ext.ux.PasswordMeter Extension Class
*
* @author Eelco Wiersma
* @version 0.2
*
* Algorithm based on code of Tane
* http://digitalspaghetti.me.uk/index.php?q=jquery-pstrength
* and Steve Moitozo
* http://www.geekwisdom.com/dyn/passwdmeter
*
* @license MIT License: http://www.opensource.org/licenses/mit-license.php
*
* @class Ext.ux.PasswordMeter
* @extends Ext.form.TextField
* @constructor
* Creates new Ext.ux.PasswordMeter
*/
Ext.ux.PasswordMeter = function(config) {
// call parent constructor
Ext.ux.PasswordMeter.superclass.constructor.call(this, config);
};
Ext.extend(Ext.ux.PasswordMeter, Ext.form.TextField, {
/**
* @cfg {String} inputType The type attribute for input fields -- e.g. text, password (defaults to "password").
*/
inputType: 'text',
// private
onRender: function(ct, position) {
Ext.ux.PasswordMeter.superclass.onRender.call(this, ct, position);
var elp = this.el.findParent('.x-form-element', 5, true);
this.objMeter = ct.createChild({tag: "div", 'class': "strengthMeter"});
this.objMeter.setWidth(elp.getWidth(true)-17);
this.scoreBar = this.objMeter.createChild({tag: "div", 'class': "scoreBar"});
if(Ext.isIE && !Ext.isIE7) { // Fix style for IE6
this.objMeter.setStyle('margin-left', '3px');
}
},
// private
initEvents: function() {
Ext.ux.PasswordMeter.superclass.initEvents.call(this);
this.el.on('keyup', this.updateMeter, this);
},
/**
* Sets the width of the meter, based on the score
* @param {Object} e
* Private function
*/
updateMeter: function(e) {
var score = 0
var p = e.target.value;
var maxWidth = this.objMeter.getWidth() - 2;
var nScore = this.calcStrength(p);
// Set new width
var nRound = Math.round(nScore * 2);
if (nRound > 100) {
nRound = 100;
}
var scoreWidth = (maxWidth / 100) * nRound;
this.scoreBar.setWidth(scoreWidth, true);
},
/**
* Calculates the strength of a password
* @param {Object} p The password that needs to be calculated
* @return {int} intScore The strength score of the password
*/
calcStrength: function(p) {
var intScore = 0;
// PASSWORD LENGTH
intScore += p.length;
if(p.length > 0 && p.length <= 4) { // length 4 or less
intScore += p.length;
}
else if (p.length >= 5 && p.length <= 7) { // length between 5 and 7
intScore += 6;
}
else if (p.length >= 8 && p.length <= 15) { // length between 8 and 15
intScore += 12;
//alert(intScore);
}
else if (p.length >= 16) { // length 16 or more
intScore += 18;
//alert(intScore);
}
// LETTERS (Not exactly implemented as dictacted above because of my limited understanding of Regex)
if (p.match(/[a-z]/)) { // [verified] at least one lower case letter
intScore += 1;
}
if (p.match(/[A-Z]/)) { // [verified] at least one upper case letter
intScore += 5;
}
// NUMBERS
if (p.match(/\d/)) { // [verified] at least one number
intScore += 5;
}
if (p.match(/.*\d.*\d.*\d/)) { // [verified] at least three numbers
intScore += 5;
}
// SPECIAL CHAR
if (p.match(/[!,@,#,$,%,^,&,*,?,_,~]/)) { // [verified] at least one special character
intScore += 5;
}
// [verified] at least two special characters
if (p.match(/.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~]/)) {
intScore += 5;
}
// COMBOS
if (p.match(/(?=.*[a-z])(?=.*[A-Z])/)) { // [verified] both upper and lower case
intScore += 2;
}
if (p.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/)) { // [verified] both letters and numbers
intScore += 2;
}
// [verified] letters, numbers, and special characters
if (p.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!,@,#,$,%,^,&,*,?,_,~])/)) {
intScore += 2;
}
return intScore;
},
// private
onFocus: function() {
Ext.ux.PasswordMeter.superclass.onFocus.call(this);
if(!Ext.isOpera) { // don't touch in Opera
this.objMeter.addClass('strengthMeter-focus');
}
},
// private
onBlur: function() {
Ext.ux.PasswordMeter.superclass.onBlur.call(this);
if(!Ext.isOpera) { // don't touch in Opera
this.objMeter.removeClass('strengthMeter-focus');
}
}
});

View file

@ -13,6 +13,19 @@
<configfile>config.php</configfile>
</config>
<components>
<!-- <component>
<info>
<name>passwordmeter</name>
<title>PasswordMeter</title>
<author>Eelco Wiersma</author>
<description>Ext user extension to check password strength</description>
</info>
<files>
<client>
<clientfile>lib/PasswordMeter.js</clientfile>
</client>
</files>
</component> -->
<component>
<files>
<server>
@ -25,6 +38,7 @@
<clientfile load="source">js/PasswdPlugin.js</clientfile>
<clientfile load="source">js/PasswdContentPanel.js</clientfile>
<clientfile load="source">js/PasswdPanel.js</clientfile>
<clientfile load="source">js/data/PasswdResponseHandler.js</clientfile>
<clientfile load="source">js/ABOUT.js</clientfile>
</client>
<!-- <resources>

View file

@ -1,7 +1,7 @@
<?php
/**
* Passwd module.
*
* Module that will be used to change passwords of the user
*/
class PasswdModule extends Module
{
@ -30,24 +30,56 @@ class PasswdModule extends Module
}
}
/**
* Change the password of user. Do some calidation and call proper methods based on
* zarafa setup.
* @param {Array} $data data sent by client.
*/
public function save($data)
{
$errorMessage = '';
// some sanity checks
if(empty($data)) {
$this->sendFeedback(false);
$errorMessage = _('No data received.');
}
if(empty($data['username']) || empty($data['current_password']) || empty($data['new_password']) || empty($data['new_password_repeat'])) {
$this->sendFeedback(false);
$errorMessage = _('User name is empty.');
}
if(PLUGIN_PASSWD_LDAP) {
$this->saveInLDAP($data);
if(empty($data['current_password'])) {
$errorMessage = _('Current password is empty.');
}
if(empty($data['new_password']) || empty($data['new_password_repeat'])) {
$errorMessage = _('New password is empty.');
}
if($data['new_password'] !== $data['new_password_repeat']) {
$errorMessage = _('New passwords does not match.');
}
if(empty($errorMessage)) {
if(PLUGIN_PASSWD_LDAP) {
$this->saveInLDAP($data);
} else {
$this->saveInDB($data);
}
} else {
$this->saveInDB($data);
$this->sendFeedback(false, array(
'type' => ERROR_ZARAFA,
'info' => array(
'display_message' => $errorMessage
)
));
}
}
/**
* Function will connect to LDAP and will try to modify user's password.
* @param {Array} $data data sent by client.
*/
public function saveInLDAP($data)
{
$errorMessage = '';
@ -79,26 +111,22 @@ class PasswdModule extends Module
$passwd = $data['new_password'];
$passwdRepeat = $data['new_password_repeat'];
if($passwd === $passwdRepeat) {
if(checkPasswordStrenth($passwd)) {
$password_hash = sshaEncode($passwd);
$entry = array('userPassword' => $password_hash);
$return_mod = ldap_modify($ldapconn, $userdn, $entry);
if (ldap_errno($ldapconn) === 0) {
// password changed successfully
$this->sendFeedback(true, {
'info' => array(
'display_message' => _('Password is changed successfully.')
)
});
} else {
$errorMessage = _('Password is not changed.');
}
if($this->checkPasswordStrenth($passwd)) {
$password_hash = $this->sshaEncode($passwd);
$entry = array('userPassword' => $password_hash);
$return_mod = ldap_modify($ldapconn, $userdn, $entry);
if (ldap_errno($ldapconn) === 0) {
// password changed successfully
$this->sendFeedback(true, array(
'info' => array(
'display_message' => _('Password is changed successfully.')
)
));
} else {
$errorMessage = _('Password is weak.');
$errorMessage = _('Password is not changed.');
}
} else {
$errorMessage = _('New passwords does not match.');
$errorMessage = _('Password is weak.');
}
} else {
$errorMessage = _('Current password does not match.');
@ -110,55 +138,72 @@ class PasswdModule extends Module
}
if(!empty($errorMessage)) {
$this->sendFeedback(false, {
'type' => 999, // ERROR_LDAP
$this->sendFeedback(false, array(
'type' => ERROR_ZARAFA,
'info' => array(
'ldap_error' => ldap_errno(),
'ldap_error_name' => ldap_error(),
'display_message' => $errorMessage
)
});
));
}
}
/**
* Function will execute zarafa-passwd command and will try to change user's password,
* this method is unsecure and unreliable.
* @param {Array} $data data sent by client.
*/
public function saveInDB($data)
{
$errorMessage = '';
$passwd = $data['new_password'];
$passwdRepeat = $data['new_password_repeat'];
$passwd_cmd = "/usr/bin/zarafa-passwd -u %s -o %s -p %s";
if($passwd === $passwdRepeat) {
if(checkPasswordStrenth($passwd)) {
// all information correct, change password
$cmd = sprintf($passwd_cmd, $data['username'], $data['current_passwd'], $passwd);
exec($cmd, $arrayout, $retval);
if($this->checkPasswordStrenth($passwd)) {
// all information correct, change password
$cmd = sprintf($passwd_cmd, $data['username'], $data['current_passwd'], $passwd);
exec($cmd, $arrayout, $retval);
if ($retval === 0) {
// password changed successfully
$this->sendFeedback(true, {
'info' => array(
'display_message' => _('Password is changed successfully.')
)
});
} else {
$errorMessage = _('Password is not changed.');
}
if ($retval === 0) {
// password changed successfully
$this->sendFeedback(true, array(
'info' => array(
'display_message' => _('Password is changed successfully.')
)
));
} else {
$errorMessage = _('Password is weak.');
}
$errorMessage = _('Password is not changed.');
}
} else {
$errorMessage = _('New passwords does not match.');
}
$errorMessage = _('Password is weak.');
}
if(!empty($errorMessage)) {
$this->sendFeedback(false, array(
'type' => ERROR_ZARAFA,
'info' => array(
'display_message' => $errorMessage
)
));
}
}
// check passwords. They should meet the following criteria:
// - min. 8 chars, max. 20
// - contain caps und noncaps characters
// - contain numbers
// return FALSE if not all criteria are met
/**
* 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 und 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)
{
return true;
// @FIXME should be moved to client side
if (preg_match("#.*^(?=.{8,20})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$#", $password)) {
return true;
@ -167,7 +212,10 @@ class PasswdModule extends Module
}
}
// create a ldap-password-hash from $text
/**
* 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.
*/
function sshaEncode($text)
{
$salt = '';