Esempio n. 1
0
def load(info):
    registerAccessFlag(constants.ACCESS_FLAG_EXECUTE_TASK, name='Execute analyses', admin=True)
    TokenScope.describeScope(
        constants.TOKEN_SCOPE_EXECUTE_TASK, name='Execute tasks', description='Execute item tasks.')
    TokenScope.describeScope(
        constants.TOKEN_SCOPE_AUTO_CREATE_CLI, 'Item task auto-creation',
        'Create new CLIs via automatic introspection.', admin=True)

    ModelImporter.model('item').ensureIndex(['meta.isItemTask', {'sparse': True}])
    ModelImporter.model('item').exposeFields(level=AccessType.READ, fields='createdByJob')
    ModelImporter.model('job', 'jobs').exposeFields(level=AccessType.READ, fields={
        'itemTaskId', 'itemTaskBindings'})

    events.bind('jobs.job.update', info['name'], _onJobSave)
    events.bind('data.process', info['name'], _onUpload)

    info['apiRoot'].item_task = ItemTask()

    info['apiRoot'].item.route('POST', (':id', 'item_task_slicer_cli_description'),
                               runSlicerCliTasksDescriptionForItem)
    info['apiRoot'].item.route('PUT', (':id', 'item_task_slicer_cli_xml'),
                               configureItemTaskFromSlicerCliXml)
    info['apiRoot'].item.route('POST', (':id', 'item_task_json_description'),
                               runJsonTasksDescriptionForItem)
    info['apiRoot'].item.route('PUT', (':id', 'item_task_json_specs'),
                               configureItemTaskFromJson)

    info['apiRoot'].folder.route('POST', (':id', 'item_task_slicer_cli_description'),
                                 runSlicerCliTasksDescriptionForFolder)
    info['apiRoot'].folder.route('POST', (':id', 'item_task_slicer_cli_xml'),
                                 createItemTasksFromSlicerCliXml)
    info['apiRoot'].folder.route('POST', (':id', 'item_task_json_description'),
                                 runJsonTasksDescriptionForFolder)
    info['apiRoot'].folder.route('POST', (':id', 'item_task_json_specs'),
                                 createItemTasksFromJson)
Esempio n. 2
0
def load(info):
    registerAccessFlag(constants.ACCESS_FLAG_EXECUTE_TASK,
                       name='Execute analyses',
                       admin=True)
    TokenScope.describeScope(constants.TOKEN_SCOPE_EXECUTE_TASK,
                             name='Execute tasks',
                             description='Execute item tasks.')
    TokenScope.describeScope(constants.TOKEN_SCOPE_AUTO_CREATE_CLI,
                             'Item task auto-creation',
                             'Create new CLIs via automatic introspection.',
                             admin=True)

    ModelImporter.model('item').ensureIndex(
        ['meta.isItemTask', {
            'sparse': True
        }])
    ModelImporter.model('item').exposeFields(level=AccessType.READ,
                                             fields='createdByJob')
    ModelImporter.model('job', 'jobs').exposeFields(
        level=AccessType.READ, fields={'itemTaskId', 'itemTaskBindings'})

    events.bind('jobs.job.update', info['name'], _onJobSave)
    events.bind('data.process', info['name'], _onUpload)

    info['apiRoot'].item_task = ItemTask()
Esempio n. 3
0
 def registerAccessFlags(self, params):
     """
     Helper that can be used to register access flags in the system. This is
     used to test the access flags UI since the core does not expose any flags.
     """
     flags = self.getBodyJson()
     for key, info in six.viewitems(flags):
         registerAccessFlag(key, info['name'], info['description'], info['admin'])
Esempio n. 4
0
 def registerAccessFlags(self, params):
     """
     Helper that can be used to register access flags in the system. This is
     used to test the access flags UI since the core does not expose any flags.
     """
     flags = self.getBodyJson()
     for key, info in six.viewitems(flags):
         registerAccessFlag(key, info['name'], info['description'], info['admin'])
Esempio n. 5
0
def load(info):
    registerAccessFlag(constants.ACCESS_FLAG_EXECUTE_TASK,
                       name='Execute analyses',
                       admin=True)
    TokenScope.describeScope(constants.TOKEN_SCOPE_EXECUTE_TASK,
                             name='Execute tasks',
                             description='Execute item tasks.')
    TokenScope.describeScope(constants.TOKEN_SCOPE_AUTO_CREATE_CLI,
                             'Item task auto-creation',
                             'Create new CLIs via automatic introspection.',
                             admin=True)

    ModelImporter.model('item').ensureIndex(
        ['meta.isItemTask', {
            'sparse': True
        }])
    ModelImporter.model('item').exposeFields(level=AccessType.READ,
                                             fields='createdByJob')
    ModelImporter.model('job', 'jobs').exposeFields(
        level=AccessType.READ, fields={'itemTaskId', 'itemTaskBindings'})

    events.bind('jobs.job.update', info['name'], _onJobSave)
    events.bind('data.process', info['name'], _onUpload)

    info['apiRoot'].item_task = ItemTask()

    info['apiRoot'].item.route('POST',
                               (':id', 'item_task_slicer_cli_description'),
                               runSlicerCliTasksDescriptionForItem)
    info['apiRoot'].item.route('PUT', (':id', 'item_task_slicer_cli_xml'),
                               configureItemTaskFromSlicerCliXml)
    info['apiRoot'].item.route('POST', (':id', 'item_task_json_description'),
                               runJsonTasksDescriptionForItem)
    info['apiRoot'].item.route('PUT', (':id', 'item_task_json_specs'),
                               configureItemTaskFromJson)

    info['apiRoot'].folder.route('POST',
                                 (':id', 'item_task_slicer_cli_description'),
                                 runSlicerCliTasksDescriptionForFolder)
    info['apiRoot'].folder.route('POST', (':id', 'item_task_slicer_cli_xml'),
                                 createItemTasksFromSlicerCliXml)
    info['apiRoot'].folder.route('POST', (':id', 'item_task_json_description'),
                                 runJsonTasksDescriptionForFolder)
    info['apiRoot'].folder.route('POST', (':id', 'item_task_json_specs'),
                                 createItemTasksFromJson)
Esempio n. 6
0
    def testAutoDescribeRoute(self):
        testRuns = []

        registerAccessFlag('my_flag', name='My flag')

        class AutoDescribe(Resource):
            def __init__(self):
                super(AutoDescribe, self).__init__()
                self.resourceName = 'auto_describe'
                self.route('GET', ('test', ), self.test)
                self.route('POST', ('body', ), self.body)
                self.route('POST', ('json_body', ), self.jsonBody)
                self.route('POST', ('json_body_required', ),
                           self.jsonBodyRequired)
                self.route('GET', ('model_param_flags', ),
                           self.hasModelParamFlags)
                self.route('GET', ('model_param_query', ),
                           self.hasModelQueryParam)
                self.route('GET', ('json_schema', ), self.hasJsonSchema)
                self.route('GET', ('missing_arg', ), self.hasMissingArg)

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('test').param(
                    'b1', '', dataType='boolean', required=False,
                    default=True).param('b2',
                                        '',
                                        dataType='boolean',
                                        required=False).param(
                                            'float',
                                            '',
                                            dataType='number',
                                            required=False,
                                            default=1.0).param(
                                                'integer',
                                                '',
                                                dataType='integer',
                                                required=False).param(
                                                    'timestamp',
                                                    '',
                                                    dataType='dateTime',
                                                    required=False).
                param('datestamp', '', dataType='date', required=False).param(
                    'string',
                    '',
                    enum=['hello', 'world'],
                    strip=True,
                    lower=True).param('upper', '', required=False,
                                      upper=True).jsonParam(
                                          'json1',
                                          '',
                                          required=False,
                                          requireArray=True).jsonParam(
                                              'json2',
                                              '',
                                              required=False,
                                              requireObject=True,
                                              default={}))
            def test(self, b1, b2, string, upper, integer, float, timestamp,
                     datestamp, json1, json2, params):
                testRuns.append({
                    'b1': b1,
                    'b2': b2,
                    'string': string,
                    'upper': upper,
                    'integer': integer,
                    'float': float,
                    'timestamp': timestamp,
                    'datestamp': datestamp,
                    'json1': json1,
                    'json2': json2
                })

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('body').param('body',
                                                   '',
                                                   required=False,
                                                   paramType='body'))
            def body(self, body):
                testRuns.append({'body': body})

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('json_body').jsonParam('json_body',
                                                            '',
                                                            required=False,
                                                            paramType='body'))
            def jsonBody(self, json_body):
                testRuns.append({'json_body': json_body})

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('json_body_required').jsonParam(
                    'json_body',
                    '',
                    required=True,
                    requireObject=True,
                    paramType='body'))
            def jsonBodyRequired(self, json_body):
                testRuns.append({'json_body': json_body})

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_model_param_query').modelParam(
                    'userId',
                    model='user',
                    level=AccessType.READ,
                    paramType='query'))
            @filtermodel(model='user')
            def hasModelQueryParam(self, user):
                return user

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_model_param_flags').modelParam(
                    'userId',
                    model='user',
                    level=AccessType.READ,
                    paramType='query',
                    requiredFlags='my_flag'))
            def hasModelParamFlags(self, user):
                return user

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_json_schema').jsonParam(
                    'obj',
                    '',
                    schema={
                        'type': 'object',
                        'required': ['foo', 'bar']
                    }))
            def hasJsonSchema(self, obj):
                return obj

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_missing_arg').param('foo', ''))
            def hasMissingArg(self, params):
                return params

        server.root.api.v1.auto_describe = AutoDescribe()

        def testBad(inputs, expected):
            resp = self.request('/auto_describe/test', params=inputs)
            self.assertStatus(resp, 400)
            self.assertEqual(testRuns, [])
            self.assertEqual(resp.json['message'], expected)

        def testOk(inputs, expected):
            resp = self.request('/auto_describe/test', params=inputs)
            self.assertStatusOk(resp)
            self.assertEqual(len(testRuns), 1)
            self.assertEqual(testRuns[0], expected)
            del testRuns[-1]

        testBad({}, 'Parameter "string" is required.')
        testBad({
            'string': 'invalid value'
        }, 'Invalid value for string: "invalid value". Allowed values: hello, world.'
                )
        testBad({
            'string': 'hello',
            'float': 'not a float'
        }, 'Invalid value for numeric parameter float: not a float.')

        testBad({
            'string': 'hello',
            'integer': '7.5'
        }, 'Invalid value for integer parameter integer: 7.5.')

        testBad({
            'string': 'hello',
            'timestamp': 'hello world'
        }, 'Invalid date format for parameter timestamp: hello world.')

        testBad({
            'string': 'hello',
            'datestamp': 'not a date'
        }, 'Invalid date format for parameter datestamp: not a date.')

        testBad({
            'string': 'hello',
            'json1': json.dumps({'hello': 'world'})
        }, 'Parameter json1 must be a JSON array.')

        testBad({
            'string': 'hello',
            'json2': json.dumps(['hello', 'world'])
        }, 'Parameter json2 must be a JSON object.')

        testOk({'string': '  WoRlD '}, {
            'string': 'world',
            'upper': None,
            'b1': True,
            'b2': None,
            'integer': None,
            'float': 1.,
            'json1': None,
            'json2': {},
            'timestamp': None,
            'datestamp': None
        })

        testOk(
            {
                'string': ' hello',
                'upper': ' hello',
                'b1': 'false',
                'b2': 'true',
                'integer': '3',
                'float': '0.25',
                'json1': json.dumps([1, 2, 'abc']),
                'json2': json.dumps({'hello': 'world'}),
                'timestamp': '2017-01-01T11:35:22',
                'datestamp': '2017-02-02T11:33:22'
            }, {
                'string': 'hello',
                'upper': ' HELLO',
                'b1': False,
                'b2': True,
                'integer': 3,
                'float': 0.25,
                'json1': [1, 2, 'abc'],
                'json2': {
                    'hello': 'world'
                },
                'timestamp': datetime.datetime(2017, 1, 1, 11, 35, 22),
                'datestamp': datetime.date(2017, 2, 2)
            })

        # Test request body
        body = 'torso'
        resp = self.request('/auto_describe/body',
                            method='POST',
                            body=json.dumps(body),
                            type='application/json')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        self.assertTrue('body' in testRuns[0])
        self.assertTrue(hasattr(testRuns[0]['body'], 'read'))
        del testRuns[-1]

        # Test request JSON body (optional)
        body = {'emmet': 'otter'}
        resp = self.request('/auto_describe/json_body',
                            method='POST',
                            body=json.dumps(body),
                            type='application/json')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        expected = {'json_body': body}
        self.assertEqual(testRuns[0], expected)
        del testRuns[-1]

        # Test request JSON body (optional), omitting body
        resp = self.request('/auto_describe/json_body', method='POST')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        expected = {'json_body': None}
        self.assertEqual(testRuns[0], expected)
        del testRuns[-1]

        # Test request JSON body (required)
        body = {'emmet': 'otter'}
        resp = self.request('/auto_describe/json_body_required',
                            method='POST',
                            body=json.dumps(body),
                            type='application/json')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        expected = {'json_body': body}
        self.assertEqual(testRuns[0], expected)
        del testRuns[-1]

        # Test request JSON body (required), omitting body
        resp = self.request('/auto_describe/json_body_required', method='POST')
        self.assertStatus(resp, 400)

        # Test request JSON body (required), pass list
        body = [{'emmet': 'otter'}]
        resp = self.request('/auto_describe/json_body_required',
                            method='POST',
                            body=json.dumps(body),
                            type='application/json')
        self.assertStatus(resp, 400)

        # Test omission of required modelParam
        resp = self.request('/auto_describe/model_param_query')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'],
                         'Parameter "userId" is required.')

        resp = self.request('/auto_describe/model_param_query',
                            params={'userId': None})
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'], 'Invalid ObjectId: None')

        user = User().createUser(firstName='admin',
                                 lastName='admin',
                                 email='*****@*****.**',
                                 login='******',
                                 password='******')
        resp = self.request('/auto_describe/model_param_query',
                            user=user,
                            params={'userId': user['_id']})
        self.assertStatusOk(resp)

        # Test requiredFlags in modelParam
        resp = self.request('/auto_describe/model_param_flags',
                            params={'userId': user['_id']})
        self.assertStatus(resp, 401)
        self.assertRegex(resp.json['message'], '^Access denied for user')

        resp = self.request('/auto_describe/json_schema',
                            params={'obj': json.dumps([])})
        self.assertStatus(resp, 400)
        self.assertRegex(
            resp.json['message'],
            r"^Invalid JSON object for parameter obj: \[\] is not of type 'object'"
        )

        resp = self.request('/auto_describe/json_schema',
                            params={'obj': json.dumps({})})
        self.assertStatus(resp, 400)
        self.assertRegex(
            resp.json['message'],
            r"^Invalid JSON object for parameter obj: 'foo' is a required property"
        )

        obj = {'foo': 1, 'bar': 2}
        resp = self.request('/auto_describe/json_schema',
                            params={'obj': json.dumps(obj)})
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, obj)

        # Test missing arg in wrapped function, should fall through to params dict
        resp = self.request('/auto_describe/missing_arg',
                            params={'foo': 'bar'})
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, {'foo': 'bar'})
Esempio n. 7
0
    def testAccessFlags(self):
        resp = self.request('/system/access_flag')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, {})

        registerAccessFlag('my_key', name='hello', description='a custom flag')

        resp = self.request('/system/access_flag')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, {
            'my_key': {
                'name': 'hello',
                'description': 'a custom flag',
                'admin': False
            }
        })

        self.users[1] = self.model('user').load(self.users[1]['_id'], force=True)
        user = self.users[1]

        # Manage custom access flags on an access controlled resource
        self.assertFalse(self.model('user').hasAccessFlags(user, user, flags=['my_key']))

        # Admin should always have permission
        self.assertTrue(self.model('user').hasAccessFlags(user, self.users[0], flags=['my_key']))

        # Test the requireAccessFlags method
        with self.assertRaises(AccessException):
            self.model('user').requireAccessFlags(user, user=user, flags='my_key')

        self.model('user').requireAccessFlags(user, user=self.users[0], flags='my_key')

        acl = self.model('user').getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], [])

        # Test loadmodel requiredFlags argument via REST endpoint
        resp = self.request(
            '/test_endpoints/loadmodel_with_flags/%s' % user['_id'], user=self.users[1])
        self.assertStatus(resp, 403)

        user = self.model('user').setAccessList(self.users[0], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key', 'not a registered flag']
            }],
            'groups': [{
                'id': self.group['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key']
            }]
        }, save=True)

        resp = self.request(
            '/test_endpoints/loadmodel_with_flags/%s' % user['_id'], user=self.users[1])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, 'success')

        # Only registered flags should be stored
        acl = self.model('user').getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], ['my_key'])
        self.assertTrue(self.model('user').hasAccessFlags(user, user, flags=['my_key']))

        # Create an admin-only access flag
        registerAccessFlag('admin_flag', name='admin flag', admin=True)

        # Non-admin shouldn't be able to set it
        user = self.model('user').setAccessList(self.users[0], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }],
            'groups': []
        }, save=True, user=self.users[1])

        acl = self.model('user').getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], [])

        # Admin user should be able to set it
        user = self.model('user').setAccessList(self.users[1], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }],
            'groups': [{
                'id': self.group['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }]
        }, save=True, user=self.users[0])

        acl = self.model('user').getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], ['admin_flag'])

        # An already-enabled admin-only flag should stay enabled for non-admin user
        user = self.model('user').setAccessList(self.users[1], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key', 'admin_flag']
            }],
            'groups': [{
                'id': self.group['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }]
        }, save=True, user=self.users[1])

        acl = self.model('user').getFullAccessList(user)
        self.assertEqual(set(acl['users'][0]['flags']), {'my_key', 'admin_flag'})
        self.assertEqual(acl['groups'][0]['flags'], ['admin_flag'])

        # Test setting public flags on a collection and folder
        collectionModel = self.model('collection')
        folderModel = self.model('folder')
        itemModel = self.model('item')
        collection = collectionModel.createCollection('coll', creator=self.users[0], public=True)
        folder = folderModel.createFolder(
            collection, 'folder', parentType='collection', creator=self.users[0])

        # Add an item to the folder so we can test AclMixin flag behavior
        item = itemModel.createItem(folder=folder, name='test', creator=self.users[0])

        folder = folderModel.setUserAccess(
            folder, self.users[1], level=AccessType.ADMIN, save=True, currentUser=self.users[0])

        with self.assertRaises(AccessException):
            collectionModel.requireAccessFlags(collection, user=None, flags='my_key')

        # Test AclMixin flag behavior
        with self.assertRaises(AccessException):
            itemModel.requireAccessFlags(item, user=None, flags='my_key')

        self.assertFalse(itemModel.hasAccessFlags(item, user=None, flags='my_key'))

        collection = collectionModel.setAccessList(
            collection, access=collection['access'], save=True, recurse=True, user=self.users[0],
            publicFlags=['my_key'])
        collectionModel.requireAccessFlags(collection, user=None, flags='my_key')

        # Make sure recursive setting of public flags worked
        folder = folderModel.load(folder['_id'], force=True)
        self.assertEqual(folder['publicFlags'], ['my_key'])

        itemModel.requireAccessFlags(item, user=None, flags='my_key')

        # Non-admin shouldn't be able to set admin-only public flags
        folder = folderModel.setPublicFlags(
            folder, flags=['admin_flag'], user=self.users[1], save=True)
        self.assertEqual(folder['publicFlags'], [])

        # Admin users should be able to set admin-only public flags
        folder = folderModel.setPublicFlags(
            folder, flags=['admin_flag'], user=self.users[0], save=True, append=True)
        self.assertEqual(folder['publicFlags'], ['admin_flag'])

        # Non-admin users can set admin-only public flags if they are already enabled
        folder = folderModel.setPublicFlags(
            folder, flags=['admin_flag', 'my_key'], user=self.users[1], save=True)
        self.assertEqual(set(folder['publicFlags']), {'admin_flag', 'my_key'})

        # Test "force" options
        folder = folderModel.setPublicFlags(folder, flags='admin_flag', force=True, save=True)
        self.assertEqual(folder['publicFlags'], ['admin_flag'])

        folder = folderModel.setAccessList(folder, access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key', 'admin_flag']
            }],
            'groups': []
        }, save=True, force=True)
        folderModel.requireAccessFlags(folder, user=self.users[1], flags='my_key')

        folder = folderModel.setUserAccess(
            folder, self.users[1], level=AccessType.READ, save=True, force=True, flags=[])
        self.assertFalse(folderModel.hasAccessFlags(folder, self.users[1], flags='my_key'))

        folder = folderModel.setGroupAccess(
            folder, self.group, level=AccessType.READ, save=True, force=True, flags='my_key')
        folderModel.requireAccessFlags(folder, user=self.users[1], flags='my_key')

        # Testing with flags=None should give sensible behavior
        folderModel.requireAccessFlags(folder, user=None, flags=None)

        # Test filtering results by access flags (both ACModel and AclMixin)
        for model, doc in ((folderModel, folder), (itemModel, item)):
            cursor = model.find({})
            self.assertGreater(len(list(cursor)), 0)

            cursor = model.find({})
            filtered = list(model.filterResultsByPermission(
                cursor, user=None, level=AccessType.READ, flags='my_key'))
            self.assertEqual(len(filtered), 0)

            cursor = model.find({})
            filtered = list(model.filterResultsByPermission(
                cursor, user=self.users[1], level=AccessType.READ, flags=('my_key', 'admin_flag')))
            self.assertEqual(len(filtered), 1)
            self.assertEqual(filtered[0]['_id'], doc['_id'])
Esempio n. 8
0
    def testAccessFlags(self):
        resp = self.request('/system/access_flag')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, {})

        registerAccessFlag('my_key', name='hello', description='a custom flag')

        resp = self.request('/system/access_flag')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, {
            'my_key': {
                'name': 'hello',
                'description': 'a custom flag',
                'admin': False
            }
        })

        self.users[1] = User().load(self.users[1]['_id'], force=True)
        user = self.users[1]

        # Manage custom access flags on an access controlled resource
        self.assertFalse(User().hasAccessFlags(user, user, flags=['my_key']))

        # Admin should always have permission
        self.assertTrue(User().hasAccessFlags(user, self.users[0], flags=['my_key']))

        # Test the requireAccessFlags method
        with self.assertRaises(AccessException):
            User().requireAccessFlags(user, user=user, flags='my_key')

        User().requireAccessFlags(user, user=self.users[0], flags='my_key')

        acl = User().getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], [])

        # Test loadmodel requiredFlags argument via REST endpoint
        resp = self.request(
            '/test_endpoints/loadmodel_with_flags/%s' % user['_id'], user=self.users[1])
        self.assertStatus(resp, 403)

        user = User().setAccessList(self.users[0], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key', 'not a registered flag']
            }],
            'groups': [{
                'id': self.group['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key']
            }]
        }, save=True)

        resp = self.request(
            '/test_endpoints/loadmodel_with_flags/%s' % user['_id'], user=self.users[1])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, 'success')

        # Only registered flags should be stored
        acl = User().getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], ['my_key'])
        self.assertTrue(User().hasAccessFlags(user, user, flags=['my_key']))

        # Create an admin-only access flag
        registerAccessFlag('admin_flag', name='admin flag', admin=True)

        # Non-admin shouldn't be able to set it
        user = User().setAccessList(self.users[0], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }],
            'groups': []
        }, save=True, user=self.users[1])

        acl = User().getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], [])

        # Admin user should be able to set it
        user = User().setAccessList(self.users[1], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }],
            'groups': [{
                'id': self.group['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }]
        }, save=True, user=self.users[0])

        acl = User().getFullAccessList(user)
        self.assertEqual(acl['users'][0]['flags'], ['admin_flag'])

        # An already-enabled admin-only flag should stay enabled for non-admin user
        user = User().setAccessList(self.users[1], access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key', 'admin_flag']
            }],
            'groups': [{
                'id': self.group['_id'],
                'level': AccessType.ADMIN,
                'flags': ['admin_flag']
            }]
        }, save=True, user=self.users[1])

        acl = User().getFullAccessList(user)
        self.assertEqual(set(acl['users'][0]['flags']), {'my_key', 'admin_flag'})
        self.assertEqual(acl['groups'][0]['flags'], ['admin_flag'])

        # Test setting public flags on a collection and folder
        collectionModel = Collection()
        folderModel = Folder()
        itemModel = Item()
        collection = collectionModel.createCollection('coll', creator=self.users[0], public=True)
        folder = folderModel.createFolder(
            collection, 'folder', parentType='collection', creator=self.users[0])

        # Add an item to the folder so we can test AclMixin flag behavior
        item = itemModel.createItem(folder=folder, name='test', creator=self.users[0])

        folder = folderModel.setUserAccess(
            folder, self.users[1], level=AccessType.ADMIN, save=True, currentUser=self.users[0])

        with self.assertRaises(AccessException):
            collectionModel.requireAccessFlags(collection, user=None, flags='my_key')

        # Test AclMixin flag behavior
        with self.assertRaises(AccessException):
            itemModel.requireAccessFlags(item, user=None, flags='my_key')

        self.assertFalse(itemModel.hasAccessFlags(item, user=None, flags='my_key'))

        collection = collectionModel.setAccessList(
            collection, access=collection['access'], save=True, recurse=True, user=self.users[0],
            publicFlags=['my_key'])
        collectionModel.requireAccessFlags(collection, user=None, flags='my_key')

        # Make sure recursive setting of public flags worked
        folder = folderModel.load(folder['_id'], force=True)
        self.assertEqual(folder['publicFlags'], ['my_key'])

        itemModel.requireAccessFlags(item, user=None, flags='my_key')

        # Non-admin shouldn't be able to set admin-only public flags
        folder = folderModel.setPublicFlags(
            folder, flags=['admin_flag'], user=self.users[1], save=True)
        self.assertEqual(folder['publicFlags'], [])

        # Admin users should be able to set admin-only public flags
        folder = folderModel.setPublicFlags(
            folder, flags=['admin_flag'], user=self.users[0], save=True, append=True)
        self.assertEqual(folder['publicFlags'], ['admin_flag'])

        # Non-admin users can set admin-only public flags if they are already enabled
        folder = folderModel.setPublicFlags(
            folder, flags=['admin_flag', 'my_key'], user=self.users[1], save=True)
        self.assertEqual(set(folder['publicFlags']), {'admin_flag', 'my_key'})

        # Test "force" options
        folder = folderModel.setPublicFlags(folder, flags='admin_flag', force=True, save=True)
        self.assertEqual(folder['publicFlags'], ['admin_flag'])

        folder = folderModel.setAccessList(folder, access={
            'users': [{
                'id': self.users[1]['_id'],
                'level': AccessType.ADMIN,
                'flags': ['my_key', 'admin_flag']
            }],
            'groups': []
        }, save=True, force=True)
        folderModel.requireAccessFlags(folder, user=self.users[1], flags='my_key')

        folder = folderModel.setUserAccess(
            folder, self.users[1], level=AccessType.READ, save=True, force=True, flags=[])
        self.assertFalse(folderModel.hasAccessFlags(folder, self.users[1], flags='my_key'))

        folder = folderModel.setGroupAccess(
            folder, self.group, level=AccessType.READ, save=True, force=True, flags='my_key')
        folderModel.requireAccessFlags(folder, user=self.users[1], flags='my_key')

        # Testing with flags=None should give sensible behavior
        folderModel.requireAccessFlags(folder, user=None, flags=None)

        # Test filtering results by access flags (both ACModel and AclMixin)
        for model, doc in ((folderModel, folder), (itemModel, item)):
            cursor = model.find({})
            self.assertGreater(len(list(cursor)), 0)

            cursor = model.find({})
            filtered = list(model.filterResultsByPermission(
                cursor, user=None, level=AccessType.READ, flags='my_key'))
            self.assertEqual(len(filtered), 0)

            cursor = model.find({})
            filtered = list(model.filterResultsByPermission(
                cursor, user=self.users[1], level=AccessType.READ, flags=('my_key', 'admin_flag')))
            self.assertEqual(len(filtered), 1)
            self.assertEqual(filtered[0]['_id'], doc['_id'])
Esempio n. 9
0
    def testAutoDescribeRoute(self):
        testRuns = []

        registerAccessFlag('my_flag', name='My flag')

        class AutoDescribe(Resource):
            def __init__(self):
                super(AutoDescribe, self).__init__()
                self.resourceName = 'auto_describe'
                self.route('GET', ('test',), self.test)
                self.route('POST', ('body',), self.body)
                self.route('POST', ('json_body',), self.jsonBody)
                self.route('POST', ('json_body_required',), self.jsonBodyRequired)
                self.route('GET', ('model_param_flags',), self.hasModelParamFlags)
                self.route('GET', ('model_param_query',), self.hasModelQueryParam)
                self.route('GET', ('json_schema',), self.hasJsonSchema)
                self.route('GET', ('missing_arg',), self.hasMissingArg)

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('test')
                .param('b1', '', dataType='boolean', required=False, default=True)
                .param('b2', '', dataType='boolean', required=False)
                .param('float', '', dataType='number', required=False, default=1.0)
                .param('integer', '', dataType='integer', required=False)
                .param('timestamp', '', dataType='dateTime', required=False)
                .param('datestamp', '', dataType='date', required=False)
                .param('string', '', enum=['hello', 'world'], strip=True, lower=True)
                .param('upper', '', required=False, upper=True)
                .jsonParam('json1', '', required=False, requireArray=True)
                .jsonParam('json2', '', required=False, requireObject=True, default={})
            )
            def test(self, b1, b2, string, upper, integer, float, timestamp, datestamp, json1,
                     json2, params):
                testRuns.append({
                    'b1': b1,
                    'b2': b2,
                    'string': string,
                    'upper': upper,
                    'integer': integer,
                    'float': float,
                    'timestamp': timestamp,
                    'datestamp': datestamp,
                    'json1': json1,
                    'json2': json2
                })

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('body')
                .param('body', '', required=False, paramType='body')
            )
            def body(self, body):
                testRuns.append({
                    'body': body
                })

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('json_body')
                .jsonParam('json_body', '', required=False, paramType='body')
            )
            def jsonBody(self, json_body):
                testRuns.append({
                    'json_body': json_body
                })

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('json_body_required')
                .jsonParam('json_body', '', required=True, requireObject=True, paramType='body')
            )
            def jsonBodyRequired(self, json_body):
                testRuns.append({
                    'json_body': json_body
                })

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_model_param_query')
                .modelParam('userId', model='user', level=AccessType.READ, paramType='query')
            )
            @filtermodel(model='user')
            def hasModelQueryParam(self, user):
                return user

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_model_param_flags')
                .modelParam('userId', model='user', level=AccessType.READ, paramType='query',
                            requiredFlags='my_flag')
            )
            def hasModelParamFlags(self, user):
                return user

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_json_schema')
                .jsonParam('obj', '', schema={
                    'type': 'object',
                    'required': ['foo', 'bar']
                })
            )
            def hasJsonSchema(self, obj):
                return obj

            @access.public
            @describe.autoDescribeRoute(
                describe.Description('has_missing_arg')
                .param('foo', '')
            )
            def hasMissingArg(self, params):
                return params

        server.root.api.v1.auto_describe = AutoDescribe()

        def testBad(inputs, expected):
            resp = self.request('/auto_describe/test', params=inputs)
            self.assertStatus(resp, 400)
            self.assertEqual(testRuns, [])
            self.assertEqual(resp.json['message'], expected)

        def testOk(inputs, expected):
            resp = self.request('/auto_describe/test', params=inputs)
            self.assertStatusOk(resp)
            self.assertEqual(len(testRuns), 1)
            self.assertEqual(testRuns[0], expected)
            del testRuns[-1]

        testBad({}, 'Parameter "string" is required.')
        testBad({
            'string': 'invalid value'
        }, 'Invalid value for string: "invalid value". Allowed values: hello, world.')
        testBad({
            'string': 'hello',
            'float': 'not a float'
        }, 'Invalid value for numeric parameter float: not a float.')

        testBad({
            'string': 'hello',
            'integer': '7.5'
        }, 'Invalid value for integer parameter integer: 7.5.')

        testBad({
            'string': 'hello',
            'timestamp': 'hello world'
        }, 'Invalid date format for parameter timestamp: hello world.')

        testBad({
            'string': 'hello',
            'datestamp': 'not a date'
        }, 'Invalid date format for parameter datestamp: not a date.')

        testBad({
            'string': 'hello',
            'json1': json.dumps({'hello': 'world'})
        }, 'Parameter json1 must be a JSON array.')

        testBad({
            'string': 'hello',
            'json2': json.dumps(['hello', 'world'])
        }, 'Parameter json2 must be a JSON object.')

        testOk({
            'string': '  WoRlD '
        }, {
            'string': 'world',
            'upper': None,
            'b1': True,
            'b2': None,
            'integer': None,
            'float': 1.,
            'json1': None,
            'json2': {},
            'timestamp': None,
            'datestamp': None
        })

        testOk({
            'string': ' hello',
            'upper': ' hello',
            'b1': 'false',
            'b2': 'true',
            'integer': '3',
            'float': '0.25',
            'json1': json.dumps([1, 2, 'abc']),
            'json2': json.dumps({'hello': 'world'}),
            'timestamp': '2017-01-01T11:35:22',
            'datestamp': '2017-02-02T11:33:22'
        }, {
            'string': 'hello',
            'upper': ' HELLO',
            'b1': False,
            'b2': True,
            'integer': 3,
            'float': 0.25,
            'json1': [1, 2, 'abc'],
            'json2': {'hello': 'world'},
            'timestamp': datetime.datetime(2017, 1, 1, 11, 35, 22),
            'datestamp': datetime.date(2017, 2, 2)
        })

        # Test request body
        body = 'torso'
        resp = self.request('/auto_describe/body', method='POST',
                            body=json.dumps(body), type='application/json')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        self.assertTrue('body' in testRuns[0])
        self.assertTrue(hasattr(testRuns[0]['body'], 'read'))
        del testRuns[-1]

        # Test request JSON body (optional)
        body = {
            'emmet': 'otter'
        }
        resp = self.request('/auto_describe/json_body', method='POST',
                            body=json.dumps(body), type='application/json')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        expected = {
            'json_body': body
        }
        self.assertEqual(testRuns[0], expected)
        del testRuns[-1]

        # Test request JSON body (optional), omitting body
        resp = self.request('/auto_describe/json_body', method='POST')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        expected = {
            'json_body': None
        }
        self.assertEqual(testRuns[0], expected)
        del testRuns[-1]

        # Test request JSON body (required)
        body = {
            'emmet': 'otter'
        }
        resp = self.request('/auto_describe/json_body_required', method='POST',
                            body=json.dumps(body), type='application/json')
        self.assertStatusOk(resp)
        self.assertEqual(len(testRuns), 1)
        expected = {
            'json_body': body
        }
        self.assertEqual(testRuns[0], expected)
        del testRuns[-1]

        # Test request JSON body (required), omitting body
        resp = self.request('/auto_describe/json_body_required', method='POST')
        self.assertStatus(resp, 400)

        # Test request JSON body (required), pass list
        body = [{
            'emmet': 'otter'
        }]
        resp = self.request('/auto_describe/json_body_required', method='POST',
                            body=json.dumps(body), type='application/json')
        self.assertStatus(resp, 400)

        # Test omission of required modelParam
        resp = self.request('/auto_describe/model_param_query')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'], 'Parameter "userId" is required.')

        resp = self.request('/auto_describe/model_param_query', params={'userId': None})
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'], 'Invalid ObjectId: None')

        user = self.model('user').createUser(
            firstName='admin', lastName='admin', email='*****@*****.**', login='******',
            password='******')
        resp = self.request(
            '/auto_describe/model_param_query', user=user, params={'userId': user['_id']})
        self.assertStatusOk(resp)

        # Test requiredFlags in modelParam
        resp = self.request('/auto_describe/model_param_flags', params={
            'userId': user['_id']
        })
        self.assertStatus(resp, 401)
        six.assertRegex(self, resp.json['message'], '^Access denied for user')

        resp = self.request('/auto_describe/json_schema', params={
            'obj': json.dumps([])
        })
        self.assertStatus(resp, 400)
        self.assertEqual(
            resp.json['message'],
            "Invalid JSON object for parameter obj: [] is not of type 'object'")

        resp = self.request('/auto_describe/json_schema', params={
            'obj': json.dumps({})
        })
        self.assertStatus(resp, 400)
        self.assertEqual(
            resp.json['message'],
            "Invalid JSON object for parameter obj: 'foo' is a required property")

        obj = {
            'foo': 1,
            'bar': 2
        }
        resp = self.request('/auto_describe/json_schema', params={
            'obj': json.dumps(obj)
        })
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, obj)

        # Test missing arg in wrapped function, should fall through to params dict
        resp = self.request('/auto_describe/missing_arg', params={
            'foo': 'bar'
        })
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, {'foo': 'bar'})
Esempio n. 10
0
class CatResource(Resource):
    def __init__(self):
        super(CatResource, self).__init__()
        self.resourceName = 'cat'

        self.route('GET', (), self.findCat)
        self.route('GET', (':id', ), self.getCat)
        self.route('POST', (), self.createCat)
        self.route('PUT', (':id', ), self.updateCat)
        self.route('DELETE', (':id', ), self.deleteCat)
        self.route('PUT', (':id', 'feed'), self.feedCat)

    @access.public
    @autoDescribeRoute(Description('Find a cat'))
    def findCat(self, params):
        print('findCat() was called!')
        print('params is', params)

    @access.public
    @autoDescribeRoute(
        Description('Get a cat').modelParam('id',
                                            'The cat ID',
                                            model=CatModel,
                                            level=AccessType.READ))
    def getCat(self, params):
        print('getCat() was called!')
        print('id is', id)
        print('params is', params)

    @access.public
    @autoDescribeRoute(Description('Create a cat'))
    def createCat(self, params):
        document = {}
        catModel = CatModel().save(document)
        return catModel

    @access.public
    @autoDescribeRoute(
        Description('Update a cat').modelParam('id',
                                               'The cat ID',
                                               model=CatModel,
                                               level=AccessType.WRITE))
    def updateCat(self, params):
        print("params is", params)
        if 'cat_model' not in params:
            print("Error: no cat model in the parameter!")
            return

        catModel = params['cat_model']
        if '_id' not in catModel:
            print("Error: missing id from catModel!")
            return

        id = catModel['_id']

        print("id is", id)
        print('updateCat() was called!')

    @access.public
    @autoDescribeRoute(
        Description('Delete a cat').modelParam('id',
                                               'The cat ID',
                                               model=CatModel,
                                               level=AccessType.WRITE,
                                               destName='doc'))
    def deleteCat(self, doc, params):
        print('doc is', doc)
        print('params is', params)
        print('deleteCat() was called!')
        CatModel().remove(doc)

    registerAccessFlag(key='cat.feed',
                       name='Feed a cat',
                       description='Allows users to feed a cat')

    @access.user
    @autoDescribeRoute(
        Description('Feed a cat').modelParam('id',
                                             'The cat ID',
                                             model=CatModel,
                                             plugin='cats',
                                             level=AccessType.WRITE,
                                             requiredFlags='cat.feed',
                                             destName='doc'))
    def feedCat(self, doc, params):
        print('doc is', doc)
        print('params is', params)

        # Feed the cat
        return CatModel().feed(doc)