Exemple #1
0
def _onUpload(event):
    """
    Look at uploads containing references related to this plugin. If found,
    they are used to link item task outputs back to a job document.
    """
    try:
        ref = json.loads(event.info.get('reference', ''))
    except ValueError:
        return

    if isinstance(ref, dict) and ref.get('type') == 'item_tasks.output':
        jobModel = Job()
        tokenModel = Token()
        token = event.info['currentToken']

        if tokenModel.hasScope(token, 'item_tasks.job_write:%s' % ref['jobId']):
            job = jobModel.load(ref['jobId'], force=True, exc=True)
        else:
            job = jobModel.load(
                ref['jobId'], level=AccessType.WRITE, user=event.info['currentUser'], exc=True)

        file = event.info['file']
        item = Item().load(file['itemId'], force=True)

        # Add link to job model to the output item
        jobModel.updateJob(job, otherFields={
            'itemTaskBindings.outputs.%s.itemId' % ref['id']: item['_id']
        })

        # Also a link in the item to the job that created it
        item['createdByJob'] = job['_id']
        Item().save(item)
Exemple #2
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 = 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),
                '' if token is None else ' '.join(tokenModel.getAllowedScopes(token))))
Exemple #3
0
    def verifyEmail(self, user, token):
        token = Token().load(
            token, user=user, level=AccessType.ADMIN, objectId=False, exc=True)
        delta = (token['expires'] - datetime.datetime.utcnow()).total_seconds()
        hasScope = Token().hasScope(token, TokenScope.EMAIL_VERIFICATION)

        if token.get('userId') != user['_id'] or delta <= 0 or not hasScope:
            raise AccessException('The token is invalid or expired.')

        user['emailVerified'] = True
        Token().remove(token)
        user = self._model.save(user)

        if self._model.canLogin(user):
            setCurrentUser(user)
            authToken = self.sendAuthTokenCookie(user)
            return {
                'user': self._model.filter(user, user),
                'authToken': {
                    'token': authToken['_id'],
                    'expires': authToken['expires'],
                    'scope': authToken['scope']
                },
                'message': 'Email verification succeeded.'
            }
        else:
            return {
                'user': self._model.filter(user, user),
                'message': 'Email verification succeeded.'
            }
Exemple #4
0
class Token(Resource):
    """API Endpoint for non-user tokens in the system."""

    def __init__(self):
        super(Token, self).__init__()
        self.resourceName = 'token'
        self._model = TokenModel()

        self.route('DELETE', ('session',), self.deleteSession)
        self.route('GET', ('session',), self.getSession)
        self.route('GET', ('current',), self.currentSession)
        self.route('GET', ('scopes',), self.listScopes)

    @access.public
    @autoDescribeRoute(
        Description('Retrieve the current session information.')
        .responseClass('Token')
    )
    def currentSession(self):
        return self.getCurrentToken()

    @access.public
    @autoDescribeRoute(
        Description('Get an anonymous session token for the system.')
        .notes('If you are logged in, this will return a token associated with that login.')
        .responseClass('Token')
    )
    def getSession(self):
        token = self.getCurrentToken()

        # Only create and send new cookie if token isn't valid or will expire soon
        if not token:
            token = self.sendAuthTokenCookie(None, scope=TokenScope.ANONYMOUS_SESSION)

        return {
            'token': token['_id'],
            'expires': token['expires']
        }

    @access.token
    @autoDescribeRoute(
        Description('Remove a session from the system.')
        .responseClass('Token')
        .notes('Attempts to delete your authentication cookie.')
    )
    def deleteSession(self):
        token = self.getCurrentToken()
        if token:
            self._model.remove(token)
        self.deleteAuthTokenCookie()
        return {'message': 'Session deleted.'}

    @access.public
    @autoDescribeRoute(
        Description('List all token scopes available in the system.')
    )
    def listScopes(self):
        return TokenScope.listScopes()
Exemple #5
0
def testRequireScope(db):
    scope = TokenScope.DATA_OWN
    anotherScope = TokenScope.SETTINGS_READ
    tokenModel = Token()
    token = tokenModel.createToken(scope=scope)

    # If specified scope does not exist raise an error
    with pytest.raises(AccessException):
        tokenModel.requireScope(token, anotherScope)
Exemple #6
0
def testHasScope(db):
    scope = TokenScope.DATA_READ
    tokenModel = Token()
    token = tokenModel.createToken(scope=scope)

    # If token is None should return False
    assert not tokenModel.hasScope(None, scope)

    # If scope is None should return True
    assert tokenModel.hasScope(token, None)
Exemple #7
0
    def executeTask(self, item, jobTitle, includeJobInfo, inputs, outputs):
        user = self.getCurrentUser()
        if jobTitle is None:
            jobTitle = item['name']
        task, handler = self._validateTask(item)

        if task.get('mode') == 'girder_worker':
            return runCeleryTask(item['meta']['itemTaskImport'], inputs)

        jobModel = self.model('job', 'jobs')
        jobModel = Job()
        job = jobModel.createJob(
            title=jobTitle, type='item_task', handler=handler, user=user)

        # If this is a user auth token, we make an IO-enabled token
        token = self.getCurrentToken()
        tokenModel = Token()
        if tokenModel.hasScope(token, TokenScope.USER_AUTH):
            token = tokenModel.createToken(
                user=user, days=7, scope=(TokenScope.DATA_READ, TokenScope.DATA_WRITE))
            job['itemTaskTempToken'] = token['_id']

        token = tokenModel.addScope(token, 'item_tasks.job_write:%s' % job['_id'])

        job.update({
            'itemTaskId': item['_id'],
            'itemTaskBindings': {
                'inputs': inputs,
                'outputs': outputs
            },
            'kwargs': {
                'task': task,
                'inputs': self._transformInputs(inputs, token),
                'outputs': self._transformOutputs(outputs, token, job, task, item['_id']),
                'validate': False,
                'auto_convert': False,
                'cleanup': True
            }
        })

        if includeJobInfo:
            job['kwargs']['jobInfo'] = utils.jobInfoSpec(job)

        if 'itemTaskCeleryQueue' in item.get('meta', {}):
            job['celeryQueue'] = item['meta']['itemTaskCeleryQueue']

        job = jobModel.save(job)
        jobModel.scheduleJob(job)

        return job
Exemple #8
0
def _authorizeInitUpload(event):
    """
    Called when initializing an upload, prior to the default handler. Checks if
    the user is passing an authorized upload token, and if so, sets the current
    request-thread user to be whoever created the token.
    """
    token = getCurrentToken()
    params = event.info['params']
    tokenModel = Token()
    parentType = params.get('parentType')
    parentId = params.get('parentId', '')
    requiredScopes = {TOKEN_SCOPE_AUTHORIZED_UPLOAD, 'authorized_upload_folder_%s' % parentId}

    if parentType == 'folder' and tokenModel.hasScope(token=token, scope=requiredScopes):
        user = User().load(token['userId'], force=True)
        setCurrentUser(user)
Exemple #9
0
def _storeUploadId(event):
    """
    Called after an upload is first initialized successfully. Sets the authorized upload ID
    in the token, ensuring it can be used for only this upload.
    """
    returnVal = event.info['returnVal']
    token = getCurrentToken()
    tokenModel = Token()
    isAuthorizedUpload = tokenModel.hasScope(token, TOKEN_SCOPE_AUTHORIZED_UPLOAD)

    if isAuthorizedUpload and returnVal.get('_modelType', 'upload') == 'upload':
        params = event.info['params']
        token['scope'].remove(TOKEN_SCOPE_AUTHORIZED_UPLOAD)
        token['authorizedUploadId'] = returnVal['_id']
        token['authorizedUploadDescription'] = params.get('authorizedUploadDescription', '')
        token['authorizedUploadEmail'] = params.get('authorizedUploadEmail')
        tokenModel.save(token)
Exemple #10
0
    def __init__(self):
        super(Token, self).__init__()
        self.resourceName = 'token'
        self._model = TokenModel()

        self.route('DELETE', ('session',), self.deleteSession)
        self.route('GET', ('session',), self.getSession)
        self.route('GET', ('current',), self.currentSession)
        self.route('GET', ('scopes',), self.listScopes)
Exemple #11
0
    def changePassword(self, old, new):
        user = self.getCurrentUser()
        token = None

        if not old:
            raise RestException('Old password must not be empty.')

        if not Password().hasPassword(user) or not Password().authenticate(user, old):
            # If not the user's actual password, check for temp access token
            token = Token().load(old, force=True, objectId=False, exc=False)
            if (not token or not token.get('userId') or
                    token['userId'] != user['_id'] or
                    not Token().hasScope(token, TokenScope.TEMPORARY_USER_AUTH)):
                raise AccessException('Old password is incorrect.')

        self._model.setPassword(user, new)

        if token:
            # Remove the temporary access token if one was used
            Token().remove(token)

        return {'message': 'Password changed.'}
Exemple #12
0
    def checkTemporaryPassword(self, user, token):
        token = Token().load(
            token, user=user, level=AccessType.ADMIN, objectId=False, exc=True)
        delta = (token['expires'] - datetime.datetime.utcnow()).total_seconds()
        hasScope = Token().hasScope(token, TokenScope.TEMPORARY_USER_AUTH)

        if token.get('userId') != user['_id'] or delta <= 0 or not hasScope:
            raise AccessException('The token does not grant temporary access to this user.')

        # Temp auth is verified, send an actual auth token now. We keep the
        # temp token around since it can still be used on a subsequent request
        # to change the password
        authToken = self.sendAuthTokenCookie(user)

        return {
            'user': self._model.filter(user, user),
            'authToken': {
                'token': authToken['_id'],
                'expires': authToken['expires'],
                'temporary': True
            },
            'message': 'Temporary access token is valid.'
        }
Exemple #13
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 = 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))))
Exemple #14
0
def testTokenCreationDuration(server, user, apiKey):
    defaultDuration = Setting().get(SettingKey.COOKIE_LIFETIME)
    # We should be able to request a duration shorter than default
    resp = server.request('/api_key/token',
                          method='POST',
                          params={
                              'key': apiKey['key'],
                              'duration': defaultDuration - 1
                          })
    assertStatusOk(resp)
    token = Token().load(resp.json['authToken']['token'],
                         force=True,
                         objectId=False)
    duration = token['expires'] - token['created']
    assert duration == datetime.timedelta(days=defaultDuration - 1)
def models(fsAssetstore, admin, user):
    adminFolder = six.next(Folder().childFolders(
        parent=admin, parentType='user', user=admin))
    adminToken = Token().createToken(admin)
    sampleData = b'Hello world'
    sampleFile = Upload().uploadFromFile(
        obj=six.BytesIO(sampleData), size=len(sampleData), name='Sample',
        parentType='folder', parent=adminFolder, user=admin)

    return {
        'user': user,
        'admin': admin,
        'adminFolder': adminFolder,
        'adminToken': adminToken,
        'sampleFile': sampleFile
    }
Exemple #16
0
    def createAuthorizedUpload(self, folder, params):
        try:
            if params.get('duration'):
                days = int(params.get('duration'))
            else:
                days = Setting().get(SettingKey.COOKIE_LIFETIME)
        except ValueError:
            raise ValidationException('Token duration must be an integer, or leave it empty.')

        token = Token().createToken(days=days, user=self.getCurrentUser(), scope=(
            TOKEN_SCOPE_AUTHORIZED_UPLOAD, 'authorized_upload_folder_%s' % folder['_id']))

        url = '%s#authorized_upload/%s/%s' % (
            mail_utils.getEmailUrlPrefix(), folder['_id'], token['_id'])

        return {'url': url}
Exemple #17
0
def testRequiredScopeExists(server, user):
    token = Token().createToken(scope=CUSTOM_SCOPE)

    resp = server.request(path='/accesstest/test_required_scope_exists')
    # If not given a user or a valid auth token the status should be 401
    assertStatus(resp, 401)

    resp2 = server.request(path='/accesstest/test_required_scope_exists',
                           user=user)
    # If the token does not have the CUSTOM_SCOPE the status should be 403
    assertStatus(resp2, 403)

    # If user is not given but the token has the correct scope
    # the status should be 200
    resp3 = server.request(path='/accesstest/test_required_scope_exists',
                           token=token)

    assertStatus(resp3, 200)
Exemple #18
0
    def cliHandler(resource, params):
        from .girder_worker_plugin.direct_docker_run import run

        user = resource.getCurrentUser()
        currentItem = CLIItem.find(itemId, user)
        if not currentItem:
            raise RestException('Invalid CLI Item id (%s).' % (itemId))
        # Create a new token for this job; otherwise, the user could log out
        # and the job would fail to finish.  We may want to override the
        # duration of this token (it defaults to the setting for cookie
        # lifetime).
        token = Token().createToken(user=user)
        if hasattr(getCurrentToken, 'set'):
            getCurrentToken.set(token)

        container_args = [currentItem.name]
        reference = {
            'slicer_cli_web': {
                'title': cliTitle,
                'image': currentItem.image,
                'name': currentItem.name,
            }
        }
        args, result_hooks, primary_input_name = prepare_task(
            params, user, token, index_params, opt_params,
            has_simple_return_file, reference)
        container_args.extend(args)

        jobType = '%s#%s' % (currentItem.image, currentItem.name)

        if primary_input_name:
            jobTitle = '%s on %s' % (cliTitle, primary_input_name)
        else:
            jobTitle = cliTitle

        job = run.delay(girder_user=user,
                        girder_job_type=jobType,
                        girder_job_title=jobTitle,
                        girder_result_hooks=result_hooks,
                        image=currentItem.digest,
                        pull_image='if-not-present',
                        container_args=container_args)
        return job.job
Exemple #19
0
    def sendAuthTokenCookie(self, user=None, scope=None, token=None, days=None):
        """
        Helper method to send the authentication cookie
        """
        if days is None:
            days = float(Setting().get(SettingKey.COOKIE_LIFETIME))

        if token is None:
            token = Token().createToken(user, days=days, scope=scope)

        cookie = cherrypy.response.cookie
        cookie['girderToken'] = str(token['_id'])
        cookie['girderToken']['path'] = '/'
        cookie['girderToken']['expires'] = int(days * 3600 * 24)

        if Setting().get(SettingKey.SECURE_COOKIE):
            cookie['girderToken']['secure'] = True

        return token
Exemple #20
0
    def run_pipeline_task(self, folder, pipeline):
        user = self.getCurrentUser()
        token = Token().createToken(user=user, days=1)
        move_existing_result_to_auxiliary_folder(folder, user)
        input_type = folder["meta"]["type"]

        return run_pipeline.apply_async(
            queue="pipelines",
            kwargs=dict(
                input_path=GetPathFromFolderId(str(folder["_id"])),
                output_folder=str(folder["_id"]),
                pipeline=pipeline,
                input_type=input_type,
                girder_job_title=(
                    "Running {} on {}".format(pipeline, str(folder["name"]))
                ),
                girder_client_token=str(token["_id"]),
                girder_job_type="pipelines",
            ),
        )
Exemple #21
0
    def setUp(self):
        base.TestCase.setUp(self)

        self.users = [
            User().createUser('usr' + str(n), 'passwd', 'tst', 'usr',
                              '*****@*****.**' % n) for n in range(2)
        ]
        self.admin = self.users[0]

        self.adminFolder = six.next(Folder().childFolders(parent=self.admin,
                                                          parentType='user',
                                                          user=self.admin))
        self.adminToken = Token().createToken(self.admin)
        sampleData = b'Hello world'
        self.sampleFile = Upload().uploadFromFile(obj=six.BytesIO(sampleData),
                                                  size=len(sampleData),
                                                  name='Sample',
                                                  parentType='folder',
                                                  parent=self.adminFolder,
                                                  user=self.admin)
Exemple #22
0
    def generateTemporaryPassword(self, email):
        user = self._model.findOne({'email': email.lower()})

        if not user:
            raise RestException('That email is not registered.')

        token = Token().createToken(user, days=1, scope=TokenScope.TEMPORARY_USER_AUTH)

        url = '%s#useraccount/%s/token/%s' % (
            mail_utils.getEmailUrlPrefix(), str(user['_id']), str(token['_id']))

        html = mail_utils.renderTemplate('temporaryAccess.mako', {
            'url': url,
            'token': str(token['_id'])
        })
        mail_utils.sendEmail(
            to=email, subject='%s: Temporary access' % Setting().get(SettingKey.BRAND_NAME),
            text=html
        )
        return {'message': 'Sent temporary access email.'}
Exemple #23
0
def testArtificialScopedAccess(server, admin, user, userDataReadToken,
                               userToken):
    # Test public access
    for route in ('public_access', 'fn_public', 'scoped_public'):
        path = '/accesstest/%s' % route

        for t in (userDataReadToken, None):
            resp = server.request(path=path, token=t)
            assertStatusOk(resp)
            assert resp.json is None

        resp = server.request(path=path, token=userToken)
        assertStatusOk(resp)
        assert resp.json['_id'] == str(user['_id'])

    # Make a correctly scoped token, should work.
    token = Token().createToken(user=user, scope=TokenScope.SETTINGS_READ)
    resp = server.request(path=path, token=token)
    assertStatusOk(resp)
    assert resp.json['_id'] == str(user['_id'])
Exemple #24
0
def buildHeaders(headers, cookie, user, token, basicAuth, authHeader):
    from girder.models.token import Token

    headers = headers[:]
    if cookie is not None:
        headers.append(('Cookie', cookie))

    if user is not None:
        token = Token().createToken(user)
        headers.append(('Girder-Token', str(token['_id'])))
    elif token is not None:
        if isinstance(token, dict):
            headers.append(('Girder-Token', token['_id']))
        else:
            headers.append(('Girder-Token', token))

    if basicAuth is not None:
        auth = base64.b64encode(basicAuth.encode('utf8'))
        headers.append((authHeader, 'Basic %s' % auth.decode()))

    return headers
Exemple #25
0
def testDeactivatingKeyDeletesAssociatedTokens(server, user, apiKey):
    resp = server.request('/api_key/token',
                          method='POST',
                          params={'key': apiKey['key']})
    assertStatusOk(resp)

    newScopes = [TokenScope.DATA_READ, TokenScope.DATA_WRITE]
    resp = server.request('/api_key/%s' % apiKey['_id'],
                          params={
                              'active': False,
                              'tokenDuration': 10,
                              'scope': json.dumps(newScopes)
                          },
                          method='PUT',
                          user=user)
    assertStatusOk(resp)

    # This should have deleted all corresponding tokens
    q = {'userId': user['_id'], 'apiKeyId': apiKey['_id']}
    count = Token().find(q).count()
    assert count == 0
Exemple #26
0
def inviteUser(self, params):
    params = self._decodeParams(params)
    self.requireParams(['login', 'email', 'firstName', 'lastName'], params)
    if 'validityPeriod' in params:
        try:
            validityPeriod = float(params['validityPeriod'])
        except ValueError:
            raise ValidationException('Validity period must be a number.',
                                      'validityPeriod')
    else:
        validityPeriod = 60.0

    currentUser = self.getCurrentUser()
    User().requireAdminStudy(currentUser)

    newUser = User().createUser(login=params['login'],
                                password=None,
                                email=params['email'],
                                firstName=params['firstName'],
                                lastName=params['lastName'])

    token = Token().createToken(newUser,
                                days=validityPeriod,
                                scope=[TokenScope.TEMPORARY_USER_AUTH])

    inviteUrl = '%s/#user/%s/rsvp/%s' % (mail_utils.getEmailUrlPrefix(),
                                         newUser['_id'], token['_id'])

    html = mail_utils.renderTemplate('inviteUser.mako', {
        'newUser': newUser,
        'inviteUrl': inviteUrl,
    })
    mail_utils.sendEmail(to=newUser['email'],
                         subject='ISIC Archive: Invitation',
                         text=html)

    return {
        'newUser': User().filterSummary(newUser, currentUser),
        'inviteUrl': inviteUrl
    }
Exemple #27
0
    def testCreateJobRest(self):
        resp = self.request('/job',
                            method='POST',
                            user=self.users[0],
                            params={
                                'title': 'job',
                                'type': 'job'
                            })
        # If user does not have the necessary token status is 403
        self.assertStatus(resp, 403)

        token = Token().createToken(scope=REST_CREATE_JOB_TOKEN_SCOPE)

        resp2 = self.request('/job',
                             method='POST',
                             token=token,
                             params={
                                 'title': 'job',
                                 'type': 'job'
                             })
        # If user has the necessary token status is 200
        self.assertStatusOk(resp2)
Exemple #28
0
def testTokenCreation(server, user, apiKey):
    defaultDuration = Setting().get(SettingKey.COOKIE_LIFETIME)
    # Create a token using the key
    resp = server.request('/api_key/token',
                          method='POST',
                          params={
                              'key': apiKey['key'],
                              'duration': defaultDuration + 1000
                          })
    assertStatusOk(resp)
    token = Token().load(resp.json['authToken']['token'],
                         force=True,
                         objectId=False)
    # Make sure token has full user auth access
    assert token['userId'] == user['_id']
    assert token['scope'] == [TokenScope.USER_AUTH]
    # Make sure the token references the API key used to create it
    assert token['apiKeyId'] == apiKey['_id']

    # Make sure the token duration is not longer than the default
    duration = token['expires'] - token['created']
    assert duration == datetime.timedelta(days=defaultDuration)
Exemple #29
0
    def test_docker_run_transfer_encoding_stream(self, params):
        item_id = params.get('itemId')
        file_id = params.get('fileId')
        delimiter = params.get('delimiter')

        headers = {
            'Girder-Token': str(Token().createToken(getCurrentUser())['_id'])
        }
        url = '%s/%s?itemId=%s&delimiter=%s' % (
            getApiUrl(), 'integration_tests/docker/input_stream', item_id, delimiter)

        container_args = [
            'read_write',
            '-i', GirderFileIdToVolume(file_id),
            '-o', Connect(NamedOutputPipe('out'),
                          ChunkedTransferEncodingStream(url, headers))
        ]
        result = docker_run.delay(
            TEST_IMAGE, pull_image=True, container_args=container_args,
            remove_container=True)

        return result.job
Exemple #30
0
    def __init__(self, *args, **kwargs):
        gc = kwargs.pop('gc', None)

        try:
            if gc is None:
                # We need to resolve Girder's API URL, but girder_worker can
                # specify a different value than what Girder gets from a rest
                # request.
                # Girder 3
                try:
                    from girder_worker.girder_plugin.utils import getWorkerApiUrl
                except ImportError:
                    # Girder 2
                    try:
                        from girder.plugins.worker.utils import getWorkerApiUrl
                    # Fall back if the worker plugin is unavailble
                    except ImportError:
                        from girder.api.rest import getApiUrl as getWorkerApiUrl

                self.gc = GirderClient(apiUrl=getWorkerApiUrl())
                from girder.api.rest import getCurrentUser
                if getCurrentUser():
                    from girder.constants import TokenScope
                    from girder.models.token import Token
                    token = Token().createToken(
                        days=7,
                        scope=[TokenScope.DATA_READ, TokenScope.DATA_WRITE],
                        user=getCurrentUser(),
                    )['_id']
                else:
                    from girder.api.rest import getCurrentToken
                    token = getCurrentToken()['_id']
                self.gc.token = token
            else:
                self.gc = gc
        except ImportError:
            self.gc = None
Exemple #31
0
def configureItemTaskFromSlicerCliXml(self, item, xml, setName, setDescription,
                                      params):
    Token().requireScope(self.getCurrentToken(),
                         'item_task.set_task_spec.%s' % item['_id'])

    args = item.get('meta', {}).get('itemTaskSlicerCliArgs') or []
    cliSpec = cli_parser.parseSlicerCliXml(xml)

    itemTaskSpec = item.get('meta', {}).get('itemTaskSpec', {})
    itemTaskSpec.update({
        'container_args': args + cliSpec['args'],
        'inputs': cliSpec['inputs'],
        'outputs': cliSpec['outputs']
    })

    if setName:
        item['name'] = cliSpec['title']
    if setDescription:
        item['description'] = cliSpec['description']

    Item().setMetadata(item, {
        'itemTaskSpec': itemTaskSpec,
        'isItemTask': True
    })
    def publishTale(self, tale, repository):
        user = self.getCurrentUser()
        publishers = {
            entry["repository"]: entry["auth_provider"]
            for entry in Setting().get(PluginSettings.PUBLISHER_REPOS)
        }

        try:
            publisher = publishers[repository]
        except KeyError:
            raise RestException(
                "Unknown publisher repository ({})".format(repository))

        if publisher.startswith("dataone"):
            key = "provider"  # Dataone
            value = publisher
        else:
            key = "resource_server"
            value = repository

        token = next(
            (_ for _ in user.get("otherTokens", []) if _.get(key) == value),
            None)
        if not token:
            raise RestException(
                "Missing a token for publisher ({}).".format(publisher))

        girder_token = Token().createToken(user=user, days=0.5)

        publishTask = publish.delay(
            str(tale["_id"]),
            token,
            repository=repository,
            girder_client_token=str(girder_token["_id"]),
        )
        return publishTask.job
Exemple #33
0
    def testTemporaryPassword(self):
        User().createUser('user1', 'passwd', 'tst', 'usr', '*****@*****.**')
        # Temporary password should require email param
        self.ensureRequiredParams(path='/user/password/temporary',
                                  method='PUT',
                                  required={'email'})
        # Temporary password with an incorrect email
        resp = self.request(path='/user/password/temporary',
                            method='PUT',
                            params={'email': '*****@*****.**'})
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'], "That email is not registered.")
        # Actually generate temporary access token
        self.assertTrue(base.mockSmtp.isMailQueueEmpty())
        resp = self.request(path='/user/password/temporary',
                            method='PUT',
                            params={'email': '*****@*****.**'})
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['message'], "Sent temporary access email.")
        self.assertTrue(base.mockSmtp.waitForMail())
        msg = base.mockSmtp.getMail(parse=True)
        # Pull out the auto-generated token from the email
        body = msg.get_payload(decode=True).decode('utf8')
        search = re.search('<a href="(.*)">', body)
        link = search.group(1)
        linkParts = link.split('/')
        userId = linkParts[-3]
        tokenId = linkParts[-1]
        # Checking if a token is a valid temporary token should fail if the
        # token is missing or doesn't match the user ID
        path = '/user/password/temporary/' + userId
        self.ensureRequiredParams(path=path, required={'token'})
        resp = self.request(path=path,
                            method='GET',
                            params={'token': 'not valid'})
        self.assertStatus(resp, 400)
        resp = self.request(path=path, method='GET', params={'token': tokenId})
        self.assertStatusOk(resp)
        user = resp.json['user']

        # We should have a real auth token now
        self.assertTrue('girderToken' in resp.cookie)
        authToken = resp.cookie['girderToken'].value
        token = Token().load(authToken, force=True, objectId=False)
        self.assertEqual(str(token['userId']), userId)
        self.assertFalse(Token().hasScope(token,
                                          [TokenScope.TEMPORARY_USER_AUTH]))
        self.assertTrue(Token().hasScope(token, [TokenScope.USER_AUTH]))

        # Artificially adjust the token to have expired.
        token = Token().load(tokenId, force=True, objectId=False)
        token['expires'] = (datetime.datetime.utcnow() -
                            datetime.timedelta(days=1))
        Token().save(token)
        resp = self.request(path=path, method='GET', params={'token': tokenId})
        self.assertStatus(resp, 401)

        # We should now be able to change the password
        resp = self.request(path='/user/password',
                            method='PUT',
                            params={
                                'old': tokenId,
                                'new': 'another_password'
                            },
                            user=user)
        self.assertStatusOk(resp)

        # The token should have been deleted
        token = Token().load(tokenId, force=True, objectId=False)
        self.assertEqual(token, None)
Exemple #34
0
def userToken(db, user):
    yield Token().createToken(user=user)
Exemple #35
0
 def logout(self):
     token = self.getCurrentToken()
     if token:
         Token().remove(token)
     self.deleteAuthTokenCookie()
     return {'message': 'Logged out.'}
Exemple #36
0
def userDataReadToken(db, user):
    yield Token().createToken(user=user, scope=TokenScope.DATA_READ)
Exemple #37
0
def userSettingToken(db, user):
    yield Token().createToken(user=user, scope=TokenScope.SETTINGS_READ)
Exemple #38
0
def adminEmailToken(db, admin):
    yield Token().createToken(user=admin, scope=TokenScope.DATA_READ)
Exemple #39
0
def adminSettingToken(db, admin):
    yield Token().createToken(user=admin, scope=TokenScope.SETTINGS_READ)
Exemple #40
0
def cookie(user):
    yield 'girderToken=%s' % str(Token().createToken(user)['_id'])
Exemple #41
0
    def testAddItemTasksToFolderFromJson(self):
        """
        Test adding item tasks to a folder from a JSON spec.
        """
        # Create a new folder that will contain the tasks
        folder = Folder().createFolder(name='placeholder',
                                       creator=self.admin,
                                       parent=self.admin,
                                       parentType='user')

        # Create task to introspect container
        with mock.patch('girder.plugins.jobs.models.job.Job.scheduleJob'
                        ) as scheduleMock:
            resp = self.request('/folder/%s/item_task_json_description' %
                                folder['_id'],
                                method='POST',
                                params={'image': 'johndoe/foo:v5'},
                                user=self.admin)
            self.assertStatusOk(resp)
            self.assertEqual(resp.json['_modelType'], 'job')
            self.assertEqual(len(scheduleMock.mock_calls), 1)
            job = scheduleMock.mock_calls[0][1][0]
            self.assertEqual(job['handler'], 'worker_handler')
            self.assertEqual(job['itemTaskId'], folder['_id'])
            self.assertEqual(job['kwargs']['outputs']['_stdout']['method'],
                             'POST')
            self.assertTrue(
                job['kwargs']['outputs']['_stdout']['url'].endswith(
                    'folder/%s/item_task_json_specs' % folder['_id']))
            params = job['kwargs']['outputs']['_stdout']['params']
            self.assertEqual(params['image'], 'johndoe/foo:v5')
            self.assertEqual(params['pullImage'], True)
            token = job['kwargs']['outputs']['_stdout']['headers'][
                'Girder-Token']

        # Task should not be registered until we get the callback
        resp = self.request('/item_task', user=self.admin)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])

        # Simulate callback from introspection job
        with open(os.path.join(os.path.dirname(__file__), 'specs.json')) as f:
            specs = f.read()

        parsedSpecs = json.loads(specs)

        resp = self.request('/folder/%s/item_task_json_specs' % folder['_id'],
                            method='POST',
                            params={
                                'image': 'johndoe/foo:v5',
                                'pullImage': False
                            },
                            token=token,
                            body=specs,
                            type='application/json')

        self.assertStatusOk(resp)

        items = list(Folder().childItems(folder, user=self.admin))
        self.assertEqual(len(items), 2)

        # Image name and item task flag should be stored in the item metadata
        for itemIndex, item in enumerate(items):
            item = Item().load(item['_id'], force=True)
            self.assertEqual(item['name'],
                             'johndoe/foo:v5 %s' % (str(itemIndex)))
            self.assertEqual(item['description'],
                             parsedSpecs[itemIndex]['description'])
            self.assertTrue(item['meta']['isItemTask'])
            parsedSpecs[itemIndex]['pull_image'] = False
            parsedSpecs[itemIndex]['docker_image'] = 'johndoe/foo:v5'
            self.assertEqual(item['meta']['itemTaskSpec'],
                             parsedSpecs[itemIndex])
            self.assertEqual(item['meta']['itemTaskName'], '')

        # We should only be able to see tasks we have read access on
        resp = self.request('/item_task')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])

        resp = self.request('/item_task', user=self.admin)
        self.assertStatusOk(resp)
        self.assertEqual(len(resp.json), 2)

        # Test adding single task spec
        folder2 = Folder().createFolder(name='placeholder2',
                                        creator=self.admin,
                                        parent=self.admin,
                                        parentType='user')
        with open(os.path.join(os.path.dirname(__file__), 'spec.json')) as f:
            spec = f.read()
        parsedSpec = json.loads(spec)

        token = Token().createToken(user=self.admin,
                                    scope='item_task.set_task_spec.%s' %
                                    folder2['_id'])
        resp = self.request('/folder/%s/item_task_json_specs' % folder2['_id'],
                            method='POST',
                            params={
                                'image': 'johndoe/foo:v5',
                                'pullImage': False
                            },
                            token=token,
                            body=spec,
                            type='application/json')
        self.assertStatusOk(resp)
        items = list(Folder().childItems(folder2, user=self.admin))
        self.assertEqual(len(items), 1)

        # Check that the single item has the correct metadata
        item = Item().load(items[0]['_id'], force=True)
        self.assertEqual(item['name'], 'johndoe/foo:v5')
        self.assertEqual(item['description'], parsedSpec['description'])
        self.assertTrue(item['meta']['isItemTask'])
        parsedSpec['pull_image'] = False
        parsedSpec['docker_image'] = 'johndoe/foo:v5'
        self.assertEqual(item['meta']['itemTaskSpec'], parsedSpec)
        self.assertEqual(item['meta']['itemTaskName'], '')
Exemple #42
0
    def testDeleteUser(self):
        """
        Test the behavior of deleting users.
        """
        # Create a couple of users
        users = [
            User().createUser('usr%s' % num, 'passwd', 'tst', 'usr',
                              '*****@*****.**' % num) for num in [0, 1]
        ]

        # Create a folder and give both users some access on it
        folder = Folder().createFolder(parent=users[0],
                                       name='x',
                                       parentType='user',
                                       public=False,
                                       creator=users[0])
        Folder().setUserAccess(folder, users[0], AccessType.WRITE)
        Folder().setUserAccess(folder, users[1], AccessType.READ)
        folder = Folder().save(folder)

        self.assertEqual(len(folder['access']['users']), 2)

        # Create a token for user 1
        token = Token().createToken(users[1])

        # Create a group, and have user 1 request to join it
        group = Group().createGroup('test', users[0], public=True)
        resp = self.request(path='/group/%s/member' % group['_id'],
                            method='POST',
                            user=users[1])
        self.assertStatusOk(resp)

        # Make sure non-admin users can't delete other users
        resp = self.request(path='/user/%s' % users[0]['_id'],
                            method='DELETE',
                            user=users[1])
        self.assertStatus(resp, 403)

        # Delete user 1 as admin, should work
        resp = self.request(path='/user/%s' % users[1]['_id'],
                            method='DELETE',
                            user=users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['message'],
                         'Deleted user %s.' % users[1]['login'])

        users[1] = User().load(users[1]['_id'], force=True)
        folder = Folder().load(folder['_id'], force=True)
        token = Token().load(token['_id'], force=True, objectId=False)
        group = Group().load(group['_id'], force=True)

        # Make sure user and token were deleted
        self.assertEqual(users[1], None)
        self.assertEqual(token, None)

        # Make sure pending invite to group was deleted
        self.assertEqual(len(list(Group().getFullRequestList(group))), 0)

        # Make sure access control references for the user were deleted
        self.assertEqual(len(folder['access']['users']), 1)

        # Delete user 0
        resp = self.request(path='/user/%s' % users[0]['_id'],
                            method='DELETE',
                            user=users[0])
        self.assertStatusOk(resp)

        # Make sure the user's folder was deleted
        folder = Folder().load(folder['_id'], force=True)
        self.assertEqual(folder, None)