summaryrefslogtreecommitdiff
path: root/Mailman/SecurityManager.py
diff options
context:
space:
mode:
authorbwarsaw2006-12-29 22:20:25 +0000
committerbwarsaw2006-12-29 22:20:25 +0000
commitf4a456a83b630feb294724ab462c87ca1ce1c3ae (patch)
treec5c88540dae8306d11671f603d8975b01803ea16 /Mailman/SecurityManager.py
parentae185106a624bfa7888aa8722d35194d3c5150e8 (diff)
downloadmailman-f4a456a83b630feb294724ab462c87ca1ce1c3ae.tar.gz
mailman-f4a456a83b630feb294724ab462c87ca1ce1c3ae.tar.zst
mailman-f4a456a83b630feb294724ab462c87ca1ce1c3ae.zip
Diffstat (limited to 'Mailman/SecurityManager.py')
-rw-r--r--Mailman/SecurityManager.py65
1 files changed, 13 insertions, 52 deletions
diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py
index 3865071b5..6740a958f 100644
--- a/Mailman/SecurityManager.py
+++ b/Mailman/SecurityManager.py
@@ -28,7 +28,7 @@
#
# Each cookie has the following ingredients: the authorization context's
# secret (i.e. the password, and a timestamp. We generate an SHA1 hex
-# digest of these ingredients, which we call the `mac'. We then marshal
+# digest of these ingredients, which we call the 'mac'. We then marshal
# up a tuple of the timestamp and the mac, hexlify that and return that as
# a cookie keyed off the authcontext. Note that authenticating the user
# also requires the user's email address to be included in the cookie.
@@ -48,7 +48,6 @@
import os
import re
-import md5
import sha
import time
import urllib
@@ -64,19 +63,15 @@ from Mailman import Errors
from Mailman import Utils
from Mailman.configuration import config
-try:
- import crypt
-except ImportError:
- crypt = None
-
log = logging.getLogger('mailman.error')
+dlog = logging.getLogger('mailman.debug')
+
+SLASH = '/'
class SecurityManager:
def InitVars(self):
- # We used to set self.password here, from a crypted_password argument,
- # but that's been removed when we generalized the mixin architecture.
# self.password is really a SecurityManager attribute, but it's set in
# MailList.InitVars().
self.mod_password = None
@@ -144,50 +139,15 @@ class SecurityManager:
if ok:
return Defaults.AuthSiteAdmin
elif ac == Defaults.AuthListAdmin:
- def cryptmatchp(response, secret):
- try:
- salt = secret[:2]
- if crypt and crypt.crypt(response, salt) == secret:
- return True
- return False
- except TypeError:
- # BAW: Hard to say why we can get a TypeError here.
- # SF bug report #585776 says crypt.crypt() can raise
- # this if salt contains null bytes, although I don't
- # know how that can happen (perhaps if a MM2.0 list
- # with USE_CRYPT = 0 has been updated? Doubtful.
- return False
# The password for the list admin and list moderator are not
# kept as plain text, but instead as an sha hexdigest. The
# response being passed in is plain text, so we need to
- # digestify it first. Note however, that for backwards
- # compatibility reasons, we'll also check the admin response
- # against the crypted and md5'd passwords, and if they match,
- # we'll auto-migrate the passwords to sha.
+ # digestify it first.
key, secret = self.AuthContextInfo(ac)
if secret is None:
continue
sharesponse = sha.new(response).hexdigest()
- upgrade = ok = False
if sharesponse == secret:
- ok = True
- elif md5.new(response).digest() == secret:
- ok = upgrade = True
- elif cryptmatchp(response, secret):
- ok = upgrade = True
- if upgrade:
- save_and_unlock = False
- if not self.Locked():
- self.Lock()
- save_and_unlock = True
- try:
- self.password = sharesponse
- if save_and_unlock:
- self.Save()
- finally:
- if save_and_unlock:
- self.Unlock()
- if ok:
return ac
elif ac == Defaults.AuthListModerator:
# The list moderator password must be sha'd
@@ -227,21 +187,22 @@ class SecurityManager:
return False
def _cookie_path(self):
- return '/'.join(os.environ['SCRIPT_NAME'].split('/')[:-1]) + '/'
+ script_name = os.environ.get('SCRIPT_NAME', '')
+ return SLASH.join(script_name.split(SLASH)[:-1]) + SLASH
def MakeCookie(self, authcontext, user=None):
key, secret = self.AuthContextInfo(authcontext, user)
- if key is None or secret is None or not isinstance(secret, str):
+ if key is None or secret is None or not isinstance(secret, basestring):
raise ValueError
# Timestamp
issued = int(time.time())
# Get a digest of the secret, plus other information.
- mac = sha.new(secret + `issued`).hexdigest()
+ mac = sha.new(secret + repr(issued)).hexdigest()
# Create the cookie object.
c = Cookie.SimpleCookie()
c[key] = binascii.hexlify(marshal.dumps((issued, mac)))
c[key]['path'] = self._cookie_path()
- # We use session cookies, so don't set `expires' or `max-age' keys.
+ # We use session cookies, so don't set 'expires' or 'max-age' keys.
# Set the RFC 2109 required header.
c[key]['version'] = 1
return c
@@ -290,7 +251,7 @@ class SecurityManager:
for k in c.keys():
if k.startswith(prefix):
usernames.append(k[len(prefix):])
- # If any check out, we're golden. Note: `@'s are no longer legal
+ # If any check out, we're golden. Note: '@'s are no longer legal
# values in cookie keys.
for user in [Utils.UnobscureEmail(u) for u in usernames]:
ok = self.__checkone(c, authcontext, user)
@@ -307,7 +268,7 @@ class SecurityManager:
key, secret = self.AuthContextInfo(authcontext, user)
except Errors.NotAMemberError:
return False
- if not c.has_key(key) or not isinstance(secret, str):
+ if key not in c or not isinstance(secret, basestring):
return False
# Undo the encoding we performed in MakeCookie() above. BAW: I
# believe this is safe from exploit because marshal can't be forced to
@@ -329,7 +290,7 @@ class SecurityManager:
return False
# Calculate what the mac ought to be based on the cookie's timestamp
# and the shared secret.
- mac = sha.new(secret + `issued`).hexdigest()
+ mac = sha.new(secret + repr(issued)).hexdigest()
if mac <> received_mac:
return False
# Authenticated!