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 _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 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 _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 _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 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 _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 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 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 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 _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 _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 _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 getName(self): return GroupProxy(self.id).name
def proxy(self): """Return a GroupProxy wrapping this group.""" from indico.modules.groups import GroupProxy return GroupProxy(self.id, _group=self)
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 group(self): return GroupProxy(self.id)
def principal_from_identifier(identifier, allow_groups=False, allow_external_users=False, allow_event_roles=False, allow_category_roles=False, allow_registration_forms=False, allow_emails=False, event_id=None, soft_fail=False): from indico.modules.events.models.events import Event from indico.modules.events.models.roles import EventRole from indico.modules.categories.models.roles import CategoryRole from indico.modules.events.registration.models.forms import RegistrationForm 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=(None if soft_fail else 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 not soft_fail and group.group is None: raise ValueError('Invalid group: {}'.format(data)) return group elif type_ == 'EventRole': if not allow_event_roles: raise ValueError('Event roles are not allowed') try: event_role_id = int(data) except ValueError: raise ValueError('Invalid data') event_role = EventRole.get(event_role_id) if event_role is None or event_role.event_id != event_id: raise ValueError('Invalid event role: {}'.format(event_role_id)) return event_role elif type_ == 'CategoryRole': if not allow_category_roles: raise ValueError('Category roles are not allowed') event = Event.get(event_id) if event is None: raise ValueError('Invalid event id: {}'.format(event_id)) try: category_role_id = int(data) except ValueError: raise ValueError('Invalid data') if soft_fail: category_role = CategoryRole.get(category_role_id) else: category_role = CategoryRole.get_category_role_by_id(event.category, category_role_id) if category_role is None: raise ValueError('Invalid category role: {}'.format(category_role_id)) return category_role elif type_ == 'RegistrationForm': if not allow_registration_forms: raise ValueError('Registration forms are not allowed') try: reg_form_id = int(data) except ValueError: raise ValueError('Invalid data') registration_form = RegistrationForm.get(reg_form_id, is_deleted=(None if soft_fail else False)) if registration_form is None or registration_form.event_id != event_id: raise ValueError('Invalid registration form: {}'.format(reg_form_id)) return registration_form elif type_ == 'Email': if not allow_emails: raise ValueError('Emails are not allowed') return EmailPrincipal(data) else: raise ValueError('Invalid data')
def group(self): return GroupProxy(self.id, self.provider)
def _include_capitalized_groups(groups): alternatives = _get_alternative_group_names() for group in groups: yield group.identifier for alt_name in alternatives.get((group.provider, group.name.lower()), ()): yield GroupProxy(alt_name, group.provider).identifier
def fetch_rooms(self, connection, room_name=None): self._logger.debug("Fetching room information...") counter = Counter() foundation_rooms = [] coordinates = self.fetch_buildings_coordinates(connection) cursor = connection.cursor() if room_name: cursor.execute( 'SELECT * FROM foundation_pub.meeting_rooms WHERE ID = :room_name', room_name=room_name) else: cursor.execute( 'SELECT * FROM foundation_pub.meeting_rooms ORDER BY ID') for row in cursor: counter['found'] += 1 data = self._prepare_row(row, cursor) room_id = data['ID'] try: room_data, email_warning = self._parse_room_data( data, coordinates, room_id) manager_group = data.get('EMAIL_LIST') self._logger.debug("Fetched data for room with id='%s'", room_id) except SkipRoom as e: counter['skipped'] += 1 self._logger.info("Skipped room %s: %s", room_id, e) continue room = Room.query.filter_by(building=room_data['building'], floor=room_data['floor'], number=room_data['number'], location=self._location).first() if room_data['owner'] is None: del room_data['owner'] if room is None: counter['skipped'] += 1 self._logger.info("Skipped room %s: %s", room_id, email_warning[0] % email_warning[1:]) continue elif not room.is_deleted: self._logger.warning(*email_warning) # Insert new room if room is None: room = Room() self._location.rooms.append(room) counter['inserted'] += 1 self._logger.info("Created new room '%s'", room_id) else: counter['updated'] += 1 # Update room data self._update_room(room, room_data) new_managers = set() if manager_group is not None: group = GroupProxy(manager_group.strip(), provider='cern-ldap') if group.group is None: self._logger.warning("Group '%s' does not exist in LDAP", manager_group) new_managers.add(group) current_managers = room.get_manager_list() for principal in current_managers - new_managers: room.update_principal(principal, full_access=False) for principal in new_managers - current_managers: room.update_principal(principal, full_access=True) self._logger.info("Updated room '%s' information", room_id) foundation_rooms.append(room) # Deactivate rooms not found in Foundation indico_rooms = Room.find( Room.name == room_name) if room_name else Room.find( location=self._location) rooms_to_deactivate = ( room for room in indico_rooms if room not in foundation_rooms and not room.is_deleted) for room in rooms_to_deactivate: self._logger.info("Deactivated room '%s'", room.full_name) room.is_deleted = True counter['deactivated'] += 1 self._logger.info("Deactivated %d rooms not found in Foundation", counter['deactivated']) db.session.commit() self._logger.info( "Rooms summary: %d in Foundation - %d skipped - %d inserted - %d updated - %d deactivated", counter['found'], counter['skipped'], counter['inserted'], counter['updated'], counter['deactivated'])
user._affiliation.name = user._affiliation.affiliation_link.name 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 not soft_fail and group.group is None: raise ValueError(f'Invalid group: {data}') return group elif type_ == 'EventRole': if not allow_event_roles: raise ValueError('Event roles are not allowed') try: event_role_id = int(data) except ValueError: raise ValueError('Invalid data') event_role = EventRole.get(event_role_id) if event_role is None or event_role.event_id != event_id:
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)