Esempio n. 1
0
    def testDirectAdd(self):
        """
        Tests the functionality of an admin user adding a user directly to
        a group, bypassing the invitation process.
        """
        group = Group().createGroup('g1', self.users[0])
        self.assertFalse(Group().hasAccess(group, self.users[1], AccessType.WRITE))

        # Admin user can add user 1 directly if they pass force=True.
        resp = self.request(path='/group/%s/invitation' % group['_id'],
                            method='POST', user=self.users[0],
                            params={
                                'force': 'true',
                                'userId': self.users[1]['_id'],
                                'level': AccessType.WRITE
                                })
        self.assertStatus(resp, 200)
        user1 = User().load(self.users[1]['_id'], force=True)
        group = Group().load(group['_id'], force=True)
        self.assertTrue(Group().hasAccess(group, user1, AccessType.WRITE))
        self.assertFalse(Group().hasAccess(group, user1, AccessType.ADMIN))
        self.assertTrue(group['_id'] in user1['groups'])

        # User 1 should not be able to use the force option.
        resp = self.request(path='/group/%s/invitation' % group['_id'],
                            method='POST', user=self.users[1],
                            params={
                                'force': 'true',
                                'userId': self.users[2]['_id']
                                })
        self.assertStatus(resp, 403)
        self.assertEqual(resp.json['message'], 'Administrator access required.')
        user2 = User().load(self.users[2]['_id'], force=True)
        self.assertFalse(group['_id'] in user2.get('groups',  ()))
Esempio n. 2
0
def fastCrypt():
    """
    Use faster password hashing to avoid unnecessary testing bottlenecks.
    """
    from girder.models.user import User

    # CryptContext.update could be used to mutate the existing instance, but if this fixture's scope
    # is ever made more limited (so that the teardown matters), this approach is more maintainable
    originalCryptContext = User()._cryptContext
    User()._cryptContext = originalCryptContext.copy(schemes=['plaintext'])
    yield
    User()._cryptContext = originalCryptContext
Esempio n. 3
0
def _getLdapUser(attrs, server):
    emails = attrs.get('mail')
    if not emails:
        raise Exception('No email record present for the given LDAP user.')

    if not isinstance(emails, (list, tuple)):
        emails = (emails,)

    emails = [e.decode('utf8').lower() for e in emails]
    existing = User().find({
        'email': {'$in': emails}
    }, limit=1)
    if existing.count():
        return existing.next()

    return _registerLdapUser(attrs, emails[0], server)
Esempio n. 4
0
    def __init__(self):
        super(User, self).__init__()
        self.resourceName = 'user'
        self._model = UserModel()

        self.route('DELETE', ('authentication',), self.logout)
        self.route('DELETE', (':id',), self.deleteUser)
        self.route('GET', (), self.find)
        self.route('GET', ('me',), self.getMe)
        self.route('GET', ('authentication',), self.login)
        self.route('GET', (':id',), self.getUser)
        self.route('GET', (':id', 'details'), self.getUserDetails)
        self.route('GET', ('details',), self.getUsersDetails)
        self.route('POST', (), self.createUser)
        self.route('PUT', (':id',), self.updateUser)
        self.route('PUT', ('password',), self.changePassword)
        self.route('PUT', (':id', 'password'), self.changeUserPassword)
        self.route('GET', ('password', 'temporary', ':id'),
                   self.checkTemporaryPassword)
        self.route('PUT', ('password', 'temporary'),
                   self.generateTemporaryPassword)
        self.route('POST', (':id', 'otp'), self.initializeOtp)
        self.route('PUT', (':id', 'otp'), self.finalizeOtp)
        self.route('DELETE', (':id', 'otp'), self.removeOtp)
        self.route('PUT', (':id', 'verification'), self.verifyEmail)
        self.route('POST', ('verification',), self.sendVerificationEmail)
Esempio n. 5
0
def testVerifyOtp(server, user):
    # Enable OTP
    otpUris = User().initializeOtp(user)
    user['otp']['enabled'] = True

    # Generate an invalid token
    otpToken = _tokenFromTotpUri(otpUris['totpUri'], False)

    with pytest.raises(AccessException):
        User().verifyOtp(user, otpToken)

    # Generate a valid token
    otpToken = _tokenFromTotpUri(otpUris['totpUri'])
    # Verify the token, which should succeed without raising an exception
    User().verifyOtp(user, otpToken)

    # Re-verify the same token, which should fail
    # The "server" fixture is necessary for this to work
    with pytest.raises(AccessException):
        User().verifyOtp(user, otpToken)
Esempio n. 6
0
    def listKeys(self, userId, limit, offset, sort):
        user = self.getCurrentUser()

        if userId not in {None, str(user['_id'])}:
            self.requireAdmin(user)
            user = User().load(userId, force=True, exc=True)

        return list(ApiKeyModel().list(user,
                                       offset=offset,
                                       limit=limit,
                                       sort=sort))
Esempio n. 7
0
    def setUp(self):
        base.TestCase.setUp(self)

        user = {
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'First',
            'lastName': 'Last',
            'password': '******'
        }
        self.admin = User().createUser(**user)
Esempio n. 8
0
    def setUp(self):
        base.TestCase.setUp(self)

        self.admin = User().createUser(login='******',
                                       firstName='admin',
                                       lastName='admin',
                                       email='*****@*****.**',
                                       password='******')
        self.user = User().createUser(login='******',
                                      firstName='user',
                                      lastName='1',
                                      email='*****@*****.**',
                                      password='******')
        folders = Folder().childFolders(self.admin,
                                        parentType='user',
                                        user=self.admin)
        self.privateFolder, self.publicFolder = list(folders)

        # show full diff when objects don't match
        self.maxDiff = None
Esempio n. 9
0
    def check_auth_password(self, username, password):
        if username.lower() == 'anonymous':
            return paramiko.AUTH_SUCCESSFUL

        try:
            self.girderUser = User().authenticate(username,
                                                  password,
                                                  otpToken=True)
            return paramiko.AUTH_SUCCESSFUL
        except AccessException:
            return paramiko.AUTH_FAILED
Esempio n. 10
0
    def setUp(self):
        base.TestCase.setUp(self)

        self.siteAdminUser = User().createUser(
            email='*****@*****.**',
            login='******',
            firstName='Robert',
            lastName='Balboa',
            password='******'
        )
        self.creatorUser = User().createUser(
            email='*****@*****.**',
            login='******',
            firstName='Apollo',
            lastName='Creed',
            password='******'
        )
        creationSetting = Setting().getDefault(SettingKey.COLLECTION_CREATE_POLICY)
        creationSetting['open'] = True
        Setting().set(SettingKey.COLLECTION_CREATE_POLICY, creationSetting)
Esempio n. 11
0
    def setUp(self):
        super().setUp()

        user = {
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'First',
            'lastName': 'Last',
            'password': '******'
        }
        self.admin = User().createUser(**user)
Esempio n. 12
0
def testDatabaseConnectivityRequiresDbFixtureInTesting():
    """
    This test exists to verify that attempting to use Girder's model layer without using the
    `db` fixture will raise a reasonable exception rather than accidentally polluting users'
    actual databases.
    """
    with pytest.raises(Exception) as e:
        User().find()
    assert str(
        e.value
    ) == 'You must use the "db" fixture in tests that connect to the database.'
Esempio n. 13
0
    def testRegisterAndLoginSha512(self):
        cherrypy.config['auth']['hash_alg'] = 'sha512'

        params = {
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'First',
            'lastName': 'Last',
            'password': '******'
        }

        # Register a user with sha512 storage backend
        resp = self.request(path='/user', method='POST', params=params)
        self.assertStatusOk(resp)
        self._verifyUserDocument(resp.json)

        user = User().load(resp.json['_id'], force=True)
        self.assertEqual(user['hashAlg'], 'sha512')

        # Login unsuccessfully
        resp = self.request(path='/user/authentication', method='GET',
                            basicAuth='goodlogin:badpassword')
        self.assertStatus(resp, 401)
        self.assertEqual('Login failed.', resp.json['message'])

        # Login successfully
        resp = self.request(path='/user/authentication', method='GET',
                            basicAuth='goodlogin:goodpassword')
        self.assertStatusOk(resp)
        self.assertEqual('Login succeeded.', resp.json['message'])
        self.assertEqual('*****@*****.**', resp.json['user']['email'])
        self._verifyUserDocument(resp.json['user'])

        # Make sure we got a nice cookie
        self._verifyAuthCookie(resp)

        token = Token().load(self.cookieVal, objectId=False, force=True)
        self.assertEqual(str(token['userId']), resp.json['user']['_id'])

        # Hit the logout endpoint
        resp = self.request(path='/user/authentication', method='DELETE',
                            token=token['_id'])
        self._verifyDeletedCookie(resp)

        token = Token().load(token['_id'], objectId=False, force=True)
        self.assertEqual(token, None)

        # Test disabling password login
        Setting().set(SettingKey.ENABLE_PASSWORD_LOGIN, False)

        resp = self.request(
            path='/user/authentication', method='GET', basicAuth='goodlogin:goodpassword')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'], 'Password login is disabled on this instance.')
Esempio n. 14
0
def import_recursive(job):
    try:
        root = job['kwargs']['root']
        token = job['kwargs']['token']

        user = User().load(job['userId'], force=True)

        children = list(Folder().childFolders(root, 'collection', user=user))
        count = len(children)
        progress = 0

        job = Job().updateJob(job,
                              log='Started TCGA import\n',
                              status=JobStatus.RUNNING,
                              progressCurrent=progress,
                              progressTotal=count)
        logger.info('Starting recursive TCGA import')

        for child in children:
            progress += 1
            try:
                msg = 'Importing "%s"' % child.get('name', '')
                job = Job().updateJob(job,
                                      log=msg,
                                      progressMessage=msg + '\n',
                                      progressCurrent=progress)
                logger.debug(msg)
                Cohort().importDocument(child,
                                        recurse=True,
                                        user=user,
                                        token=token,
                                        job=job)
                job = Job().load(id=job['_id'], force=True)

                # handle any request to stop execution
                if (not job or job['status']
                        in (JobStatus.CANCELED, JobStatus.ERROR)):
                    logger.info('TCGA import job halted with')
                    return

            except ValidationException:
                logger.warning('Failed to import %s' % child.get('name', ''))

        logger.info('Starting recursive TCGA import')
        job = Job().updateJob(job,
                              log='Finished TCGA import\n',
                              status=JobStatus.SUCCESS,
                              progressCurrent=count,
                              progressMessage='Finished TCGA import')
    except Exception as e:
        logger.exception('Importing TCGA failed with %s' % str(e))
        job = Job().updateJob(job,
                              log='Import failed with %s\n' % str(e),
                              status=JobStatus.ERROR)
Esempio n. 15
0
 def _recalculateSizes(self, progress):
     fixes = 0
     models = [Collection(), User()]
     steps = sum(model.find().count() for model in models)
     progress.update(total=steps, current=0)
     for model in models:
         for doc in model.find():
             progress.update(increment=1)
             _, f = model.updateSize(doc)
             fixes += f
     return fixes
Esempio n. 16
0
def admin(db):
    """
    Require an admin user.

    Provides a user with the admin flag set to True.
    """
    from girder.models.user import User
    u = User().createUser(email='*****@*****.**', login='******', firstName='Admin',
                          lastName='Admin', password='******', admin=True)

    yield u
Esempio n. 17
0
def sendEmail(to=None, subject=None, text=None, toAdmins=False, bcc=None):
    """
    Send an email. This builds the appropriate email object and then triggers
    an asynchronous event to send the email (handled in _sendmail).

    :param to: The recipient's email address, or a list of addresses.
    :type to: str, list/tuple, or None
    :param subject: The subject line of the email.
    :type subject: str
    :param text: The body of the email.
    :type text: str
    :param toAdmins: To send an email to all site administrators, set this
        to True, which will override any "to" argument that was passed.
    :type toAdmins: bool
    :param bcc: Recipient email address(es) that should be specified using the
        Bcc header.
    :type bcc: str, list/tuple, or None
    """
    from girder.models.setting import Setting
    from girder.models.user import User

    to = to or ()
    bcc = bcc or ()

    if toAdmins:
        to = [u['email'] for u in User().getAdmins()]
    else:
        if isinstance(to, six.string_types):
            to = (to, )
        if isinstance(bcc, six.string_types):
            bcc = (bcc, )

    if not to and not bcc:
        raise Exception('You must specify email recipients via "to" or "bcc", '
                        'or use toAdmins=True.')

    if isinstance(text, six.text_type):
        text = text.encode('utf8')

    msg = MIMEText(text, 'html', 'UTF-8')
    msg['Subject'] = subject or '[no subject]'

    if to:
        msg['To'] = ', '.join(to)
    if bcc:
        msg['Bcc'] = ', '.join(bcc)

    msg['From'] = Setting().get(SettingKey.EMAIL_FROM_ADDRESS)

    events.daemon.trigger('_sendmail',
                          info={
                              'message': msg,
                              'recipients': list(set(to) | set(bcc))
                          })
Esempio n. 18
0
    def processNotification(store: AssetstoreModel, rootFolder: GirderModel,
                            importPath: str):
        """
        Import at proper location
        """
        if rootFolder is None:
            raise RestException('Root folder missing')
        # Find the correct import location given rootFolder and importPath
        owner = User().findOne({
            '_id':
            ObjectId(rootFolder['creatorId'] or rootFolder['baseParentId'])
        })
        if owner is None:
            raise RestException('Root has no owner')

        target = rootFolder

        importPath = importPath.lstrip('/')
        realImportPathDir, _ = os.path.split(importPath)
        storePrefix = str(store['prefix']).lstrip('/')
        common_path = os.path.commonpath([storePrefix, importPath])

        realImportPath = common_path
        path_from_root = importPath[len(common_path):].lstrip('/')
        path_from_root_list, _ = os.path.split(path_from_root)

        for folder_name in path_from_root_list.split('/'):
            new_target = Folder().findOne({
                'parentId': ObjectId(target['_id']),
                'name': folder_name,
            })
            new_import_path = f'{realImportPath}/{folder_name}'
            if new_target is not None:
                target = new_target
                realImportPath = new_import_path
            else:
                break

        realImportPath = realImportPath.lstrip('/')

        if realImportPath == realImportPathDir:
            # All the chain of parent directories exist
            realImportPath = importPath

        Assetstore().importData(
            store,
            target,
            'folder',
            {'importPath': realImportPath},
            None,
            owner,
            force_recursive=False,
        )
Esempio n. 19
0
def addVersionsAndRuns(event: events.Event) -> None:
    tale = event.info
    creator = User().load(tale['creatorId'], force=True)
    versions_root, _ = _createAuxFolder(tale, Constants.VERSIONS_ROOT_DIR_NAME,
                                        PluginSettings.VERSIONS_DIRS_ROOT,
                                        creator)
    tale["versionsRootId"] = versions_root["_id"]
    runs_root, _ = _createAuxFolder(tale, Constants.RUNS_ROOT_DIR_NAME,
                                    PluginSettings.RUNS_DIRS_ROOT, creator)
    tale["runsRootId"] = runs_root["_id"]
    tale = Tale().save(tale)
    event.addResponse(tale)
Esempio n. 20
0
def extract(path):
    resources = []

    if '/' in path:
        resources += list(Collection().find())
        resources += list(User().find())
    elif '/collection' in path:
        resources += list(Collection().find())
    elif '/user' in path:
        resources += list(User().find())
    else:
        resources += [lookUpPath(p)['document'] for p in path]

    for resource in resources:
        items = list(Item().find({'baseParentId': resource['_id']}))

        for item in items:
            files = list(File().find({'itemId': item['_id']}))

            for file in files:
                create_geometa(item, file)
Esempio n. 21
0
    def load(self, info):
        getPlugin('jobs').load(info)

        name = 'thumbnails'
        info['apiRoot'].thumbnail = rest.Thumbnail()

        for model in (Item(), Collection(), Folder(), User()):
            model.exposeFields(level=AccessType.READ, fields='_thumbnails')
            events.bind('model.%s.remove' % model.name, name, removeThumbnails)

        events.bind('model.file.remove', name, removeThumbnailLink)
        events.bind('data.process', name, _onUpload)
Esempio n. 22
0
def user(db, admin):
    """
    Require a user.

    Provides a regular user with no additional privileges. Note this fixture requires
    the admin fixture since an administrative user must exist before a regular user can.
    """
    from girder.models.user import User
    u = User().createUser(email='*****@*****.**', login='******', firstName='user',
                          lastName='user', password='******', admin=False)

    yield u
Esempio n. 23
0
 def testUsersDetails(self):
     """
     Test that the user count is correct.
     """
     # Create an admin user
     admin = User().createUser(
         firstName='Admin', lastName='Admin', login='******',
         email='*****@*****.**', password='******')
     # Create a couple of users
     users = [User().createUser(
         'usr%s' % num, 'passwd', 'tst', 'usr', '*****@*****.**' % num)
         for num in [0, 1]]
     resp = self.request(path='/user/details', user=admin, method='GET')
     self.assertStatusOk(resp)
     self.assertEqual(resp.json['nUsers'], 3)
     # test for a non-admin user
     resp = self.request(path='/user/details', user=users[0], method='GET')
     self.assertStatus(resp, 403)
     # test for a non-user
     resp = self.request(path='/user/details', method='GET')
     self.assertStatus(resp, 401)
Esempio n. 24
0
    def load(self, info):
        ModelImporter.registerModel('annotationItem', AnnotationItem, plugin='dive_server')
        ModelImporter.registerModel('revisionLogItem', RevisionLogItem, plugin='dive_server')

        info["apiRoot"].dive_annotation = AnnotationResource("dive_annotation")
        info["apiRoot"].dive_configuration = ConfigurationResource("dive_configuration")
        info["apiRoot"].dive_dataset = DatasetResource("dive_dataset")
        info["apiRoot"].dive_rpc = RpcResource("dive_rpc")

        # Setup route additions for exsting resources
        info["apiRoot"].user.route("PUT", (":id", "use_private_queue"), use_private_queue)
        User().exposeFields(AccessType.READ, constants.UserPrivateQueueEnabledMarker)

        # Expose Job dataset assocation
        Job().exposeFields(AccessType.READ, constants.JOBCONST_DATASET_ID)

        DIVE_MAIL_TEMPLATES = Path(os.path.realpath(__file__)).parent / 'mail_templates'
        mail_utils.addTemplateDirectory(str(DIVE_MAIL_TEMPLATES))

        # Relocate Girder
        info["serverRoot"], info["serverRoot"].girder = (
            ClientWebroot(),
            info["serverRoot"],
        )
        info["serverRoot"].api = info["serverRoot"].girder.api

        events.bind(
            "filesystem_assetstore_imported",
            "process_fs_import",
            process_fs_import,
        )
        events.bind(
            "s3_assetstore_imported",
            "process_s3_import",
            process_s3_import,
        )
        events.bind(
            'model.user.save.created',
            'send_new_user_email',
            send_new_user_email,
        )

        # Create dependency on worker
        plugin.getPlugin('worker').load(info)
        Setting().set(
            'worker.api_url',
            os.environ.get('WORKER_API_URL', 'http://girder:8080/api/v1'),
        )

        broker_url = os.environ.get('CELERY_BROKER_URL', None)
        if broker_url is None:
            raise RuntimeError('CELERY_BROKER_URL must be set')
        Setting().set('worker.broker', broker_url)
Esempio n. 25
0
    def setUp(self):
        base.TestCase.setUp(self)

        info = {
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'Admin',
            'lastName': 'Admin',
            'password': '******',
            'admin': True
        }
        self.admin = User().createUser(**info)
Esempio n. 26
0
    def listChildJobs(self, job):
        """
        Lists the child jobs for a given job

        :param job: Job document
        :type job: Job
        """
        query = {'parentId': job['_id']}
        cursor = self.find(query)
        user = User().load(job['userId'], force=True)
        for r in self.filterResultsByPermission(cursor=cursor, user=user, level=AccessType.READ):
            yield r
Esempio n. 27
0
    def __init__(self):
        super().__init__()

        self.coll_m = Collection()
        self.file_m = File()
        self.folder_m = Folder()
        self.item_m = Item()
        self.upload_m = Upload()
        self.asset_m = Assetstore()
        self.user_m = User()

        self.setupRoutes()
Esempio n. 28
0
    def testPrivateUser(self):
        """
        Make sure private users behave correctly.
        """
        # Create an admin user
        User().createUser(firstName='Admin',
                          lastName='Admin',
                          login='******',
                          email='*****@*****.**',
                          password='******')

        # Register a private user (non-admin)
        pvt = User().createUser(firstName='Guy',
                                lastName='Noir',
                                login='******',
                                email='*****@*****.**',
                                password='******',
                                public=False)

        self.assertEqual(pvt['public'], False)

        folder = six.next(Folder().childFolders(parentType='user', parent=pvt))

        # Private users should be able to upload files
        resp = self.request(path='/item',
                            method='POST',
                            user=pvt,
                            params={
                                'name': 'foo.txt',
                                'folderId': folder['_id']
                            })
        self.assertStatusOk(resp)
        itemId = resp.json['_id']

        file = self.uploadFile('hi.txt',
                               'hello',
                               user=pvt,
                               parent=resp.json,
                               parentType='item')
        self.assertEqual(str(file['itemId']), itemId)
Esempio n. 29
0
    def testPublishDataONE(self):
        with mock.patch("gwvolman.tasks.publish.apply_async"), mock.patch(
                "gwvolman.tasks.publish.delay") as dl:

            dl.return_value = FakeJob()

            remoteMemberNode = "nowhere"  # non exisiting repository
            resp = self.request(
                path="/tale/{_id}/publish".format(**self.tale),
                method="PUT",
                user=self.user,
                params={"repository": remoteMemberNode},
            )
            self.assertStatus(resp, 400)
            self.assertEqual(resp.json["message"],
                             "Unknown publisher repository (nowhere)")

            remoteMemberNode = "https://dev.nceas.ucsb.edu/knb/d1/mn"
            resp = self.request(
                path="/tale/{_id}/publish".format(**self.tale),
                method="PUT",
                user=self.user,
                params={"repository": remoteMemberNode},
            )
            self.assertStatus(resp, 400)
            self.assertEqual(resp.json["message"],
                             "Missing a token for publisher (dataonestage2).")

            # "Authenticate" with DataONE
            token = {
                "access_token": "dataone_token",
                "provider": "dataonestage2",
                "resource_server": "cn-stage-2.dataone.org",
                "token_type": "dataone",
            }
            self.user["otherTokens"] = [token]
            self.user = User().save(self.user)

            resp = self.request(
                path="/tale/{_id}/publish".format(**self.tale),
                method="PUT",
                user=self.user,
                params={"repository": remoteMemberNode},
            )
            self.assertStatusOk(resp)

            job_kwargs = dl.call_args_list[-1][1]
            job_args = dl.call_args_list[-1][0]
            self.assertEqual(job_args[0], str(self.tale["_id"]))
            self.assertDictEqual(job_args[1], token)
            job_kwargs.pop("girder_client_token")
            self.assertDictEqual(job_kwargs, {"repository": remoteMemberNode})
Esempio n. 30
0
    def setUp(self):
        base.TestCase.setUp(self)

        self.user = User().createUser(
            firstName='First', lastName='Last', login='******',
            password='******', email='*****@*****.**')
        self.publicFolder = six.next(Folder().childFolders(
            parentType='user', parent=self.user, user=None, limit=1))
        self.apiKey = ApiKey().createApiKey(self.user, name='')

        self.downloadDir = os.path.join(
            os.path.dirname(__file__), '_testDownload')
        shutil.rmtree(self.downloadDir, ignore_errors=True)
Esempio n. 31
0
def send_approved(event):
    dataset = event.info['dataset']
    approver = event.info['approver']
    user = User().load(dataset['userId'], force=True)
    html = mail_utils.renderTemplate('mdb.dataset_approved.mako', {
        'dataset': dataset,
        'user': user,
        'approver': approver
    })

    email_address = user['email']

    mail_utils.sendEmail(to=email_address, subject='Materials Data Bank: Dataset approved.', text=html)
Esempio n. 32
0
def _authorizeUploadStep(event):
    """
    Called before any requests dealing with partially completed uploads. Sets the
    request thread user to the authorized upload token creator if the requested
    upload is an authorized upload.
    """
    token = getCurrentToken()
    uploadId = ObjectId(event.info['params'].get('uploadId'))

    if token and 'authorizedUploadId' in token and token[
            'authorizedUploadId'] == uploadId:
        user = User().load(token['userId'], force=True)
        setCurrentUser(user)
Esempio n. 33
0
def setTaleFolderMapping(event: events.Event):
    tale = event.info
    root_path = Setting().get(PluginSettings.TALE_DIRS_ROOT)
    creator = User().load(tale["creatorId"], force=True)
    workspace = Tale()._createAuxFolder(tale, WORKSPACE_NAME, creator=creator)
    absDir = "%s/%s" % (root_path, TalePathMapper().davToPhysical("/" + str(tale["_id"])))
    absDir = pathlib.Path(absDir)
    absDir.mkdir(parents=True, exist_ok=True)
    workspace.update({'fsPath': absDir.as_posix(), 'isMapping': True})
    Folder().save(workspace, validate=True, triggerEvents=False)
    tale["workspaceId"] = workspace["_id"]
    tale = Tale().save(tale)
    event.addResponse(tale)
Esempio n. 34
0
def createInitialUser():
    try:
        User().createUser(
            ADMIN_USER,
            ADMIN_PASS,
            ADMIN_USER,
            ADMIN_USER,
            "*****@*****.**",
            admin=True,
            public=True,
        )
    except ValidationException:
        print("Admin user already exists, skipping...")
Esempio n. 35
0
    def setUp(self):
        base.TestCase.setUp(self)

        user = {
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'First',
            'lastName': 'Last',
            'password': '******'
        }
        self.admin = User().createUser(**user)
        self.infoMessage = 'Log info message'
        self.errorMessage = 'Log error message'
Esempio n. 36
0
    def _createOrReuseUser(cls, oauthId, email, firstName, lastName,
                           userName=None):
        providerName = cls.getProviderName()

        # Try finding by ID first, since a user can change their email address
        query = {
            # PyMongo may not properly support full embedded document queries,
            # since the object order matters (and Python dicts are unordered),
            # so search by individual embedded fields
            'oauth.provider': providerName,
            'oauth.id': oauthId
        }
        if providerName == 'google':
            # The Google provider was previously stored as capitalized, and
            # legacy databases may still have these entries
            query['oauth.provider'] = {'$in': ['google', 'Google']}
        user = User().findOne(query)
        setId = not user

        # Existing users using OAuth2 for the first time will not have an ID
        if not user:
            user = User().findOne({'email': email})

        dirty = False
        # Create the user if it's still not found
        if not user:
            policy = Setting().get(SettingKey.REGISTRATION_POLICY)
            if policy == 'closed':
                ignore = Setting().get(PluginSettings.IGNORE_REGISTRATION_POLICY)
                if not ignore:
                    raise RestException(
                        'Registration on this instance is closed. Contact an '
                        'administrator to create an account for you.')
            login = cls._deriveLogin(email, firstName, lastName, userName)

            user = User().createUser(
                login=login, password=None, firstName=firstName, lastName=lastName, email=email)
        else:
            # Migrate from a legacy format where only 1 provider was stored
            if isinstance(user.get('oauth'), dict):
                user['oauth'] = [user['oauth']]
                dirty = True
            # Update user data from provider
            if email != user['email']:
                user['email'] = email
                dirty = True
            # Don't set names to empty string
            if firstName != user['firstName'] and firstName:
                user['firstName'] = firstName
                dirty = True
            if lastName != user['lastName'] and lastName:
                user['lastName'] = lastName
                dirty = True
        if setId:
            user.setdefault('oauth', []).append(
                {
                    'provider': providerName,
                    'id': oauthId
                })
            dirty = True
        if dirty:
            user = User().save(user)

        return user
Esempio n. 37
0
GIRDER_COLLECTION = "GeoParser_Upload_Files"



class GeoParser(object):

    @cherrypy.expose
    def index(self):
        tmpl = lookup.get_template("index.html")
        return tmpl.render(salutation="Hello", target="World")



if __name__ == '__main__':

    girderUser = User()
    girderCollection = Collection()
    girderFolder = Folder()

    try:
        currentUser = girderUser.getAdmins()[0]
    except:
        print "ERROR: No user registered or logged in."
    existinig_collections = [each['name'] for each in girderCollection.list()]

    if len(existinig_collections) == 0 or not GIRDER_COLLECTION in existinig_collections:
        girderCollection.createCollection(GIRDER_COLLECTION, currentUser)
        existinig_collections = [each['name'] for each in girderCollection.list()]
    else:
        print "ERROR: Cannot create Collection. User not registered or logged in."
Esempio n. 38
0
class User(Resource):
    """API Endpoint for users in the system."""

    def __init__(self):
        super(User, self).__init__()
        self.resourceName = 'user'
        self._model = UserModel()

        self.route('DELETE', ('authentication',), self.logout)
        self.route('DELETE', (':id',), self.deleteUser)
        self.route('GET', (), self.find)
        self.route('GET', ('me',), self.getMe)
        self.route('GET', ('authentication',), self.login)
        self.route('GET', (':id',), self.getUser)
        self.route('GET', (':id', 'details'), self.getUserDetails)
        self.route('GET', ('details',), self.getUsersDetails)
        self.route('POST', (), self.createUser)
        self.route('PUT', (':id',), self.updateUser)
        self.route('PUT', ('password',), self.changePassword)
        self.route('PUT', (':id', 'password'), self.changeUserPassword)
        self.route('GET', ('password', 'temporary', ':id'),
                   self.checkTemporaryPassword)
        self.route('PUT', ('password', 'temporary'),
                   self.generateTemporaryPassword)
        self.route('POST', (':id', 'otp'), self.initializeOtp)
        self.route('PUT', (':id', 'otp'), self.finalizeOtp)
        self.route('DELETE', (':id', 'otp'), self.removeOtp)
        self.route('PUT', (':id', 'verification'), self.verifyEmail)
        self.route('POST', ('verification',), self.sendVerificationEmail)

    @access.public
    @filtermodel(model=UserModel)
    @autoDescribeRoute(
        Description('List or search for users.')
        .responseClass('User', array=True)
        .param('text', "Pass this to perform a full text search for items.", required=False)
        .pagingParams(defaultSort='lastName')
    )
    def find(self, text, limit, offset, sort):
        return list(self._model.search(
            text=text, user=self.getCurrentUser(), offset=offset, limit=limit, sort=sort))

    @access.public(scope=TokenScope.USER_INFO_READ)
    @filtermodel(model=UserModel)
    @autoDescribeRoute(
        Description('Get a user by ID.')
        .responseClass('User')
        .modelParam('id', model=UserModel, level=AccessType.READ)
        .errorResponse('ID was invalid.')
        .errorResponse('You do not have permission to see this user.', 403)
    )
    def getUser(self, user):
        return user

    @access.public(scope=TokenScope.USER_INFO_READ)
    @filtermodel(model=UserModel)
    @autoDescribeRoute(
        Description('Retrieve the currently logged-in user information.')
        .responseClass('User')
    )
    def getMe(self):
        return self.getCurrentUser()

    @access.public
    @autoDescribeRoute(
        Description('Log in to the system.')
        .notes('Pass your username and password using HTTP Basic Auth. Sends'
               ' a cookie that should be passed back in future requests.')
        .param('Girder-OTP', 'A one-time password for this user', paramType='header',
               required=False)
        .errorResponse('Missing Authorization header.', 401)
        .errorResponse('Invalid login or password.', 403)
    )
    def login(self):
        if not Setting().get(SettingKey.ENABLE_PASSWORD_LOGIN):
            raise RestException('Password login is disabled on this instance.')

        user, token = self.getCurrentUser(returnToken=True)

        # Only create and send new cookie if user isn't already sending a valid one.
        if not user:
            authHeader = cherrypy.request.headers.get('Girder-Authorization')

            if not authHeader:
                authHeader = cherrypy.request.headers.get('Authorization')

            if not authHeader or not authHeader[0:6] == 'Basic ':
                raise RestException('Use HTTP Basic Authentication', 401)

            try:
                credentials = base64.b64decode(authHeader[6:]).decode('utf8')
                if ':' not in credentials:
                    raise TypeError
            except Exception:
                raise RestException('Invalid HTTP Authorization header', 401)

            login, password = credentials.split(':', 1)
            otpToken = cherrypy.request.headers.get('Girder-OTP')
            user = self._model.authenticate(login, password, otpToken)

            setCurrentUser(user)
            token = self.sendAuthTokenCookie(user)

        return {
            'user': self._model.filter(user, user),
            'authToken': {
                'token': token['_id'],
                'expires': token['expires'],
                'scope': token['scope']
            },
            'message': 'Login succeeded.'
        }

    @access.public
    @autoDescribeRoute(
        Description('Log out of the system.')
        .responseClass('Token')
        .notes('Attempts to delete your authentication cookie.')
    )
    def logout(self):
        token = self.getCurrentToken()
        if token:
            Token().remove(token)
        self.deleteAuthTokenCookie()
        return {'message': 'Logged out.'}

    @access.public
    @filtermodel(model=UserModel, addFields={'authToken'})
    @autoDescribeRoute(
        Description('Create a new user.')
        .responseClass('User')
        .param('login', "The user's requested login.")
        .param('email', "The user's email address.")
        .param('firstName', "The user's first name.")
        .param('lastName', "The user's last name.")
        .param('password', "The user's requested password")
        .param('admin', 'Whether this user should be a site administrator.',
               required=False, dataType='boolean', default=False)
        .errorResponse('A parameter was invalid, or the specified login or'
                       ' email already exists in the system.')
    )
    def createUser(self, login, email, firstName, lastName, password, admin):
        currentUser = self.getCurrentUser()

        regPolicy = Setting().get(SettingKey.REGISTRATION_POLICY)

        if not currentUser or not currentUser['admin']:
            admin = False
            if regPolicy == 'closed':
                raise RestException(
                    'Registration on this instance is closed. Contact an '
                    'administrator to create an account for you.')

        user = self._model.createUser(
            login=login, password=password, email=email, firstName=firstName,
            lastName=lastName, admin=admin)

        if not currentUser and self._model.canLogin(user):
            setCurrentUser(user)
            token = self.sendAuthTokenCookie(user)
            user['authToken'] = {
                'token': token['_id'],
                'expires': token['expires']
            }
        return user

    @access.user
    @autoDescribeRoute(
        Description('Delete a user by ID.')
        .modelParam('id', model=UserModel, level=AccessType.ADMIN)
        .errorResponse('ID was invalid.')
        .errorResponse('You do not have permission to delete this user.', 403)
    )
    def deleteUser(self, user):
        self._model.remove(user)
        return {'message': 'Deleted user %s.' % user['login']}

    @access.admin
    @autoDescribeRoute(
        Description('Get detailed information about all users.')
        .errorResponse('You are not a system administrator.', 403)
    )
    def getUsersDetails(self):
        nUsers = self._model.find().count()
        return {'nUsers': nUsers}

    @access.user
    @filtermodel(model=UserModel)
    @autoDescribeRoute(
        Description("Update a user's information.")
        .modelParam('id', model=UserModel, level=AccessType.WRITE)
        .param('firstName', 'First name of the user.')
        .param('lastName', 'Last name of the user.')
        .param('email', 'The email of the user.')
        .param('admin', 'Is the user a site admin (admin access required)',
               required=False, dataType='boolean')
        .param('status', 'The account status (admin access required)',
               required=False, enum=('pending', 'enabled', 'disabled'))
        .errorResponse()
        .errorResponse(('You do not have write access for this user.',
                        'Must be an admin to create an admin.'), 403)
    )
    def updateUser(self, user, firstName, lastName, email, admin, status):
        user['firstName'] = firstName
        user['lastName'] = lastName
        user['email'] = email

        # Only admins can change admin state
        if admin is not None:
            if self.getCurrentUser()['admin']:
                user['admin'] = admin
            elif user['admin'] is not admin:
                raise AccessException('Only admins may change admin status.')

        # Only admins can change status
        if status is not None and status != user.get('status', 'enabled'):
            if not self.getCurrentUser()['admin']:
                raise AccessException('Only admins may change status.')
            if user['status'] == 'pending' and status == 'enabled':
                # Send email on the 'pending' -> 'enabled' transition
                self._model._sendApprovedEmail(user)
            user['status'] = status

        return self._model.save(user)

    @access.admin
    @autoDescribeRoute(
        Description('Change a user\'s password.')
        .notes('Only administrators may use this endpoint.')
        .modelParam('id', model=UserModel, level=AccessType.ADMIN)
        .param('password', 'The user\'s new password.')
        .errorResponse('You are not an administrator.', 403)
        .errorResponse('The new password is invalid.')
    )
    def changeUserPassword(self, user, password):
        self._model.setPassword(user, password)
        return {'message': 'Password changed.'}

    @access.user
    @autoDescribeRoute(
        Description('Change your password.')
        .param('old', 'Your current password or a temporary access token.')
        .param('new', 'Your new password.')
        .errorResponse(('You are not logged in.',
                        'Your old password is incorrect.'), 401)
        .errorResponse('Your new password is invalid.')
    )
    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.'}

    @access.public
    @autoDescribeRoute(
        Description('Create a temporary access token for a user.  The user\'s '
                    'password is not changed.')
        .param('email', 'Your email address.', strip=True)
        .errorResponse('That email does not exist in the system.')
    )
    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.'}

    @access.public
    @autoDescribeRoute(
        Description('Check if a specified token is a temporary access token '
                    'for the specified user.  If the token is valid, returns '
                    'information on the token and user.')
        .modelParam('id', 'The user ID to check.', model=UserModel, force=True)
        .param('token', 'The token to check.')
        .errorResponse('The token does not grant temporary access to the specified user.', 401)
    )
    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.'
        }

    @access.public
    @autoDescribeRoute(
        Description('Get detailed information about a user.')
        .modelParam('id', model=UserModel, level=AccessType.READ)
        .errorResponse()
        .errorResponse('Read access was denied on the user.', 403)
    )
    def getUserDetails(self, user):
        return {
            'nFolders': self._model.countFolders(
                user, filterUser=self.getCurrentUser(), level=AccessType.READ)
        }

    @access.user
    @autoDescribeRoute(
        Description('Initiate the enablement of one-time passwords for this user.')
        .modelParam('id', model=UserModel, level=AccessType.ADMIN)
        .errorResponse()
        .errorResponse('Admin access was denied on the user.', 403)
    )
    def initializeOtp(self, user):
        if self._model.hasOtpEnabled(user):
            raise RestException('The user has already enabled one-time passwords.')

        otpUris = self._model.initializeOtp(user)
        self._model.save(user)

        return otpUris

    @access.user
    @autoDescribeRoute(
        Description('Finalize the enablement of one-time passwords for this user.')
        .modelParam('id', model=UserModel, level=AccessType.ADMIN)
        .param('Girder-OTP', 'A one-time password for this user', paramType='header')
        .errorResponse()
        .errorResponse('Admin access was denied on the user.', 403)
    )
    def finalizeOtp(self, user):
        otpToken = cherrypy.request.headers.get('Girder-OTP')
        if not otpToken:
            raise RestException('The "Girder-OTP" header must be provided.')

        if 'otp' not in user:
            raise RestException('The user has not initialized one-time passwords.')
        if self._model.hasOtpEnabled(user):
            raise RestException('The user has already enabled one-time passwords.')

        user['otp']['enabled'] = True
        # This will raise an exception if the verification fails, so the user will not be saved
        self._model.verifyOtp(user, otpToken)

        self._model.save(user)

    @access.user
    @autoDescribeRoute(
        Description('Disable one-time passwords for this user.')
        .modelParam('id', model=UserModel, level=AccessType.ADMIN)
        .errorResponse()
        .errorResponse('Admin access was denied on the user.', 403)
    )
    def removeOtp(self, user):
        if not self._model.hasOtpEnabled(user):
            raise RestException('The user has not enabled one-time passwords.')

        del user['otp']
        self._model.save(user)

    @access.public
    @autoDescribeRoute(
        Description('Verify an email address using a token.')
        .modelParam('id', 'The user ID to check.', model=UserModel, force=True)
        .param('token', 'The token to check.')
        .errorResponse('The token is invalid or expired.', 401)
    )
    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.'
            }

    @access.public
    @autoDescribeRoute(
        Description('Send verification email.')
        .param('login', 'Your login or email address.', strip=True)
        .errorResponse('That login is not registered.', 401)
    )
    def sendVerificationEmail(self, login):
        loginField = 'email' if '@' in login else 'login'
        user = self._model.findOne({loginField: login.lower()})

        if not user:
            raise RestException('That login is not registered.', 401)

        self._model._sendVerificationEmail(user)
        return {'message': 'Sent verification email.'}
Esempio n. 39
0
class AssignmentResource(Resource):
    def __init__(self):
        super().__init__()

        self.coll_m = Collection()
        self.file_m = File()
        self.folder_m = Folder()
        self.item_m = Item()
        self.upload_m = Upload()
        self.asset_m = Assetstore()
        self.user_m = User()

        self.setupRoutes()

    def setupRoutes(self):
        self.route('GET', (), handler=self.list)
        self.route('GET', (':a_id',), handler=self.getAssignment)
        self.route('GET', ('admin_data',), handler=self.getAdminData)

    def __findName(self, folder):
        imageFolder = self.__findImageFolder(folder)
        if isinstance(imageFolder, dict):
            return imageFolder['name']

        return ""

    def __findImageFolder(self, folder):
        owner = self.__findOwner(folder)
        ret = ""
        if self.folder_m.getAccessLevel(folder, self.getCurrentUser()) == AccessType.ADMIN:
            # this folder was created by this user, and so it will contain the images
            # printFail(folder)
            ret = folder
        else:
            meta = folder['meta']
            # this is the label file, and so should only have one entry in the metadata
            assert len(meta) == 1
            # that one entry contains link to the image folder, key must be the creator of this folder
            assert str(owner['_id']) in meta, (str(owner['_id']), meta)

            ret = self.folder_m.load(meta[str(owner['_id'])],
                                     level=AccessType.READ,
                                     user=self.getCurrentUser())

        return ret

    def __findLabelFolder(self, folder):
        owner = self.__findOwner(folder)
        ret = []
        if self.folder_m.getAccessLevel(folder, self.getCurrentUser()) == AccessType.ADMIN:
            # this folder was created by this user, so it will contain images
            if 'meta' not in folder:
                return []

            meta = folder['meta']
            for k, v in meta.items():
                ret.append(self.folder_m.load(v, level=AccessType.READ, user=self.getCurrentUser()))
        else:
            # this folder was not created by this user, so it will contain labels
            ret = [folder]

        return ret

    def __findOwner(self, folder):
        aclList = Folder().getFullAccessList(folder)
        for acl in aclList['users']:
            if acl['level'] == AccessType.ADMIN:
                return self.user_m.load(str(acl['id']), level=AccessType.READ, user=self.getCurrentUser())
        return None

    @access.public
    @autoDescribeRoute(
        Description('Get list of all assignments that it owns or is a part of')
            .param('limit', 'Number of assignments to return')
            .param('offset', 'offset from 0th assignment to start looking for assignments'))
    @rest.rawResponse
    def list(self, limit, offset):
        try:
            printOk((limit, offset))
            ret = self.__list(int(limit), int(offset))
            cherrypy.response.headers["Content-Type"] = "application/json"
            return dumps(ret)

        except:
            printFail(traceback.print_exc)

    def __list(self, limit=0, offset=0):
        user = self.getCurrentUser()
        folders = self.folder_m.find({'parentId': user['_id'],
                                      'parentCollection': 'user'}, limit=limit, offset=offset)
        ret = []
        for folder in folders:
            if self.__findName(folder):
                ret.append({'name': self.__findName(folder),
                            'image_folder': self.__findImageFolder(folder),
                            'label_folders': self.__findLabelFolder(folder),
                            'owner': self.__findOwner(folder)})

        return ret

    def __getAssignment(self, _id):
        assignments = self.__list()
        for assignment in assignments:
            # printOk2(assignment)
            if str(assignment['image_folder']['_id']) == _id:
                return assignment

        return None

    def __getAnnotators(self, assignment):
        ret = []
        for label_folder in assignment['label_folders']:
            printOk(label_folder)
            ret.append({
                'user': self.user_m.load(label_folder['parentId'], user=self.getCurrentUser(), level=AccessType.READ),
                'expanded': False,
            })

        return ret

    @access.public
    @autoDescribeRoute(
        Description('Get assignment by id').param('a_id', 'folder id that controls the assignment'))
    @rest.rawResponse
    def getAssignment(self, a_id):
        try:
            assignment = self.__getAssignment(a_id)
            return dumps(assignment)
        except:
            printFail(traceback.print_exc)

    @access.public
    @autoDescribeRoute(
        Description('Get admin data associated with assignment id').param('a_id',
                                                                          'folder id that controls the assignment'))
    @rest.rawResponse
    def getAdminData(self, a_id):
        try:
            assignment = self.__getAssignment(a_id)
            if assignment['owner']['_id'] == self.getCurrentUser()['_id']:
                # then current user is this assignment's admin
                return dumps({'annotators': self.__getAnnotators(assignment)})

        except:
            printFail(traceback.print_exc)