예제 #1
0
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 Permission(need_class(None))  # pragma: nocover

    arg = None
    if isinstance(obj, Taxonomy):
        arg = str(obj.code)
    elif isinstance(obj, TaxonomyTerm):
        arg = str(obj.tree_path)
    else:
        raise RuntimeError('Unknown object')  # pragma: nocover

    return Permission(need_class(arg))
예제 #2
0
def detail_permission_factory(record=None):
    """Permissions factory for record detail."""
    # TODO: adapt for more owners
    owners = _get_owners(record)
    if len(owners) > 0:
        return Permission(UserNeed(int(owners[0])))
    return Permission(any_user)
예제 #3
0
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.Permission` instance.
    """
    need_class = _action2need_map[action]

    if obj is None:
        return Permission(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 Permission(need_class(arg))
예제 #4
0
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))
예제 #5
0
def user_is_term_manager(uuid, user: User):
    if not user or not uuid:
        raise PermissionDenied()
    identity = get_identity(user)
    permission = Permission(ObjectSourceTermManager(uuid))
    if permission.allows(identity):
        return True
    raise PermissionDenied()
예제 #6
0
 def wrapper(*args, **kwargs):
     permission = Permission(notification_admin_actions)
     current_identity = get_identity(current_user)
     if not permission.allows(current_identity):
         return iroko_json_response(IrokoResponseStatus.ERROR,
                                    'Need to be source administrator.',
                                    None, None)
     else:
         return fn(*args, **kwargs)
예제 #7
0
def vocabulary_editor_permission_factory(obj):
    try:
        permission = Permission(vocabularies_full_editor_actions)
        current_identity = get_identity(current_user)
        if permission.allows(current_identity):
            return permission
    except Exception as e:
        msg = str(e)
    return Permission(ObjectVocabularyEditor(obj['name']))
예제 #8
0
def source_manager_permission_factory(obj):
    try:
        permission = Permission(source_full_manager_actions)
        current_identity = get_identity(current_user)
        if permission.allows(current_identity):
            return permission
    except Exception as e:
        pass

    return Permission(ObjectSourceManager(obj['uuid']))
예제 #9
0
def is_user_sources_admin(user: User):
    its = False
    permission = Permission(source_full_manager_actions)
    current_identity = get_identity(user)
    if permission.allows(current_identity):
        its = True

    # except Exception as e:
    #     # print(str(e))

    return its
예제 #10
0
def notification_viewed_permission_factory(obj):
    try:
        permission = Permission(notification_admin_actions)
        current_identity = get_identity(current_user)
        if permission.allows(current_identity):
            return permission

    except Exception as e:
        pass

    return Permission(ObjectNotificationViewed(obj['id']))
예제 #11
0
 def can(self):
     """Return boolean if permission valid."""
     identity = get_identity(self.user)
     return (
         is_owner(self.user, self.record) or
         (
             Permission(menrva_edit_published_record).allows(identity) and
             has_published(self.record)
         ) or
         Permission(menrva_edit).allows(identity)
         # NOTE: by default any Permission has a super-user Need
     )
예제 #12
0
def user_has_edit_permission(source, user: User):
    if not user or not source:
        raise PermissionDenied()
    try:
        if user_has_manager_permission(source, user):
            return True
    except PermissionDenied as err:
        pass

    identity = get_identity(user)
    perm = Permission(ObjectSourceEditor(source.id))
    if perm.allows(identity):
        return True
    raise PermissionDenied()
예제 #13
0
파일: permissions.py 프로젝트: nuest/zenodo
def files_permission_factory(obj, action=None):
    """Permission for files are always based on the type of bucket.

    1. Community bucket: Read access for everyone
    2. Record bucket: Read access only with open and restricted access.
    3. Deposit bucket: Read/update with restricted access.
    4. Any other bucket is restricted to admins only.
    """
    # 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:
        # Community bucket
        if str(bucket_id) in get_public_bucket_uuids():
            return PublicBucketPermission(action)

        # 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_record(record):
                return RecordFilesPermission.create(record, action)
            elif is_deposit(record):
                return DepositFilesPermission.create(record, action)

    return Permission(ActionNeed('admin-access'))
예제 #14
0
def check_and_handle_spam(community=None, deposit=None):
    """Checks community/deposit metadata for spam."""
    try:
        if current_app.config.get('ZENODO_SPAM_MODEL_LOCATION'):
            if community:
                task = check_metadata_for_spam.delay(community_id=community.id)
            if deposit:
                task = check_metadata_for_spam.delay(dep_id=str(deposit.id))
            spam_proba = task.get(
                timeout=current_app.config['ZENODO_SPAM_CHECK_TIMEOUT'])
        else:
            spam_proba = 0

        if spam_proba > current_app.config['ZENODO_SPAM_THRESHOLD']:
            if not Permission(ActionNeed('admin-access')).can():
                has_records = RecordsSearch(index='records').query(
                    Q('query_string',
                      query="owners:{}".format(community.id_user))).count()
                has_communities = Community.query.filter_by(
                    id_user=community.id_user).count() - 1

                if not (has_records or has_communities):
                    current_app.config['ZENODO_SPAM_HANDLING_ACTIONS'](
                        community=community, deposit=deposit)
    except HTTPException:
        raise
    except Exception:
        current_app.logger.exception(u'Could not check for spam')
예제 #15
0
파일: permissions.py 프로젝트: xbee/zenodo
def files_permission_factory(obj, action=None):
    """Permission for files are always based on the type of bucket.

    1. Community bucket: Read access for everyone
    2. Record bucket: Read access only with open and restricted access.
    3. Deposit bucket: Read/update with restricted access.
    4. Any other bucket is restricted to admins only.
    """
    # 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:
        # Community bucket
        if str(bucket_id) in get_public_bucket_uuids():
            return PublicBucketPermission(action)

        # Record or deposit bucket
        rbs = RecordsBuckets.query.filter_by(bucket_id=bucket_id).all()
        if len(rbs) >= 2:  # Extra formats bucket or bad records-buckets state
            # Only admins should access. Users use the ".../formats" endpoints
            return Permission(ActionNeed('admin-access'))
        rb = next(iter(rbs), None)  # Use first bucket
        if rb:
            record = Record.get_record(rb.record_id)
            # "Cache" the file's record in the request context (e.g for stats)
            if record and request:
                setattr(request, 'current_file_record', record)

            # Bail if extra formats bucket
            if str(bucket_id) == \
                    record.get('_buckets', {}).get('extra_formats'):
                return Permission(ActionNeed('admin-access'))
            if is_record(record):
                return RecordFilesPermission.create(record, action)
            elif is_deposit(record):
                return DepositFilesPermission.create(record, action)

    return Permission(ActionNeed('admin-access'))
예제 #16
0
    def create(cls, obj, action):
        """Create an <Action>FilesPermission for record associated with `obj`.

        For now it defaults to ReadFilesPermission for all actions.

        Adapted from https://github.com/zenodo/zenodo
        """
        # 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 not bucket_id:
            # Don't think this conditional should be hit
            return Permission(ActionNeed('superuser-access'))

        # WARNING: invenio-records-files implies a one-to-one relationship
        #          between Record and Bucket, but does not enforce it
        #          "for better future" the invenio-records-files code says
        record_bucket = \
            RecordsBuckets.query.filter_by(bucket_id=bucket_id).one_or_none()
        if not record_bucket:
            return Permission(ActionNeed('superuser-access'))

        record_metadata = record_bucket.record
        record = Record(record_metadata.json, model=record_metadata)

        # "Cache" the file's record in the request context
        if record and request:
            setattr(request, 'current_file_record', record)

        if record:
            # TODO: Differentiate between actions
            if action in cls.actions:
                if '-read' in action:
                    return ReadFilesPermission(current_user, record)
                elif '-update' in action:
                    return CreateFilesPermission(current_user, record)

        return Permission(ActionNeed('superuser-access'))
예제 #17
0
def user_has_editor_or_manager_permissions(obj):
    permission = Permission(source_full_manager_actions)
    current_identity = get_identity(current_user)
    if permission.allows(current_identity):
        return permission

    permiso = None
    permiso = Permission(ObjectSourceManager(obj['uuid']))
    if permiso:
        return permiso

    aux = obj['terms']
    terms = aux.split(',')
    permiso = None
    for term_uuid in terms:
        try:
            permiso = Permission(ObjectSourceTermManager(term_uuid))
            if permiso:
                return permiso
        except Exception as e:
            raise e

    aux = obj['orgs']
    orgs = aux.split(',')
    permiso = None
    for org_uuid in orgs:
        try:
            permiso = Permission(ObjectSourceTermManager(org_uuid))
            if permiso:
                return permiso
        except Exception as e:
            raise e
    return Permission(ObjectSourceEditor(obj['uuid']))
예제 #18
0
def check_and_handle_spam(community=None, deposit=None, retry=True):
    """Checks community/deposit metadata for spam."""
    try:
        if current_app.config.get('ZENODO_SPAM_MODEL_LOCATION'):
            if community:
                task = check_metadata_for_spam.delay(community_id=community.id)
                user_id = community.id_user
            if deposit:
                task = check_metadata_for_spam.delay(dep_id=str(deposit.id))
                user_id = deposit['owners'][0]
            spam_proba = task.get(
                timeout=current_app.config['ZENODO_SPAM_CHECK_TIMEOUT'])
        else:
            spam_proba = 0
        if spam_proba > current_app.config['ZENODO_SPAM_THRESHOLD']:
            if not Permission(ActionNeed('admin-access')).can():
                user_records = RecordsSearch(index='records').query(
                    Q('query_string',
                      query="owners:{}".format(user_id))).count()
                user_communities = Community.query.filter_by(
                    id_user=user_id).count()
                if community:
                    # Ignore the newly created community
                    user_communities = user_communities - 1
                current_app.logger.warning(
                    u'Found spam upload',
                    extra={
                        'depid': deposit.id if deposit else None,
                        'comid': community.id if community else None
                    })
                if not (user_records + user_communities >
                        current_app.config['ZENODO_SPAM_SKIP_CHECK_NUM']):
                    current_app.config['ZENODO_SPAM_HANDLING_ACTIONS'](
                        community=community, deposit=deposit)
    except HTTPException:
        raise
    except TimeoutError:
        if retry:
            check_and_handle_spam(community=community,
                                  deposit=deposit,
                                  retry=False)
        else:
            current_app.logger.exception(
                u'Could not check for spam',
                extra={
                    'depid': deposit.id if deposit else None,
                    'comid': community.id if community else None
                })
    except Exception:
        current_app.logger.exception(u'Could not check for spam',
                                     extra={
                                         'depid':
                                         deposit.id if deposit else None,
                                         'comid':
                                         community.id if community else None
                                     })
예제 #19
0
def test_cli_action_allow(app, script_info, community, authenticated_user, db):
    runner = CliRunner()
    app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv(
        'SQLALCHEMY_DATABASE_URI', 'sqlite://')
    role = community[1].roles[0]
    current_datastore.add_role_to_user(authenticated_user, role)

    read_need = action_factory(COMMUNITY_READ, parameter=True)
    login_user(authenticated_user)
    assert not Permission(read_need(community[0])).allows(g.identity)
예제 #20
0
def owner_permission_impl(record, *args, **kwargs):
    f"""Record owner permission factory.

       * Allows access to record if current_user if record is owned by the current user.
       * If the record is not owned by any user, access to the record is denied.
    """
    owner = current_oarepo_communities.get_owned_by_field(record)
    if owner:
        return Permission(UserNeed(owner))
    return deny_all()
예제 #21
0
    def check_user_vocabulary_editor_permission(
            user_id, vocabulary_id) -> Dict[str, bool]:
        done = False
        msg = ''
        try:
            if is_current_user_taxonomy_admin():
                done = True
            else:
                vocabulary = Vocabulary.query.filter_by(
                    identifier=vocabulary_id).first()
                user = User.query.filter_by(id=user_id)
                user_identity = get_identity(user)
                permission = Permission(ObjectVocabularyEditor(
                    vocabulary.name))
                done = permission.allows(user_identity)
        except Exception as e:
            msg = str(e)
            # print(str(e))

        return msg, done
예제 #22
0
def test_action_needs(app, db, community, community_curator):
    """Test action needs creation."""
    role = current_datastore.find_role('community:comtest:member')
    current_datastore.add_role_to_user(community_curator, role)

    ar = ActionRoles(action=COMMUNITY_READ, argument=community[1].id, role=role)
    db.session.add(ar)
    db.session.commit()

    login_user(community_curator)

    assert Permission(ParameterizedActionNeed(COMMUNITY_READ, community[1].id)).can()
예제 #23
0
 def can(self):
     """Return boolean if permission valid."""
     # Enforce the fact that this is only for published record.
     return RecordType.is_published(self.published_record) and (
         is_open_access(self.published_record) or
         has_restricted_access(self.user, self.published_record) or
         is_owner(self.user, self.published_record) or
         Permission(menrva_view_published_record).allows(
             get_identity(self.user)
         )
         # NOTE: by default any Permission has a super-user Need
     )
예제 #24
0
def test_owner_permissions(app, db, community, authenticated_user):
    """Test owner system role permissions."""
    login_user(authenticated_user)
    assert len(g.identity.provides) == 4
    assert community_record_owner in g.identity.provides

    permissions = require_any(
        # Approval is granted either by user role
        Permission(ParameterizedActionNeed(COMMUNITY_REQUEST_APPROVAL, community[0])),
        require_all(
            # Or user id must match and record owners must be granted the action
            Permission(UserNeed(authenticated_user.id)),
            Permission(ParameterizedActionNeed(f'owner-{COMMUNITY_REQUEST_APPROVAL}', community[0]))
        )
    )

    assert not permissions().can()

    db.session.add(
        ActionSystemRoles(action=f'owner-{COMMUNITY_REQUEST_APPROVAL}', role_name=community_record_owner.value,
                          argument=community[0]))

    assert permissions().can()
예제 #25
0
def source_organization_manager_permission_factory(obj):
    permission = Permission(source_full_manager_actions)
    current_identity = get_identity(current_user)
    if permission.allows(current_identity):
        return permission

    permiso = None
    permiso = Permission(ObjectSourceManager(obj['uuid']))
    if permiso:
        return permiso

    aux = obj['orgs']
    orgs = aux.split(',')
    permiso = None

    for org_uuid in orgs:
        try:
            permiso = Permission(ObjectSourceOrganizationManager(org_uuid))
            if permiso:
                return permiso
        except Exception as e:
            raise e
    raise PermissionDenied('No tiene permisos de gestión')
예제 #26
0
    def inner(record, *args, **kwargs):
        if record is None:
            raise RuntimeError('Record is missing.')

        arg = None
        if isinstance(record, Record):
            arg = record.primary_community
        elif isinstance(record, dict):
            arg = current_oarepo_communities.get_primary_community_field(record)
        else:
            raise RuntimeError('Unknown or missing object')
        return require_all(
            require_action_allowed(action),
            Permission(ParameterizedActionNeed(action, arg)))
예제 #27
0
def test_cli_action_deny(app, community, authenticated_user, db):
    runner = CliRunner()
    script_info = ScriptInfo(create_app=lambda info: app)
    app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv(
        'SQLALCHEMY_DATABASE_URI', 'sqlite://')

    role = community[1].roles[0]
    current_datastore.add_role_to_user(authenticated_user, role)

    login_user(authenticated_user)

    db.session.add(
        ActionRoles(action=COMMUNITY_READ, argument=community[0], role=role))

    assert Permission(ParameterizedActionNeed(COMMUNITY_READ,
                                              community[0])).allows(g.identity)
예제 #28
0
def read_permission_factory(record, *args, **kwargs):
    f"""Read permission factory that takes secondary communities into account.

    Allows access to record in one of the following cases:
        * Record is PUBLISHED
        * Current user is the OWNER of the record
        * User's role has allowed READ action in one of record's communities AND:
            1) User is in one of the roles of the community from the request path AND record is atleast APPROVED. OR
            2) User is CURATOR in the community from the request path

    :param record: An instance of :class:`oarepo_communities.record.CommunityRecordMixin`
        or ``None`` if the action is global.
    :raises RuntimeError: If the object is unknown.
    :returns: A :class:`invenio_access.permissions.Permission` instance.
    """
    if isinstance(record, Record):
        communities = [record.primary_community, *record.secondary_communities]
        return require_any(
            #: Anyone can read published records
            state_required(STATE_PUBLISHED),
            require_all(
                require_action_allowed(COMMUNITY_READ),
                require_any(
                    #: Record AUTHOR can READ his own records
                    owner_permission_impl,
                    require_all(
                        #: User's role has granted READ permissions in record's communities
                        Permission(*[ParameterizedActionNeed(COMMUNITY_READ, x) for x in communities]),
                        require_any(
                            #: Community MEMBERS can READ APPROVED community records
                            require_all(
                                state_required(STATE_APPROVED),
                                require_any(
                                    community_member_permission_impl,
                                    community_publisher_permission_impl
                                )
                            ),
                            #: Community CURATORS can READ ALL community records
                            community_curator_permission_impl
                        )
                    )
                )
            )
        )(record, *args, **kwargs)
    else:
        raise RuntimeError('Unknown or missing object')
예제 #29
0
def admin_permission_factory(admin_view):
    """Default factory for creating a permission for an admin.

    It tries to load a :class:`invenio_access.permissions.Permission`
    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.
    """
    try:
        pkg_resources.get_distribution('invenio-access')
        from invenio_access import Permission
    except pkg_resources.DistributionNotFound:
        from flask_principal import Permission

    return Permission(action_admin_access)
예제 #30
0
def records_filter():
    """Query ElasticSearch for a *filtered* list of Records.

    NOTE: Any of these queries is run in a filtered context. So ES can
          optimize them.
    """
    if not has_request_context():
        return Q()
    elif Permission(ActionNeed('admin-access')).can():
        return Q()
    elif not current_user.is_authenticated:
        return (Q('term', type='published')
                & Q('term', permissions=RecordPermissions.ALL_VIEW))
    else:
        return (Q('term', type='published') &
                (Q('term', permissions=RecordPermissions.ALL_VIEW)
                 | Q('term', permissions=RecordPermissions.RESTRICTED_VIEW) |
                 (Q('term', permissions=RecordPermissions.PRIVATE_VIEW) &
                  Q('term', _deposit__owners=getattr(current_user, 'id', 0)))))