Skip to content

Commit

Permalink
option to logout from all devices while changing password (#4419)
Browse files Browse the repository at this point in the history
  • Loading branch information
Manas Solanki authored and rmehta committed Nov 10, 2017
1 parent 4ef61f3 commit 3c7683e
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 10 deletions.
5 changes: 3 additions & 2 deletions frappe/commands/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,9 @@ def move(dest_dir, site):

@click.command('set-admin-password')
@click.argument('admin-password')
@click.option('--logout-all-sessions', help='Logout from all sessions', is_flag=True, default=False)
@pass_context
def set_admin_password(context, admin_password):
def set_admin_password(context, admin_password, logout_all_sessions=False):
"Set Administrator password for a site"
import getpass
from frappe.utils.password import update_password
Expand All @@ -419,7 +420,7 @@ def set_admin_password(context, admin_password):
admin_password = getpass.getpass("Administrator's password for {0}: ".format(site))

frappe.connect()
update_password('Administrator', admin_password)
update_password(user='Administrator', pwd=admin_password, logout_all_sessions=logout_all_sessions)
frappe.db.commit()
admin_password = None
finally:
Expand Down
35 changes: 33 additions & 2 deletions frappe/core/doctype/user/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "logout_all_sessions",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Logout from all devices while changing Password",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
Expand Down Expand Up @@ -2032,8 +2063,8 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
"modified": "2017-10-17 11:06:05.570463",
"modified_by": "Administrator",
"modified": "2017-11-01 09:04:51.151347",
"modified_by": "manas@erpnext.com",
"module": "Core",
"name": "User",
"owner": "Administrator",
Expand Down
5 changes: 3 additions & 2 deletions frappe/core/doctype/user/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def add_system_manager_role(self):

def email_new_password(self, new_password=None):
if new_password and not self.flags.in_insert:
_update_password(self.name, new_password)
_update_password(user=self.name, pwd=new_password, logout_all_sessions=self.logout_all_sessions)

if self.send_password_update_notification:
self.password_update_mail(new_password)
Expand Down Expand Up @@ -191,7 +191,8 @@ def send_password_notification(self, new_password):
if self.name not in STANDARD_USERS:
if new_password:
# new password given, no email required
_update_password(self.name, new_password)
_update_password(user=self.name, pwd=new_password,
logout_all_sessions=self.logout_all_sessions)

if not self.flags.no_welcome_mail and self.send_welcome_email:
self.send_welcome_mail_to_user()
Expand Down
10 changes: 8 additions & 2 deletions frappe/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,21 @@ def clear_global_cache():
frappe.setup_module_map()


def clear_sessions(user=None, keep_current=False, device=None):
def clear_sessions(user=None, keep_current=False, device=None, force=False):
'''Clear other sessions of the current user. Called at login / logout
:param user: user name (default: current user)
:param keep_current: keep current session (default: false)
:param device: delete sessions of this device (default: desktop)
:param force: triggered by the user (default false)
'''

reason = "Logged In From Another Session"
if force:
reason = "Force Logged out by the user"

for sid in get_sessions_to_clear(user, keep_current, device):
delete_session(sid, reason="Logged In From Another Session")
delete_session(sid, reason=reason)

def get_sessions_to_clear(user=None, keep_current=False, device=None):
'''Returns sessions of the current user. Called at login / logout
Expand Down
18 changes: 16 additions & 2 deletions frappe/utils/password.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,29 @@ def check_password(user, pwd, doctype='User', fieldname='password'):

return user

def update_password(user, pwd, doctype='User', fieldname='password'):
salt = frappe.generate_hash()
def update_password(user, pwd, doctype='User', fieldname='password', logout_all_sessions=False):
'''
Update the password for the User
:param user: username
:param pwd: new password
:param doctype: doctype name (for encryption)
:param fieldname: fieldname (in given doctype) (for encryption)
:param logout_all_session: delete all other session
'''

salt = frappe.generate_hash()
frappe.db.sql("""insert into __Auth (doctype, name, fieldname, `password`, salt, encrypted)
values (%(doctype)s, %(name)s, %(fieldname)s, password(concat(%(pwd)s, %(salt)s)), %(salt)s, 0)
on duplicate key update
`password`=password(concat(%(pwd)s, %(salt)s)), salt=%(salt)s, encrypted=0""",
{ 'doctype': doctype, 'name': user, 'fieldname': fieldname, 'pwd': pwd, 'salt': salt })

# clear all the sessions except current
if logout_all_sessions:
from frappe.sessions import clear_sessions
clear_sessions(user=user, keep_current=True, force=True)

def delete_all_passwords_for(doctype, name):
try:
frappe.db.sql("""delete from __Auth where doctype=%(doctype)s and name=%(name)s""",
Expand Down

0 comments on commit 3c7683e

Please sign in to comment.