diff --git a/roundup/mailgw.py b/roundup/mailgw.py
index b5d802d150b6b2af0db135c5cd50c5c3536c30be..edbfb89254cb66621090fc246985b0dd8fb93583 100644 (file)
--- a/roundup/mailgw.py
+++ b/roundup/mailgw.py
an exception, the original message is bounced back to the sender with the
explanatory message given in the exception.
-$Id: mailgw.py,v 1.77 2002-07-18 11:17:31 gmcm Exp $
+$Id: mailgw.py,v 1.81 2002-08-19 00:21:56 richard Exp $
'''
class MailUsageHelp(Exception):
pass
-class UnAuthorized(Exception):
+class Unauthorized(Exception):
""" Access denied """
+def initialiseSecurity(security):
+ ''' Create some Permissions and Roles on the security object
+
+ This function is directly invoked by security.Security.__init__()
+ as a part of the Security object instantiation.
+ '''
+ security.addPermission(name="Email Registration",
+ description="Anonymous may register through e-mail")
+ p = security.addPermission(name="Email Access",
+ description="User may use the email interface")
+ security.addPermissionToRole('Admin', p)
+
class Message(mimetools.Message):
''' subclass mimetools.Message so we can retrieve the parts of the
message...
m.append('\n\nMail Gateway Help\n=================')
m.append(fulldoc)
m = self.bounce_message(message, sendto, m)
- except UnAuthorized, value:
+ except Unauthorized, value:
# just inform the user that he is not authorized
sendto = [sendto[0][1]]
m = ['']
# handle the users
#
- # Don't create users if ANONYMOUS_REGISTER_MAIL is denied
- # ... fall back on ANONYMOUS_REGISTER if the other doesn't exist
+ # Don't create users if anonymous isn't allowed to register
create = 1
- if hasattr(self.instance, 'ANONYMOUS_REGISTER_MAIL'):
- if self.instance.ANONYMOUS_REGISTER_MAIL == 'deny':
- create = 0
- elif self.instance.ANONYMOUS_REGISTER == 'deny':
+ anonid = self.db.user.lookup('anonymous')
+ if not self.db.security.hasPermission('Email Registration', anonid):
create = 0
- author = self.db.uidFromAddress(message.getaddrlist('from')[0],
+ # ok, now figure out who the author is - create a new user if the
+ # "create" flag is true
+ author = uidFromAddress(self.db, message.getaddrlist('from')[0],
create=create)
+
+ # no author? means we're not author
if not author:
- raise UnAuthorized, '''
+ raise Unauthorized, '''
You are not a registered user.
Unknown address: %s
'''%message.getaddrlist('from')[0][1]
+ # make sure the author has permission to use the email interface
+ if not self.db.security.hasPermission('Email Access', author):
+ raise Unauthorized, 'You are not permitted to access this tracker.'
+
# the author may have been created - make sure the change is
# committed before we reopen the database
self.db.commit()
# look up the recipient - create if necessary (and we're
# allowed to)
- recipient = self.db.uidFromAddress(recipient, create)
+ recipient = uidFromAddress(self.db, recipient, create)
# if all's well, add the recipient to the list
if recipient:
return nodeid
+def extractUserFromList(userClass, users):
+ '''Given a list of users, try to extract the first non-anonymous user
+ and return that user, otherwise return None
+ '''
+ if len(users) > 1:
+ for user in users:
+ # make sure we don't match the anonymous or admin user
+ if userClass.get(user, 'username') in ('admin', 'anonymous'):
+ continue
+ # first valid match will do
+ return user
+ # well, I guess we have no choice
+ return user[0]
+ elif users:
+ return users[0]
+ return None
+
+def uidFromAddress(db, address, create=1):
+ ''' address is from the rfc822 module, and therefore is (name, addr)
+
+ user is created if they don't exist in the db already
+ '''
+ (realname, address) = address
+
+ # try a straight match of the address
+ user = extractUserFromList(db.user, db.user.stringFind(address=address))
+ if user is not None: return user
+
+ # try the user alternate addresses if possible
+ props = db.user.getprops()
+ if props.has_key('alternate_addresses'):
+ users = db.user.filter(None, {'alternate_addresses': address},
+ [], [])
+ user = extractUserFromList(db.user, users)
+ if user is not None: return user
+
+ # try to match the username to the address (for local
+ # submissions where the address is empty)
+ user = extractUserFromList(db.user, db.user.stringFind(username=address))
+
+ # couldn't match address or username, so create a new user
+ if create:
+ return db.user.create(username=address, address=address,
+ realname=realname, roles=db.config.NEW_EMAIL_USER_ROLES)
+ else:
+ return 0
+
def parseContent(content, keep_citations, keep_body,
blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'),
eol=re.compile(r'[\r\n]+'),
#
# $Log: not supported by cvs2svn $
+# Revision 1.80 2002/08/01 00:56:22 richard
+# Added the web access and email access permissions, so people can restrict
+# access to users who register through the email interface (for example).
+# Also added "security" command to the roundup-admin interface to display the
+# Role/Permission config for an instance.
+#
+# Revision 1.79 2002/07/26 08:26:59 richard
+# Very close now. The cgi and mailgw now use the new security API. The two
+# templates have been migrated to that setup. Lots of unit tests. Still some
+# issue in the web form for editing Roles assigned to users.
+#
+# Revision 1.78 2002/07/25 07:14:06 richard
+# Bugger it. Here's the current shape of the new security implementation.
+# Still to do:
+# . call the security funcs from cgi and mailgw
+# . change shipped templates to include correct initialisation and remove
+# the old config vars
+# ... that seems like a lot. The bulk of the work has been done though. Honest :)
+#
+# Revision 1.77 2002/07/18 11:17:31 gmcm
+# Add Number and Boolean types to hyperdb.
+# Add conversion cases to web, mail & admin interfaces.
+# Add storage/serialization cases to back_anydbm & back_metakit.
+#
# Revision 1.76 2002/07/10 06:39:37 richard
# . made mailgw handle set and modify operations on multilinks (bug #579094)
#