Ticket #131: remember_me.2.patch
| File remember_me.2.patch, 10.3 kB (added by s0undt3ch, 6 months ago) |
|---|
-
a/acct_mgr/admin.py
old new 60 60 self.config.save() 61 61 self.config.set('account-manager', 'force_passwd_change', 62 62 req.args.get('force_passwd_change')) 63 self.config.set('account-manager', 'persistent_sessions', 64 req.args.get('persistent_sessions')) 63 65 self.config.save() 64 66 65 67 … … 82 84 ] 83 85 sections = sorted(sections, key=lambda i: i['name']) 84 86 data = {'sections': sections, 85 'force_passwd_change': self.account_manager.force_passwd_change} 87 'force_passwd_change': self.account_manager.force_passwd_change, 88 'persistent_sessions': self.account_manager.persistent_sessions} 86 89 return 'admin_accountsconfig.html', data 87 90 88 91 def _do_users(self, req): -
a/acct_mgr/api.py
old new 90 90 "password when it's reset.") 91 91 verify_accounts = BoolOption('account-manager', 'verify_accounts', True, 92 92 "Force user to verify their email address") 93 persistent_sessions = BoolOption('account-manager', 'persistent_sessions', 94 False, doc="Allow the user to be " 95 "remembered across sessions without " 96 "needing to re-authenticate. This is, " 97 "user checks a \"Remember Me\" checkbox " 98 "and, next time he visits the site, he'll " 99 "be remembered") 93 100 94 101 # Public API 95 102 … … 109 116 return self.password_store.check_password(user, password) 110 117 111 118 def delete_user(self, user): 112 db = self.env.get_db_cnx() 113 cursor = db.cursor() 114 # Delete session attributes 115 cursor.execute("DELETE FROM session_attribute where sid=%s", (user,)) 116 # Delete session 117 cursor.execute("DELETE FROM session where sid=%s", (user,)) 118 # Delete any custom permissions set for the user 119 cursor.execute("DELETE FROM permission where username=%s", (user,)) 119 db = self.env.get_db_cnx() 120 cursor = db.cursor() 121 # Delete session attributes 122 cursor.execute("DELETE FROM session_attribute where sid=%s", (user,)) 123 # Delete session 124 cursor.execute("DELETE FROM session where sid=%s", (user,)) 125 # Delete any custom permissions set for the user 126 cursor.execute("DELETE FROM permission where username=%s", (user,)) 120 127 db.commit() 121 128 db.close() 122 # Delete from password store 129 # Delete from password store 123 130 self.log.debug('deleted user') 124 131 if self.password_store.delete_user(user): 125 132 self._notify('deleted', user) -
a/acct_mgr/templates/admin_accountsconfig.html
old new 39 39 <input type="radio" name="force_passwd_change" value="false" 40 40 checked="${not force_passwd_change and 'checked' or None}">No</input> 41 41 </fieldset> 42 43 <fieldset> 44 <legend>Persistent Sessions</legend> 45 <label for="persistent_sessions"> 46 Allow the user to be remembered across sessions without needing to 47 re-authenticate?<br/> 48 This is, user checks a "Remember Me" <tt>checkbox</tt> and, next time 49 he visits the site,<br/> 50 he'll be remembered and automatically authenticated. 51 </label> 52 <input type="radio" name="persistent_sessions" value="true" 53 checked="${persistent_sessions and 'checked' or None}">Yes</input> 54 <input type="radio" name="persistent_sessions" value="false" 55 checked="${not persistent_sessions and 'checked' or None}">No</input> 56 </fieldset> 57 42 58 <div class="buttons"> 43 59 <input type="submit" name="save" value="Save" /> 44 60 </div> -
a/acct_mgr/templates/login.html
old new 34 34 <label for="password">Password:</label> 35 35 <input type="password" id="password" name="password" class="textwidget" size="20" /> 36 36 </div> 37 <div py:if="persistent_sessions"> 38 <input type="checkbox" id="rememberme" name="rememberme" value="1" /> 39 <label for="rememberme">Remember me</label> 40 </div> 37 41 <input type="submit" value="Login" /> 38 42 39 43 <p py:if="reset_password_enabled"> -
a/acct_mgr/web_ui.py
old new 11 11 12 12 import random 13 13 import string 14 import time 14 15 15 16 from trac import perm, util 16 17 from trac.core import * … … 416 417 417 418 class LoginModule(auth.LoginModule): 418 419 419 implements(ITemplateProvider )420 implements(ITemplateProvider, IRequestFilter) 420 421 421 422 def authenticate(self, req): 422 423 if req.method == 'POST' and req.path_info.startswith('/login'): … … 430 431 if req.path_info.startswith('/login') and req.authname == 'anonymous': 431 432 data = { 432 433 'referer': self._referer(req), 433 'reset_password_enabled': AccountModule(self.env).reset_password_enabled 434 'reset_password_enabled': \ 435 AccountModule(self.env).reset_password_enabled, 436 'persistent_sessions': \ 437 AccountManager(self.env).persistent_sessions 434 438 } 435 439 if req.method == 'POST': 436 440 data['login_error'] = 'Invalid username or password' 437 441 return 'login.html', data, None 438 442 return auth.LoginModule.process_request(self, req) 439 443 444 # IRequestFilter methods 445 def pre_process_request(self, req, handler): 446 if 'trac_auth_session' in req.incookie: 447 # Let's check for a matching IP, proxy'ed or not 448 remote_addr = req.get_header("X-Forwarded-For") or req.remote_addr 449 if not req.incookie['trac_auth_session'].value == remote_addr: 450 self.log.debug("Cookie IP does not match Remote address IP: " 451 "'%s'!='%s'; Killing Session", 452 req.incookie['trac_auth_session'].value, 453 remote_addr) 454 self._do_logout(req) 455 # Repeat request after logout in order for the user not to 456 # think he's logged in 457 req.redirect(req.path_info) 458 459 460 # Let's now check with the one we have on auth_cookie db table 461 db = self.env.get_db_cnx() 462 cursor = db.cursor() 463 cursor.execute("SELECT ipnr from auth_cookie WHERE cookie=%s", 464 (req.incookie['trac_auth'].value,)) 465 row = cursor.fetchone() 466 if not req.incookie['trac_auth_session'].value == row[0]: 467 self.log.debug("Cookie IP does not match DB IP: '%s'!='%s'; " 468 "Killing Session", 469 req.incookie['trac_auth_session'].value, 470 row[0]) 471 self._do_logout(req) 472 # Repeat request after logout in order for the user not to 473 # think he's logged in 474 req.redirect(req.path_info) 475 # XXX: Would there be a way to know if a user authenticated using a 476 # cookie and not the login form, and, if he requested /prefs force him 477 # to re-authenticate? 478 return handler 479 480 def post_process_request(self, req, template, data, content_type): 481 return (template, data, content_type) 482 483 def _get_name_for_cookie(self, req, cookie): 484 name = auth.LoginModule._get_name_for_cookie(self, req, cookie) 485 if not AccountManager(self.env).persistent_sessions: 486 # Persistent sessions not enabled 487 return name 488 489 self.env.log.debug('Updating auth cookie %s for user %s' % 490 (cookie.value, name)) 491 db = self.env.get_db_cnx() 492 cursor = db.cursor() 493 cursor.execute('UPDATE auth_cookie SET time=%s WHERE cookie=%s', 494 (int(time.time()), cookie.value)) 495 db.commit() 496 req.outcookie['trac_auth'] = cookie.value 497 req.outcookie['trac_auth']['path'] = self.env.href() 498 499 if 'trac_auth_session' in req.incookie: 500 # Let's check for a matching IP, proxy'ed or not 501 remote_addr = req.get_header("X-Forwarded-For") or req.remote_addr 502 if req.incookie['trac_auth_session'].value == remote_addr: 503 req.outcookie['trac_auth']['expires'] = 86400 * 30 504 return name 505 440 506 def _do_login(self, req): 441 507 if not req.remote_user: 442 508 req.redirect(self.env.abs_href()) 443 return auth.LoginModule._do_login(self, req) 509 res = auth.LoginModule._do_login(self, req) 510 if req.args.get('rememberme', '0') == '1': 511 req.outcookie['trac_auth']['expires'] = 86400 * 30 512 req.outcookie['trac_auth_session'] = req.remote_addr 513 req.outcookie['trac_auth_session']['expires'] = 86400 * 30 514 return res 515 516 def _do_logout(self, req): 517 """Log the user out. 518 519 Simply deletes the corresponding record from the auth_cookie table. 520 """ 521 if req.authname == 'anonymous': 522 # Not logged in 523 return 524 525 # While deleting this cookie we also take the opportunity to delete 526 # cookies older than 30 days 527 db = self.env.get_db_cnx() 528 cursor = db.cursor() 529 cursor.execute("DELETE FROM auth_cookie WHERE name=%s OR time < %s", 530 (req.authname, int(time.time()) - 86400 * 30)) 531 db.commit() 532 self._expire_cookie(req) 533 534 # Expire the persistent session cookie 535 req.outcookie['trac_auth_session'] = '' 536 req.outcookie['trac_auth_session']['path'] = self.env.href() 537 req.outcookie['trac_auth_session']['expires'] = -10000 444 538 445 539 def _remote_user(self, req): 446 540 user = req.args.get('user')
