def owner_permission_factory(record=None): """Permissions factory for record owners.""" # TODO: adapt for more owners owners = _get_owners(record) if len(owners) > 0: return Permission(UserNeed(int(owners[0]))) return Permission(UserNeed(-1))
def test_record_owner(app, mocker): generator = RecordOwners() record = _owned_record() assert generator.needs(record=record) == [ UserNeed(16), UserNeed(17), ] assert generator.excludes(record=record) == [] # Anonymous identity. assert not generator.query_filter(identity=mocker.Mock(provides=[])) # Authenticated identity query_filter = generator.query_filter( identity=mocker.Mock( provides=[mocker.Mock(method='id', value=15)] ) ) expected_query_filter = { "terms": { "parent.access.owned_by.user": [15] } } assert query_filter.to_dict() == expected_query_filter
def populate_identity_roles(identity, user=None): identity.user = user if user is None or user.is_anonymous: if current_app.config['POLICY_ANONYMOUS_VIEW_INDEX']: identity.provides.add(roles.index_view) if current_app.config['POLICY_ANONYMOUS_VIEW_POST']: identity.provides.add(roles.post_view) if current_app.config['POLICY_ANONYMOUS_VIEW_STATS']: identity.provides.add(roles.stats_view) if current_app.config['POLICY_ANONYMOUS_DOWNLOADS']: identity.provides.add(roles.post_download) # This user identifier from google shouldn't be spoofable. # And `@` is not a valid email character, except as delimiter b/w domain. # SECURITY WARNING: THIS ASSUMES `user.identifier` IS A GOOGLE EMAIL. # ONLY GOOGLE MUST BE THE AUTHENTICATION METHOD. elif any( user.identifier.endswith("@" + domain) for domain in current_app.config['USER_IDENTIFIER_DOMAINS']): identity.provides.add(UserNeed(user.identifier)) identity.provides.add(roles.index_view) identity.provides.add(roles.post_view) identity.provides.add(roles.post_edit) identity.provides.add(roles.post_comment) identity.provides.add(roles.post_download) identity.provides.add(roles.stats_view) # TODO: Populate group permissions, and port existing group admin # code to roles. else: identity.provides.add(UserNeed(user.identifier)) identity.provides.add(roles.stats_view) return identity
def test_permission_factory(app, db, action, permission_factory): """Test revisions.""" InvenioAccess(app) rec_uuid = uuid.uuid4() with db.session.begin_nested(): user_all = User(email='*****@*****.**') user_one = User(email='*****@*****.**') user_none = User(email='*****@*****.**') db.session.add(user_all) db.session.add(user_one) db.session.add(user_none) db.session.add(ActionUsers(action=action, user=user_all, argument=None)) db.session.add( ActionUsers(action=action, user=user_one, argument=str(rec_uuid))) record = Record.create({'title': 'permission test'}, id_=rec_uuid) # Create a record and assign permissions. permission = permission_factory(record) # Assert which permissions has access. assert permission.allows(FakeIdentity(UserNeed(user_all.id))) assert permission.allows(FakeIdentity(UserNeed(user_one.id))) assert not permission.allows(FakeIdentity(UserNeed(user_none.id)))
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_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_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_deny_by_user_id(access_app): """Ensure deny permission when user is denied.""" admin, reader = create_users("admin", "reader") permission, = create_permissions( {"excludes": [UserNeed(admin.id), UserNeed(reader.id)]}) assert not permission.allows(admin) assert not permission.allows(reader) assert permission.allows(get_superuser())
def record_needs(self): """Create needs of the record.""" needs = [] for access_entity in self.record_allows(): try: if isinstance(access_entity, string_types): needs.append(UserNeed(int(access_entity))) elif isinstance(access_entity, int): needs.append(UserNeed(access_entity)) except ValueError: needs.append(RoleNeed(access_entity.lower())) return needs
def test_update_permission_factory(app, mocker, record, superuser_role_need): patched_g = mocker.patch('invenio_records_permissions.generators.g') patched_g.identity.provides = [mocker.Mock(method='id', value=4)] permission = record_update_permission_factory(record) assert permission.needs == { superuser_role_need, UserNeed(1), UserNeed(2), UserNeed(3) } assert permission.excludes == set()
def test_allow_deny_by_user_id(access_app): """Ensure allow/deny permission when same user is allowed and denied.""" admin, reader = create_users("admin", "reader") permission, = create_permissions({ "needs": [UserNeed(admin.id)], "excludes": [UserNeed(admin.id), UserNeed(reader.id)], }) # `excludes` prevail over `needs` assert not permission.allows(admin) assert not permission.allows(reader) assert permission.allows(get_superuser())
def check_perm(): is_perm_required = Permission.query.filter_by( content_type=request.path).first() if is_perm_required: permissions = set() perm_users = db.session.query(UserPermission.uid)\ .join(Permission, UserPermission.pid == Permission.id)\ .filter(Permission.content_type == request.path).all() admins = db.session.query(User.id).filter_by(role_id=ADMIN).all() for user in perm_users: permissions.add(UserNeed(user.uid)) for user in admins: permissions.add(UserNeed(user.id)) if not PrincipalPermission(*permissions).can(): raise PermissionDenied('PermissionDenied.')
def on_identity_loaded(sender, identity): '''基础权限''' identity.user = current_user if hasattr(current_user, 'id'): identity.provides.add(UserNeed(current_user.id)) if hasattr(current_user, 'is_superuser'): if current_user.is_superuser: identity.provides.add(RoleNeed('super')) if hasattr(current_user, 'is_confirmed'): if current_user.is_confirmed: identity.provides.add(RoleNeed('confirmed')) if hasattr(current_user, 'is_authenticated'): if current_user.is_authenticated: identity.provides.add(RoleNeed('auth')) else: identity.provides.add(RoleNeed('guest')) if hasattr(current_user, 'topics'): for topic in current_user.topics: identity.provides.add(TopicNeed(topic.id)) if hasattr(current_user, 'replies'): for reply in current_user.replies: identity.provides.add(ReplyNeed(reply.id)) if hasattr(current_user, 'collects'): for collect in current_user.collects: identity.provides.add(CollectNeed(collect.id))
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 update_user(): """Update current logged user """ user = current_user form = UserForm(request.form, obj=user) del form.role del form.is_active perm = Permission(UserNeed(user.id), RoleNeed('admin')) perm.test() if form.validate_on_submit(): if form.username.data != user.username and User.username_is_in_use( form.username.data): flash( "This username is already been used. Please choose another one!", "alert-danger") form.username.errors.append('Please correct this field') elif form.email.data != user.email and User.email_is_in_use( form.email.data): flash( "This email is already been used. Please choose another one!", "alert-danger") form.email.errors.append('Please correct this field') else: form.populate_obj(user) db.session.commit() flash("Informations updated", "alert-info") return redirect(url_for('dashboard.index')) return render_template("user/update.html", form=form, user=current_user)
def provides(self): needs = [RoleNeed('authenticated'), UserNeed(self.id)] if self.is_member: needs.append(RoleNeed('member')) if self.is_admin: needs.append(RoleNeed('admin')) return needs
def identity(): """Identity fixture with rights to interact with service.""" i = Identity(1) i.provides.add(UserNeed(1)) i.provides.add(any_user) i.provides.add(system_process) return i
def __init__(self, record=None, previous_record=None): """Constructor. Args: record: data submitted for the new deposit """ super(CreateDepositPermission, self).__init__() self.record = record if record is not None: needs = set() community = Community.get(record['community']) publication_state = record.get('publication_state', 'draft') if publication_state != 'draft' or community.restricted_submission: needs.add(create_deposit_need_factory()) needs.add(create_deposit_need_factory( community=record['community'], publication_state=publication_state, )) elif not community.restricted_submission: needs.add(AuthenticatedNeed) self.permissions.add(StrictDynamicPermission(*needs)) if previous_record: # we allow only the owner of a record to # create a new version of it. needs = set() for owner_id in previous_record['_deposit']['owners']: needs.add(UserNeed(owner_id)) self.permissions.add(StrictDynamicPermission(*needs))
def __init__(self, deposit, new_state=None): """Constructor Args: deposit (Deposit): deposit which is modified. new_state (str): new publication state of the deposit if applicable. """ super(UpdateDepositMetadataPermission, self).__init__() # Owners are allowed to update for owner_id in deposit['_deposit']['owners']: self.explicit_needs.add(UserNeed(owner_id)) # authorize if the user can modify metadata in the old # publication state self.explicit_needs.add( update_deposit_metadata_need_factory( community=deposit['community'], publication_state=deposit['publication_state'] ) ) # authorize if the user can modify metadata in the new # publication state if new_state != deposit['publication_state']: self.explicit_needs.add( update_deposit_metadata_need_factory( community=deposit['community'], publication_state=new_state ) )
def identity_simple(users): """Simple identity fixture.""" user = users[0] i = Identity(user.id) i.provides.add(UserNeed(user.id)) i.provides.add(Need(method='system_role', value='any_user')) return i
def update_user(user=None): """ Install the user as current user of the app. Setup the g.current_user variable. Add the user to the session. Update Flask-Principal. If no user, install AnonymousIdentity """ if user: db.session.add(user) db.session.commit() g.current_user = user # Tell Flask-Principal the identity changed identity = Identity(user.id) identity.user = user # By default we can self need identity.provides.add(UserNeed(user.id)) # Add roles for role in user.roles: identity.provides.add(RoleNeed(role.name)) identity_changed.send(current_app._get_current_object(), identity=identity) else: # Tell Flask-Principal the user is anonymous identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity())
def test_load_permissions_on_identity_loaded(app): """Check that the needs are loaded properly in the user Identity.""" InvenioAccess(app) with app.test_request_context(): identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity()) assert g.identity.provides == {any_user} with app.test_request_context(): user = testutils.create_test_user('*****@*****.**') login_user(user) assert g.identity.provides == { any_user, authenticated_user, UserNeed(user.id) } logout_user() # FIXME: The user is still authenticatd when the identity loader # is called during logout. We could filter on AnonymousIdentity, but # This would be inconsistent as the UserNeed(user.id) is still there. # This will pass even if it is unexpected: # assert g.identity.provides == { # any_user, authenticated_user, UserNeed(user.id) # } # Forcing the identity to reload again cleans the mess. In practice # this won't be needed as the identity is reloaded between requests. identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity()) assert g.identity.provides == {any_user}
def extend_identity(identity, groups): """Extend identity with roles based on CERN groups.""" provides = set([UserNeed(current_user.email)] + [ RoleNeed('{0}@cern.ch'.format(name)) for name in groups ]) identity.provides |= provides session[OAUTHCLIENT_CERN_SESSION_KEY] = provides
def on_identity_loaded(sender, identity): # Set the identity user object identity.user = current_user # Add the UserNeed to the identity if hasattr(current_user, 'id'): identity.provides.add(UserNeed(current_user.id))
def edit_post(id): post = Post.query.get_or_404(id) permission = Permission(UserNeed(post.author.id)) # 设置访问本视图的权限 if permission.can() or admin_permission.can(): # 判断Identity是否有要求的permission form = PostForm() if form.validate_on_submit(): post.title = form.title.data post.text = form.text.data post.publish_date = datetime.datetime.now() db.session.add(post) db.session.commit() return redirect(url_for('blog.post', post_id=post.id)) form.text.data = post.text return render_template('blog/edit.html', form=form, post=post) abort(403)
def identity(): """Simple identity to interact with the service.""" i = Identity(1) i.provides.add(UserNeed(1)) i.provides.add(any_user) i.provides.add(system_process) return i
def test_allowedbyaccesslevels_metadata_curator(action, create_record): # Restricted record, only viewable by owner and a Metadata Curator record = create_record({ "owners": [4], "_access": { "metadata_restricted": True, "files_restricted": True }, "internal": { "access_levels": { "metadata_curator": [{ "scheme": "person", "id": 1 }] } }, }) generator = AllowedByAccessLevel(action=action) if action in ["read", "update"]: assert generator.needs(record=record) == [UserNeed(1)] else: assert generator.needs(record=record) == [] assert generator.excludes(record=record) == []
def on_identity_loaded(sender, identity): identity.user = current_user if hasattr(current_user, 'id'): identity.provides.add(UserNeed(current_user.id)) if hasattr(current_user, 'roles'): for role in current_user.roles: identity.provides.add(RoleNeed(role.name))
def on_identity_loaded(sender, identity): """ Sets the identity of a given option, assigns additional permissions based on the role that the user is a part of. :param sender: :param identity: """ # load the user user = user_service.get(identity.id) # add the UserNeed to the identity identity.provides.add(UserNeed(identity.id)) # identity with the roles that the user provides if hasattr(user, 'roles'): for role in user.roles: identity.provides.add(RoleNeed(role.name)) identity.provides.add(RoleMemberNeed(role.id)) # apply ownership for authorities if hasattr(user, 'authorities'): for authority in user.authorities: identity.provides.add(AuthorityCreatorNeed(authority.id)) g.user = user
def edit_post(id): post = Post.query.get_or_404(id) #保证用户市登录的 if not current_user: return redirect(url_for('main.login')) if current_user != post.users: return redirect(url_for('blog.post', post_id=id)) #当user是poster或者admin,才可以编辑文章 permission = Permission(UserNeed(post.users.id)) if permission.can() or admin_permission.can(): form = PostForm() if form.validate_on_submit(): post.title = form.title.data post.text = form.text.data post.published_date = datetime.now() db.session.add(post) db.session.commit() return redirect(url_for('blog.post', post_id=post.id)) else: abort(403) form.title.data = post.title form.text.data = post.text return render_template('edit_post.html', form=form, post=post)