def principal_from_identifier(identifier, allow_groups=False, allow_external_users=False): # XXX: this is currently only used in PrincipalList # if we ever need to support more than just users and groups, # make sure to add it in here as well from indico.modules.groups import GroupProxy from indico.modules.users import User try: type_, data = identifier.split(':', 1) except ValueError: raise ValueError('Invalid data') if type_ == 'User': try: user_id = int(data) except ValueError: raise ValueError('Invalid data') user = User.get(user_id, is_deleted=False) if user is None: raise ValueError('Invalid user: {}'.format(user_id)) return user elif type_ == 'ExternalUser': if not allow_external_users: raise ValueError('External users are not allowed') cache = GenericCache('external-user') external_user_data = cache.get(data) if not external_user_data: raise ValueError('Invalid data') user = User.query.filter(User.all_emails == external_user_data['email'], ~User.is_deleted).first() if user: return user # create a pending user. this user isn't sent to the DB unless it gets added # to the sqlalchemy session somehow (e.g. by adding it to an ACL). # like this processing form data does not result in something being stored in # the database, which is good! return User(first_name=external_user_data['first_name'], last_name=external_user_data['last_name'], email=external_user_data['email'], affiliation=external_user_data['affiliation'], address=external_user_data['address'], phone=external_user_data['phone'], is_pending=True) elif type_ == 'Group': if not allow_groups: raise ValueError('Groups are not allowed') try: provider, name = data.split(':', 1) except ValueError: raise ValueError('Invalid data') if not provider: # local group try: group_id = int(name) except ValueError: raise ValueError('Invalid data') group = GroupProxy(group_id) else: # multipass group group = GroupProxy(name, provider) if group.group is None: raise ValueError('Invalid group: {}'.format(data)) return group else: raise ValueError('Invalid data')
def principal_from_fossil(fossil, allow_pending=False, allow_groups=True, legacy=True, allow_missing_groups=False, allow_emails=False): """Gets a GroupWrapper or AvatarUserWrapper from a fossil""" from indico.modules.groups import GroupProxy from indico.modules.users import User type_ = fossil['_type'] id_ = fossil['id'] if type_ == 'Avatar': if isinstance(id_, int) or id_.isdigit(): # regular user user = User.get(int(id_)) elif allow_pending: data = GenericCache('pending_identities').get(id_) if not data: raise ValueError("Cannot find user '{}' in cache".format(id_)) data = {k: '' if v is None else v for (k, v) in data.items()} email = data['email'].lower() # check if there is not already a pending user with that e-mail user = User.find_first(email=email, is_pending=True) if not user: user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=email, address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() else: raise ValueError( "Id '{}' is not a number and allow_pending=False".format(id_)) if user is None: raise ValueError('User does not exist: {}'.format(id_)) return user.as_avatar if legacy else user elif allow_emails and type_ == 'Email': return EmailPrincipal(id_) elif allow_groups and type_ in {'LocalGroupWrapper', 'LocalGroup'}: group = GroupProxy(int(id_)) if group.group is None: raise ValueError('Local group does not exist: {}'.format(id_)) return group.as_legacy_group if legacy else group elif allow_groups and type_ in {'LDAPGroupWrapper', 'MultipassGroup'}: provider = fossil['provider'] group = GroupProxy(id_, provider) if group.group is None and not allow_missing_groups: raise ValueError('Multipass group does not exist: {}:{}'.format( provider, id_)) return group.as_legacy_group if legacy else group else: raise ValueError('Unexpected fossil type: {}'.format(type_))
def convert_principal(principal): """Converts a legacy principal to PrincipalMixin style""" if isinstance(principal, AvatarUserWrapper): return principal.user elif isinstance(principal, GroupWrapper): return principal.group elif principal.__class__.__name__ == 'Avatar': return AvatarUserWrapper(principal.id).user elif principal.__class__.__name__ == 'Group': return GroupProxy(principal.id) elif principal.__class__.__name__ in {'CERNGroup', 'LDAPGroup', 'NiceGroup'}: return GroupProxy(principal.id, multipass.default_group_provider.name)
def get_user_access(user, admin_override_enabled=False): if not user: return [] if admin_override_enabled and user.is_admin: return ['IndicoAdmin'] access = [user.identifier] + [u.identifier for u in user.get_merged_from_users_recursive()] access += [GroupProxy(x.id, _group=x).identifier for x in user.local_groups] if user.can_get_all_multipass_groups: multipass_groups = [GroupProxy(x.name, x.provider.name, x) for x in user.iter_all_multipass_groups()] access += _include_capitalized_groups(multipass_groups) return access
def retrieve_principal(principal, allow_groups=True, legacy=True): """Retrieves principal object from a `(type, id)` tuple. Valid principal types are 'Avatar', 'User' and 'Group'. :param principal: The principal (a tuple/list) :param allow_groups: If group principals are allowed :param legacy: If legacy wrappers or new objects should be returned. """ from indico.modules.groups import GroupProxy from indico.modules.groups.legacy import LocalGroupWrapper, LDAPGroupWrapper from indico.modules.users import User type_, id_ = principal if type_ in {'Avatar', 'User'}: user = User.get(int(id_)) if not user: return None return user.as_avatar if legacy else user elif type_ == 'Group' and allow_groups: if isinstance(id_, (int, basestring)): # legacy group group = LocalGroupWrapper(id_) if unicode( id_).isdigit() else LDAPGroupWrapper(id_) return group if legacy else group.group else: # new group provider, name_or_id = id_ group = GroupProxy(name_or_id, provider) return group.as_legacy_group if legacy else group else: raise ValueError('Unexpected type: {}'.format(type_))
def _process(self): query = LocalGroup.query.options(joinedload(LocalGroup.members)).order_by(db.func.lower(LocalGroup.name)) groups = [g.proxy for g in query] providers = [p for p in multipass.identity_providers.itervalues() if p.supports_groups] form = SearchForm(obj=FormDefaults(exact=True)) groups_enabled = True if not providers and not config.LOCAL_GROUPS: groups_enabled = False elif not providers: del form.provider else: choices = [('', _('All'))] if config.LOCAL_GROUPS: choices.append(('indico', _('Local Groups'))) choices += [(p.name, p.title) for p in sorted(providers, key=attrgetter('title'))] form.provider.choices = choices search_results = None if groups_enabled and form.validate_on_submit(): search_providers = None if not providers or not form.provider.data else {form.provider.data} search_results = GroupProxy.search(form.name.data, exact=form.exact.data, providers=search_providers) search_results.sort(key=attrgetter('provider', 'name')) provider_titles = {p.name: p.title for p in multipass.identity_providers.itervalues()} provider_titles[None] = _('Local') return WPGroupsAdmin.render_template('groups.html', groups=groups, providers=providers, form=form, search_results=search_results, provider_titles=provider_titles, groups_enabled=groups_enabled)
def _process(self): query = LocalGroup.query.options(joinedload(LocalGroup.members)).order_by(db.func.lower(LocalGroup.name)) groups = [g.proxy for g in query] providers = [p for p in multipass.identity_providers.itervalues() if p.supports_groups] form = SearchForm(obj=FormDefaults(exact=True)) if not providers: del form.provider else: form.provider.choices = [("", _("All")), ("indico", _("Local Groups"))] + [ (p.name, p.title) for p in sorted(providers, key=attrgetter("title")) ] search_results = None if form.validate_on_submit(): search_providers = None if not providers or not form.provider.data else {form.provider.data} search_results = GroupProxy.search(form.name.data, exact=form.exact.data, providers=search_providers) search_results.sort(key=attrgetter("provider", "name")) provider_titles = {p.name: p.title for p in multipass.identity_providers.itervalues()} provider_titles[None] = _("Local") return WPGroupsAdmin.render_template( "groups.html", groups=groups, providers=providers, form=form, search_results=search_results, provider_titles=provider_titles, )
def _populate_blocking(blocking, room_ids, allowed_principals, reason): blocking.blocked_rooms = [BlockedRoom(room_id=room.id) for room in Room.query.filter(Room.id.in_(room_ids))] blocking.reason = reason blocking.allowed = [GroupProxy(_group_id_or_name(pr), provider=pr['provider']) if pr.get('is_group') else User.get_one(pr['id']) for pr in allowed_principals]
def _create_group(id_): group = LocalGroup() group.id = id_ group.name = u'dummy-{}'.format(id_) db.session.add(group) db.session.flush() _groups.add(group) return GroupProxy(group.id, _group=group)
def test_iter_acl(): user = User() user_p = MagicMock(principal=user, spec=['principal']) ipn = IPNetworkGroup() ipn_p = MagicMock(principal=ipn, spec=['principal']) local_group = GroupProxy(123, _group=MagicMock()) local_group_p = MagicMock(principal=local_group, spec=['principal']) remote_group = GroupProxy('foo', 'bar') remote_group_p = MagicMock(principal=remote_group, spec=['principal']) acl = [ ipn, user_p, remote_group, local_group_p, user, local_group, remote_group_p, ipn_p ] assert list(iter_acl(iter(acl))) == [ user_p, user, ipn, ipn_p, local_group_p, local_group, remote_group, remote_group_p ]
def is_owned_by(self, user): """Checks if the user is managing the room (owner or manager)""" if self.owner == user: return True manager_group = self.get_attribute_value('manager-group') if not manager_group: return False return user in GroupProxy.get_named_default_group(manager_group)
def _checkParams(self): try: group = GroupProxy(request.view_args['group_id'], request.view_args['provider']) except ValueError: group = None if group is None or group.group is None: raise NotFound self.group = group
def _process(self, name): groups = GroupProxy.search(name) return jsonify([{ 'is_group': True, 'name': group.name, 'id': getattr(group, 'id', group.name), 'provider': group.provider } for group in groups])
def _getAnswer(self): results = [ g.as_legacy_group for g in GroupProxy.search(self._group, exact=self._exactMatch) ] fossilized_results = fossilize(results, IGroupFossil) for fossilizedGroup in fossilized_results: fossilizedGroup["isGroup"] = True return fossilized_results
def _process(self): query = LocalGroup.query.options(joinedload(LocalGroup.members)).order_by(db.func.lower(LocalGroup.name)) groups = [GroupProxy(g.id, _group=g) for g in query] providers = [p for p in multipass.identity_providers.itervalues() if p.supports_groups] form = SearchForm(obj=FormDefaults(exact=True)) if not providers: del form.provider else: form.provider.choices = ([('', _('All')), ('indico', _('Local Groups'))] + [(p.name, p.title) for p in sorted(providers, key=attrgetter('title'))]) search_results = None if form.validate_on_submit(): search_providers = None if not providers or not form.provider.data else {form.provider.data} search_results = GroupProxy.search(form.name.data, exact=form.exact.data, providers=search_providers) search_results.sort(key=attrgetter('provider', 'name')) provider_titles = {p.name: p.title for p in multipass.auth_providers.itervalues()} provider_titles[None] = _('Local') return WPGroupsAdmin.render_template('groups.html', groups=groups, providers=providers, form=form, search_results=search_results, provider_titles=provider_titles)
def get_principal(name): if '@' in name: return get_user(name) # otherwise we assume it's a group's name group = group_cache.setdefault(name, GroupProxy(name, provider='cern-ldap')) if not group or not group.group: group = None print(cformat("%{red}!%{reset} Group %{cyan}{}%{reset} doesn't seem to exist!").format(name)) return group
def _process_args(self): try: group = GroupProxy(request.view_args['group_id'], request.view_args['provider']) except ValueError: group = None if group is None or group.group is None: raise NotFound if not config.LOCAL_GROUPS and group.is_local: raise Forbidden('Local groups are disabled.') self.group = group
def principal_from_identifier(identifier, allow_groups=False): # XXX: this is currently only used in PrincipalList # if we ever need to support more than just users and groups, # make sure to add it in here as well from indico.modules.groups import GroupProxy from indico.modules.users import User try: type_, data = identifier.split(':', 1) except ValueError: raise ValueError('Invalid data') if type_ == 'User': try: user_id = int(data) except ValueError: raise ValueError('Invalid data') user = User.get(user_id, is_deleted=False) if user is None: raise ValueError('Invalid user: {}'.format(user_id)) return user elif type_ == 'Group': if not allow_groups: raise ValueError('Groups are not allowed') try: provider, name = data.split(':', 1) except ValueError: raise ValueError('Invalid data') if not provider: # local group try: group_id = int(name) except ValueError: raise ValueError('Invalid data') group = GroupProxy(group_id) else: # multipass group group = GroupProxy(name, provider) if group.group is None: raise ValueError('Invalid group: {}'.format(data)) return group else: raise ValueError('Invalid data')
def _populate_blocking(blocking, room_ids, allowed_principals, reason): blocking.reason = reason principals = { GroupProxy(_group_id_or_name(pr), provider=pr['provider']) if pr.get('is_group') else User.get_one(pr['id']) for pr in allowed_principals } # We don't use `=` here to prevent SQLAlchemy from deleting and re-adding unchanged entries blocking.allowed |= principals # add new blocking.allowed &= principals # remove deleted _update_blocked_rooms(blocking, room_ids)
def principal(self): from indico.modules.groups import GroupProxy if self.type == PrincipalType.user: return self.user elif self.type == PrincipalType.local_group: return self.local_group.proxy elif self.type == PrincipalType.multipass_group: return GroupProxy(self.multipass_group_name, self.multipass_group_provider) elif self.type == PrincipalType.email: return EmailPrincipal(self.email)
def _can_be_booked(self, user, prebook=False, ignore_admin=False): if not user or not rb_check_user_access(user): return False if (not ignore_admin and rb_is_admin(user)) or (self.is_owned_by(user) and self.is_active): return True if self.is_active and self.is_reservable and (prebook or not self.reservations_need_confirmation): group_name = self.get_attribute_value('allowed-booking-group') if not group_name or user in GroupProxy.get_named_default_group(group_name): return True return False
def _process(self, room_ids, start_date, end_date, reason, allowed_principals): rooms = Room.query.filter(Room.id.in_(room_ids)).all() allowed = [] for obj in allowed_principals: if obj.get('is_group'): allowed.append(GroupProxy(obj['id'], provider=obj['provider'])) else: allowed.append(User.query.filter(User.id == obj['id']).one()) blocking = create_blocking(rooms, start_date, end_date, reason, allowed) approve_or_request_blocking(blocking) return jsonify_data(flash=False)
def convert_principal(self, old_principal): """Converts a legacy principal to PrincipalMixin style""" if old_principal.__class__.__name__ == 'Avatar': principal = self.global_ns.avatar_merged_user.get(old_principal.id) if not principal and 'email' in old_principal.__dict__: email = convert_to_unicode( old_principal.__dict__['email']).lower() principal = self.global_ns.users_by_primary_email.get( email, self.global_ns.users_by_secondary_email.get(email)) if principal is not None: self.print_warning( 'Using {} for {} (matched via {})'.format( principal, old_principal, email)) if not principal: self.print_error("User {} doesn't exist".format( old_principal.id)) return principal elif old_principal.__class__.__name__ == 'Group': assert int(old_principal.id) in self.global_ns.all_groups return GroupProxy(int(old_principal.id)) elif old_principal.__class__.__name__ in { 'CERNGroup', 'LDAPGroup', 'NiceGroup' }: return GroupProxy(old_principal.id, self.default_group_provider)
def principal(self): from indico.modules.groups import GroupProxy if self.type == PrincipalType.user: return self.user elif self.type == PrincipalType.local_group: return self.local_group.proxy elif self.type == PrincipalType.multipass_group: return GroupProxy(self.multipass_group_name, self.multipass_group_provider) elif self.type == PrincipalType.email: return EmailPrincipal(self.email) elif self.type == PrincipalType.network: return self.ip_network_group elif self.type == PrincipalType.event_role: return self.event_role elif self.type == PrincipalType.category_role: return self.category_role
def manager_emails(self): manager_group = self.get_attribute_value('manager-group') if not manager_group: return set() group = GroupProxy.get_named_default_group(manager_group) return {u.email for u in group.get_members()}
def _process(self, name, exact): groups = GroupProxy.search(name, exact=exact) total = len(groups) return jsonify( groups=[serialize_group(group) for group in groups[:10]], total=total)
def principal_from_fossil(fossil, allow_pending=False, allow_groups=True, allow_missing_groups=False, allow_emails=False, allow_networks=False, existing_data=None, event=None): from indico.modules.networks.models.networks import IPNetworkGroup from indico.modules.events.models.roles import EventRole from indico.modules.groups import GroupProxy from indico.modules.users import User if existing_data is None: existing_data = set() type_ = fossil['_type'] id_ = fossil['id'] if type_ == 'Avatar': if isinstance(id_, int) or id_.isdigit(): # regular user user = User.get(int(id_)) elif allow_pending: data = GenericCache('pending_identities').get(id_) if not data: raise ValueError("Cannot find user '{}' in cache".format(id_)) data = {k: '' if v is None else v for k, v in data.items()} email = data['email'].lower() # check if there is not already a (pending) user with that e-mail # we need to check for non-pending users too since the search may # show a user from external results even though the email belongs # to an indico account in case some of the search criteria did not # match the indico account user = User.query.filter(User.all_emails == email, ~User.is_deleted).first() if not user: user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=email, address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() else: raise ValueError("Id '{}' is not a number and allow_pending=False".format(id_)) if user is None: raise ValueError('User does not exist: {}'.format(id_)) return user elif allow_emails and type_ == 'Email': return EmailPrincipal(id_) elif allow_networks and type_ == 'IPNetworkGroup': group = IPNetworkGroup.get(int(id_)) if group is None or (group.hidden and group not in existing_data): raise ValueError('IP network group does not exist: {}'.format(id_)) return group elif allow_groups and type_ in {'LocalGroupWrapper', 'LocalGroup'}: group = GroupProxy(int(id_)) if group.group is None: raise ValueError('Local group does not exist: {}'.format(id_)) return group elif allow_groups and type_ in {'LDAPGroupWrapper', 'MultipassGroup'}: provider = fossil['provider'] group = GroupProxy(id_, provider) if group.group is None and not allow_missing_groups: raise ValueError('Multipass group does not exist: {}:{}'.format(provider, id_)) return group elif event and type_ == 'EventRole': role = EventRole.get(id_) role_name = fossil.get('name') if role is None: raise ValueError('Role does not exist: {}:{}'.format(role_name, id_)) if role.event != event: raise ValueError('Role does not belong to provided event: {}:{} - {}'.format(role_name, id_, event)) return role else: raise ValueError('Unexpected fossil type: {}'.format(type_))
def _process(self, name, exact): groups = GroupProxy.search(name, exact=exact) total = len(groups) return jsonify(groups=[serialize_group(group) for group in groups[:10]], total=total)
def _getAnswer(self): results = [g.as_legacy_group for g in GroupProxy.search(self._group, exact=self._exactMatch)] fossilized_results = fossilize(results, IGroupFossil) for fossilizedGroup in fossilized_results: fossilizedGroup["isGroup"] = True return fossilized_results
def _process(self, name): groups = GroupProxy.search(name) return jsonify([serialize_group(group) for group in groups])
def is_member_of_group(self, group_name): group_provider = multipass.default_group_provider group = GroupProxy(group_name, group_provider.name if group_provider else None) return group.has_member(self.user)
def proxy(self): """Return a GroupProxy wrapping this group.""" from indico.modules.groups import GroupProxy return GroupProxy(self.id, _group=self)
def group(self): return GroupProxy(self.id, self.provider)
def getName(self): return GroupProxy(self.id).name
def group(self): return GroupProxy(self.id)