New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add User lockout and user unlock options #2897
Merged
mattlorimer
merged 16 commits into
salesagility:feature/user_lockout
from
JimMackin:UserLockout
Jan 17, 2017
Merged
Changes from 15 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
ab5b114
Lockout the user if they have more than max_failed_logins failed logi…
JimMackin db1c711
Add an option to unlock users for admin
JimMackin 2271120
Add an admin setting to change the max failed logins setting.
JimMackin 4a4403f
Switch the max failed logins setting to it's own section.
JimMackin f25fcc1
Add an option to automatically unlock a user after a set period.
JimMackin 48ece1b
Allow setting the automatic unlock time in admin. Also add validation…
JimMackin 535fe33
Tweak the max failed logins and automatic unlock settings to be a bit…
JimMackin 7ca24e5
Document the isUserLockedOut method.
JimMackin 8b10f26
Hide the user lock settings when using LDAP or SAML.
JimMackin ab598e9
Reset the login failed count when unlocking the user.
JimMackin e85f925
PSR and style changes, update license.
JimMackin db8966b
Style and licence changes.
JimMackin d27a932
PSR and style changes, update license. Also explicitly add method vis…
JimMackin c5820b8
Update license.
JimMackin 931cc54
Remove unnecessary if statement.
JimMackin 632b28a
Remove unused language string.
JimMackin File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
<?php | ||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); | ||
/********************************************************************************* | ||
* SugarCRM Community Edition is a customer relationship management program developed by | ||
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. | ||
|
||
* SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd. | ||
* Copyright (C) 2011 - 2014 Salesagility Ltd. | ||
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. | ||
* Copyright (C) 2011 - 2017 SalesAgility Ltd. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU Affero General Public License version 3 as published by the | ||
|
@@ -47,6 +46,10 @@ | |
* based on the users validation | ||
* | ||
*/ | ||
if (!defined('sugarEntry') || !sugarEntry) { | ||
die('Not A Valid Entry Point'); | ||
} | ||
|
||
class SugarAuthenticate{ | ||
var $userAuthenticateClass = 'SugarAuthenticateUser'; | ||
var $authenticationDir = 'SugarAuthenticate'; | ||
|
@@ -83,6 +86,30 @@ public function SugarAuthenticate(){ | |
self::__construct(); | ||
} | ||
|
||
/** | ||
* Given a user returns true if this user is currently locked out based on the `user_locked_out` and | ||
* on whether the unlock time has passed, if set. | ||
* | ||
* @see SugarAuthenticate::loginAuthenticate() | ||
* @param User $user | ||
* | ||
* @return bool | ||
*/ | ||
private function isUserLockedOut(User $user){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Docblocks Comment missing |
||
global $sugar_config; | ||
if(!$user->getPreference('user_locked_out')){ | ||
return false; | ||
} | ||
if(empty($sugar_config['userlockout']['automaticunlocktime'])){ | ||
return true; | ||
} | ||
$unlockCutoff = time() - ($sugar_config['userlockout']['automaticunlocktime'] * 60); | ||
if($user->getPreference('user_locked_out_time') < $unlockCutoff){ | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* Authenticates a user based on the username and password | ||
* returns true if the user was authenticated false otherwise | ||
|
@@ -92,15 +119,19 @@ public function SugarAuthenticate(){ | |
* @param string $password | ||
* @return boolean | ||
*/ | ||
function loginAuthenticate($username, $password, $fallback=false, $PARAMS = array ()){ | ||
global $mod_strings; | ||
public function loginAuthenticate($username, $password, $fallback=false, $PARAMS = array ()){ | ||
global $mod_strings, $sugar_config; | ||
unset($_SESSION['login_error']); | ||
$usr= new user(); | ||
$usr_id=$usr->retrieve_user_id($username); | ||
$usr->retrieve($usr_id); | ||
$_SESSION['login_error']=''; | ||
$_SESSION['waiting_error']=''; | ||
$_SESSION['hasExpiredPassword']='0'; | ||
if ($this->isUserLockedOut($usr)) { | ||
$_SESSION['login_error'] = translate('ERR_USER_IS_LOCKED_OUT', 'Users'); | ||
return false; | ||
} | ||
if ($this->userAuthenticate->loadUserOnLogin($username, $password, $fallback, $PARAMS)) { | ||
require_once('modules/Users/password_utils.php'); | ||
if(hasPasswordExpired($username)) { | ||
|
@@ -109,19 +140,27 @@ function loginAuthenticate($username, $password, $fallback=false, $PARAMS = arra | |
// now that user is authenticated, reset loginfailed | ||
if ($usr->getPreference('loginfailed') != '' && $usr->getPreference('loginfailed') != 0) { | ||
$usr->setPreference('loginfailed','0'); | ||
$usr->setPreference('user_locked_out', false); | ||
$usr->setPreference('user_locked_out_time', ''); | ||
$usr->savePreferencesToDB(); | ||
} | ||
return $this->postLoginAuthenticate(); | ||
|
||
} | ||
else | ||
{ | ||
//if(!empty($usr_id) && $res['lockoutexpiration'] > 0){ | ||
if(!empty($usr_id)){ | ||
if (($logout=$usr->getPreference('loginfailed'))=='') | ||
$usr->setPreference('loginfailed','1'); | ||
else | ||
if (($logout=$usr->getPreference('loginfailed'))=='') { | ||
$usr->setPreference('loginfailed', '1'); | ||
}else{ | ||
$usr->setPreference('loginfailed',$logout+1); | ||
} | ||
if (!empty($sugar_config['userlockout']['maxfailedlogins']) && | ||
($logout + 1) >= $sugar_config['userlockout']['maxfailedlogins'] | ||
) { | ||
$usr->setPreference('user_locked_out', true); | ||
$usr->setPreference('user_locked_out_time', time()); | ||
} | ||
$usr->savePreferencesToDB(); | ||
} | ||
} | ||
|
@@ -149,7 +188,7 @@ function loginAuthenticate($username, $password, $fallback=false, $PARAMS = arra | |
* Once a user is authenticated on login this function will be called. Populate the session with what is needed and log anything that needs to be logged | ||
* | ||
*/ | ||
function postLoginAuthenticate(){ | ||
public function postLoginAuthenticate(){ | ||
|
||
global $reset_language_on_default_user, $sugar_config; | ||
|
||
|
@@ -188,7 +227,7 @@ function postLoginAuthenticate(){ | |
* On every page hit this will be called to ensure a user is authenticated | ||
* @return boolean | ||
*/ | ||
function sessionAuthenticate(){ | ||
public function sessionAuthenticate(){ | ||
|
||
global $module, $action, $allowed_actions; | ||
$authenticated = false; | ||
|
@@ -234,7 +273,7 @@ function sessionAuthenticate(){ | |
* @return boolean | ||
*/ | ||
|
||
function postSessionAuthenticate(){ | ||
public function postSessionAuthenticate(){ | ||
|
||
global $action, $allowed_actions, $sugar_config; | ||
$_SESSION['userTime']['last'] = time(); | ||
|
@@ -263,7 +302,7 @@ function postSessionAuthenticate(){ | |
* Make sure a user isn't stealing sessions so check the ip to ensure that the ip address hasn't dramatically changed | ||
* | ||
*/ | ||
function validateIP() { | ||
public function validateIP() { | ||
global $sugar_config; | ||
// grab client ip address | ||
$clientIP = query_client_ip(); | ||
|
@@ -310,7 +349,7 @@ function validateIP() { | |
* Called when a user requests to logout | ||
* | ||
*/ | ||
function logout(){ | ||
public function logout(){ | ||
session_start(); | ||
session_destroy(); | ||
ob_clean(); | ||
|
@@ -325,22 +364,22 @@ function logout(){ | |
* @param STRING $password | ||
* @return STRING $encoded_password | ||
*/ | ||
static function encodePassword($password){ | ||
public static function encodePassword($password){ | ||
return strtolower(md5($password)); | ||
} | ||
|
||
/** | ||
* If a user may change there password through the Sugar UI | ||
* | ||
*/ | ||
function canChangePassword(){ | ||
public function canChangePassword(){ | ||
return true; | ||
} | ||
/** | ||
* If a user may change there user name through the Sugar UI | ||
* | ||
*/ | ||
function canChangeUserName(){ | ||
public function canChangeUserName(){ | ||
return true; | ||
} | ||
|
||
|
@@ -350,7 +389,7 @@ function canChangeUserName(){ | |
* | ||
* This function allows the SugarAuthenticate subclasses to perform some pre login initialization as needed | ||
*/ | ||
function pre_login() | ||
public function pre_login() | ||
{ | ||
if (isset($_SESSION['authenticated_user_id'])) | ||
{ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
<?php | ||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); | ||
/********************************************************************************* | ||
* SugarCRM Community Edition is a customer relationship management program developed by | ||
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. | ||
|
||
* SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd. | ||
* Copyright (C) 2011 - 2014 Salesagility Ltd. | ||
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. | ||
* Copyright (C) 2011 - 2017 Salesagility Ltd. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU Affero General Public License version 3 as published by the | ||
|
@@ -44,6 +43,11 @@ | |
* All Rights Reserved. | ||
* Contributor(s): ______________________________________.. | ||
********************************************************************************/ | ||
|
||
if (!defined('sugarEntry') || !sugarEntry) { | ||
die('Not A Valid Entry Point'); | ||
} | ||
|
||
require_once("include/OutboundEmail/OutboundEmail.php"); | ||
|
||
class UsersController extends SugarController | ||
|
@@ -130,5 +134,19 @@ public function action_save() | |
{ | ||
require 'modules/Users/Save.php'; | ||
} | ||
|
||
public function action_unlockuser(){ | ||
global $current_user; | ||
if (!is_admin($current_user)) { | ||
SugarApplication::redirect("index.php?module=Users&record=" . $_REQUEST['record'] . "&action=DetailView"); | ||
return; | ||
} | ||
$this->bean->setPreference('user_locked_out', false); | ||
$this->bean->setPreference('user_locked_out_time', ''); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. needs to also reset the loginfailed preference |
||
$this->bean->setPreference('loginfailed', '0'); | ||
$this->bean->savePreferencesToDB(); | ||
SugarApplication::appendErrorMessage(translate('LBL_USER_UNLOCKED_MSG', 'Users')); | ||
SugarApplication::redirect("index.php?module=Users&record=" . $_REQUEST['record'] . "&action=DetailView"); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty language string!