def deactivate_profile_view(context, request): page_title = 'Deactivate user account for %s %s' % (context.firstname, context.lastname) api = TemplateAPI(context, request, page_title) name = context.__name__ myself = authenticated_userid(request) == context.__name__ if not api.user_is_admin and not myself: raise Forbidden("Only owner or admin can deactivate profile") confirm = request.params.get('confirm') if confirm: try: find_users(context).remove(name) except KeyError: pass workflow = get_workflow(IProfile, 'security', context) workflow.transition_to_state(context, request, 'inactive') if myself: return logout_view(context, request, reason='User removed') query = {'status_message': 'Deactivated user account: %s' % name} parent = context.__parent__ location = resource_url(parent, request, query=query) return HTTPFound(location=location) # Show confirmation page. return dict(api=api, myself=myself)
def delete_profile_view(context, request): confirm = request.params.get('confirm') if confirm: parent = context.__parent__ name = context.__name__ find_users(context).remove(name) del parent[name] if authenticated_userid(request) == name: return logout_view(context, request, reason='User removed') query = {'status_message': 'Deleted profile: %s' % name} location = model_url(parent, request, query=query) return HTTPFound(location=location) page_title = 'Delete Profile for %s %s' % (context.firstname, context.lastname) api = TemplateAPI(context, request, page_title) # Get a layout return render_template_to_response( 'templates/delete_profile.pt', api=api, )
def deactivate_profile_view(context, request): name = context.__name__ myself = authenticated_userid(request) == context.__name__ confirm = request.params.get('confirm') if confirm: try: find_users(context).remove(name) except KeyError: pass workflow = get_workflow(IProfile, 'security', context) workflow.transition_to_state(context, request, 'inactive') if myself: return logout_view(context, request, reason='User removed') query = {'status_message': 'Deactivated user account: %s' % name} parent = context.__parent__ location = resource_url(parent, request, query=query) return HTTPFound(location=location) page_title = 'Deactivate user account for %s %s' % (context.firstname, context.lastname) api = TemplateAPI(context, request, page_title) # Show confirmation page. return dict(api=api, myself=myself)
def checkPermission(self, info): """ Does user have permission to author content in the given context? Uses ACL security policy to test. """ users = find_users(self.context) for target in info['targets']: if 'error' in target: continue report_name = target.get('report') if report_name is not None: pd = find_peopledirectory(self.context) context = find_resource(pd, report_name.split('+')) permission = "email" else: communities = find_communities(self.context) community = communities[target['community']] context = community[target['tool']] permission = "create" # XXX In theory could depend on target user = users.get_by_id(info['author']) if user is not None: user = dict(user) # XXX check this! user['karl.identity'] = {'id': info['author']} # BFG Security API always assumes http request, so we fabricate a # fake request. request = Request.blank('/') request.environ['karl.identity'] = user request.context = self.context if not has_permission(permission, context, request): target['error'] = 'Permission Denied'
def _check(credentials, request): login, password = credentials['login'], credentials['password'] users = find_users(request.context) user = users.get(login=login) if user is None or user['password'] != get_sha_password(password): return None return [user['id']] + list(user['groups'])
def delete_community(obj, event): # delete the groups related to the community when a community is # deleted context = obj users = find_users(context) users.delete_group(context.members_group_name) users.delete_group(context.moderators_group_name)
def create_access_request(self): email = self.data.get('email') system_name = get_setting(self.context, 'title') self.context.access_requests[email] = self.data mailer = getUtility(IMailDelivery) message = MIMEMultipart('alternative') message['Subject'] = '%s Access Request(%s)' % ( system_name, self.data.get('fullname')) message['From'] = get_setting(self.context, 'admin_email') bodyhtml = u'''<html><body> <p>New access request has been submitted for the site %s</p> <p><b>Email</b>: %s <br /> %s </p> </body></html>''' % (self.request.application_url, email, '<br />'.join([ _email_field_tmp % (f['label'], self.data.get(f['id'], '')) for f in self.fields ])) bodyplain = html2text.html2text(bodyhtml) htmlpart = MIMEText(bodyhtml.encode('UTF-8'), 'html', 'UTF-8') plainpart = MIMEText(bodyplain.encode('UTF-8'), 'plain', 'UTF-8') message.attach(plainpart) message.attach(htmlpart) # First, send mail to all admins users = find_users(self.context) search = ICatalogSearch(self.context) count, docids, resolver = search(interfaces=[IProfile]) for docid in docids: profile = resolver(docid) if getattr(profile, 'security_state', None) == 'inactive': continue userid = profile.__name__ if not users.member_of_group(userid, 'group.KarlAdmin'): continue copyofmsg = copy.deepcopy(message) fullemail = '%s <%s>' % (profile.title, profile.email) copyofmsg['To'] = fullemail mailer.send([profile.email], copyofmsg) # next, send to person that submitted message = MIMEMultipart('alternative') message['Subject'] = 'Access Request to %s' % system_name message['From'] = get_setting(self.context, 'admin_email') user_message = get_setting( self.context, 'request_access_user_message', '') % (SafeDict( self.data, {'system_name': system_name})) bodyhtml = u'<html><body>%s</body></html>' % user_message bodyplain = html2text.html2text(bodyhtml) htmlpart = MIMEText(bodyhtml.encode('UTF-8'), 'html', 'UTF-8') plainpart = MIMEText(bodyplain.encode('UTF-8'), 'plain', 'UTF-8') message.attach(plainpart) message.attach(htmlpart) copyofmsg = copy.deepcopy(message) fullemail = '%s <%s>' % (self.data.get('fullname', ''), email) copyofmsg['To'] = fullemail mailer.send([email], copyofmsg) self.submitted = True self.errors.append('Successfully requested access')
def get_profile_actions(profile, request): profile_url = request.resource_url(profile) actions = [] same_user = (authenticated_userid(request) == profile.__name__) if has_permission('administer', profile, request): actions.append(('Edit', '%sadmin_edit_profile.html' % profile_url)) elif same_user: actions.append(('Edit', '%sedit_profile.html' % profile_url)) if same_user: actions.append(('Manage Communities', 'manage_communities.html')) actions.append(('Manage Tags', 'manage_tags.html')) if has_permission('administer', profile, request): actions.append(('Advanced', '%sadvanced.html' % profile_url)) if request.cookies.get('ux2') == 'true': if same_user: actions.append(('Deactivate My Account', 'javascript:deactivate()')) if has_permission('administer', profile, request) and not same_user: users = find_users(profile) userid = profile.__name__ user = users.get_by_id(userid) if user is not None: is_active = True else: is_active = False if is_active: actions.append(('Deactivate This User', 'javascript:deactivate()')) if not is_active: actions.append(('Reactivate This User', 'javascript:reactivate()')) return actions
def sync(self, data): context = self.context timestamp = data.pop('timestamp', None) if timestamp: context.usersync_timestamp = timestamp elif hasattr(context, 'usersync_timestamp'): del context.usersync_timestamp deactivate_missing = data.pop('deactivate_missing', False) if deactivate_missing: profiles = find_profiles(self.context) missing = set([p.__name__ for p in profiles.values() if p.security_state == 'active' and getattr(p, 'usersync_managed', False)]) else: missing = Empty() users = data.pop('users') for user in users: self.syncuser(user, missing) if data: raise ValueError("Unrecognized keys in user sync data: %s" % data.keys()) if missing: users = find_users(self.context) for username in missing: profile = profiles[username] workflow = get_workflow(IProfile, 'security', profile) workflow.transition_to_state(profile, None, 'inactive') users.remove(username)
def collect_profile_metrics(context, year, month): result = {} search = ICatalogSearch(context) begin, end = date_range(year, month) users = find_users(context) staff_set = users.users_in_group('group.KarlStaff') _, docids, resolver = search( creation_date=(None, end), interfaces=[IProfile], ) for profile in (resolver(docid) for docid in docids): userid = profile.__name__ created_count, _, _ = search(creation_date=(begin, end), creator=userid) total_count, _, _ = search(creation_date=(None, end), creator=userid) is_staff = userid in staff_set result[userid] = dict( total=total_count, created=created_count, is_staff=is_staff, ) return result
def handle_submit(self, converted): context = self.context request = self.request system_name = get_setting(context, 'system_name', 'KARL') address = converted['email'] if address: address = address.lower() search = getAdapter(context, ICatalogSearch) count, docids, resolver = search( interfaces=[IProfile], email=[address]) users = find_users(context) for docid in docids: profile = resolver(docid) if profile is None: continue userid = profile.__name__ user = users.get_by_id(userid) if user is None: continue # found the profile and user break else: raise ValidationError(**{"email": "%s has no account with the email address: %s" % (system_name, address)}) request_password_reset(user, profile, request) url = resource_url(context, request, 'reset_sent.html') + ( '?email=%s' % urllib.quote_plus(address)) return HTTPFound(location=url)
def __init__(self, context, request): super(AdminEditProfileFormController, self).__init__(context, request) self.users = find_users(context) self.userid = context.__name__ self.user = self.users.get_by_id(self.userid) self.user_groups = set(self.user['groups']) self.group_options = get_group_options(self.context)
def visit(self, context): if IProfile.providedBy(context): users = find_users(context) person = self._get_person(context.__name__) person['first_last'] = ' '.join( (context.firstname, context.lastname)) person['create_date'] = context.created person['is_staff'] = users.member_of_group( context.__name__, 'group.KarlStaff') person['location'] = context.location person['department'] = context.department tags = find_tags(context) person['tags'] = len(tags.getTags(users=[context.__name__])) elif ICommunity.providedBy(context): for id in context.member_names: self._get_person(id)['membership'] += 1 for id in context.moderator_names: self._get_person(id)['communities_moderator'] += 1 else: creator = getattr(context, 'creator', None) if creator is not None: person = self._get_person(creator) person['content_created'] += 1 if context.created > self.one_month_ago: person['created_this_month'] += 1
def evolve(context): users = find_users(context) profiles = find_profiles(context) for id in bad_users: users.remove(id) del profiles[id]
def to_profile_active(ob, info): acl = [ (Allow, ob.creator, MEMBER_PERMS + ('view_only',)), ] acl.append((Allow, 'group.KarlUserAdmin', ADMINISTRATOR_PERMS + ('view_only',))) acl.append((Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS + ('view_only',))) acl.append((Allow, 'group.KarlStaff', GUEST_PERMS + ('view_only',))) users = find_users(ob) user = users.get_by_id(ob.creator) if user is not None: groups = user['groups'] for group, role in get_community_groups(groups): c_group = 'group.community:%s:%s' % (group, role) acl.append((Allow, c_group, GUEST_PERMS + ('view_only',))) acl.append((Allow, 'system.Authenticated', ('view_only',))) acl.append(NO_INHERIT) msg = None added, removed = acl_diff(ob, acl) if added or removed: ob.__acl__ = acl msg = ts('to-active', resource_path(ob), added, removed) _reindex(ob, texts=True) _reindex_peopledir(ob) return msg
def discover_community_members_json(context, request): """ Return users who share a community with the given user. Query string may include: - 'userid': the user whose communities we enumerate (defaults to the current user). """ users = find_users(context) userid = request.GET.get('userid', None) if userid is None: userid = authenticated_userid(request) principals = effective_principals(request) communities = [x[0] for x in get_community_groups(principals)] else: info = users.get(userid) communities = [x[0] for x in get_community_groups(info['groups'])] c_groups = [(x, _quippers_from_users( context, request, users.users_in_group('group.community:%s:members' % x))) for x in communities] return { 'userid': userid, 'members': dict(c_groups), }
def to_profile_active(ob, info): acl = [ (Allow, ob.creator, MEMBER_PERMS + ('view_only', )), ] acl.append( (Allow, 'group.KarlUserAdmin', ADMINISTRATOR_PERMS + ('view_only', ))) acl.append( (Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS + ('view_only', ))) acl.append((Allow, 'group.KarlStaff', GUEST_PERMS + ('view_only', ))) users = find_users(ob) user = users.get_by_id(ob.creator) if user is not None: groups = user['groups'] for group, role in get_community_groups(groups): c_group = 'group.community:%s:%s' % (group, role) acl.append((Allow, c_group, GUEST_PERMS + ('view_only', ))) acl.append((Allow, 'system.Authenticated', ('view_only', ))) acl.append(NO_INHERIT) msg = None added, removed = acl_diff(ob, acl) if added or removed: ob.__acl__ = acl msg = ts('to-active', resource_path(ob), added, removed) _reindex(ob, texts=True) _reindex_peopledir(ob) return msg
def checkPermission(self, info): """ Does user have permission to author content in the given context? Uses ACL security policy to test. """ users = find_users(self.context) for target in info['targets']: if 'error' in target: continue report_name = target.get('report') if report_name is not None: pd = find_peopledirectory(self.context) context = find_model(pd, report_name.split('+')) permission = "email" else: communities = find_communities(self.context) community = communities[target['community']] context = community[target['tool']] permission = "create" # XXX In theory could depend on target user = users.get_by_id(info['author']) if user is not None: user = dict(user) user['repoze.who.userid'] = info['author'] # BFG Security API always assumes http request, so we fabricate a # fake request. request = webob.Request.blank('/') request.environ['repoze.who.identity'] = user if not has_permission(permission, context, request): target['error'] = 'Permission Denied'
def create(self, profiles): element = self.element login = self._element_value(element, 'username') username = login.replace(' ', '') password = get_random_password() groups = self._groups(element) users = find_users(profiles) users.add(username, login, password, groups, encrypted=False) profile = create_content(IProfile) profiles[username] = profile self._populate(profile) workflow = get_workflow(IProfile, 'security', profile) if workflow is not None: workflow.initialize(profile) profile.created_by = profile.modified_by = username profile.created = profile.modified = datetime.datetime.now() # Profile was indexed before workflow was initialized, so there is a # a bogus value for the 'allowed' index. Unfortunately, we can't just # add the profile to the profiles folder (which triggers indexing) # after the workflow is initialized, because the workflow # initialization code for profiles requires that the profile already # be in the content tree since a call to 'find_users' is made. The # work around is to just remove the profile and add it back again to # trigger reindexing. del profiles[username] profiles[username] = profile
def evolve(context): out = codecs.getwriter('UTF-8')(sys.stdout) # Fix strange user db inconsistency from (hopefully) distant past. # Some users in the db have user info but their login is missing from # the logins dict. users = find_users(context) logins = users.logins for id in users.byid.keys(): login = users.get_by_id(id)['login'] if login not in logins: logins[login] = id # Convert profiles to new workflow. workflow = get_workflow(IProfile, 'security') for profile in find_profiles(context).values(): print >>out, ("Updating security workflow for profile: %s" % profile.__name__) if not hasattr(profile, 'security_state'): # 'formeruser' was added without initializing workflow, oops. workflow.initialize(profile) workflow.transition_to_state(profile, None, 'inactive') continue assert profile.security_state == 'profile' assert not has_custom_acl(profile) profile.security_state = 'active' workflow.reset(profile)
def sync(self, data): context = self.context timestamp = data.pop('timestamp', None) if timestamp: context.usersync_timestamp = timestamp elif hasattr(context, 'usersync_timestamp'): del context.usersync_timestamp deactivate_missing = data.pop('deactivate_missing', False) if deactivate_missing: profiles = find_profiles(self.context) missing = set([ p.__name__ for p in profiles.values() if p.security_state == 'active' and getattr(p, 'usersync_managed', False) ]) else: missing = Empty() users = data.pop('users') for user in users: self.syncuser(user, missing) if data: raise ValueError("Unrecognized keys in user sync data: %s" % data.keys()) if missing: users = find_users(self.context) for username in missing: profile = profiles[username] workflow = get_workflow(IProfile, 'security', profile) workflow.transition_to_state(profile, None, 'inactive') users.remove(username)
def _add_existing_users(context, community, profiles, text, request): users = find_users(community) for profile in profiles: group_name = community.members_group_name user_name = profile.__name__ users.add_group(user_name, group_name) # Generate HTML and text mail messages and send a mail for # each user added to the community. community_href = resource_url(community, request) _send_aeu_emails(community, community_href, profiles, text) # We delivered invitation messages to each user. Redirect to # Manage Members with a status message. n = len(profiles) if n == 1: msg = 'One member added and email sent.' else: fmt = '%s members added and emails sent.' msg = fmt % len(profiles) location = resource_url(context, request, 'manage.html', query={'status_message': msg}) return HTTPFound(location=location)
def evolve(context): out = codecs.getwriter('UTF-8')(sys.stdout) # Fix strange user db inconsistency from (hopefully) distant past. # Some users in the db have user info but their login is missing from # the logins dict. users = find_users(context) logins = users.logins for id in users.byid.keys(): login = users.get_by_id(id)['login'] if login not in logins: logins[login] = id # Convert profiles to new workflow. workflow = get_workflow(IProfile, 'security') for profile in find_profiles(context).values(): print >> out, ("Updating security workflow for profile: %s" % profile.__name__) if not hasattr(profile, 'security_state'): # 'formeruser' was added without initializing workflow, oops. workflow.initialize(profile) workflow.transition_to_state(profile, None, 'inactive') continue assert profile.security_state == 'profile' assert not has_custom_acl(profile) profile.security_state = 'active' workflow.reset(profile)
def handle_submit(self, converted): try: context = self.context request = self.request key = request.params.get('key') if not key or len(key) != 40: e = ResetFailed() e.page_title = 'Password Reset URL Problem' raise e users = find_users(context) user = users.get_by_login(converted['login']) if user is None: raise ValidationError(login='******') userid = user.get('id') if userid is None: userid = user['login'] profiles = find_profiles(context) profile = profiles.get(userid) if profile is None: raise ValidationError(login='******') if key != getattr(profile, 'password_reset_key', None): e = ResetFailed() e.page_title = 'Password Reset Confirmation Problem' raise e now = datetime.datetime.now() t = getattr(profile, 'password_reset_time', None) if t is None or now - t > max_reset_timedelta: e = ResetFailed() e.page_title = 'Password Reset Confirmation Key Expired' raise e # The key matched. Clear the key and reset the password. profile.password_reset_key = None profile.password_reset_time = None password = converted['password'].encode('UTF-8') users.change_password(userid, password) request.session['password_expired'] = False profile.password_expiration_date = (datetime.datetime.utcnow() + datetime.timedelta(days=180)) max_retries = request.registry.settings.get('max_login_retries', 8) context.login_tries[converted['login']] = max_retries page_title = 'Password Reset Complete' api = TemplateAPI(context, request, page_title) return render_to_response( 'templates/reset_complete.pt', dict(api=api, login=converted['login'], password=converted['password']), request=request, ) except ResetFailed, e: api = TemplateAPI(context, request, e.page_title) return render_to_response('templates/reset_failed.pt', dict(api=api), request=request)
def move_content(root, src, dst, wf_state): try: context = find_resource(root, src) except KeyError: print >> sys.stderr, "Source content not found: %s" % src sys.exit(-1) try: dest_folder = find_resource(root, dst) except KeyError: print >> sys.stderr, "Destination folder not found: %s" % dst sys.exit(-1) src_community = find_community(context) catalog = find_catalog(root) assert catalog is not None users = find_users(root) assert users is not None if src_community is not None: move_header = ('<p><em>This was originally authored ' 'in the "%s" community.</em></p>' % src_community.title) else: move_header = '' src_folder = context.__parent__ name = context.__name__ log.info("Moving %s", resource_path(context)) for obj in postorder(context): if hasattr(obj, 'docid'): docid = obj.docid catalog.document_map.remove_docid(docid) catalog.unindex_doc(docid) del src_folder[name] if (context.creator != 'admin' and users.get_by_id(context.creator) is None): # give the entry to the system admin log.warning("User %s not found; reassigning to admin", context.creator) context.creator = 'admin' if name in dest_folder: name = make_unique_name(dest_folder, context.title) dest_folder[name] = context for obj in postorder(context): if hasattr(obj, 'docid'): docid = obj.docid catalog.document_map.add(resource_path(obj), docid) catalog.index_doc(docid, obj) if wf_state is not None: wf = get_workflow(get_content_type(context), 'security', context) wf.transition_to_state(context, None, wf_state) if hasattr(context, 'text'): context.text = "%s\n%s" % (move_header, context.text)
def login_locked_out(self, login): users = find_users(self.context) user = users and users.get(login=login) if not user: return False mng = LockoutManager(self.context, login) return mng.maxed_number_of_attempts()
def __init__(self, context, request): self.context = context self.request = request self.filestore = get_filestore(context, request, 'add-user') self.photo = None self.users = find_users(context) self.group_options = get_group_options(self.context) self.page_title = 'Add User'
def get_groups(obj, default): if not IProfile.providedBy(obj): return default users = find_users(obj) user = users.get_by_id(obj.__name__) if user: return user.get('groups', default) return default
def showall(args): root, closer = args.get_root(args.inst) users = find_users(root) mapping = getattr(users, 'kerberos_map', None) if not mapping: return for principal, userid in mapping.items(): print '%s\t%s' % (userid, principal)
def _authenticate(context, login, password): userid = None users = find_users(context) for authenticate in (password_authenticator, impersonate_authenticator): userid = authenticate(users, login, password) if userid: break return userid
def showall(args): root, closer = args.get_root(args.inst) users = find_users(root) mapping = getattr(users, 'sso_map', None) if not mapping: return for principal, userid in mapping.items(): print '%s\t%s' % (userid, principal)
def syncuser(self, data, missing): for key in self.required_keys: if not data.get(key): raise ValueError("Invalid user data: '%s' key is required" % key) users = find_users(self.context) profiles = find_profiles(self.context) username = data.pop("username") profile = profiles.get(username) active = profile and profile.security_state == "active" if username in missing: missing.remove(username) if not profile: profile = self.createuser(data) self.update(profile, data) profiles[username] = profile activate = data.pop("active", "true") security_state = "active" if activate else "inactive" log.info("Created user: %s", username) else: objectEventNotify(ObjectWillBeModifiedEvent(profile)) self.update(profile, data) objectEventNotify(ObjectModifiedEvent(profile)) activate = data.pop("active", None) if activate is not None: security_state = "active" if activate else "inactive" else: security_state = profile.security_state activate = active if type(missing) is Empty: log.info("Updated user: %s", username) profile.usersync_managed = True if active: info = users.get(username) password = data.pop("password", info["password"]) groups = data.pop("groups", info["groups"]) login = data.pop("login", info["login"]) users.remove(username) elif activate: # reactivate log.info("Reactivating user: %s", username) login = data.pop("login", username) password = data.pop("password", None) groups = data.pop("groups", []) if not password: raise ValueError("Invalid user data: 'password' key is required to " "reactivate user") if activate: users.add(username, login, password, groups, encrypted=True) if security_state != getattr(profile, "security_state", None): workflow = get_workflow(IProfile, "security", profile) workflow.transition_to_state(profile, None, security_state) if security_state == "inactive": log.info("Deactivated user: %s", username) if data: raise ValueError("Unrecognized keys in sync data for user: %s: %s" % (username, data.keys()))
def login_failed(event): # we are only going to log attempts for valid users users = find_users(event.site) user = users and users.get(login=event.login) if not user: return mng = LockoutManager(event.site, event.login) mng.add_attempt()
def reset_passwords(root, group): user_store = find_users(root) users = user_store.users_in_group(group) for user in users: password = ''.join(random.SystemRandom().choice( string.ascii_uppercase + string.digits) for _ in range(32)) user_store.change_password(user, password) print "reset password for {}".format(user)
def mapuser(args): root, closer = args.get_root(args.inst) users = find_users(root) if not hasattr(users, 'kerberos_map'): users.kerberos_map = PersistentMapping() if not users.get(args.userid): args.parser.error("No such userid: %s" % args.userid) users.kerberos_map[args.principal] = args.userid transaction.commit()
def handle_submit(self, converted): context = self.context users = find_users(context) userid = context.__name__ users.change_password(userid, converted['password']) path = resource_url(context, self.request) msg = '?status_message=Password%20changed' return HTTPFound(location=path + msg)
def __init__(self, site, login): self.site = site self.login = login self.users = find_users(site) try: self.login_attempts = site.failed_login_attempts except AttributeError: log.warn('Upgrade step to install login_attempts storage not run') self.login_attempts = None
def handle_submit(self, converted): context = self.context users = find_users(context) userid = context.__name__ users.change_password(userid, converted['password']) path = resource_url(context, self.request) msg = '?status_message=Password%20changed' return HTTPFound(location=path+msg)
def __call__(self): context, request = self.context, self.request api = AdminTemplateAPI(context, request, "Admin UI: Send Email") admin_email = get_setting(context, "admin_email") system_name = get_setting(context, "system_name") profiles = find_profiles(context) admin = profiles[authenticated_userid(request)] from_emails = [ ("self", "%s <%s>" % (admin.title, admin.email)), ("admin", "%s Administrator <%s>" % (system_name, admin_email)), ] if "send_email" in request.params: mailer = getUtility(IMailDelivery) group = request.params["to_group"] users = find_users(context) search = ICatalogSearch(context) count, docids, resolver = search(interfaces=[IProfile]) n = 0 for docid in docids: profile = resolver(docid) if getattr(profile, "security_state", None) == "inactive": continue userid = profile.__name__ if group and not users.member_of_group(userid, group): continue message = Message() if request.params["from_email"] == "self": message["From"] = from_emails[0][1] message_from = admin.email else: message["From"] = from_emails[1][1] message_from = admin_email message["To"] = "%s <%s>" % (profile.title, profile.email) message["Subject"] = request.params["subject"] body = u"<html><body>%s</body></html>" % (request.params["text"]) message.set_payload(body.encode("UTF-8"), "UTF-8") message.set_type("text/html") mailer.send([profile.email], message) n += 1 status_message = "Sent message to %d users." % n if has_permission(ADMINISTER, context, request): redirect_to = model_url(context, request, "admin.html", query=dict(status_message=status_message)) else: redirect_to = model_url( find_communities(context), request, "all_communities.html", query=dict(status_message=status_message), ) return HTTPFound(location=redirect_to) return dict(api=api, menu=_menu_macro(), to_groups=self.to_groups, from_emails=from_emails)
def mapuser(args): root, closer = args.get_root(args.inst) users = find_users(root) if not hasattr(users, 'sso_map'): users.sso_map = PersistentMapping() if not users.get(args.userid): args.parser.error("No such userid: %s" % args.userid) users.sso_map[args.principal] = args.userid transaction.commit()
def handle_submit(self, converted): try: context = self.context request = self.request key = request.params.get('key') if not key or len(key) != 40: e = ResetFailed() e.page_title = 'Password Reset URL Problem' raise e users = find_users(context) user = users.get_by_login(converted['login']) if user is None: raise ValidationError(login='******') userid = user.get('id') if userid is None: userid = user['login'] profiles = find_profiles(context) profile = profiles.get(userid) if profile is None: raise ValidationError(login='******') if key != getattr(profile, 'password_reset_key', None): e = ResetFailed() e.page_title = 'Password Reset Confirmation Problem' raise e now = datetime.datetime.now() t = getattr(profile, 'password_reset_time', None) if t is None or now - t > max_reset_timedelta: e = ResetFailed() e.page_title = 'Password Reset Confirmation Key Expired' raise e # The key matched. Clear the key and reset the password. profile.password_reset_key = None profile.password_reset_time = None password = converted['password'].encode('UTF-8') users.change_password(userid, password) page_title = 'Password Reset Complete' api = TemplateAPI(context, request, page_title) return render_to_response( 'templates/reset_complete.pt', dict(api=api, login=converted['login'], password=converted['password']), request = request, ) except ResetFailed, e: api = TemplateAPI(context, request, e.page_title) return render_to_response( 'templates/reset_failed.pt', dict(api=api), request=request)
def change_password_view(context, request): min_pw_length = get_setting(context, 'min_pw_length') form = ChangePasswordForm(min_pw_length=min_pw_length) if 'form.cancel' in request.POST: return HTTPFound(location=model_url(context, request)) if 'form.submitted' in request.POST: try: converted = form.validate(request.POST) users = find_users(context) userid = context.__name__ user = users.get_by_id(userid) # check the old password # XXX: repoze.who.plugins.zodb.interfaces.IUsers # really should have a check_password(id, password) # method. We shouldn't have to use get_sha_password # directly. enc = get_sha_password(converted['old_password']) if enc != user['password']: raise CustomInvalid({'old_password': '******'}) users.change_password(userid, converted['password']) # send email system_name = get_setting(context, 'system_name', 'KARL') mail = karl.mail.Message() admin_email = get_setting(context, 'admin_email') mail["From"] = "%s Administrator <%s>" % (system_name, admin_email) mail["To"] = "%s <%s>" % (context.title, context.email) mail["Subject"] = "%s Password Change Notification" % system_name system_name = get_setting(context, 'system_name', 'KARL') body = render_template( "templates/email_change_password.pt", login=user['login'], password=converted['password'], system_name=system_name, ) if isinstance(body, unicode): body = body.encode("UTF-8") mail.set_payload(body, "UTF-8") mail.set_type("text/html") recipients = [context.email] mailer = getUtility(IMailDelivery) mailer.send(admin_email, recipients, mail) path = model_url(context, request) msg = '?status_message=Password%20changed' return HTTPFound(location=path+msg) except Invalid, e: fielderrors = e.error_dict fill_values = form.convert(request.POST)
def __call__(self): context = self.context request = self.request errors = [] messages = [] # Handle CSV upload field = request.params.get("csv", None) if hasattr(field, "file"): reactivate = request.params.get("reactivate") == "true" reader = csv.DictReader(field.file) try: rows = list(reader) except Error, e: errors.append("Malformed CSV: %s" % e[0]) # Make sure we have required fields if not errors: fieldnames = rows[0].keys() if None in fieldnames: errors.append("Malformed CSV: line 2 does not match header.") else: for required_field in self.required_fields: if required_field not in fieldnames: errors.append("Missing required field: %s" % required_field) if not ("password" in fieldnames or "sha_password" in fieldnames): errors.append("Must supply either password or " "sha_password field.") # Restrict to allowed fields allowed_fields = self.allowed_fields for fieldname in fieldnames: if fieldname not in allowed_fields: errors.append("Unrecognized field: %s" % fieldname) # Add users if not errors: search = ICatalogSearch(context) profiles = find_profiles(context) users = find_users(context) n_added = 0 for i, row in enumerate(rows): row_has_errors = False if None in row or None in row.values(): errors.append("Malformed CSV: line %d does not match header." % (i + 2)) break added_users, row_messages, row_errors = self._add_user_csv_row( search, profiles, users, row, reactivate, i ) n_added += added_users messages += row_messages errors += row_errors if not errors: messages.append("Created %d users." % n_added)
def login(self): context = self.context request = self.request # identify login = request.POST.get('login') password = request.POST.get('password') if self.login_locked_out(login): redirect = request.resource_url( request.root, 'login.html', query={ 'reason': 'User locked out. Too many failed login attempts.'}) return HTTPFound(location=redirect) notify(events.LoginAttempt(context, request, login, password)) if login is None or password is None: return HTTPFound(location='%s/login.html' % request.application_url) max_age = request.POST.get('max_age') if max_age is not None: max_age = int(max_age) # authenticate userid = None reason = 'Bad username or password' users = find_users(context) for authenticate in (password_authenticator, impersonate_authenticator): userid = authenticate(context, users, login, password) if userid: break # if not successful, try again if not userid: notify(events.LoginFailed(context, request, login, password)) redirect = request.resource_url( request.root, 'login.html', query={'reason': reason}) return HTTPFound(location=redirect) tf = TwoFactor(context, request) if tf.enabled: code = request.POST.get('code') if not code: redirect = request.resource_url( request.root, 'login.html', query={'reason': 'No authentication code provided'}) notify(events.LoginFailed(context, request, login, password)) return HTTPFound(location=redirect) if tf.validate(userid, code): # noqa notify(events.LoginFailed(context, request, login, password)) redirect = request.resource_url( request.root, 'login.html', query={'reason': 'Invalid authorization code'}) # noqa return HTTPFound(location=redirect) # else, remember notify(events.LoginSuccess(context, request, login, password)) return remember_login(context, request, userid, max_age)
def __call__(self): context = self.context kw = super(OsiEditProfileFormController, self).__call__() if isinstance(kw, dict): kw['is_own_profile'] = True users = find_users(context) userid = context.__name__ kw['is_staff'] = users.member_of_group(userid, 'group.KarlStaff') kw['is_active'] = context.security_state == 'active' return kw
def __call__(self): context, request = self.context, self.request api = AdminTemplateAPI(context, request, 'Admin UI: Send Email') admin_email = get_setting(context, 'admin_email') system_name = get_setting(context, 'system_name') profiles = find_profiles(context) admin = profiles[authenticated_userid(request)] from_emails = [ ('self', '%s <%s>' % (admin.title, admin.email)), ('admin', '%s Administrator <%s>' % (system_name, admin_email)), ] if 'send_email' in request.params: mailer = getUtility(IMailDelivery) group = request.params['to_group'] users = find_users(context) search = ICatalogSearch(context) count, docids, resolver = search(interfaces=[IProfile]) n = 0 for docid in docids: profile = resolver(docid) userid = profile.__name__ if group and not users.member_of_group(userid, group): continue message = Message() if request.params['from_email'] == 'self': message['From'] = from_emails[0][1] message_from = admin.email else: message['From'] = from_emails[1][1] message_from = admin_email message['To'] = '%s <%s>' % (profile.title, profile.email) message['Subject'] = request.params['subject'] body = u'<html><body>%s</body></html>' % ( request.params['text'] ) message.set_payload(body.encode('UTF-8'), 'UTF-8') message.set_type('text/html') mailer.send(message_from, [profile.email], message) n += 1 status_message = "Sent message to %d users." % n redirect_to = model_url(context, request, 'admin.html', query=dict(status_message=status_message)) return HTTPFound(location=redirect_to) return render_template_to_response( 'templates/admin/email_users.pt', api=api, menu=_menu_macro(), to_groups = self.to_groups, from_emails=from_emails, )
def mapusers(args): root, closer = args.get_root(args.inst) users = find_users(root) if not hasattr(users, 'kerberos_map'): users.kerberos_map = PersistentMapping() for line in sys.stdin: userid, principal = line.split() if not users.get(userid): args.parser.error("No such userid: %s" % userid) users.kerberos_map[principal] = userid transaction.commit()
def handle_submit(self, converted): request = self.request context = self.context name = make_name(context, converted['title']) userid = authenticated_userid(request) community = create_content( ICommunity, converted['title'], converted['description'], converted['text'], userid, ) community.sendalert_default = converted.get('sendalert_default', True) # this *must* directly follow content creation because the # toolinfo add stuff depends on the community having a full # path. context[name] = community # required to use moderators_group_name and # members_group_name community.__name__ = name tools_present = [] for toolinfo in self.available_tools: if toolinfo['name'] in converted.get('tools', []): toolinfo['component'].add(community, request) tools_present.append(toolinfo['name']) # Set the default tool if converted.get('default_tool') in tools_present: community.default_tool = converted['default_tool'] else: community.default_tool = None users = find_users(context) moderators_group_name = community.moderators_group_name members_group_name = community.members_group_name for group_name in moderators_group_name, members_group_name: users.add_group(userid, group_name) if self.workflow is not None: if 'security_state' in converted: self.workflow.transition_to_state(community, request, converted['security_state']) # Save the tags on it. set_tags(community, request, converted['tags']) # Adding a community should take you to the Add Existing # User screen, so the moderator can include some users. location = resource_url(community, request, 'members', 'add_existing.html', query={'status_message': 'Community added'}) return HTTPFound(location=location)
def __init__(self, context, request): super(AdminEditProfileFormController, self).__init__(context, request) self.users = find_users(context) self.userid = context.__name__ self.user = self.users.get_by_id(self.userid) if self.user is not None: self.is_active = True self.user_groups = set(self.user['groups']) self.group_options = get_group_options(self.context) else: self.is_active = False
def handle_submit(self, converted): context = self.context users = find_users(context) userid = context.__name__ user = users.get_by_id(userid) users.change_password(userid, converted["password"]) path = model_url(context, self.request) msg = "?status_message=Password%20changed" return HTTPFound(location=path + msg)