Trac is being migrated to new services! Issues can be found in our new
YouTrack instance and WIKI pages can be found on our
website.
LocalTracChanges: acct_mgr_plugin_ssl_remember_me_rev_4111.patch
| File acct_mgr_plugin_ssl_remember_me_rev_4111.patch, 9.1 KB (added by datallah, 15 years ago) |
|
AccountManager? rev. 4111 patch to implement SSL login and admin screens and persistent sessions
|
-
|
|
|
|
| 13 | 13 | import os |
| 14 | 14 | import random |
| 15 | 15 | import string |
| | 16 | import time |
| | 17 | import re |
| | 18 | import urlparse |
| 16 | 19 | |
| 17 | 20 | from trac import perm, util |
| 18 | 21 | from trac.core import * |
| 19 | 22 | from trac.config import IntOption |
| 20 | 23 | from trac.notification import NotificationSystem, NotifyEmail |
| 21 | 24 | from trac.prefs import IPreferencePanelProvider |
| | 25 | from trac.util.text import unicode_urlencode |
| 22 | 26 | from trac.web import auth |
| 23 | 27 | from trac.web.api import IAuthenticator |
| 24 | 28 | from trac.web.main import IRequestHandler, IRequestFilter |
| … |
… |
|
| 53 | 57 | if password != req.args.get('password_confirm'): |
| 54 | 58 | raise TracError('The passwords must match.') |
| 55 | 59 | |
| | 60 | if not req.args.get('email'): |
| | 61 | raise TracError('You must enter a valid Email address.') |
| | 62 | |
| 56 | 63 | mgr.set_password(user, password) |
| 57 | 64 | |
| 58 | 65 | db = env.get_db_cnx() |
| … |
… |
|
| 157 | 164 | 'store does not support writing.') |
| 158 | 165 | return writable |
| 159 | 166 | |
| | 167 | |
| | 168 | def _redirect_to_scheme(self, req, scheme): |
| | 169 | self.log.debug("Forwarding to '%s' for '%s%s'" % (scheme, req.base_path, req.path_info)) |
| | 170 | referer_param = req.args.get('referer') |
| | 171 | if referer_param: |
| | 172 | referer_param = "referer=%s" % referer_param |
| | 173 | req.redirect(urlparse.urlunparse((scheme, req.server_name, req.base_path + req.path_info, None, referer_param, None))) |
| | 174 | |
| | 175 | def _needs_ssl(self, path_info): |
| | 176 | return re.match('/prefs(?:/([^/]+))?', path_info) \ |
| | 177 | or path_info == '/reset_password' \ |
| | 178 | or path_info == '/register' \ |
| | 179 | or path_info == '/login' \ |
| | 180 | or path_info == '/admin/accounts/users' |
| | 181 | |
| | 182 | def _needs_session_cookie(self, path_info): |
| | 183 | return re.match('/admin(?:/([^/]+))?', path_info) \ |
| | 184 | or path_info == '/prefs/account' |
| | 185 | |
| 160 | 186 | #IPreferencePanelProvider methods |
| 161 | 187 | def get_preference_panels(self, req): |
| 162 | 188 | if not self._write_check(): |
| … |
… |
|
| 179 | 205 | |
| 180 | 206 | # IRequestFilter methods |
| 181 | 207 | def pre_process_request(self, req, handler): |
| | 208 | |
| | 209 | ssl_path = self._needs_ssl(req.path_info) |
| | 210 | # Catch the user leaving an ssl path /prefs and redirect to non-secure |
| | 211 | if req.scheme.lower() == 'https' and not ssl_path: |
| | 212 | self._redirect_to_scheme(req, 'http') |
| | 213 | # Catch the user entering /prefs or and redirect to secure |
| | 214 | elif ssl_path: |
| | 215 | if req.scheme.lower() != 'https': |
| | 216 | self._redirect_to_scheme(req, 'https') |
| | 217 | |
| | 218 | # If we're accessing a page that you should be logged in the current session for, deal with it |
| | 219 | if self._needs_session_cookie(req.path_info) \ |
| | 220 | and not req.incookie.has_key('trac_auth_session'): |
| | 221 | self.log.debug("Accessing %s requires a session login, forwarding to login screen." % req.path_info) |
| | 222 | referal_url = urlparse.urlunparse((ssl_path and 'https' or 'http', req.server_name, req.base_path + req.path_info, None, None, None)) |
| | 223 | req.redirect(self.env.href.login() + '?%s' % unicode_urlencode({'referer' : referal_url, 'force_session' : '1'})) |
| | 224 | |
| 182 | 225 | return handler |
| 183 | 226 | |
| 184 | 227 | def post_process_request(self, req, template, data, content_type): |
| … |
… |
|
| 377 | 420 | except TracError, e: |
| 378 | 421 | data['registration_error'] = e.message |
| 379 | 422 | else: |
| 380 | | req.redirect(req.href.login()) |
| | 423 | redirect_url = None |
| | 424 | referer = req.args.get('referer') |
| | 425 | if referer: |
| | 426 | redirect_url = "%s?referer=%s" % (req.href.login(), referer) |
| | 427 | req.redirect(redirect_url or req.href.login()) |
| 381 | 428 | data['reset_password_enabled'] = \ |
| 382 | 429 | (self.env.is_component_enabled(AccountModule) |
| 383 | 430 | and NotificationSystem(self.env).smtp_enabled) |
| … |
… |
|
| 422 | 469 | match_request = if_enabled(auth.LoginModule.match_request) |
| 423 | 470 | |
| 424 | 471 | def process_request(self, req): |
| 425 | | if req.path_info.startswith('/login') and req.authname == 'anonymous': |
| | 472 | if req.path_info.startswith('/login') and (req.authname == 'anonymous' or req.args.get('force_session')): |
| 426 | 473 | data = { |
| 427 | 474 | 'referer': self._referer(req), |
| 428 | 475 | 'reset_password_enabled': AccountModule(self.env).reset_password_enabled |
| … |
… |
|
| 432 | 479 | return 'login.html', data, None |
| 433 | 480 | return auth.LoginModule.process_request(self, req) |
| 434 | 481 | |
| | 482 | #def _get_name_for_cookie(self, req, cookie): |
| | 483 | # name = auth.LoginModule._get_name_for_cookie(self, req, cookie) |
| | 484 | # if name and not req.incookie.has_key('trac_auth_session'): |
| | 485 | # self.env.log.debug('Updating auth cookie %s for user %s' % |
| | 486 | # (cookie.value, name)) |
| | 487 | # db = self.env.get_db_cnx() |
| | 488 | # cursor = db.cursor() |
| | 489 | # cursor.execute('UPDATE auth_cookie SET time=%s WHERE cookie=%s', |
| | 490 | # (int(time.time()), cookie.value)) |
| | 491 | # req.outcookie['trac_auth'] = cookie.value |
| | 492 | # req.outcookie['trac_auth']['path'] = self.env.href() |
| | 493 | # req.outcookie['trac_auth']['expires'] = 86400 * 30 |
| | 494 | # req.outcookie['trac_auth_session'] = '1' |
| | 495 | # req.outcookie['trac_auth_session']['path'] = self.env.href() |
| | 496 | # return name |
| | 497 | |
| 435 | 498 | def _do_login(self, req): |
| 436 | 499 | if not req.remote_user: |
| 437 | 500 | req.redirect(self.env.abs_href()) |
| 438 | | return auth.LoginModule._do_login(self, req) |
| | 501 | res = auth.LoginModule._do_login(self, req) |
| | 502 | if req.args.get('rememberme', '0') == '1': |
| | 503 | req.outcookie['trac_auth']['expires'] = 86400 * 30 |
| | 504 | req.outcookie['trac_auth_session'] = '1' |
| | 505 | req.outcookie['trac_auth_session']['path'] = self.env.href() |
| | 506 | return res |
| 439 | 507 | |
| | 508 | def _do_logout(self, req): |
| | 509 | """Log the user out. |
| | 510 | |
| | 511 | Simply deletes the corresponding record from the auth_cookie table. |
| | 512 | """ |
| | 513 | if req.authname == 'anonymous': |
| | 514 | # Not logged in |
| | 515 | return |
| | 516 | |
| | 517 | # While deleting this cookie we also take the opportunity to delete |
| | 518 | # cookies older than 30 days |
| | 519 | db = self.env.get_db_cnx() |
| | 520 | cursor = db.cursor() |
| | 521 | cursor.execute("DELETE FROM auth_cookie WHERE name=%s OR time < %s", |
| | 522 | (req.authname, int(time.time()) - 86400 * 30)) |
| | 523 | db.commit() |
| | 524 | self._expire_cookie(req) |
| | 525 | |
| 440 | 526 | def _remote_user(self, req): |
| 441 | 527 | user = req.args.get('user') |
| 442 | 528 | password = req.args.get('password') |
| … |
… |
|
| 449 | 535 | def _redirect_back(self, req): |
| 450 | 536 | """Redirect the user back to the URL she came from.""" |
| 451 | 537 | referer = self._referer(req) |
| 452 | | if referer and not referer.startswith(req.base_url): |
| 453 | | # don't redirect to external sites |
| 454 | | referer = None |
| | 538 | if referer: |
| | 539 | u = urlparse.urlparse(referer) |
| | 540 | r = urlparse.urlparse(req.base_url) |
| | 541 | if u[1] and u[1] != r[1]: |
| | 542 | # don't redirect to external sites |
| | 543 | referer = None |
| 455 | 544 | req.redirect(referer or self.env.abs_href()) |
| 456 | 545 | |
| 457 | 546 | def _referer(self, req): |
| … |
… |
|
| 576 | 665 | def _send_email(self, req): |
| 577 | 666 | notifier = EmailVerificationNotification(self.env) |
| 578 | 667 | notifier.notify(req.authname, req.session['email_verification_token']) |
| | 668 | |
-
|
|
|
|
| 24 | 24 | </div> |
| 25 | 25 | |
| 26 | 26 | <form method="post" id="acctmgr_registerform" action=""> |
| | 27 | <input type="hidden" name="referer" value="${req.args.get('referer')}" /> |
| 27 | 28 | <fieldset> |
| 28 | 29 | <legend>Required</legend> |
| 29 | 30 | <div> |
| … |
… |
|
| 43 | 44 | class="textwidget" size="20" /> |
| 44 | 45 | </label> |
| 45 | 46 | </div> |
| 46 | | </fieldset> |
| 47 | | <fieldset> |
| 48 | | <legend>Optional</legend> |
| 49 | 47 | <div> |
| 50 | 48 | <label>Name: |
| 51 | 49 | <input type="text" name="name" class="textwidget" size="20" /> |
-
|
|
|
|
| 28 | 28 | <input type="hidden" name="referer" value="${referer}" /> |
| 29 | 29 | <div> |
| 30 | 30 | <label for="user">Username:</label> |
| 31 | | <input type="text" id="user" name="user" class="textwidget" size="20" /> |
| | 31 | <input type="text" id="user" name="user" class="textwidget" size="20" value="${req.authname != 'anonymous' and req.authname or None}"/> |
| 32 | 32 | </div> |
| 33 | 33 | <div> |
| 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> |
| | 38 | <input type="checkbox" id="rememberme" name="rememberme" value="1" checked="${req.authname != 'anonymous' and req.authname or None}"/> |
| | 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"> |
Download in other formats:
All information, including names and email addresses, entered onto this website or sent to mailing lists affiliated with this website will be public. Do not post confidential information, especially passwords!