summaryrefslogtreecommitdiff
path: root/Mailman/SecurityManager.py
Commit message (Collapse)AuthorAgeFilesLines
* FSF office has moved. chdcking in for MAIN branch.tkikuchi2005-08-271-1/+1
|
* parsecookie(): Be defensive about bogus cookie data.bwarsaw2003-02-041-2/+6
|
* CheckCookie(), __checkone(), parsecookie(): A fix for the MM2.0/MM2.1bwarsaw2003-01-311-12/+22
| | | | | | | | cookie problem. We can't use the Cookie module to parse the cookie because it's too strict in what it accepts. Parse it ourselves using re.split(). Should close SF bug # 664466.
* Updated comments to reflect that NotAMemberError is the one truebwarsaw2002-12-021-3/+3
| | | | exception that can get raised.
* Authenticate(): Checking in a change discussed a while ago onbwarsaw2002-08-291-8/+6
| | | | | | | | mailman-developers. There's an inconsistent use of the MemberAdaptor API -- authenticateMember() is never called. This change seems to work just fine. Also: whitespace normalization.
* Authenticate(): SF bug # 585776 complains that crypt.crypt() can raisebwarsaw2002-07-241-2/+14
| | | | | | | | | a TypeError if its second argument contains null bytes. I have a hard time understanding how that could happen, but it must be related to a MM2.0.x upgrade. This patch should fix the problem by catching and ignoring the TypeError, which is equivalent to a failed challenge.
* CheckCookie(): If the SimpleCookie constructor throws a CookieError,bwarsaw2002-01-291-1/+4
| | | | catch it and return false.
* "import Cookie" instead of "from Cookie import SimpleCookie as Cookie"bwarsaw2002-01-111-12/+9
| | | | | | | | | | | | | The latter broke the upgrade script when upgrading from MM2.1a2 to current cvs. This is because bin/update imports Mailman.MailList which imports Mailman.SecurityManager which, if /that/ tries to from...import...as will fail with an import error since there's still a residual old Cookie.py laying around that doesn't have a SimpleCookie class. Once bin/update does its thing and gets rid of Mailman/Cookie.py{,c} we're safe, but for now this is the best way to worm around the problem.
* AuthContextInfo(): If ALLOW_SITE_ADMIN_COOKIES is true, and there is abwarsaw2002-01-061-7/+12
| | | | | site password, and we're doing AuthSiteAdmin, then issue a secret/key combination that allows the site password to be cookie-fied.
* CheckCookie(): Let's be explicit about using the Cookie.SimpleCookiebwarsaw2001-11-201-6/+19
| | | | | | | | | | | class to decode the cookie data so there's no possibility of unpickling exploits of untrusted data. I'm still mildly concerned about using marshal.loads() to de-serialize the cookie data we want to use for authorization, although I think we're more or less safe for the reasons described in the preceding comment. I should probably think about this some more, possibly using the newly documented pickle anti-exploit measures.
* AuthContextInfo(): Python 2.x's Cookie.py module is strict about legalbwarsaw2001-10-091-6/+7
| | | | | | | | | | | | | | | | | | characters in keys, and it complains about the `@' signs in the email addresses of AuthUser keys. So we'll obscure the email address, changing `@' to `--at--', which contains only happy characters. This doesn't affect auto-guessing of the user based on the presence of the cookie, because we just need to unobscure whatever follows the `user+' prefix. WebAuthenticate(): MMNotAMemberError -> NotAMemberError MakeCookie(): Raise ValueError instead of MMBadUserError. CheckCookie(): The prefix for AuthUser is listname+user+, and here's where we unobscure anything we've found.
* AuthContextInfo(): Python's standard Cookie.py doesn't allow colons inbwarsaw2001-10-041-2/+2
| | | | | | | | the key. It's strictly interpreting the relevant RFC. We may change Cookie.py to be more relaxed, but instead of trying to maintain our own copy of this file, we'll just change the separator to be a `+' intead of a `:' -- Cookie.py seems happy with this.
* Use Python's default Cookie.py module instead of our own copy.bwarsaw2001-10-011-1/+1
|
* MakeCookie(): If the secret isn't a string, raise MMBadUserError.bwarsaw2001-08-161-2/+2
| | | | | __checkone(): Likewise, if the secret isn't a string, return 0 (i.e. no the user isn't authenticated).
* InitVars(): With the new mixin architecture, InitVars() needs to takebwarsaw2001-07-191-19/+7
| | | | | | | | | | | | | zero arguments, so we remove the crypted_password parameter. This means that self.password will be set in MailList instead. AuthContextInfo(): Instead of getting the user password directly out of self.passwords, use the API method getMemberPassword() -- which itself raises MMNotAMemberError if the user isn't a member of the list. ChangeUserPassword(): Removed. Use the new setMemberPassword() API method.
* SecurityManager.MakeCookie(): 'MMBadUserError' -> 'Errors.MMBadUserError'twouters2001-07-101-1/+1
|
* ConfirmUserPassword(): Obsolete; removed.bwarsaw2001-07-031-27/+49
| | | | | | | | | | | | | AuthContextInfo(): Allow `user' argument to be optional; default to None. Authenticate(): Re-install backwards compatibility for pre-MM2.1 list passwords. For AuthListAdmin context only, if the sha check fails, fallback to crypt (if the crypt module could be imported) and md5 checks. If either of the latter two matches, assume that the list password is "old style" and auto-upgrade it to the sha password, based on the matching plain text response. This way, MM2.0.x list passwords won't just be broken upon an upgrade.
* CheckCookie(): If the authcontext is AuthUser and the `user' argumentbwarsaw2001-06-011-1/+27
| | | | | | | | | | | | | is false, then scan the cookie keys for user names. This is used in private archive authentication (which doesn't have a user context in the url), so that if a user has already authenticated to edit their options, they get into the private archives with no login necessary. Note that this does /not/ open a hole for user option pages because those have a user context in the url which is passed to CheckCookie and must match explicitly. __checkone(): Does one authcontext/user authentication.
* Authenticate(): When sha hex digesting the response, save the resultsbwarsaw2001-05-311-2/+4
| | | | | in a temporary variable and check that variable against the secret (this is so that subsequent checks have the raw password).
* Changes to support the new world order of authentication, usingbwarsaw2001-05-311-61/+150
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | authorization contexts and the roles of User, List Owner, List Moderator, (List) Creator/Destroyer, Site Administrator. Specifically, InitVars(): Add a mod_password attribute that can contain the sha hashed list moderator's password. ValidAdminPassword(), ConfirmAdminPassword(): Removed as obsolete. AuthContextInfo(): Given an authorization context, and optionally a user (if authcontext == AuthUser), return the context's secret and cookie key. The tuple (None, None) is returned if the authcontext is bogus. MMNotAMemberError is raised if the user isn't a member of the list, and MMBadUserError is raised if the user's secret is None. Authenticate(): The non-web way of doing authentication. Takes a list of allowed authcontexts (and optionally a user name if AuthUser is one of those contexts), and a response string (i.e. password). Returns the authcontext from the argument sequence that matches the response, or UnAuthorized if none of them did. WebAuthenticate(): The web way of doing authentication. The arguments are the same as Authenticate(), but first the cookie data is checked. If that fails, then Authenticate() is used. Returns a flag indicating whether authentication succeeded or not. MakeCookie(): Now takes an authcontext and optionally a user (required if authcontext is AuthUser). Generates a cookie item for this context. ZapCookie(): Now takes an authcontext and optionally a user (required if authcontext is AuthUser). Generates an empty cookie item for this context, effectively logging out that authcontext. CheckCookie(): Now takes an authcontext and optionally a user (required if authcontext is AuthUser). Returns a flag indicating whether the authcontext's cookie matches the expected value, i.e. whether they are cookie authenticated or not. ChangeUserPassword(): Remove the test for IsListInitialized(), and removed the Save() call, since all paths to this method should be wrapped in the standard lock-modify-save-unlock fence.
* WebAuthenticate(): Minor simplification.bwarsaw2001-05-161-3/+3
|
* ValidAdminPassword(): CheckSiteAdminPassword -> check_global_passwordbwarsaw2001-05-091-2/+2
|
* ValidAdminPassword(): First, use SHA1 as the default hash, and comparebwarsaw2001-02-151-18/+25
| | | | | | | | | | | the response against the SHA encrypted password. If that fails, and the crypt module can be imported, try that as a fallback, but if that succeeds, update the password to be the SHA1 version. MakeCookie(), CheckCookie(): Use Python 2.0's binascii.{un,}hexlify() functions instead of the slower (and obsolete) ones in Utils.py. ExtractApproval(): Removed.
* SetSiteAdminPassword(), CheckSiteAdminPassword(): These are betterbwarsaw2000-10-021-20/+2
| | | | | suited in Utils than in the SecurityManager class because they don't require the MailList object at all.
* ZapCookie(): add a comment about why expires=0 isn't set here.bwarsaw2000-07-211-0/+1
|
* Several changes to the cookie management code, to support sessionbwarsaw2000-07-201-13/+29
| | | | | | | | | | | | | | | | | | | | cookies by default. Specifically, MakeCookie(): We don't include the expires time in the mac or in the marshaled state-tuple. These cookies live until the browser is exited or the user explicitly logs out. In order to tell browsers this is a session cookie, we do not set the cookie fields `Expires' or `Max-Age' explicitly (when ADMIN_COOKIE_LIFE <= 0, as it is by default). Also, set the RFC 2109 required `Version' field. ZapCookie(): New method which creates a `session-logout' Set-Cookie: header. According to RFC 2109, setting `Max-Age' to 0 ought to be enough to zap the cookie, but for compatibility with the old Netscape cookie spec, we also set the cookie data to the empty string. CheckCookie(): The state-tuple and the mac no longer contain the expired value. No need to test for now>expires and raise MMExpiredCookieError either.
* Several changes which will hopefully fix the cookie re-authenticationbwarsaw2000-07-191-37/+33
| | | | | | | | | | | | | | | | | | | | | | | problem. Specifically, WebAuthenticate(): Coding style changes. MakeCookie(): Create the cookie value in such a way as to guarantee that only the characters [0-9][a-f] are used. This should eliminate the need for the ugly quote-hack in CheckCookie(), and eliminate the possibility that wacky characters like semicolon, comma, and space (not to mention binary data) can confuse the browsers. Specifically, we marshal the tuple ourselves and hexlify the results, setting the key to a string. That way we avoid the Cookie module pickling the data and creating a binary string. Also, coerce both `issued' and `expires' to integers. Use sha module and hexdigest() instead of md5 and digest() to hash password+now+expires. CheckCookie(): Remove the crufty cookie data quote-hack. Decode the cookie value by unhexlifying and unmarshaling the string value ourselves. Use sha module hexdigest() instead of md5's digest().
* Update the copyright lines to include the years 1999 & 2000.bwarsaw2000-03-211-1/+1
|
* MakeCookie(), CheckCookie(): Don't include the client's IP address inbwarsaw1999-12-091-19/+17
| | | | | | the mac and cookie. This breaks for some folks going through proxies, since the client IP will change. I don't think this reduces our security at all.
* CheckCookie(): Watch out for cookiedata getting truncated to bebwarsaw1999-11-261-4/+6
| | | | | shorter than len(key). Just let it fail normally in those cases. Fixes PR#158.
* Remove some extraneous parens.bwarsaw1999-09-041-11/+9
| | | | ExtractApproval(): Use `is' test to compare against None, not ==
* ConfirmUserPassword(): It's possible that user is None. Raise abwarsaw1999-07-221-0/+2
| | | | MMBadUserError in that case.
* MakeCookie(): Set cookie's "path" based on the list-specific settinghmeland1999-07-221-1/+1
| | | | web_page_url instead of the installation-global mm_cfg.DEFAULT_URL.
* CheckCookie(): Workaround for IE4.01 (and other pre-5.0 MSIEs?) bug inbwarsaw1999-07-161-2/+17
| | | | | their cookie storing algorithm. This fixes PR#80, but does so with a simpler approach than the posted patch.
* SetSiteAdminPassword(): Open data/adm.pw with Utils.open_ex() so webwarsaw1999-07-091-5/+3
| | | | | | | | | | can exactly specify the permissions on the file. We don't need to save the umask since open_ex() does this. The permissions must be exactly 0640, which restricts as much as possible. Group must be able to read the file or site-password override in the Web interface will not work. Fixes PR#67
* SecurityManager:hmeland1999-06-131-11/+43
| | | | | | | | | | | | | | | | | | * New method WebAuthenticate(). Takes up to three keyword arguments: user-address, password and cookie-suffix. If password is supplied (and authenticates OK), issue a cookie -- otherwise try to do authentication based on cookies. * MakeCookie(): Changed to actually return a finished Cookie object. Takes one (non-optional) argument; the created cookie's name. Fixed bug in setting of cookie's path. * CheckCookie(): Now takes cookie's name as single argument, and can raise various MMAuthenticationErrors if that cookie doesn't authenticate OK. admin.py: Do explicit re-authentication when changing list admin password. admin.py, admindb.py and private.py: Removed isAuthenticated() function -- use MailList.WebAuthenticate() instead. This removed the need to import Cookie, so now we don't.
* Changes to fix the CGI cookie security flaw reported by John Morton.hmeland1999-06-111-0/+27
| | | | | | | | | SecurityManager: New functions MakeCookie() and CheckCookie(). These functions work with cookies containing cookie creation and expire time, the client's IP number, and a checksum hash of these values as well as a secret (the lists (encrypted) admin password). admin.py, admindb.py and private.py: isAuthenticated now uses these new cookie functions.
* Sweeping changes to hopefully and finally (for 1.0 at least) make sanebwarsaw1999-03-291-19/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | address case matching. These changes require the DATA_FILE_VERSION to be bumped, which should auto-update your config.db files. I sure hope this works correctly! Details of changes: MailList.GetUserSubscribedAddress(): New method. If the address is a member, this returns the case-preserved address the user is subscribed with. If not a member, None is returned. MailList.GetUserCanonicalAddress(): New method. If the address is a member, this returns the lowercased address the user is subscribed with. If not a member, None is returned. MailList.FindUser(): Wrote down, in a big comment, the constraints for the dictionaries self.members, self.digest_members, self.passwords. This wasn't always followed, but now it should be. FindUser() is now also guaranteed to return the lowercased version of the subscribed email address. This wasn't always the case. FindUser() also provides a shortcut for the common case. ApprovedAddMember(): Guarantee that passwords stored in self.passwords are keyed off the lowercased address. Deliverer.MailUserPassword(): Find the user's password using the lowercased version of their address. However, be sure to use their case-preserved address for the recipient of the password email. Digester.SetUserDigest(): Fixed a fairly old bug where a user switching from regular to digest membership (or vice versa) would get their case-preserved address blown away. I don't think there's any way to recover this information, but at least now we properly save it. SecurityManager.ConfirmUserPassword(): Simplified address matching stuff, since we now guarantee that FindUser() will return a lowercased address, and that the passwords dictionary has lowercased keys. FindUser() will return None if the address isn't found, and it also has a built-in shortcut so that the more expensive FindMatchingAddresses() isn't called in the common case. I eliminated the case-insensitive password comparision that Ken rightly questioned in his comment. admin.py: In the list of members, display a member's case-preserved address instead of their lowercased address. Also, obscure the URL in the hyperlink (probably not terribly necessary). handle_opts.py: When the password can't be found (when emailing it), put the address we tried to find in the result message. Makes for better debugging. options.py: Use a better mechanism for finding if the member has a case-preserved address different from their lowercased address.
* .ConfirmUserPassword(): Someone is setting (inklm1998-12-101-4/+8
| | | | | | | | | | | Digester.SetUserDigest(), and possibly other places) the members dict values to 1 now, as well as 0, breaking the user password recognition. This is fucked up. Anyway, i'm dealing with that by not checking the for a 0 from the get, but rather assuming a string returned means that the returned value should be used instead of the index. The complications with the different values should be fixed, as well, but i no longer know what the right thing is, because i don't know the purpose of the use of 1 instead of 0, if any. Sigh.
* .ConfirmUserPassword(): Was broken by the case-sensitive subscriptionklm1998-11-241-7/+16
| | | | | | | | | | | name optimizations - provisions to fix it are gross. It would be nice to have an abstraction for getting the user account name under which their password is registered (which i would call the normalized account name). I suspect that FindUser() could serve for that, but i'm not certain what the optimizations considerations are. I am afraid that it is significantly more confusing, overall, to figure out which subscription name to use (user-specified case-preserved, or lower case) in what situation.
* This change implements storing list members and digest members ascotton1998-11-191-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | dicts instead of lists, which optimizes Utils.FindMatchingAddresses and general membership management, especially for large lists. MailList.py now supplies .GetMembers() and .GetDigestMembers() to supply the data in list form to anything that needs it that way. An new install showed this worked fine with some cursory testing of the cgi's and interactive poking around. A detailed listing of the changes follows: Mailman/Defaults.py.in: change data version to 11 Mailman/Digester.py: initvars now instantiates digest_members as {} instead of [] lines 113-114 and 121-122 now use del This change implements storing list members and digest members as dicts instead of lists, which optimizes Utils.FindMatchingAddresses and general membership management, especially for large lists. MailList.py now supplies .GetMembers() and .GetDigestMembers() to supply the data in list form to anything that needs it that way. Though INSTALL shows up on the changed files section, a diff a few seconds ago didn't show any differences in that file, so I hope nobody changed it in the interim. An new install showed this worked fine with some cursory testing of the cgi's and interactive poking around. A detailed listing of the changes follows: Mailman/Defaults.py.in: change data version to 11 Mailman/Digester.py: initvars now instantiates digest_members as {} instead of [] lines 113-114 and 121-122 now use del list.[digest_]member instead of list.[digest_]members.remove when figuring who to actually send digests to, use list.GetDigestMembers() instead of list.digest_members. Mailman/HTMLFormatter: now uses list.Get[Digest]Members to get subscribers, and length of digested subscribers and regular members MailCommandHandler, SecurityManager,Cgi/handle_opts, Cgi/options: all simple replacements of list.[digest_]members with list.Get[Digest]Members(). Mailman/Cgi/admin.py: mostly simple replacements of list.[digest_]members with the Get..() methods, however, the membership management section now works much quicker and changes digest->nodigest subscriptions via dictionary manipulations. Mailman/versions.py: updates lists to use dicts and changed list.[digest_]members to use the list.Get[Digest]Members() methods. Mailman/Utils.py: added a function "GetPossibleMatchingAddresses" which when fed an address, returns the list of addresses that "smart" address matching would match. changed FindMatchingAddresses(name, list) to use a new signature: FindMatchingAddresses(name, *dicts), where dicts is a list of dictionaries keyed by addresses. Just realized that this would better be FindMatchingAddresses(name, dict, *dicts) so that it enforces atleast 2 args... I'll make that change in a sec. All uses of FindMatchingAddresses have been changed to fit the new arguments. scott ----:**-F1 cvs30458aaa 1:12PM 0.98 Mail (Text Fill)--L59--32%------------------------------------------- ?
* Convert all module names to their new names.bwarsaw1998-06-191-10/+15
|
* The site password wasnt working because:viega1998-06-031-1/+1
| | | | | | 1) the password data file was changed to g-w (which is good) 2) the open(...) used "r+" instead of "r" (which is bad) I changed #2...
* Added mm_crypt, which trys to import crypt, and provides a wrapperviega1998-05-301-4/+4
| | | | | | | interface to an md5 digest if the import fails. This way, we don't have to tell people to recompile python if they compiled it out of the box. (since crypt is no longer in by default). mm_security now uses mm_crypt instead of crypt.
* SITE_PW_FILE: Use DATA_DIR as directory to store adm.pw inbwarsaw1998-05-291-1/+1
|
* Calculate site password file location in global scope, using abwarsaw1998-05-261-4/+6
| | | | | different variable from mm_cfg. The file location is stored in SITE_PW_FILE.
* Fixed a typo in the zipcode.viega1998-05-261-2/+2
|
* Added copyright notices to all source files where I am legally entitled to ↵viega1998-05-251-1/+18
| | | | | | | do so. Added a copy of the GNU GPL. Added information about mailman-users in README, and reworded some text in there (made the credits less verbose... perhaps they should move to a credits file?)
* Use new mm_message __delitem__ discipline.klm1998-04-131-2/+2
|
* Preparing to package a distribution - add a module docstring andmailman1998-04-091-0/+5
| | | | __version__ info.