def test_invenio_access_permissions_deny(app): """User without any provides can't access to a place limited to user 0""" with app.test_request_context(): permission = DynamicPermission(UserNeed(0)) fake_identity = FakeIdentity() assert not permission.allows(fake_identity)
def test_invenio_access_permission_cache_redis(app): """Caching the user using redis.""" cache = RedisCache() InvenioAccess(app, cache=cache) with app.test_request_context(): user_can_all = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_open) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.flush() identity_open = FakeIdentity(UserNeed(user_can_open.id)) permission_open = DynamicPermission(ActionNeed('open')) assert not permission_open.allows(identity_open) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.flush() permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_open) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) )
def permission_factory(obj, action): """Get default permission factory. :param obj: An instance of :class:`invenio_files_rest.models.Bucket` or :class:`invenio_files_rest.models.ObjectVersion` or :class:`invenio_files_rest.models.MultipartObject` or ``None`` if the action is global. :param action: The required action. :raises RuntimeError: If the object is unknown. :returns: A :class:`invenio_access.permissions.DynamicPermission` instance. """ need_class = _action2need_map[action] if obj is None: return DynamicPermission(need_class(None)) arg = None if isinstance(obj, Bucket): arg = str(obj.id) elif isinstance(obj, ObjectVersion): arg = str(obj.bucket_id) elif isinstance(obj, MultipartObject): arg = str(obj.bucket_id) else: raise RuntimeError('Unknown object') return DynamicPermission(need_class(arg))
def test_invenio_access_permission_for_users(app): """User can access to an action allowed/denied to the user""" InvenioAccess(app) with app.test_request_context(): db.session.begin(nested=True) user_can_all = User(email='*****@*****.**') user_can_read = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_read) db.session.add(user_can_open) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.add(ActionUsers(action='read', user=user_can_all)) db.session.add(ActionUsers(action='read', user=user_can_read)) db.session.commit() permission_open = DynamicPermission(ActionNeed('open')) permission_read = DynamicPermission(ActionNeed('read')) identity_all = FakeIdentity(UserNeed(user_can_all.id)) identity_read = FakeIdentity(UserNeed(user_can_read.id)) identity_open = FakeIdentity(UserNeed(user_can_open.id)) assert permission_open.allows(identity_all) assert permission_read.allows(identity_all) assert permission_open.allows(identity_open) assert not permission_read.allows(identity_open) assert not permission_open.allows(identity_read) assert permission_read.allows(identity_read)
def test_invenio_access_permissions_deny(app): """User without any provides can't access to a place limited to user 0""" InvenioAccess(app) with app.test_request_context(): permission = DynamicPermission(UserNeed(0)) fake_identity = FakeIdentity() assert not permission.allows(fake_identity)
def test_invenio_access_permission_cache(app): """Caching the user using memory caching.""" cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): user_can_all = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') user_can_open_1 = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_open) db.session.add(user_can_open_1) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.flush() permission_open = DynamicPermission(ActionNeed('open')) identity_open = FakeIdentity(UserNeed(user_can_open.id)) assert not permission_open.allows(identity_open) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.flush() permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_open) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) db.session.add(ActionUsers(action='open', argument=1, user=user_can_open_1)) db.session.flush() identity_open_1 = FakeIdentity(UserNeed(user_can_open_1.id)) permission_open_1 = DynamicPermission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_open_1) assert permission_open_1.allows(identity_open_1) assert current_access.get_action_cache('open::1') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=3)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) )
def test_permissions(): """Iterates over all users checking its permissions.""" for i in range(users_number): identity = FakeIdentity(UserNeed(users[i].id)) # Allowed permission permission_allowed_both = DynamicPermission( ActionNeed('action{0}'.format( (i % actions_users_number) + actions_roles_number)), ActionNeed('action{0}'.format(i % actions_roles_number)) ) assert permission_allowed_both.allows(identity) # Not allowed action user permission_not_allowed_user = DynamicPermission( ActionNeed('action{0}'.format( (i + 1) % actions_users_number + actions_roles_number)) ) assert not permission_not_allowed_user.allows(identity) # Not allowed action role permission_not_allowed_role = DynamicPermission( ActionNeed('action{0}'.format( (i + 1) % actions_roles_number)) ) assert not permission_not_allowed_role.allows(identity)
def test_invenio_access_permission_for_roles(app): """User with a role can access to an action allowed to the role""" with app.test_request_context(): admin_role = Role(name='admin') reader_role = Role(name='reader') opener_role = Role(name='opener') db.session.add(admin_role) db.session.add(reader_role) db.session.add(opener_role) db.session.add(ActionRoles(action='open', role=admin_role)) db.session.add(ActionRoles(action='open', role=opener_role)) db.session.add(ActionRoles(action='read', role=admin_role)) db.session.add(ActionRoles(action='read', role=reader_role)) db.session.flush() permission_open = DynamicPermission(ActionNeed('open')) permission_read = DynamicPermission(ActionNeed('read')) identity_all = FakeIdentity(RoleNeed('admin')) identity_read = FakeIdentity(RoleNeed('reader')) identity_open = FakeIdentity(RoleNeed('opener')) assert permission_open.allows(identity_all) assert permission_read.allows(identity_all) assert permission_open.allows(identity_open) assert not permission_read.allows(identity_open) assert not permission_open.allows(identity_read) assert permission_read.allows(identity_read)
def test_dynamic_permission_needs_cache_invalidation(app): """Testing DynamicPermission refreshes needs. This is important when protecting a view with @permission.require(http_exception=403) If cache does not get invalidated, the needs will only be refreshed when the Python process restarts. """ cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): user_can_all = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_open) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.flush() permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.needs == set([Need(method='id', value=1)]) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.flush() assert permission_open.needs == set( [Need(method='id', value=1), Need(method='id', value=2)] )
def community_curation(record, user): """Generate a list of pending and accepted communities with permissions. Return a 2-tuple containing two lists, first for 'pending' and second for 'accepted' communities. Each item in both of the list is another 2-tuple of (Community, bool), describing community itself, and the permission (bool) to curate it. """ irs = InclusionRequest.query.filter_by(id_record=record.id).order_by( InclusionRequest.id_community).all() pending = [ir.community for ir in irs] accepted = [Community.get(c) for c in record.get('communities', [])] # Additionally filter out community IDs that did not resolve (None) accepted = [c for c in accepted if c] # Check for global curation permission (all communites on this record). global_perm = None if user.is_anonymous: global_perm = False elif DynamicPermission(ActionNeed('admin-access')).can(): global_perm = True if global_perm: return (pending, pending, accepted, accepted) else: return ( [c for c in pending if _can_curate(c, user, record)], [c for c in accepted if _can_curate(c, user, record, accepted=True)], pending, accepted, )
def files_permission_factory(obj, action=None): """Permission for files are always based on the type of record. Record bucket: Read access only with open access. Deposit bucket: Read/update with restricted access. """ # Extract bucket id bucket_id = None if isinstance(obj, Bucket): bucket_id = str(obj.id) elif isinstance(obj, ObjectVersion): bucket_id = str(obj.bucket_id) elif isinstance(obj, MultipartObject): bucket_id = str(obj.bucket_id) elif isinstance(obj, FileObject): bucket_id = str(obj.bucket_id) # Retrieve record if bucket_id is not None: # Record or deposit bucket rb = RecordsBuckets.query.filter_by(bucket_id=bucket_id).one_or_none() if rb is not None: record = Record.get_record(rb.record_id) if is_publication(record.model): return PublicationFilesPermission(record, action) elif is_deposit(record.model): return DepositFilesPermission(record, action) return DynamicPermission(superuser_access)
def community_curation(record, user): """Generate a list of pending and accepted communities with permissions. Return a 4-tuple of lists (in order): * 'pending' communities, which can be curated by given user * 'accepted' communities, which can be curated by given user * All 'pending' communities * All 'accepted' communities """ irs = ZenodoCommunity.get_irs(record).all() pending = list(set(ir.community for ir in irs)) accepted = [Community.get(c) for c in record.get('communities', [])] # Additionally filter out community IDs that did not resolve (None) accepted = [c for c in accepted if c] # Check for global curation permission (all communites on this record). global_perm = None if user.is_anonymous: global_perm = False elif DynamicPermission(ActionNeed('admin-access')).can(): global_perm = True if global_perm: return (pending, accepted, pending, accepted) else: return ( [c for c in pending if _can_curate(c, user, record)], [ c for c in accepted if _can_curate(c, user, record, accepted=True) ], pending, accepted, )
def test_invenio_access_permission_for_system_roles(app): """User can access to an action allowed/denied to their system roles.""" InvenioAccess(app) with app.test_request_context(): db.session.begin(nested=True) user = User(email='*****@*****.**') db.session.add(user) db.session.add(ActionSystemRoles.allow( action=ActionNeed('open'), role=authenticated_user)) db.session.add(ActionSystemRoles.allow( action=ActionNeed('write'), role_name='any_user')) db.session.commit() permission_open = DynamicPermission(ActionNeed('open')) permission_write = DynamicPermission(ActionNeed('write')) identity_anon_user = FakeIdentity(any_user) identity_auth_user = FakeIdentity(authenticated_user, any_user) assert not permission_open.allows(identity_anon_user) assert permission_open.allows(identity_auth_user) assert permission_write.allows(identity_anon_user) assert permission_write.allows(identity_auth_user)
def permission_factory(obj, action): """Permission factory.""" need_class = _action2need_map[action] if obj is None: return DynamicPermission(need_class(None)) arg = None if isinstance(obj, Bucket): arg = str(obj.id) elif isinstance(obj, ObjectVersion): arg = str(obj.bucket_id) elif isinstance(obj, MultipartObject): arg = str(obj.bucket_id) else: raise RuntimeError('Unknown object') return DynamicPermission(need_class(arg))
def read_permission_factory(record): """Factory for creating read permissions for records.""" permission = DynamicPermission(RecordReadActionNeed(str(record.id))) old_can = permission.can def new_can(): is_public = ActionUsers.query.filter( ActionUsers.action == 'records-read', ActionUsers.argument == str(record.id), ActionUsers.user_id.is_(None)).first() if is_public or old_can(): return True else: return False permission.can = new_can return permission
def test_invenio_access_dynamic_permission(app): """DynamicPermission allows by default.""" fake_identity = FakeIdentity() InvenioAccess(app) with app.test_request_context(): db.session.begin(nested=True) user = User(email='*****@*****.**') permission = DynamicPermission(ActionNeed('read')) # The permission is granted if nobody is assigned the "read" permission assert permission.allows(fake_identity) # Once the permission is assigned, the need is mandatory db.session.add(ActionUsers(action='read', user=user)) db.session.commit() assert not permission.allows(fake_identity) fake_identity.provides.add(UserNeed(user.id)) assert permission.allows(fake_identity)
def role_admin(): """View only allowed to admin role.""" identity = g.identity actions = {} for action in access.actions.values(): actions[action.value] = DynamicPermission(action).allows(identity) message = 'You are opening a page limited to action read' return render_template("invenio_access/limited.html", message=message, actions=actions, identity=identity)
def _load_additional_permissions(self): # owners of the deposit are allowed to read the deposit. needs = set(UserNeed(owner_id) for owner_id in self.deposit['_deposit']['owners']) # add specific permission to read deposits of this community # in this publication state needs.add(read_deposit_need_factory( community=self.deposit['community'], publication_state=self.deposit['publication_state'], )) permission = DynamicPermission(*needs) self.permissions.add(permission)
def action_read(): """View only allowed to open action.""" identity = g.identity actions = {} for action in access.actions.values(): actions[action.value] = DynamicPermission(action).allows(identity) message = 'You are opening a page requiring the "read" permission' return render_template("invenio_access/limited.html", message=message, actions=actions, identity=identity)
def test_invenio_access_permission_cache_redis(app): """Caching the user using redis.""" cache = RedisCache() InvenioAccess(app, cache=cache) with app.test_request_context(): user_can_all = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_open) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.flush() identity_open = FakeIdentity(UserNeed(user_can_open.id)) permission_open = DynamicPermission(ActionNeed('open')) assert not permission_open.allows(identity_open) assert current_access.get_action_cache('open') == (set( [Need(method='id', value=1)]), set([])) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.flush() permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_open) assert current_access.get_action_cache('open') == (set( [Need(method='id', value=1), Need(method='id', value=2)]), set([]))
def admin_permission_factory(): """Default factory for creating a permission for an admin. It tries to load a :class:`invenio_access.permissions.DynamicPermission` instance if `invenio_access` is installed. Otherwise, it loads a :class:`flask_principal.Permission` instance. :param admin_view: Instance of administration view which is currently being protected. :returns: Permission instance. """ admin_needs = set([g for g in current_app.config['SUPERUSER_EGROUPS']]) return DynamicPermission(*admin_needs)
def test_invenio_access_permission_for_roles(app): """User with a role can access to an action allowed to the role""" InvenioAccess(app) with app.test_request_context(): admin_role = Role(name='admin') reader_role = Role(name='reader') opener_role = Role(name='opener') db.session.add(admin_role) db.session.add(reader_role) db.session.add(opener_role) db.session.add(ActionRoles(action='open', role=admin_role)) db.session.add(ActionRoles(action='open', role=opener_role)) db.session.add(ActionRoles(action='read', role=admin_role)) db.session.add(ActionRoles(action='read', role=reader_role)) db.session.commit() with app.app_context(): permission_open = DynamicPermission(ActionNeed('open')) permission_read = DynamicPermission(ActionNeed('read')) identity_all = FakeIdentity(RoleNeed('admin')) identity_read = FakeIdentity(RoleNeed('reader')) identity_open = FakeIdentity(RoleNeed('opener')) assert permission_open.allows(identity_all) assert permission_read.allows(identity_all) assert permission_open.allows(identity_open) assert not permission_read.allows(identity_open) assert not permission_open.allows(identity_read) assert permission_read.allows(identity_read)
def index(): """Basic test view.""" identity = g.identity actions = {} for action in access.actions.values(): actions[action.value] = DynamicPermission(action).allows(identity) if current_user.is_anonymous: return render_template("invenio_access/open.html", actions=actions, identity=identity) else: return render_template("invenio_access/limited.html", message='', actions=actions, identity=identity)
def delete(user_id): """Delete spam.""" # Only admin can access this view if not DynamicPermission(ActionNeed('admin-access')).can(): abort(403) user = User.query.get(user_id) deleteform = DeleteSpamForm(request.values) communities = Community.query.filter_by(id_user=user.id) rs = RecordsSearch(index='records').query( Q('query_string', query="owners: {0}".format(user.id))) rec_count = rs.count() ctx = { 'user': user, 'form': deleteform, 'is_new': False, 'communities': communities, 'rec_count': rec_count, } if deleteform.validate_on_submit(): if deleteform.remove_all_communities.data: for c in communities: if not c.deleted_at: if not c.description.startswith('--SPAM--'): c.description = '--SPAM--' + c.description c.delete() db.session.commit() if deleteform.deactivate_user.data: _datastore.deactivate_user(user) db.session.commit() # delete_record function commits the session internally # for each deleted record if deleteform.remove_all_records.data: for r in rs.scan(): delete_record(r.meta.id, 'spam', int(current_user.get_id())) flash("Spam removed", category='success') return redirect(url_for('.delete', user_id=user.id)) else: records = islice(rs.scan(), 10) ctx.update(records=records) return render_template('zenodo_spam/delete.html', **ctx)
def cern_filter(): """Filter list of results.""" # Send empty query for admins if DynamicPermission(superuser_access).allows(g.identity): return Q() # Get CERN user's provides provides = get_user_provides() # Filter for restricted records, that the user has access to write_restricted = Q('terms', **{'_access.update': provides}) # Filter records where the user is owner owner = Q('match', **{'_deposit.created_by': getattr(current_user, 'id', -1)}) # OR all the filters combined_filter = write_restricted | owner return Q('bool', filter=[combined_filter])
def can(self): """Grant permission if owner or admin.""" return str(current_user.get_id()) == str(self.community.id_user) or \ DynamicPermission(ActionNeed('admin-access')).can()
def test_invenio_access_permission_for_users(app): """User can access to an action allowed/denied to the user""" InvenioAccess(app) with app.test_request_context(): db.session.begin(nested=True) superuser = User(email='*****@*****.**') user_can_all = User(email='*****@*****.**') user_can_read = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') db.session.add(superuser) db.session.add(user_can_all) db.session.add(user_can_read) db.session.add(user_can_open) db.session.add(ActionUsers(action='superuser-access', user=superuser)) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.add(ActionUsers(action='read', user=user_can_all)) db.session.add(ActionUsers(action='read', user=user_can_read)) db.session.add(ActionUsers(action='not_logged', user=user_can_all)) db.session.commit() permission_open = DynamicPermission(ActionNeed('open')) permission_read = DynamicPermission(ActionNeed('read')) permission_not_logged = DynamicPermission(ActionNeed('not_logged')) identity_superuser = FakeIdentity(UserNeed(superuser.id)) identity_all = FakeIdentity(UserNeed(user_can_all.id)) identity_read = FakeIdentity(UserNeed(user_can_read.id)) identity_open = FakeIdentity(UserNeed(user_can_open.id)) identity_unknown = AnonymousIdentity() # global permissions assert permission_open.allows(identity_superuser) assert permission_read.allows(identity_superuser) assert permission_open.allows(identity_all) assert permission_read.allows(identity_all) assert permission_not_logged.allows(identity_all) assert permission_open.allows(identity_open) assert not permission_read.allows(identity_open) assert not permission_not_logged.allows(identity_open) assert not permission_open.allows(identity_read) assert permission_read.allows(identity_read) assert not permission_not_logged.allows(identity_read) assert not permission_open.allows(identity_unknown) assert not permission_read.allows(identity_unknown)
def test_invenio_access_permission_cache_system_roles_updates(app): """Testing ActionSystemRoles cache with inserts/updates/deletes.""" # This test case is doing the same of user test case but using # system roles. cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): system_role_1 = SystemRoleNeed('system_role_1') system_role_2 = SystemRoleNeed('system_role_2') system_role_3 = SystemRoleNeed('system_role_3') system_role_4 = SystemRoleNeed('system_role_4') system_role_5 = SystemRoleNeed('system_role_5') system_role_6 = SystemRoleNeed('system_role_6') current_access.system_roles = { 'system_role_1': system_role_1, 'system_role_2': system_role_2, 'system_role_3': system_role_3, 'system_role_4': system_role_4, 'system_role_5': system_role_5, 'system_role_6': system_role_6, } # Creation of some data to test. db.session.add(ActionSystemRoles(action='open', role_name=system_role_1.value)) db.session.add(ActionSystemRoles(action='write', role_name=system_role_4.value)) db.session.flush() # Creation of identities to test. identity_fake_1 = FakeIdentity(system_role_1) identity_fake_2 = FakeIdentity(system_role_2) identity_fake_3 = FakeIdentity(system_role_3) identity_fake_4 = FakeIdentity(system_role_4) identity_fake_5 = FakeIdentity(system_role_5) identity_fake_6 = FakeIdentity(system_role_6) # Test if system_role_1 can open. In this case, the cache should store # only this object. permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_fake_1) assert current_access.get_action_cache('open') == ( set([system_role_1]), set([]) ) # Test if system_role_2 can write. In this case, the cache should # have this new object and the previous one (Open is allowed to # system_role_1) permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_4) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1]), set([]) ) # If we add a new system role to the action open, the open action in # cache should be removed but it should still containing the write # entry. db.session.add(ActionSystemRoles(action='open', role_name=system_role_2.value)) db.session.flush() assert current_access.get_action_cache('open') is None permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_fake_2) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) # Test if the new role is added to the action 'open' permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_4) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) # If we update an action swapping a role, the cache containing the # action, should be removed. role_4_action_write = ActionSystemRoles.query.filter( ActionSystemRoles.action == 'write' and ActionSystemRoles.role_name == system_role_4.value).first() role_4_action_write.role_name = system_role_3.value db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is not None assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) # Test if the system_role_3 can write now. permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_fake_4) permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_3) assert current_access.get_action_cache('write') == ( set([system_role_3]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) # If we remove a role from an action, the cache should clear the # action item. cust_action_write = ActionSystemRoles.query.filter( ActionSystemRoles.action == 'write' and ActionSystemRoles.role_name == system_role_3).first() db.session.delete(cust_action_write) db.session.flush() assert current_access.get_action_cache('write') is None # If no one is allowed to perform an action then everybody is allowed. permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_3) assert current_access.get_action_cache('write') == ( set([]), set([]) ) db.session.add(ActionSystemRoles(action='write', role_name=system_role_5.value)) db.session.flush() permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_5) permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_fake_3) assert current_access.get_action_cache('write') == ( set([system_role_5]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) # If you update the name of an existing action, the previous action # and the new action should be remove from cache. permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_5) assert current_access.get_action_cache('write') == ( set([system_role_5]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) role_5_action_write = ActionSystemRoles.query.filter( ActionSystemRoles.action == 'write' and ActionSystemRoles.role_name == system_role_5.value).first() role_5_action_write.action = 'open' db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is None permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_fake_1) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2, system_role_5]), set([]) ) db.session.add(ActionSystemRoles(action='write', role_name=system_role_4.value)) permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_fake_5) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) db.session.add(ActionSystemRoles(action='open', argument='1', role_name=system_role_6.value)) db.session.flush() permission_open_1 = DynamicPermission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_fake_6) assert permission_open_1.allows(identity_fake_6) assert current_access.get_action_cache('open::1') == ( set([system_role_1, system_role_2, system_role_5, system_role_6]), set([]) ) user_6_action_open_1 = ActionSystemRoles.query.filter_by( action='open', argument='1', role_name=system_role_6.value).first() user_6_action_open_1.argument = '2' db.session.flush() assert current_access.get_action_cache('open::1') is None assert current_access.get_action_cache('open::2') is None permission_open_2 = DynamicPermission( ParameterizedActionNeed('open', '2')) assert permission_open_2.allows(identity_fake_6) assert current_access.get_action_cache('open::2') == ( set([system_role_1, system_role_2, system_role_5, system_role_6]), set([]) ) # open action cache should remain as before assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2, system_role_5]), set([]) )
def test_invenio_access_permission_cache_users_updates(app): """Testing ActionUsers cache with inserts/updates/deletes.""" cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): # Creation of some data to test. user_1 = User(email='*****@*****.**') user_2 = User(email='*****@*****.**') user_3 = User(email='*****@*****.**') user_4 = User(email='*****@*****.**') user_5 = User(email='*****@*****.**') user_6 = User(email='*****@*****.**') db.session.add(user_1) db.session.add(user_2) db.session.add(user_3) db.session.add(user_4) db.session.add(user_5) db.session.add(user_6) db.session.add(ActionUsers(action='open', user=user_1)) db.session.add(ActionUsers(action='write', user=user_4)) db.session.flush() # Creation identities to test. identity_user_1 = FakeIdentity(UserNeed(user_1.id)) identity_user_2 = FakeIdentity(UserNeed(user_2.id)) identity_user_3 = FakeIdentity(UserNeed(user_3.id)) identity_user_4 = FakeIdentity(UserNeed(user_4.id)) identity_user_5 = FakeIdentity(UserNeed(user_5.id)) identity_user_6 = FakeIdentity(UserNeed(user_6.id)) # Test if user 1 can open. In this case, the cache should store only # this object. permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_user_1) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) # Test if user 4 can write. In this case, the cache should have this # new object and the previous one (Open is allowed to user_1) permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_user_4) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) # If we add a new user to the action open, the open action in cache # should be removed but it should still containing the write entry. db.session.add(ActionUsers(action='open', user=user_2)) db.session.flush() assert current_access.get_action_cache('open') is None permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_user_2) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) # Test if the new user is added to the action 'open' permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_user_4) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) # If we update an action swapping a user, the cache containing the # action, should be removed. user_4_action_write = ActionUsers.query.filter( ActionUsers.action == 'write' and ActionUsers.user == user_4).first() user_4_action_write.user = user_3 db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) # Test if the user_3 can now write. permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_user_4) permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_user_3) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=3)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) # If we remove a user from an action, the cache should clear the # action item. user_3_action_write = ActionUsers.query.filter( ActionUsers.action == 'write' and ActionUsers.user == user_3).first() db.session.delete(user_3_action_write) db.session.flush() assert current_access.get_action_cache('write') is None # If no one is allowed to perform an action then everybody is allowed. permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_user_3) assert current_access.get_action_cache('write') == ( set([]), set([]) ) db.session.add(ActionUsers(action='write', user=user_5)) db.session.flush() permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_user_5) permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_user_3) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=5)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) # If you update the name of an existing action, the previous action # and the new action should be remove from cache. permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_user_5) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=5)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) user_5_action_write = ActionUsers.query.filter( ActionUsers.action == 'write' and ActionUsers.user == user_5).first() user_5_action_write.action = 'open' db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is None permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_user_1) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5)]), set([]) ) db.session.add(ActionUsers(action='write', user=user_4)) permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_user_5) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) db.session.add(ActionUsers(action='open', argument='1', user=user_6)) db.session.flush() permission_open_1 = DynamicPermission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_user_6) assert permission_open_1.allows(identity_user_6) assert current_access.get_action_cache('open::1') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5), Need(method='id', value=6)]), set([]) ) user_6_action_open_1 = ActionUsers.query.filter_by( action='open', argument='1', user_id=user_6.id).first() user_6_action_open_1.argument = '2' db.session.flush() assert current_access.get_action_cache('open::1') is None assert current_access.get_action_cache('open::2') is None permission_open_2 = DynamicPermission( ParameterizedActionNeed('open', '2')) assert permission_open_2.allows(identity_user_6) assert current_access.get_action_cache('open::2') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5), Need(method='id', value=6)]), set([]) ) # open action cache should remain as before assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5)]), set([]) )
def test_invenio_access_permission_cache_roles_updates(app): """Testing ActionRoles cache with inserts/updates/deletes.""" # This test case is doing the same of user test case but using roles. cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): # Creation of some data to test. role_1 = Role(name='role_1') role_2 = Role(name='role_2') role_3 = Role(name='role_3') role_4 = Role(name='role_4') role_5 = Role(name='role_5') role_6 = Role(name='role_6') db.session.add(role_1) db.session.add(role_2) db.session.add(role_3) db.session.add(role_4) db.session.add(role_5) db.session.add(role_6) db.session.add(ActionRoles(action='open', role=role_1)) db.session.add(ActionRoles(action='write', role=role_4)) db.session.flush() # Creation of identities to test. identity_fake_role_1 = FakeIdentity(RoleNeed(role_1.name)) identity_fake_role_2 = FakeIdentity(RoleNeed(role_2.name)) identity_fake_role_3 = FakeIdentity(RoleNeed(role_3.name)) identity_fake_role_4 = FakeIdentity(RoleNeed(role_4.name)) identity_fake_role_5 = FakeIdentity(RoleNeed(role_5.name)) identity_fake_role_6 = FakeIdentity(RoleNeed(role_6.name)) # Test if role 1 can open. In this case, the cache should store only # this object. permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_fake_role_1) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name)]), set([]) ) # Test if role 4 can write. In this case, the cache should have this # new object and the previous one (Open is allowed to role_1) permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_4) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name)]), set([]) ) # If we add a new role to the action open, the open action in cache # should be removed but it should still containing the write entry. db.session.add(ActionRoles(action='open', role=role_2)) db.session.flush() assert current_access.get_action_cache('open') is None permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_fake_role_2) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) # Test if the new role is added to the action 'open' permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_4) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) # If we update an action swapping a role, the cache containing the # action, should be removed. role_4_action_write = ActionRoles.query.filter( ActionRoles.action == 'write' and ActionRoles.role == role_4).first() role_4_action_write.role = role_3 db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is not None assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) # Test if the role_3 can write now. permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_fake_role_4) permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_3) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_3.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) # If we remove a role from an action, the cache should clear the # action item. role_3_action_write = ActionRoles.query.filter( ActionRoles.action == 'write' and ActionRoles.role == role_3).first() db.session.delete(role_3_action_write) db.session.flush() assert current_access.get_action_cache('write') is None # If no one is allowed to perform an action then everybody is allowed. permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_3) assert current_access.get_action_cache('write') == ( set([]), set([]) ) db.session.add(ActionRoles(action='write', role=role_5)) db.session.flush() permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_5) permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_fake_role_3) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_5.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) # If you update the name of an existing action, the previous action # and the new action should be remove from cache. permission_write = DynamicPermission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_5) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_5.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) role_5_action_write = ActionRoles.query.filter( ActionRoles.action == 'write' and ActionRoles.role == role_5).first() role_5_action_write.action = 'open' db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is None permission_open = DynamicPermission(ActionNeed('open')) assert permission_open.allows(identity_fake_role_1) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name)]), set([]) ) db.session.add(ActionRoles(action='write', role=role_4)) permission_write = DynamicPermission(ActionNeed('write')) assert not permission_write.allows(identity_fake_role_5) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) db.session.add(ActionRoles(action='open', argument='1', role=role_6)) db.session.flush() permission_open_1 = DynamicPermission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_fake_role_6) assert permission_open_1.allows(identity_fake_role_6) assert current_access.get_action_cache('open::1') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name), Need(method='role', value=role_6.name)]), set([]) ) user_6_action_open_1 = ActionRoles.query.filter_by( action='open', argument='1', role_id=role_6.id).first() user_6_action_open_1.argument = '2' db.session.flush() assert current_access.get_action_cache('open::1') is None assert current_access.get_action_cache('open::2') is None permission_open_2 = DynamicPermission( ParameterizedActionNeed('open', '2')) assert permission_open_2.allows(identity_fake_role_6) assert current_access.get_action_cache('open::2') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name), Need(method='role', value=role_6.name)]), set([]) ) # open action cache should remain as before assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name)]), set([]) )
def has_admin_permission(user, record): """Check if user has admin access to record.""" # Allow administrators if DynamicPermission(ActionNeed('admin-access')): return True
def test_invenio_access_argument_permission_for_users(app): """User can access to an action allowed/denied with argument to the user""" InvenioAccess(app) with app.test_request_context(): db.session.begin(nested=True) superuser = User(email='*****@*****.**') user_can_all = User(email='*****@*****.**') user_can_argument_dummy = User(email='*****@*****.**') db.session.add(superuser) db.session.add(user_can_all) db.session.add(user_can_argument_dummy) db.session.add(ActionUsers(action='superuser-access', user=superuser)) db.session.add(ActionUsers(action='argument1', user=user_can_all)) db.session.add(ActionUsers(action='argument1', argument='other', user=user_can_all)) db.session.add(ActionUsers(action='argument1', argument='dummy', user=user_can_argument_dummy)) db.session.add(ActionUsers(action='argument2', argument='other', user=user_can_all)) db.session.commit() permission_argument1 = DynamicPermission(ActionNeed('argument1')) permission_argument1_dummy = DynamicPermission( ParameterizedActionNeed('argument1', 'dummy')) permission_argument1_other = DynamicPermission( ParameterizedActionNeed('argument1', 'other')) permission_argument2 = DynamicPermission(ActionNeed('argument2')) permission_argument2_dummy = DynamicPermission( ParameterizedActionNeed('argument2', 'dummy')) permission_argument2_other = DynamicPermission( ParameterizedActionNeed('argument2', 'other')) identity_superuser = FakeIdentity(UserNeed(superuser.id)) identity_all = FakeIdentity(UserNeed(user_can_all.id)) identity_unknown = AnonymousIdentity() identity_argument_dummy = FakeIdentity( UserNeed(user_can_argument_dummy.id)) # tests for super user assert permission_argument1.allows(identity_superuser) assert permission_argument1_dummy.allows(identity_superuser) assert permission_argument1_other.allows(identity_superuser) assert permission_argument2.allows(identity_superuser) assert permission_argument2_dummy.allows(identity_superuser) assert permission_argument2_other.allows(identity_superuser) # first tests for permissions with argument assert permission_argument1.allows(identity_all) assert permission_argument1_dummy.allows(identity_all) assert permission_argument1_other.allows(identity_all) assert not permission_argument1.allows(identity_argument_dummy) assert permission_argument1_dummy.allows(identity_argument_dummy) assert not permission_argument1_other.allows(identity_argument_dummy) assert not permission_argument1.allows(identity_unknown) assert not permission_argument1_dummy.allows(identity_unknown) assert not permission_argument1_other.allows(identity_unknown) # second tests for permissions with arguments # assert permission_argument2.allows(identity_all) # assert permission_argument2_dummy.allows(identity_all) assert permission_argument2_other.allows(identity_all) # assert permission_argument2.allows(identity_argument_dummy) # assert permission_argument2_dummy.allows(identity_argument_dummy) assert not permission_argument2_other.allows(identity_argument_dummy) # assert permission_argument2.allows(identity_unknown) # assert permission_argument2_dummy.allows(identity_unknown) assert not permission_argument2_other.allows(identity_unknown)
def _cant_view(collection): return not DynamicPermission( ParameterizedActionNeed('view-restricted-collection', collection)).can()
# # In applying this license, RERO does not # waive the privileges and immunities granted to it by virtue of its status # as an Intergovernmental Organization or submit itself to any jurisdiction. """Permissions for this module.""" from flask import abort from flask_login import current_user from flask_principal import RoleNeed from invenio_access.permissions import DynamicPermission from invenio_admin.permissions import \ admin_permission_factory as default_admin_permission_factory request_item_permission = DynamicPermission(RoleNeed('patron')) def login_and_librarian(): """.""" if not current_user.is_authenticated: abort(401) if not librarian_permission.can(): abort(403) def can_request(user=None): """User can request items.""" if not user: user = current_user return user.is_authenticated and request_item_permission.can()
def test_access_matrix(script_info_cli_list): """Test of combinations of cli commands.""" script_info = script_info_cli_list runner = CliRunner() user_roles = { '*****@*****.**': ['admin'], '*****@*****.**': ['admin'], '*****@*****.**': ['opener'], '*****@*****.**': ['editor'], '*****@*****.**': ['opener'], } action_roles = { 'open': ['admin', 'opener'], 'edit': ['admin', 'editor'], } for role in {role for roles in user_roles.values() for role in roles}: # Role creation result = runner.invoke(roles_create, [role], obj=script_info) assert result.exit_code == 0 for email, roles in user_roles.items(): result = runner.invoke(users_create, [email, '--password', '123456', '-a'], obj=script_info) assert result.exit_code == 0 for role in roles: # Role creation result = runner.invoke(roles_add, [email, role], obj=script_info) assert result.exit_code == 0 def role_args(roles): """Generate role arguments.""" for role in roles: yield 'role' yield role for action, roles in action_roles.items(): result = runner.invoke(access, ['allow', action] + list(role_args(roles)), obj=script_info) assert result.exit_code == 0 result = runner.invoke( access, ['deny', 'edit', 'user', '*****@*****.**'], obj=script_info) assert result.exit_code == 0 result = runner.invoke( access, ['allow', '-a', '1', 'edit', 'user', '*****@*****.**'], obj=script_info) assert result.exit_code == 0 permission_open = DynamicPermission(ActionNeed('open')) permission_edit = DynamicPermission(ActionNeed('edit')) permission_edit_1 = DynamicPermission(ParameterizedActionNeed('edit', 1)) permission_edit_2 = DynamicPermission(ParameterizedActionNeed('edit', 2)) user_permissions = { '*****@*****.**': { True: [ permission_open, permission_edit, permission_edit_1, permission_edit_2, ], }, '*****@*****.**': { True: [permission_open], False: [ permission_edit, permission_edit_1, permission_edit_2, ], }, '*****@*****.**': { True: [permission_open], False: [ permission_edit, permission_edit_1, permission_edit_2, ], }, '*****@*****.**': { True: [ permission_edit, permission_edit_1, permission_edit_2, ], False: [permission_open], }, '*****@*****.**': { True: [ permission_open, permission_edit_1, ], False: [ permission_edit, permission_edit_2, ], }, } for email, permissions in user_permissions.items(): with script_info.create_app(None).test_request_context(): user = _security.datastore.find_user(email=email) login_user(user) identity = g.identity for can, actions in permissions.items(): for action in actions: assert action.allows(identity) == can, identity result = runner.invoke(access, ['remove', 'edit'], obj=script_info) assert result.exit_code == 2 result = runner.invoke(access, ['show', '-e', '*****@*****.**'], obj=script_info) assert result.exit_code == 0 assert 'user:[email protected]:edit::deny' in result.output result = runner.invoke(access, ['show', '-r', 'editor'], obj=script_info) assert 'role:editor:edit::allow\n' == result.output assert result.exit_code == 0 # # Remove all permissions. # for action, roles in action_roles.items(): result = runner.invoke(access, ['remove', action] + list(role_args(roles)), obj=script_info) assert result.exit_code == 0 result = runner.invoke( access, ['remove', 'edit', 'user', '*****@*****.**'], obj=script_info) assert result.exit_code == 0 result = runner.invoke( access, ['remove', '-a', '1', 'edit', 'user', '*****@*****.**'], obj=script_info) assert result.exit_code == 0 # All authorizations should be removed. result = runner.invoke(access, ['show', '-r', '*****@*****.**'], obj=script_info) assert result.exit_code == 0 assert result.output == ''