Beispiel #1
0
    def readChunk(self, params):
        """
        After the temporary upload record has been created (see initUpload),
        the bytes themselves should be passed up in ordered chunks. The user
        must remain logged in when passing each chunk, to authenticate that
        the writer of the chunk is the same as the person who initiated the
        upload. The passed offset is a verification mechanism for ensuring the
        server and client agree on the number of bytes sent/received.
        """
        self.requireParams(('offset', 'uploadId', 'chunk'), params)
        user = self.getCurrentUser()

        if not user:
            raise AccessException('You must be logged in to upload.')

        upload = self.model('upload').load(params['uploadId'], exc=True)
        offset = int(params['offset'])
        chunk = params['chunk']

        if upload['userId'] != user['_id']:
            raise AccessException('You did not initiate this upload.')

        if upload['received'] != offset:
            raise RestException(
                'Server has received {} bytes, but client sent offset {}.'.
                format(upload['received'], offset))

        if type(chunk) == cherrypy._cpreqbody.Part:
            return self.model('upload').handleChunk(upload, chunk.file)
        else:
            return self.model('upload').handleChunk(upload, chunk)
Beispiel #2
0
 def authenticate(self, username, password):
     entry = self.findOne({'userName': username})
     if entry is None:
         self._authenticationFailed()
         raise AccessException('Invalid username/password')
     self._checkLocked(entry)
     if not pdigest.verify(password, entry['hash']):
         self._authenticationFailed(entry)
         raise AccessException('Invalid username/password')
Beispiel #3
0
    def getReviewImages(self, dataset, params):
        user = self.getCurrentUser()
        User().requireReviewDataset(user)

        prereviewFolder = Dataset().prereviewFolder(dataset)
        if not (prereviewFolder and
                Folder().hasAccess(prereviewFolder, user=user, level=AccessType.READ)):
            raise AccessException(
                'User does not have access to any Pre-review images for this dataset.')

        limit = int(params.get('limit', 50))

        output = [
            {
                field: image[field]
                for field in
                ['_id', 'name', 'updated', 'description', 'meta']
            }
            for image in
            Image().find(
                {'folderId': prereviewFolder['_id']},
                limit=limit, sort=[('name', SortDir.ASCENDING)]
            )
        ]

        return output
    def submit(self, params):
        url = params.get('url')
        content = params.get('content')
        user = self.getCurrentUser()

        # check permissions
        group = ModelImporter().model('group').find({'name': config['group']})

        if group.count():
            # the group must exist
            group = group[0]

            # the user must have read access to the group
            ModelImporter().model('group').requireAccess(
                group, user, AccessType.READ)

        else:
            raise AccessException('Invalid group name configured')

        # Create the diagnosis task
        statusMethod = server_support.handleDiagnosis(content=content, url=url)

        # Get the initial status
        status = statusMethod()

        # Get the maximum number of times to poll the task
        maxLoops = config['maxTaskWait'] / config['pollingInterval']

        # Loop until the task is finished
        iloop = 0
        while status['status'] == 'pending' and iloop < maxLoops:
            iloop += 1
            time.sleep(config['pollingInterval'])
            status = statusMethod()

        # Get status and report errors
        if status['status'] == 'pending':
            raise RestException("Task timed out.", code=408)

        if status['status'] == 'failure':
            raise RestException(status['message'], code=400)

        # check access to private data
        group = ModelImporter().model('group').find(
            {'name': config['privateGroup']})
        hasAccess = False
        if group.count():
            group = group[0]
            try:
                ModelImporter().model('group').requireAccess(
                    group, user, AccessType.READ)
                hasAccess = True
            except AccessException:
                pass

        # Append content data if the user has access
        if hasAccess:
            status["result"]["scrapedData"] = status["content"]

        return status["result"]
Beispiel #5
0
    def _promote(self, group, params, level):
        """
        Promote a user to moderator or administrator.

        :param group: The group to promote within.
        :param params: Request parameters.
        :param level: Either WRITE or ADMIN, for moderator or administrator.
        :type level: AccessType
        :returns: The updated group document.
        """
        self.requireParams('userId', params)
        user = self.getCurrentUser()

        userToPromote = self.model('user').load(id=params['userId'],
                                                user=user,
                                                level=AccessType.READ,
                                                exc=True)

        if not group['_id'] in userToPromote.get('groups', []):
            raise AccessException('That user is not a group member.')

        group = self.model('group').setUserAccess(group,
                                                  userToPromote,
                                                  level=level,
                                                  save=True)
        group['access'] = self.model('group').getFullAccessList(group)
        return group
Beispiel #6
0
    def romanescoRun(self, item, params):
        # Make sure that we have permission to perform this analysis.
        user = self.getCurrentUser()

        settings = ModelImporter.model('setting')
        requireAuth = settings.get(PluginSettings.REQUIRE_AUTH, True)

        if requireAuth:
            safeFolders = settings.get(PluginSettings.SAFE_FOLDERS, ())
            fullAccessUsers = settings.get(PluginSettings.FULL_ACCESS_USERS, ())
            fullAccessGrps = settings.get(PluginSettings.FULL_ACCESS_GROUPS, ())
            userGrps = {str(id) for id in user.get('groups', ())}

            if (str(item['folderId']) not in safeFolders and (
                    not user or user['login'] not in fullAccessUsers) and
                    not userGrps & set(fullAccessGrps)):
                raise AccessException('Unauthorized user.')

        analysis = item.get('meta', {}).get('analysis')

        if type(analysis) is not dict:
            raise rest.RestException(
                'Must specify a valid JSON object as the "analysis" metadata '
                'field on the input item.')
        # Get the analysis parameters (includes inputs & outputs).
        try:
            kwargs = json.load(cherrypy.request.body)
        except ValueError:
            raise rest.RestException(
                'You must pass a valid JSON object in the request body.')

        return runAnalysis(user, analysis, kwargs, item)
Beispiel #7
0
    def readChunk(self, upload, offset, chunk, params):
        """
        After the temporary upload record has been created (see initUpload),
        the bytes themselves should be passed up in ordered chunks. The user
        must remain logged in when passing each chunk, to authenticate that
        the writer of the chunk is the same as the person who initiated the
        upload. The passed offset is a verification mechanism for ensuring the
        server and client agree on the number of bytes sent/received.
        """
        user = self.getCurrentUser()

        if upload['userId'] != user['_id']:
            raise AccessException('You did not initiate this upload.')

        if upload['received'] != offset:
            raise RestException(
                'Server has received %s bytes, but client sent offset %s.' %
                (upload['received'], offset))
        try:
            if isinstance(chunk, cherrypy._cpreqbody.Part):
                return self.model('upload').handleChunk(upload,
                                                        chunk.file,
                                                        filter=True,
                                                        user=user)
            else:
                return self.model('upload').handleChunk(upload,
                                                        chunk,
                                                        filter=True,
                                                        user=user)
        except IOError as exc:
            if exc.errno == errno.EACCES:
                raise Exception('Failed to store upload.')
            raise
Beispiel #8
0
    def nextSegmentationTask(self, params):
        self.requireParams(['datasetId'], params)
        user = self.getCurrentUser()

        dataset = Dataset().load(params['datasetId'],
                                 user=user,
                                 level=AccessType.READ,
                                 exc=True)

        userSkill = User().getSegmentationSkill(user)
        if userSkill is None:
            raise AccessException(
                'You are not authorized to perform segmentations.')

        pipeline = list(
            itertools.chain(
                self._pipeline1ImagesFromDataset(dataset),
                self._pipeline2ImagesWithSegmentations(),
                (
                    # TODO: prefer an image with a novice segmentation to one with
                    # no segmentations
                    self._pipeline3NoExpertSegmentations()
                    if userSkill == Segmentation().Skill.EXPERT else
                    self._pipeline3MissingSegmentations()),
                self._pipeline4RandomImage()))

        results = list(Image().collection.aggregate(pipeline))
        if not results:
            raise RestException(
                'No segmentations are needed for this dataset.')
        nextImage = results[0]

        return Image().filterSummary(nextImage, user)
Beispiel #9
0
 def wrapped(*args, **kwargs):
     if not rest.getCurrentToken():
         raise AccessException(
             'You must be logged in or have a valid auth token.')
     if required:
         Token().requireScope(rest.getCurrentToken(), scope)
     return fun(*args, **kwargs)
Beispiel #10
0
    def cancelUpload(self, upload, params):
        user = self.getCurrentUser()

        if upload['userId'] != user['_id'] and not user['admin']:
            raise AccessException('You did not initiate this upload.')

        self.model('upload').cancelUpload(upload)
        return {'message': 'Upload canceled.'}
Beispiel #11
0
    def createCollection(self, name, description, public):
        user = self.getCurrentUser()

        if not self.model('collection').hasCreatePrivilege(user):
            raise AccessException('You are not authorized to create collections.')

        return self.model('collection').createCollection(
            name=name, description=description, public=public, creator=user)
Beispiel #12
0
 def _checkLocked(self, entry):
     now = datetime.datetime.now()
     if 'resetOn' in entry and now > entry['resetOn']:
         del entry['resetOn']
         entry['failedCount'] = 0
         self.save(entry)
     if now < entry['lockedUntil']:
         raise AccessException('Too many authentication failures. Wait some time until trying '
                               'again.')
Beispiel #13
0
    def finalizeUpload(self, params):
        self.requireParams('uploadId', params)
        user = self.getCurrentUser()

        upload = self.model('upload').load(params['uploadId'], exc=True)

        if upload['userId'] != user['_id']:
            raise AccessException('You did not initiate this upload.')

        return self.model('upload').finalizeUpload(upload)
 def checkOwnership(self, user, session):
     if user['admin']:
         # admin owns everything
         return
     if 'ownerId' in session:
         ownerId = session['ownerId']
     else:
         ownerId = session['userId']
     if ownerId != user['_id']:
         raise AccessException('Current user is not the session owner')
Beispiel #15
0
    def removeContainer(self, user, container):
        if container['ownerId'] != user['_id']:
            raise AccessException("This container is not yours")

        try:
            self._stopContainer(container)
        except:
            # some of these things need to be properly synchronized
            logger.info("Could not stop container")

        self.remove(container)
Beispiel #16
0
def requireAdmin(user):
    """
    Calling this on a user will ensure that they have admin rights.  If not,
    raises an AccessException.

    :param user: The user to check admin flag on.
    :type user: dict.
    :raises AccessException: If the user is not an administrator.
    """
    if user is None or user.get('admin', False) is not True:
        raise AccessException('Administrator access required.')
Beispiel #17
0
    def requireScope(self, token, scope):
        """
        Raise an error if given set of scopes are not included.

        :param token: The token object.
        :type token: dict
        :param scope: A scope or set of scopes that will be tested as a subset
            of the given token's allowed scopes.
        :type scope: str or list of str
        """

        if not self.hasScope(token, scope):
            raise AccessException('Invalid token scope, required: %s.' % (scope))
Beispiel #18
0
def requireAdmin(user, message=None):
    """
    Calling this on a user will ensure that they have admin rights.  If not,
    raises an AccessException.

    :param user: The user to check admin flag on.
    :type user: dict.
    :param message: The exception message.
    :type message: str or None
    :raises AccessException: If the user is not an administrator.
    """
    if user is None or not user['admin']:
        raise AccessException(message or 'Administrator access required.')
Beispiel #19
0
    def createCollection(self, params):
        self.requireParams('name', params)

        user = self.getCurrentUser()

        if not self.model('collection').hasCreatePrivilege(user):
            raise AccessException(
                'You are not authorized to create collections.')

        public = self.boolParam('public', params, default=False)

        return self.model('collection').createCollection(
            name=params['name'], description=params.get('description'),
            public=public, creator=user)
Beispiel #20
0
    def _promote(self, group, user, level):
        """
        Promote a user to moderator or administrator.

        :param group: The group to promote within.
        :param user: The user to promote.
        :param level: Either WRITE or ADMIN, for moderator or administrator.
        :type level: AccessType
        :returns: The updated group document.
        """
        if not group['_id'] in user.get('groups', []):
            raise AccessException('That user is not a group member.')

        group = self._model.setUserAccess(group, user, level=level, save=True)
        group['access'] = self._model.getFullAccessList(group)
        return group
Beispiel #21
0
    def stopContainer(self, user, container):
        """
        Stops a container.

        :param user: The current user.
        :param container: The container to stop.
        """

        if container['ownerId'] != user['_id']:
            raise AccessException("This container is not yours")
        container['status'] = 'Stopping'
        self.save(container)
        event = events.trigger('container.stop', info = container)
        self._stopContainer(container)

        return container
Beispiel #22
0
    def finalizeUpload(self, upload, params):
        user = self.getCurrentUser()

        if upload['userId'] != user['_id']:
            raise AccessException('You did not initiate this upload.')

        # If we don't have as much data as we were told would be uploaded and
        # the upload hasn't specified it has an alternate behavior, refuse to
        # complete the upload.
        if upload['received'] != upload['size'] and 'behavior' not in upload:
            raise RestException(
                'Server has only received %s bytes, but the file should be %s bytes.'
                % (upload['received'], upload['size']))

        file = self.model('upload').finalizeUpload(upload)
        extraKeys = file.get('additionalFinalizeKeys', ())
        return self.model('file').filter(file, user, additionalKeys=extraKeys)
Beispiel #23
0
    def finalizeUpload(self, params):
        self.requireParams('uploadId', params)
        user = self.getCurrentUser()

        upload = self.model('upload').load(params['uploadId'], exc=True)

        if upload['userId'] != user['_id']:
            raise AccessException('You did not initiate this upload.')

        # If we don't have as much data as we were told would be uploaded and
        # the upload hasn't specified it has an alternate behavior, refuse to
        # complete the upload.
        if upload['received'] != upload['size'] and 'behavior' not in upload:
            raise RestException(
                'Server has only received {} bytes, but the file should be {} '
                'bytes.'.format(upload['received'], upload['size']))

        return self.model('upload').finalizeUpload(upload)
Beispiel #24
0
def _checkUser(event):
    if event.info['provider'] == github.GitHub:
        requiredGitHubOrg = ModelImporter.model('setting').get(
            _REQUIRED_GITHUB_ORG)

        if requiredGitHubOrg:
            token = event.info['token']

            headers = {
                'Authorization': 'token %s' % token['access_token'],
                'Accept': 'application/json'
            }
            resp = requests.get('https://api.github.com/user/orgs',
                                headers=headers)
            orgs = [org['login'] for org in resp.json()]
            if requiredGitHubOrg not in orgs:
                raise AccessException(
                    'This user is not a member of the required GitHub org.')
Beispiel #25
0
    def readChunk(self, upload, offset, params):
        """
        After the temporary upload record has been created (see initUpload),
        the bytes themselves should be passed up in ordered chunks. The user
        must remain logged in when passing each chunk, to authenticate that
        the writer of the chunk is the same as the person who initiated the
        upload. The passed offset is a verification mechanism for ensuring the
        server and client agree on the number of bytes sent/received.

        This method accepts both the legacy multipart content encoding, as
        well as passing offset and uploadId as query parameters and passing
        the chunk as the body, which is the recommended method.

        .. deprecated :: 2.2.0
        """
        if 'chunk' in params:
            chunk = params['chunk']
            if isinstance(chunk, cherrypy._cpreqbody.Part):
                # Seek is the only obvious way to get the length of the part
                chunk.file.seek(0, os.SEEK_END)
                size = chunk.file.tell()
                chunk.file.seek(0, os.SEEK_SET)
                chunk = RequestBodyStream(chunk.file, size=size)
        else:
            chunk = RequestBodyStream(cherrypy.request.body)

        user = self.getCurrentUser()

        if upload['userId'] != user['_id']:
            raise AccessException('You did not initiate this upload.')

        if upload['received'] != offset:
            raise RestException(
                'Server has received %s bytes, but client sent offset %s.' %
                (upload['received'], offset))
        try:
            return self.model('upload').handleChunk(upload,
                                                    chunk,
                                                    filter=True,
                                                    user=user)
        except IOError as exc:
            if exc.errno == errno.EACCES:
                raise Exception('Failed to store upload.')
            raise
Beispiel #26
0
def ensureTokenScopes(token, scope):
    """
    Call this to validate a token scope for endpoints that require tokens
    other than a user authentication token. Raises an AccessException if the
    required scopes are not allowed by the given token.

    :param token: The token object used in the request.
    :type token: dict
    :param scope: The required scope or set of scopes.
    :type scope: str or list of str
    """
    tokenModel = ModelImporter.model('token')
    if not tokenModel.hasScope(token, scope):
        setattr(cherrypy.request, 'girderUser', None)
        if isinstance(scope, six.string_types):
            scope = (scope, )
        raise AccessException(
            'Invalid token scope.\nRequired: {}.\nAllowed: {}'.format(
                ' '.join(scope), ' '.join(tokenModel.getAllowedScopes(token))))
Beispiel #27
0
    def getSegmentationTasks(self, params):
        details = self.boolParam('details', params, False)

        user = self.getCurrentUser()
        userSkill = User().getSegmentationSkill(user)
        if userSkill is None:
            raise AccessException(
                'You are not authorized to perform segmentations.')

        pipeline = list(
            itertools.chain(self._pipeline1AllImages(user),
                            self._pipeline2ImagesWithSegmentations(),
                            (self._pipeline3NoExpertSegmentations()
                             if userSkill == Segmentation().Skill.EXPERT else
                             self._pipeline3MissingSegmentations()),
                            (self._pipeline4ListImages()
                             if details else self._pipeline4CountImages()),
                            self._pipeline5JoinDataset()))

        results = list(Image().collection.aggregate(pipeline))

        return results
Beispiel #28
0
    def redirectReviewTask(self, params):
        self.requireParams(['datasetId'], params)

        user = self.getCurrentUser()
        User().requireReviewDataset(user)

        dataset = Dataset().load(params['datasetId'],
                                 user=user,
                                 level=AccessType.READ,
                                 exc=True)

        prereviewFolder = Dataset().prereviewFolder(dataset)
        if not (prereviewFolder and Folder().hasAccess(
                prereviewFolder, user=user, level=AccessType.READ)):
            raise AccessException(
                'User does not have access to any Pre-review images for this dataset.'
            )

        if not Image().find({'folderId': prereviewFolder['_id']}).count():
            raise RestException(
                'No Pre-review images are available for this dataset.')

        reviewUrl = '/markup/gallery#/qc/%s' % dataset['_id']
        self._doRedirect(reviewUrl)
Beispiel #29
0
def ensureTokenScopes(token, scope):
    """
    Call this to validate a token scope for endpoints that require tokens
    other than a user authentication token. Raises an AccessException if the
    required scopes are not allowed by the given token.

    :param token: The token object used in the request.
    :type token: dict
    :param scope: The required scope or set of scopes.
    :type scope: str or list of str
    """
    tokenModel = ModelImporter.model('token')
    if tokenModel.hasScope(token, TokenScope.USER_AUTH):
        return

    if not tokenModel.hasScope(token, scope):
        setCurrentUser(None)
        if isinstance(scope, six.string_types):
            scope = (scope, )
        raise AccessException(
            'Invalid token scope.\n'
            'Required: %s.\n'
            'Allowed: %s' %
            (' '.join(scope), ' '.join(tokenModel.getAllowedScopes(token))))
Beispiel #30
0
 def accessDecorator(*args, **kwargs):
     token = rest.getCurrentToken()
     if not token:
         raise AccessException('You must be logged in or supply a valid '
                               'session token.')
     return fun(*args, **kwargs)