X-Git-Url: https://scm.cri.ensmp.fr/git/Plinn.git/blobdiff_plain/ad865412e1d18480a242f20b48043f27a20f0a94..e932032bdbb367869cd8c7346a98f6b7660c41dd:/RegistrationTool.py diff --git a/RegistrationTool.py b/RegistrationTool.py index 85133ff..8c2911d 100644 --- a/RegistrationTool.py +++ b/RegistrationTool.py @@ -32,10 +32,15 @@ from AccessControl.Permission import Permission from BTrees.OOBTree import OOBTree from Products.CMFCore.permissions import ManagePortal, AddPortalMember from Products.CMFCore.exceptions import AccessControl_Unauthorized +from Products.CMFDefault.exceptions import EmailAddressInvalid from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getUtilityByInterfaceName +from Products.CMFDefault.utils import checkEmailAddress from Products.GroupUserFolder.GroupsToolPermissions import ManageGroups from Products.Plinn.utils import Message as _ +from Products.Plinn.utils import translate +from Products.Plinn.utils import encodeQuopriEmail +from Products.Plinn.utils import encodeMailHeader from DateTime import DateTime from types import TupleType, ListType from uuid import uuid4 @@ -44,13 +49,16 @@ security = ModuleSecurityInfo('Products.Plinn.RegistrationTool') MODE_ANONYMOUS = 'anonymous' security.declarePublic('MODE_ANONYMOUS') +MODE_PASS_ANONYMOUS = 'pass_anonymous' +security.declarePublic('MODE_PASS_ANONYMOUS') + MODE_MANAGER = 'manager' security.declarePublic('MODE_MANAGER') MODE_REVIEWED = 'reviewed' security.declarePublic('MODE_REVIEWED') -MODES = [MODE_ANONYMOUS, MODE_MANAGER, MODE_REVIEWED] +MODES = [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_MANAGER, MODE_REVIEWED] security.declarePublic('MODES') DEFAULT_MEMBER_GROUP = 'members' @@ -121,7 +129,7 @@ class RegistrationTool(BaseRegistrationTool) : urlTool = getToolByName(self, 'portal_url') portal = urlTool.getPortalObject() - if mode in [MODE_ANONYMOUS, MODE_REVIEWED] : + if mode in [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_REVIEWED] : portal.manage_permission(AddPortalMember, roles = ['Anonymous', 'Manager'], acquire=1) elif mode == MODE_MANAGER : portal.manage_permission(AddPortalMember, roles = ['Manager', 'UserManager'], acquire=0) @@ -148,7 +156,7 @@ class RegistrationTool(BaseRegistrationTool) : p=Permission(AddPortalMember, [], portal) return p.getRoles() - if mode in [MODE_ANONYMOUS, MODE_REVIEWED] : + if mode in [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_REVIEWED] : if 'Anonymous' in rolesOfAddPortalMemberPerm() : return False elif mode == MODE_MANAGER : @@ -161,14 +169,34 @@ class RegistrationTool(BaseRegistrationTool) : security.declareProtected(AddPortalMember, 'addMember') def addMember(self, id, password, roles=(), groups=(DEFAULT_MEMBER_GROUP,), domains='', properties=None) : """ Idem CMFCore but without default role """ - BaseRegistrationTool.addMember(self, id, password, roles=roles, - domains=domains, properties=properties) - if self.getMode() in [MODE_ANONYMOUS, MODE_MANAGER] : + if self.getMode() != MODE_REVIEWED : gtool = getToolByName(self, 'portal_groups') mtool = getToolByName(self, 'portal_membership') utool = getToolByName(self, 'portal_url') portal = utool.getPortalObject() + + if self.getMode() == MODE_PASS_ANONYMOUS : + private_collections = portal.get('private_collections') + if not private_collections : + raise AccessControl_Unauthorized() + return + data = private_collections.data + lines = filter(None, [l.strip() for l in data.split('\n')]) + assert len(lines) % 3 == 0 + collecInfos = {} + for i in xrange(0, len(lines), 3) : + collecInfos[lines[i]] = {'pw' : lines[i+1], + 'path' : lines[i+2]} + if not (collecInfos.has_key(properties.get('collection_id')) and \ + collecInfos[properties.get('collection_id')]['pw'] == properties.get('collection_password')) : + raise AccessControl_Unauthorized('Wrong primary credentials') + return + + + BaseRegistrationTool.addMember(self, id, password, roles=roles, + domains=domains, properties=properties) + isGrpManager = mtool.checkPermission(ManageGroups, portal) ## TODO : CMF2.1 compat aclu = self.aq_inner.acl_users @@ -183,6 +211,9 @@ class RegistrationTool(BaseRegistrationTool) : aclu.changeUser(aclu.getGroupPrefix() +gid, roles=['Member', ]) g = gtool.getGroupById(gid) g.addMember(id) + else : + BaseRegistrationTool.addMember(self, id, password, roles=roles, + domains=domains, properties=properties) def afterAdd(self, member, id, password, properties): @@ -196,10 +227,46 @@ class RegistrationTool(BaseRegistrationTool) : """ add uuid / (userid, expiration) pair and return uuid """ self.clearExpiredPasswordResetRequests() mtool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IMembershipTool') - if mtool.getMemberById(userid) : + member = mtool.getMemberById(userid) + if not member : + try : + checkEmailAddress(userid) + member = mtool.searchMembers('email', userid) + if member : + userid = member[0]['username'] + member = mtool.getMemberById(userid) + except EmailAddressInvalid : + pass + if member : uuid = str(uuid4()) + while self._passwordResetRequests.has_key(uuid) : + uuid = str(uuid4()) self._passwordResetRequests[uuid] = (userid, DateTime() + 1) - return uuid + utool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IURLTool') + ptool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IPropertiesTool') + # fuck : mailhost récupéré avec getUtilityByInterfaceName n'est pas correctement + # wrappé. Un « unrestrictedTraverse » ne marche pas. + # mailhost = getUtilityByInterfaceName('Products.MailHost.interfaces.IMailHost') + portal = utool.getPortalObject() + mailhost = portal.MailHost + sender = encodeQuopriEmail(ptool.getProperty('email_from_name'), ptool.getProperty('email_from_address')) + to = encodeQuopriEmail(member.getMemberFullName(nameBefore=0), member.getProperty('email')) + subject = translate(_('How to reset your password on the %s website')) % ptool.getProperty('title') + subject = encodeMailHeader(subject) + options = {'fullName' : member.getMemberFullName(nameBefore=0), + 'siteName' : ptool.getProperty('title'), + 'resetPasswordUrl' : '%s/password_reset_form/%s' % (utool(), uuid)} + body = self.password_reset_mail(options) + message = self.echange_mail_template(From=sender, + To=to, + Subject=subject, + ContentType = 'text/plain', + charset = 'UTF-8', + body=body) + mailhost.send(message) + return + + return _('Unknown user name. Please retry.') security.declarePrivate('clearExpiredPasswordResetRequests') def clearExpiredPasswordResetRequests(self): @@ -211,19 +278,16 @@ class RegistrationTool(BaseRegistrationTool) : security.declarePublic('resetPassword') - def resetPassword(self, userid, uuid, password, confirm) : + def resetPassword(self, uuid, password, confirm) : record = self._passwordResetRequests.get(uuid) if not record : - return _('Invalid reset password request.') - - recUserid, expiration = record - - if recUserid != userid : - return _('Invalid userid.') + return None, _('Invalid reset password request.') + userid, expiration = record + now = DateTime() if expiration < now : self.clearExpiredPasswordResetRequests() - return _('Your reset password request has expired. You can ask a new one.') + return None, _('Your reset password request has expired. You can ask a new one.') msg = self.testPasswordValidity(password, confirm=confirm) if not msg : # None if everything ok. Err message otherwise. @@ -232,9 +296,9 @@ class RegistrationTool(BaseRegistrationTool) : if member : member.setSecurityProfile(password=password) del self._passwordResetRequests[uuid] - return _('Password successfully resetted.') + return userid, _('Password successfully updated.') else : - return _('"%s" username not found.') % userid + return None, _('"%s" username not found.') % userid InitializeClass(RegistrationTool) \ No newline at end of file