Package: trac-authopenid Version: 0.4.7-1 Severity: grave Tags: patch Justification: renders package unusable
on debian stretch and later, trac is version 1.2. but trac-authopenid 0.4.7-1 uses get_db_cnx(), which was deprecated in trac 0.12 and removed in trac 1.1. As a result, if trac-authopenid is installed and configured for a trac environment, that environment will fail to load at all. see https://trac.edgewall.org/wiki/TracDev/ApiChanges/1.1#DatabaseAPIChanges the attached patch appears to fix the worst errors, but hasn't been well-tested. --dkg -- System Information: Debian Release: buster/sid APT prefers testing-debug APT policy: (500, 'testing-debug'), (500, 'testing'), (500, 'oldstable'), (200, 'unstable-debug'), (200, 'unstable'), (1, 'experimental-debug'), (1, 'experimental') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 4.15.0-2-amd64 (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages trac-authopenid depends on: ii python 2.7.14-4 ii python-openid 2.2.5-6 ii trac 1.2.2+dfsg-1 trac-authopenid recommends no packages. trac-authopenid suggests no packages. -- no debconf information
From: Daniel Kahn Gillmor <d...@fifthhorseman.net> Date: Mon, 9 Apr 2018 07:30:15 -0400 Subject: move from get_db_cnx() to context manager See https://trac.edgewall.org/wiki/TracDev/ApiChanges/1.1#DatabaseAPIChanges for more details about this migration. --- authopenid/authopenid.py | 660 +++++++++++++++++++++++------------------------ 1 file changed, 330 insertions(+), 330 deletions(-) diff --git a/authopenid/authopenid.py b/authopenid/authopenid.py index da98b19..112c175 100644 --- a/authopenid/authopenid.py +++ b/authopenid/authopenid.py @@ -227,7 +227,6 @@ class AuthOpenIdPlugin(Component): return generated_list def __init__(self): - db = self.env.get_db_cnx() oidutil.log = OpenIdLogger(self.env) self.env.log.debug("Compiling white-list") self.re_white_list = self.generate_re_list(self.white_list) @@ -264,9 +263,9 @@ class AuthOpenIdPlugin(Component): # IEnvironmentSetupParticipant methods def environment_created(self): - db = self.env.get_db_cnx() - self._initStore(db) - db.commit() + with self.env.db_transaction as db: + self._initStore(db) + db.commit() def environment_needs_upgrade(self, db): c = db.cursor() @@ -414,36 +413,18 @@ class AuthOpenIdPlugin(Component): immediate = 'immediate' in req.args - db = self.env.get_db_cnx() - oidconsumer, oidsession = self._get_consumer(req, db) - try: - self.env.log.debug('beginning OpenID authentication.') - request = oidconsumer.begin(openid_url) - except consumer.DiscoveryFailure, exc: - fetch_error_string = 'Error in discovery: %s' % ( - cgi.escape(str(exc[0]))) - return 'openidlogin.html', { - 'images': req.href.chrome('authopenid/images') + '/', - 'action': req.href.openidverify(), - 'message': fetch_error_string, - 'signup': self.signup_link, - 'whatis': self.whatis_link, - 'css_class': 'error', - 'providers_regexp': self.providers_regexp, - 'custom_provider_name': self.custom_provider_name, - 'custom_provider_label': self.custom_provider_label, - 'custom_provider_url': self.custom_provider_url, - 'custom_provider_image': self.custom_provider_image, - 'custom_provider_size': self.custom_provider_size, - }, None - else: - if request is None: - msg = 'No OpenID services found for <code>%s</code>' % ( - cgi.escape(openid_url),) + with self.env.db_transaction as db: + oidconsumer, oidsession = self._get_consumer(req, db) + try: + self.env.log.debug('beginning OpenID authentication.') + request = oidconsumer.begin(openid_url) + except consumer.DiscoveryFailure, exc: + fetch_error_string = 'Error in discovery: %s' % ( + cgi.escape(str(exc[0]))) return 'openidlogin.html', { 'images': req.href.chrome('authopenid/images') + '/', 'action': req.href.openidverify(), - 'message': msg, + 'message': fetch_error_string, 'signup': self.signup_link, 'whatis': self.whatis_link, 'css_class': 'error', @@ -453,25 +434,43 @@ class AuthOpenIdPlugin(Component): 'custom_provider_url': self.custom_provider_url, 'custom_provider_image': self.custom_provider_image, 'custom_provider_size': self.custom_provider_size, - }, None + }, None else: - self._commit_oidsession(oidsession, req) - # Then, ask the library to begin the authorization. - # Here we find out the identity server that will verify the - # user's identity, and get a token that allows us to - # communicate securely with the identity server. + if request is None: + msg = 'No OpenID services found for <code>%s</code>' % ( + cgi.escape(openid_url),) + return 'openidlogin.html', { + 'images': req.href.chrome('authopenid/images') + '/', + 'action': req.href.openidverify(), + 'message': msg, + 'signup': self.signup_link, + 'whatis': self.whatis_link, + 'css_class': 'error', + 'providers_regexp': self.providers_regexp, + 'custom_provider_name': self.custom_provider_name, + 'custom_provider_label': self.custom_provider_label, + 'custom_provider_url': self.custom_provider_url, + 'custom_provider_image': self.custom_provider_image, + 'custom_provider_size': self.custom_provider_size, + }, None + else: + self._commit_oidsession(oidsession, req) + # Then, ask the library to begin the authorization. + # Here we find out the identity server that will verify the + # user's identity, and get a token that allows us to + # communicate securely with the identity server. - requested_policies = [] - if self.pape_method: - requested_policies.append(self.pape_method) + requested_policies = [] + if self.pape_method: + requested_policies.append(self.pape_method) - pape_method = req.args.get('pape_method') - if pape_method: - requested_policies.append(pape_method) + pape_method = req.args.get('pape_method') + if pape_method: + requested_policies.append(pape_method) - if requested_policies: - pape_request = pape.Request(requested_policies) - request.addExtension(pape_request) + if requested_policies: + pape_request = pape.Request(requested_policies) + request.addExtension(pape_request) # Let the sreg policy be configurable sreg_opt = [] @@ -532,17 +531,17 @@ class AuthOpenIdPlugin(Component): :returns: username or ``None``. """ - db = self.env.get_db_cnx() - cursor = db.cursor() - cursor.execute("SELECT session.sid" - " FROM session" - " INNER JOIN session_attribute AS attr" - " USING(sid, authenticated)" - " WHERE session.authenticated=%s" - " AND attr.name=%s AND attr.value=%s" - " ORDER BY session.last_visit DESC", - (1, self.openid_session_identity_url_key, openid_identifier)) - rows = cursor.fetchall() + with self.env.db_query as db: + cursor = db.cursor() + cursor.execute("SELECT session.sid" + " FROM session" + " INNER JOIN session_attribute AS attr" + " USING(sid, authenticated)" + " WHERE session.authenticated=%s" + " AND attr.name=%s AND attr.value=%s" + " ORDER BY session.last_visit DESC", + (1, self.openid_session_identity_url_key, openid_identifier)) + rows = cursor.fetchall() if len(rows) == 0: return None elif len(rows) > 1: @@ -559,242 +558,242 @@ class AuthOpenIdPlugin(Component): def _do_process(self, req): """Handle the redirect from the OpenID server. """ - db = self.env.get_db_cnx() - oidconsumer, oidsession = self._get_consumer(req, db) - - # Ask the library to check the response that the server sent - # us. Status is a code indicating the response type. info is - # either None or a string containing more information about - # the return type. - current_url = req.abs_href(req.path_info) - info = oidconsumer.complete(req.args,current_url) - - css_class = 'error' - if info.status == consumer.FAILURE and info.identity_url: - # In the case of failure, if info is non-None, it is the - # URL that we were verifying. We include it in the error - # message to help the user figure out what happened. - fmt = "Verification of %s failed: %s" - message = fmt % (cgi.escape(info.identity_url), - info.message) - elif info.status == consumer.SUCCESS: - # Success means that the transaction completed without - # error. If info is None, it means that the user cancelled - # the verification. - css_class = 'alert' - - session_attr = {} # attributes for new "user" - - # This is a successful verification attempt. If this - # was a real application, we would do our login, - # comment posting, etc. here. - fmt = "You have successfully verified %s as your identity." - message = fmt % (cgi.escape(info.identity_url),) - remote_user = info.identity_url - - sreg_info = sreg.SRegResponse.fromSuccessResponse(info) or {} - - ax_response = ax.FetchResponse.fromSuccessResponse(info) - ax_info = {} - if ax_response: - for alias, uri in self.openid_ax_attrs.items(): - values = ax_response.data.get(uri,[]) - if values: - ax_info[alias] = values[0] - - email = (ax_info.get('email') - or ax_info.get('email2') - or sreg_info.get('email')) - - fullname = ( - ' '.join(filter(None, map(ax_info.get, - ('firstname', 'lastname')))) - or sreg_info.get('fullname') - or (email and email.split('@',1)[0].replace('.', ' ').title())) - - nickname = sreg_info.get('nickname') - - if self.groups_to_request and TeamsResponse: - teams_response = TeamsResponse.fromSuccessResponse(info) - if teams_response: - # be careful not to make user a member of any trac groups - # not named in groups_to_request - teams = set(teams_response.teams - ).intersection(self.groups_to_request) - if teams: - session_attr['openid.teams'] = ','.join(teams) - - if self.strip_protocol: - remote_user = remote_user[remote_user.find('://')+3:] - if self.strip_trailing_slash and remote_user[-1] == '/': - remote_user = remote_user[:-1] - if info.endpoint.canonicalID: - # You should authorize i-name users by their canonicalID, - # rather than their more human-friendly identifiers. That - # way their account with you is not compromised if their - # i-name registration expires and is bought by someone else. - message += (" This is an i-name, and its persistent ID is %s" - % (cgi.escape(info.endpoint.canonicalID),)) - remote_user = info.endpoint.canonicalID - - allowed = True - if self.re_white_list: - self.env.log.debug("Filtering REMOTE_USER '%s' through white-list." % remote_user) - allowed = False - for item in self.re_white_list: - if not allowed and item.match(remote_user): - allowed = True - self.env.log.debug("User white-listed.") - if allowed and self.re_black_list: - self.env.log.debug("Filtering REMOTE_USER '%s' through black-list." % remote_user) - for item in self.re_black_list: - if item.match(remote_user): - allowed = False - self.env.log.debug("User black-listed.") - if allowed and self.re_email_white_list: - self.env.log.debug("Filtering email %r through email white-list." % email) - allowed = False - if email: - for item in self.re_email_white_list: - if not allowed and item.match(email): + with self.env.db_transaction as db: + oidconsumer, oidsession = self._get_consumer(req, db) + + # Ask the library to check the response that the server sent + # us. Status is a code indicating the response type. info is + # either None or a string containing more information about + # the return type. + current_url = req.abs_href(req.path_info) + info = oidconsumer.complete(req.args,current_url) + + css_class = 'error' + if info.status == consumer.FAILURE and info.identity_url: + # In the case of failure, if info is non-None, it is the + # URL that we were verifying. We include it in the error + # message to help the user figure out what happened. + fmt = "Verification of %s failed: %s" + message = fmt % (cgi.escape(info.identity_url), + info.message) + elif info.status == consumer.SUCCESS: + # Success means that the transaction completed without + # error. If info is None, it means that the user cancelled + # the verification. + css_class = 'alert' + + session_attr = {} # attributes for new "user" + + # This is a successful verification attempt. If this + # was a real application, we would do our login, + # comment posting, etc. here. + fmt = "You have successfully verified %s as your identity." + message = fmt % (cgi.escape(info.identity_url),) + remote_user = info.identity_url + + sreg_info = sreg.SRegResponse.fromSuccessResponse(info) or {} + + ax_response = ax.FetchResponse.fromSuccessResponse(info) + ax_info = {} + if ax_response: + for alias, uri in self.openid_ax_attrs.items(): + values = ax_response.data.get(uri,[]) + if values: + ax_info[alias] = values[0] + + email = (ax_info.get('email') + or ax_info.get('email2') + or sreg_info.get('email')) + + fullname = ( + ' '.join(filter(None, map(ax_info.get, + ('firstname', 'lastname')))) + or sreg_info.get('fullname') + or (email and email.split('@',1)[0].replace('.', ' ').title())) + + nickname = sreg_info.get('nickname') + + if self.groups_to_request and TeamsResponse: + teams_response = TeamsResponse.fromSuccessResponse(info) + if teams_response: + # be careful not to make user a member of any trac groups + # not named in groups_to_request + teams = set(teams_response.teams + ).intersection(self.groups_to_request) + if teams: + session_attr['openid.teams'] = ','.join(teams) + + if self.strip_protocol: + remote_user = remote_user[remote_user.find('://')+3:] + if self.strip_trailing_slash and remote_user[-1] == '/': + remote_user = remote_user[:-1] + if info.endpoint.canonicalID: + # You should authorize i-name users by their canonicalID, + # rather than their more human-friendly identifiers. That + # way their account with you is not compromised if their + # i-name registration expires and is bought by someone else. + message += (" This is an i-name, and its persistent ID is %s" + % (cgi.escape(info.endpoint.canonicalID),)) + remote_user = info.endpoint.canonicalID + + allowed = True + if self.re_white_list: + self.env.log.debug("Filtering REMOTE_USER '%s' through white-list." % remote_user) + allowed = False + for item in self.re_white_list: + if not allowed and item.match(remote_user): allowed = True - self.env.log.debug("User email white-listed.") - - if allowed and self.check_list: - allowed = False - params = {self.check_list_key: remote_user} - if email: - params['email'] = email - url = self.check_list + '?' + urllib.urlencode(params) - self.env.log.debug('OpenID check list URL: %s' % url) - try: - result = json.load(urllib.urlopen(url)) - if result[self.check_list_key]: - if self.check_list_username: - cl_username = unicode( - result[self.check_list_username]) - if not cl_username: - raise ValueError("Bad value for username") - allowed = True - except Exception, ex: - self.env.log.error('OpenID check_list failed: %s' % ex) - - if allowed: - cookie = hex_entropy() - cookie_lifetime = self.trac_auth_cookie_lifetime - - req.outcookie['trac_auth'] = cookie - req.outcookie['trac_auth']['path'] = req.href() - if cookie_lifetime > 0: - req.outcookie['trac_auth']['expires'] = cookie_lifetime - - session_attr[self.openid_session_identity_url_key] = info.identity_url - if email: - session_attr['email'] = email - if fullname: - session_attr['name'] = fullname - - self._commit_oidsession(oidsession, req) - - # First look for an existing authenticated session with - # matching identity_url. - self.env.log.debug('Checking URL: %s' % info.identity_url) - authname_for_identity_url = self.get_user(info.identity_url) - if authname_for_identity_url: - authname = authname_for_identity_url - ds = DetachedSession(self.env, authname) - # The user already exists, update team membership - # XXX: Should also update name and/or email? (This would - # be an API change.) - for name in ['openid.teams']: - if name in session_attr: - ds[name] = session_attr[name] - elif name in ds: - del ds[name] - ds.save() - else: - # New identity URL -> create new authname/user. - if self.check_list and self.check_list_username: - authname = cl_username - elif self.use_nickname_as_authname and nickname: - authname = nickname - elif session_attr.get('name'): - authname = session_attr['name'] - if self.combined_username: - authname = '%s <%s>' % (authname, remote_user) - else: - authname = remote_user + self.env.log.debug("User white-listed.") + if allowed and self.re_black_list: + self.env.log.debug("Filtering REMOTE_USER '%s' through black-list." % remote_user) + for item in self.re_black_list: + if item.match(remote_user): + allowed = False + self.env.log.debug("User black-listed.") + if allowed and self.re_email_white_list: + self.env.log.debug("Filtering email %r through email white-list." % email) + allowed = False + if email: + for item in self.re_email_white_list: + if not allowed and item.match(email): + allowed = True + self.env.log.debug("User email white-listed.") + + if allowed and self.check_list: + allowed = False + params = {self.check_list_key: remote_user} + if email: + params['email'] = email + url = self.check_list + '?' + urllib.urlencode(params) + self.env.log.debug('OpenID check list URL: %s' % url) + try: + result = json.load(urllib.urlopen(url)) + if result[self.check_list_key]: + if self.check_list_username: + cl_username = unicode( + result[self.check_list_username]) + if not cl_username: + raise ValueError("Bad value for username") + allowed = True + except Exception, ex: + self.env.log.error('OpenID check_list failed: %s' % ex) - # Possibly lower-case the authname. - if self.lowercase_authname: - authname = authname.lower() + if allowed: + cookie = hex_entropy() + cookie_lifetime = self.trac_auth_cookie_lifetime - if self.trust_authname: + req.outcookie['trac_auth'] = cookie + req.outcookie['trac_auth']['path'] = req.href() + if cookie_lifetime > 0: + req.outcookie['trac_auth']['expires'] = cookie_lifetime + + session_attr[self.openid_session_identity_url_key] = info.identity_url + if email: + session_attr['email'] = email + if fullname: + session_attr['name'] = fullname + + self._commit_oidsession(oidsession, req) + + # First look for an existing authenticated session with + # matching identity_url. + self.env.log.debug('Checking URL: %s' % info.identity_url) + authname_for_identity_url = self.get_user(info.identity_url) + if authname_for_identity_url: + authname = authname_for_identity_url ds = DetachedSession(self.env, authname) + # The user already exists, update team membership + # XXX: Should also update name and/or email? (This would + # be an API change.) + for name in ['openid.teams']: + if name in session_attr: + ds[name] = session_attr[name] + elif name in ds: + del ds[name] + ds.save() else: - # Make authname unique in case of collisions - def authnames(base): - yield base - for attempt in itertools.count(2): - yield "%s (%d)" % (base, attempt) - - users_and_groups_with_permissions = set( - user - for user, perm - in PermissionSystem(self.env).get_all_permissions()) - - for authname in authnames(authname): + # New identity URL -> create new authname/user. + if self.check_list and self.check_list_username: + authname = cl_username + elif self.use_nickname_as_authname and nickname: + authname = nickname + elif session_attr.get('name'): + authname = session_attr['name'] + if self.combined_username: + authname = '%s <%s>' % (authname, remote_user) + else: + authname = remote_user + + # Possibly lower-case the authname. + if self.lowercase_authname: + authname = authname.lower() + + if self.trust_authname: ds = DetachedSession(self.env, authname) - # At least in 0.12.2, this means no session exists. - no_session_exists = ds.last_visit == 0 and len(ds) == 0 - no_permissions_defined = authname not in users_and_groups_with_permissions - if (no_session_exists and no_permissions_defined): - # name is free :-) - break - # Set attributes for new user on the - # current anonymous session. It will be promoted to - # the new authenticated session on the next request - # (by Session.__init__). - # - # NB: avoid dict.update here to ensure that - # DetachedSession.__getitem__ gets a chance to - # normalize values - for name, value in session_attr.items(): - req.session[name] = value - self.env.log.info("Created new user '%s' for " - "OpenID identifier %s", authname, info.identity_url) - - req.authname = authname - - db = self.env.get_db_cnx() - cursor = db.cursor() - cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) " - "VALUES (%s, %s, %s, %s)", (cookie, authname, - self._get_masked_address(req.remote_addr), int(time.time()))) - db.commit() - - req.redirect(req.session.get('oid.referer') or self.env.abs_href()) - else: - message = 'You are not allowed here.' - elif info.status == consumer.CANCEL: - # cancelled - message = 'Verification cancelled' - elif info.status == consumer.SETUP_NEEDED: - if info.setup_url: - message = '<a href=%s>Setup needed</a>' % ( - quoteattr(info.setup_url),) + else: + # Make authname unique in case of collisions + def authnames(base): + yield base + for attempt in itertools.count(2): + yield "%s (%d)" % (base, attempt) + + users_and_groups_with_permissions = set( + user + for user, perm + in PermissionSystem(self.env).get_all_permissions()) + + for authname in authnames(authname): + ds = DetachedSession(self.env, authname) + # At least in 0.12.2, this means no session exists. + no_session_exists = ds.last_visit == 0 and len(ds) == 0 + no_permissions_defined = authname not in users_and_groups_with_permissions + if (no_session_exists and no_permissions_defined): + # name is free :-) + break + # Set attributes for new user on the + # current anonymous session. It will be promoted to + # the new authenticated session on the next request + # (by Session.__init__). + # + # NB: avoid dict.update here to ensure that + # DetachedSession.__getitem__ gets a chance to + # normalize values + for name, value in session_attr.items(): + req.session[name] = value + self.env.log.info("Created new user '%s' for " + "OpenID identifier %s", authname, info.identity_url) + + req.authname = authname + + with self.env.db_transaction as db: + cursor = db.cursor() + cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) " + "VALUES (%s, %s, %s, %s)", (cookie, authname, + self._get_masked_address(req.remote_addr), int(time.time()))) + db.commit() + + req.redirect(req.session.get('oid.referer') or self.env.abs_href()) + else: + message = 'You are not allowed here.' + elif info.status == consumer.CANCEL: + # cancelled + message = 'Verification cancelled' + elif info.status == consumer.SETUP_NEEDED: + if info.setup_url: + message = '<a href=%s>Setup needed</a>' % ( + quoteattr(info.setup_url),) + else: + # This means auth didn't succeed, but you're welcome to try + # non-immediate mode. + message = 'Setup needed' else: - # This means auth didn't succeed, but you're welcome to try - # non-immediate mode. - message = 'Setup needed' - else: - # Either we don't understand the code or there is no - # openid_url included with the error. Give a generic - # failure message. The library should supply debug - # information in a log. - message = 'Verification failed.' + # Either we don't understand the code or there is no + # openid_url included with the error. Give a generic + # failure message. The library should supply debug + # information in a log. + message = 'Verification failed.' - self._commit_oidsession(oidsession, req) + self._commit_oidsession(oidsession, req) add_stylesheet(req, 'authopenid/css/openid.css') add_script(req, 'authopenid/js/openid-jquery.js') @@ -838,17 +837,18 @@ class AuthOpenIdPlugin(Component): stale = int(time.time()) - expires authcookie = req.incookie.get('trac_auth') - db = self.env.get_db_cnx() - cursor = db.cursor() - if authcookie: - cursor.execute("DELETE FROM auth_cookie" - " WHERE cookie=%s OR time < %s", - (authcookie.value, stale)) - else: - cursor.execute("DELETE FROM auth_cookie" - " WHERE name=%s OR time < %s", - (req.authname, stale)) - db.commit() + with self.env.db_transaction as db: + cursor = db.cursor() + if authcookie: + cursor.execute("DELETE FROM auth_cookie" + " WHERE cookie=%s OR time < %s", + (authcookie.value, stale)) + else: + cursor.execute("DELETE FROM auth_cookie" + " WHERE name=%s OR time < %s", + (req.authname, stale)) + db.commit() + self._expire_cookie(req) custom_redirect = self.config['metanav'].get('logout.redirect') if custom_redirect: @@ -868,39 +868,39 @@ class AuthOpenIdPlugin(Component): def _get_name_for_cookie(self, req, cookie): masked_addr = self._get_masked_address(req.remote_addr) - db = self.env.get_db_cnx() - cursor = db.cursor() - if self.check_ip: - cursor.execute("SELECT name FROM auth_cookie " - "WHERE cookie=%s AND ipnr=%s", - (cookie.value, masked_addr)) - else: - cursor.execute("SELECT name FROM auth_cookie WHERE cookie=%s", - (cookie.value,)) - - row = cursor.fetchone() - if row: - name = row[0] - if self.timeout: - now = int(time.time()) - if self.check_ip: - cursor.execute("UPDATE auth_cookie SET time=%s " - "WHERE cookie=%s AND ipnr=%s AND name=%s", - (now, cookie.value, masked_addr, name)) - else: - cursor.execute("UPDATE auth_cookie SET time=%s " - "WHERE cookie=%s AND name=%s", - (now, cookie.value, name)) - - cookie_lifetime = self.trac_auth_cookie_lifetime - if cookie_lifetime > 0: - req.outcookie['trac_auth'] = cookie.value - req.outcookie['trac_auth']['path'] = req.href() - req.outcookie['trac_auth']['expires'] = cookie_lifetime - else: - # The cookie is invalid but we don't expire it because it might - # be generated by different trac authentication mechanism. - name = None + with self.env.db_transaction as db: + cursor = db.cursor() + if self.check_ip: + cursor.execute("SELECT name FROM auth_cookie " + "WHERE cookie=%s AND ipnr=%s", + (cookie.value, masked_addr)) + else: + cursor.execute("SELECT name FROM auth_cookie WHERE cookie=%s", + (cookie.value,)) + + row = cursor.fetchone() + if row: + name = row[0] + if self.timeout: + now = int(time.time()) + if self.check_ip: + cursor.execute("UPDATE auth_cookie SET time=%s " + "WHERE cookie=%s AND ipnr=%s AND name=%s", + (now, cookie.value, masked_addr, name)) + else: + cursor.execute("UPDATE auth_cookie SET time=%s " + "WHERE cookie=%s AND name=%s", + (now, cookie.value, name)) + + cookie_lifetime = self.trac_auth_cookie_lifetime + if cookie_lifetime > 0: + req.outcookie['trac_auth'] = cookie.value + req.outcookie['trac_auth']['path'] = req.href() + req.outcookie['trac_auth']['expires'] = cookie_lifetime + else: + # The cookie is invalid but we don't expire it because it might + # be generated by different trac authentication mechanism. + name = None - db.commit() + db.commit() return name