コード例 #1
0
def check_admin(user_lookup: KBaseUserLookup,
                token: Optional[str],
                perm: AdminPermission,
                method: str,
                log_fn: Callable[[str], None],
                as_user: UserID = None,
                skip_check: bool = False) -> bool:
    '''
    Check whether a user has admin privileges.
    The request is logged.

    :param user_lookup: the service to use to look up user information.
    :param token: the user's token, or None if the user is anonymous. In this case, if skip_check
        is false, an UnauthorizedError will be thrown.
    :param perm: the required administration permission.
    :param method: the method the user is trying to run. This is used in logging and error
      messages.
    :param logger: a function that logs information when called with a string.
    :param as_user: if the admin is impersonating another user, the username of that user.
    :param skip_check: Skip the administration permission check and return false.
    :returns: true if the user has the required administration permission, false if skip_check
        is true.
    :raises UnauthorizedError: if the user does not have the permission required.
    :raises InvalidUserError: if any of the user names are invalid.
    :raises UnauthorizedError: if any of the users names are valid but do not exist in the system.
    '''
    if skip_check:
        return False
    if not token:
        raise _UnauthorizedError(
            'Anonymous users may not act as service administrators.')
    _not_falsy(method, 'method')
    _not_falsy(log_fn, 'log_fn')
    if _not_falsy(perm, 'perm') == AdminPermission.NONE:
        raise ValueError(
            'what are you doing calling this method with no permission ' +
            'requirement? That totally makes no sense. Get a brain moran')
    if as_user and perm != AdminPermission.FULL:
        raise ValueError('as_user is supplied, but permission is not FULL')
    p, user = _not_falsy(user_lookup, 'user_lookup').is_admin(token)
    if p < perm:
        err = (f'User {user} does not have the necessary administration ' +
               f'privileges to run method {method}')
        log_fn(err)
        raise _UnauthorizedError(err)
    if as_user and user_lookup.invalid_users([as_user
                                              ]):  # returns list of bad users
        raise _NoSuchUserError(as_user.id)
    log_fn(
        f'User {user} is running method {method} with administration permission {p.name}'
        + (f' as user {as_user}' if as_user else ''))
    return True
コード例 #2
0
ファイル: samples.py プロジェクト: jsfillman/sample_service
 def _check_perms(self,
                  id_: UUID,
                  user: UserID,
                  access: _SampleAccessType,
                  acls: SampleACL = None,
                  as_admin: bool = False):
     if as_admin:
         return
     if not acls:
         acls = self._storage.get_sample_acls(id_)
     level = self._get_access_level(acls, user)
     if level < access:
         errmsg = f'User {user} {self._unauth_errmap[access]} sample {id_}'
         raise _UnauthorizedError(errmsg)
コード例 #3
0
 def _check_batch_perms(
     self,
     ids_: List[UUID],
     user: Optional[UserID],
     access: _SampleAccessType,
     acls: List[SampleACL] = None,
     as_admin: bool = False):
         if as_admin:
             return
         if not acls:
             acls = self._storage.get_sample_set_acls(ids_)
         levels = [self._get_access_level(acl, user) for acl in acls]
         for i, level in enumerate(levels):
             if level < access:
                 uerr = f'User {user}' if user else 'Anonymous users'
                 errmsg = f'{uerr} {self._unauth_errmap[access]} sample {ids_[i]}'
                 raise _UnauthorizedError(errmsg)
コード例 #4
0
    def is_update(self, update: SampleACLDelta) -> bool:
        '''
        Check if an acl delta update is actually an update or a noop for the sample.

        :param update: the update.
        :returns: True if the update would change the ACLs, False if not. The timestamp is not
            considered.
        :raises UnauthorizedError: if the update would affect the owner and update.at_least is
            not true, or if the owner is in the remove list regardless of at_least.
        '''
        _not_falsy(update, 'update')
        o = self.owner
        ownerchange = o in update.admin or o in update.write or o in update.read
        if (ownerchange and not update.at_least) or o in update.remove:
            raise _UnauthorizedError(
                f'ACLs for the sample owner {o.id} may not be modified by a delta update.'
            )

        rem = set(update.remove)
        admin = set(self.admin)
        write = set(self.write)
        read = set(self.read)

        # check if users are removed
        if not rem.isdisjoint(admin) or not rem.isdisjoint(
                write) or not rem.isdisjoint(read):
            return True

        # check if public read is changed
        if update.public_read is not None and update.public_read is not self.public_read:
            return True

        uadmin = set(update.admin)
        uwrite = set(update.write)
        uread = set(update.read)
        owner = set([o])

        # check if users' permission is changed
        if update.at_least:
            return (not uadmin.issubset(admin | owner)
                    or not uwrite.issubset(write | admin | owner)
                    or not uread.issubset(read | write | admin | owner))
        else:
            return (not uadmin.issubset(admin) or not uwrite.issubset(write)
                    or not uread.issubset(read))
コード例 #5
0
ファイル: workspace.py プロジェクト: jsfillman/sample_service
    def has_permission(self,
                       user: UserID,
                       perm: WorkspaceAccessType,
                       workspace_id: int = None,
                       upa: UPA = None):
        '''
        Check if a user can access a workspace resource. Exactly one of workspace_id or upa must
        be supplied - if both are supplied workspace_id takes precedence.

        Beware - passing a NONE permission will not throw errors unless the object or workspace
        does not exist.

        The user is not checked for existence.

        :param user: The user's user name.
        :param perm: The requested permission
        :param workspace_id: The ID of the workspace.
        :param upa: a workspace service UPA.
        :raises IllegalParameterError: if the wsid is illegal.
        :raises UnauthorizedError: if the user doesn't have the requested permission.
        :raises NoSuchWorkspaceDataError: if the workspace or UPA doesn't exist.
        '''
        _not_falsy(user, 'user')
        _not_falsy(perm, 'perm')
        if workspace_id is not None:
            wsid = workspace_id
            name = 'workspace'
            target = str(workspace_id)
            upa = None
        elif upa:
            wsid = upa.wsid
            name = 'upa'
            target = str(upa)
        else:
            raise ValueError('Either an UPA or a workpace ID must be supplied')
        if wsid < 1:
            raise _IllegalParameterError(f'{wsid} is not a valid workspace ID')

        try:
            p = self._ws.administer({
                'command': 'getPermissionsMass',
                'params': {
                    'workspaces': [{
                        'id': wsid
                    }]
                }
            })
        except _ServerError as se:
            # this is pretty ugly, need error codes
            if 'No workspace' in se.args[0] or 'is deleted' in se.args[0]:
                raise _NoSuchWorkspaceDataError(se.args[0]) from se
            else:
                raise
        # could optimize a bit if NONE and upa but not worth the code complication most likely
        if (perm != WorkspaceAccessType.NONE
                and p['perms'][0].get(user.id) not in _PERM_TO_PERM_SET[perm]):
            raise _UnauthorizedError(
                f'User {user} cannot {_PERM_TO_PERM_TEXT[perm]} {name} {target}'
            )
        if upa:
            # Allow any server errors to percolate upwards
            # theoretically the workspace could've been deleted between the last call and this
            # one, but that'll just result in a different error and is extremely unlikely to
            # happen, so don't worry about it
            ret = self._ws.administer({
                'command': 'getObjectInfo',
                'params': {
                    'objects': [{
                        'ref': str(upa)
                    }],
                    'ignoreErrors': 1
                }
            })
            if not ret['infos'][0]:
                raise _NoSuchWorkspaceDataError(f'Object {upa} does not exist')