def testServerRootSetting(self): settingModel = Setting() with self.assertRaises(ValidationException): settingModel.set(SettingKey.SERVER_ROOT, 'bad_value') settingModel.set(SettingKey.SERVER_ROOT, 'https://somedomain.org/foo') self.assertEqual(getApiUrl(), 'https://somedomain.org/foo/api/v1')
def getCollectionCreationPolicyAccess(self): cpp = Setting().get('core.collection_create_policy') acList = { 'users': [{'id': x} for x in cpp.get('users', [])], 'groups': [{'id': x} for x in cpp.get('groups', [])] } for user in acList['users'][:]: userDoc = User().load( user['id'], force=True, fields=['firstName', 'lastName', 'login']) if userDoc is None: acList['users'].remove(user) else: user['login'] = userDoc['login'] user['name'] = ' '.join((userDoc['firstName'], userDoc['lastName'])) for grp in acList['groups'][:]: grpDoc = Group().load( grp['id'], force=True, fields=['name', 'description']) if grpDoc is None: acList['groups'].remove(grp) else: grp['name'] = grpDoc['name'] grp['description'] = grpDoc['description'] return acList
def _setCommonCORSHeaders(): """ Set CORS headers that should be passed back with either a preflight OPTIONS or a simple CORS request. We set these headers anytime there is an Origin header present since browsers will simply ignore them if the request is not cross-origin. """ origin = cherrypy.request.headers.get('origin') if not origin: # If there is no origin header, this is not a cross origin request return allowed = Setting().get(SettingKey.CORS_ALLOW_ORIGIN) if allowed: setResponseHeader('Access-Control-Allow-Credentials', 'true') setResponseHeader( 'Access-Control-Expose-Headers', Setting().get(SettingKey.CORS_EXPOSE_HEADERS)) allowed_list = [o.strip() for o in allowed.split(',')] key = 'Access-Control-Allow-Origin' if len(allowed_list) == 1: setResponseHeader(key, allowed_list[0]) elif origin in allowed_list: setResponseHeader(key, origin)
def testValidators(self): settingModel = Setting() @setting_utilities.validator('test.key1') def key1v1(doc): raise ValidationException('key1v1') with six.assertRaisesRegex(self, ValidationException, '^key1v1$'): settingModel.set('test.key1', '') @setting_utilities.validator('test.key1') def key1v2(doc): raise ValidationException('key1v2') with six.assertRaisesRegex(self, ValidationException, '^key1v2$'): settingModel.set('test.key1', '') @setting_utilities.validator('test.key2') def key2v1(doc): raise ValidationException('key2v1') with six.assertRaisesRegex(self, ValidationException, '^key2v1$'): settingModel.set('test.key2', '') @setting_utilities.validator('test.key2', replace=True) def key2v2(doc): doc['value'] = 'modified' setting = settingModel.set('test.key2', 'original') self.assertEqual(setting['value'], 'modified')
def testUniqueIndex(self): settingModel = Setting() coll = settingModel.collection indices = coll.index_information() # Make sure we have just one index on key and that it specifies that it # is unique self.assertTrue(any(indices[index]['key'][0][0] == 'key' and indices[index].get('unique') for index in indices)) self.assertFalse(any(indices[index]['key'][0][0] == 'key' and not indices[index].get('unique') for index in indices)) # Delete that index, create a non-unique index, and make some duplicate # settings so that we can test that this will be corrected. coll.drop_index(next(index for index in indices if indices[index]['key'][0][0] == 'key')) coll.create_index('key') for val in range(3, 8): coll.insert_one({'key': 'duplicate', 'value': val}) # Check that we've broken things indices = coll.index_information() self.assertGreaterEqual(settingModel.get('duplicate'), 3) self.assertEqual(settingModel.find({'key': 'duplicate'}).count(), 5) self.assertFalse(any(indices[index]['key'][0][0] == 'key' and indices[index].get('unique') for index in indices)) self.assertTrue(any(indices[index]['key'][0][0] == 'key' and not indices[index].get('unique') for index in indices)) # Reconnecting the model should fix the issues we just created settingModel.reconnect() indices = coll.index_information() self.assertTrue(any(indices[index]['key'][0][0] == 'key' and indices[index].get('unique') for index in indices)) self.assertFalse(any(indices[index]['key'][0][0] == 'key' and not indices[index].get('unique') for index in indices)) self.assertEqual(settingModel.get('duplicate'), 3) self.assertEqual(settingModel.find({'key': 'duplicate'}).count(), 1)
def _sendmail(event): from girder.models.setting import Setting msg = event.info['message'] recipients = event.info['recipients'] setting = Setting() smtp = _SMTPConnection( host=setting.get(SettingKey.SMTP_HOST, 'localhost'), port=setting.get(SettingKey.SMTP_PORT, None), encryption=setting.get(SettingKey.SMTP_ENCRYPTION, 'none'), username=setting.get(SettingKey.SMTP_USERNAME, None), password=setting.get(SettingKey.SMTP_PASSWORD, None) ) logger.info('Sending email to %s through %s', ', '.join(recipients), smtp.host) with smtp: smtp.send(msg['From'], recipients, msg.as_string())
def bindModels(self, event=None): """ When the list of tracked provenance resources is changed, rebind the appropriate models to this instance of this class. :param event: the event when a setting is saved, or None to check the binding. """ if not event or event.name == 'provenance.initialize': pass elif event.name == 'model.setting.save.after': if not hasattr(event, "info"): return if event.info.get('key', '') != constants.PluginSettings.PROVENANCE_RESOURCES: return else: return resources = Setting().get(constants.PluginSettings.PROVENANCE_RESOURCES) if resources: resources = resources.replace(',', ' ').strip().split() else: resources = [] resources = dict.fromkeys(resources) # Always include item resources['item'] = None # Exclude resources that should never have provenance for disallowedResource in ('model_base', 'notification', 'password', 'token'): if disallowedResource in resources: del resources[disallowedResource] self.unbindModels(resources) for resource in resources: if resource not in self.boundResources: events.bind('model.%s.save' % resource, 'provenance', self.resourceSaveHandler) events.bind( 'model.%s.copy.prepare' % resource, 'provenance', self.resourceCopyHandler) if hasattr(self.loadInfo['apiRoot'], resource): getattr(self.loadInfo['apiRoot'], resource).route( 'GET', (':id', 'provenance'), self.getGetHandler(resource)) self.boundResources[resource] = True
def setUp(self, assetstoreType=None, dropModels=True): """ We want to start with a clean database each time, so we drop the test database before each test. We then add an assetstore so the file model can be used without 500 errors. :param assetstoreType: if 'gridfs' or 's3', use that assetstore. 'gridfsrs' uses a GridFS assetstore with a replicaset, and 'gridfsshard' one with a sharding server. For any other value, use a filesystem assetstore. """ self.assetstoreType = assetstoreType dropTestDatabase(dropModels=dropModels) assetstoreName = os.environ.get('GIRDER_TEST_ASSETSTORE', 'test') assetstorePath = os.path.join( ROOT_DIR, 'tests', 'assetstore', assetstoreName) if assetstoreType == 'gridfs': # Name this as '_auto' to prevent conflict with assetstores created # within test methods gridfsDbName = 'girder_test_%s_assetstore_auto' % assetstoreName.replace('.', '_') dropGridFSDatabase(gridfsDbName) self.assetstore = Assetstore().createGridFsAssetstore(name='Test', db=gridfsDbName) elif assetstoreType == 'gridfsrs': gridfsDbName = 'girder_test_%s_rs_assetstore_auto' % assetstoreName self.replicaSetConfig = mongo_replicaset.makeConfig() mongo_replicaset.startMongoReplicaSet(self.replicaSetConfig) self.assetstore = Assetstore().createGridFsAssetstore( name='Test', db=gridfsDbName, mongohost='mongodb://127.0.0.1:27070,127.0.0.1:27071,' '127.0.0.1:27072', replicaset='replicaset') elif assetstoreType == 'gridfsshard': gridfsDbName = 'girder_test_%s_shard_assetstore_auto' % assetstoreName self.replicaSetConfig = mongo_replicaset.makeConfig( port=27073, shard=True, sharddb=None) mongo_replicaset.startMongoReplicaSet(self.replicaSetConfig) self.assetstore = Assetstore().createGridFsAssetstore( name='Test', db=gridfsDbName, mongohost='mongodb://127.0.0.1:27073', shard='auto') elif assetstoreType == 's3': self.assetstore = Assetstore().createS3Assetstore( name='Test', bucket='bucketname', accessKeyId='test', secret='test', service=mockS3Server.service) else: dropFsAssetstore(assetstorePath) self.assetstore = Assetstore().createFilesystemAssetstore( name='Test', root=assetstorePath) addr = ':'.join(map(str, mockSmtp.address or ('localhost', 25))) settings = Setting() settings.set(SettingKey.SMTP_HOST, addr) settings.set(SettingKey.UPLOAD_MINIMUM_CHUNK_SIZE, 0) settings.set(SettingKey.PLUGINS_ENABLED, enabledPlugins) if os.environ.get('GIRDER_TEST_DATABASE_CONFIG'): setup_database.main(os.environ['GIRDER_TEST_DATABASE_CONFIG'])
def getSettings(self): settings = Setting() return { PluginSettings.MARKDOWN: settings.get(PluginSettings.MARKDOWN), PluginSettings.HEADER: settings.get(PluginSettings.HEADER), PluginSettings.SUBHEADER: settings.get(PluginSettings.SUBHEADER), PluginSettings.WELCOME_TEXT: settings.get(PluginSettings.WELCOME_TEXT), PluginSettings.LOGO: settings.get(PluginSettings.LOGO), }
def enablePlugins(self, plugins): # Determine what plugins have been disabled and remove their associated routes. setting = Setting() routeTable = setting.get(SettingKey.ROUTE_TABLE) oldPlugins = setting.get(SettingKey.PLUGINS_ENABLED) reservedRoutes = {GIRDER_ROUTE_ID, GIRDER_STATIC_ROUTE_ID} routeTableChanged = False removedRoutes = ( set(oldPlugins) - set(plugins) - reservedRoutes) for route in removedRoutes: if route in routeTable: del routeTable[route] routeTableChanged = True if routeTableChanged: setting.set(SettingKey.ROUTE_TABLE, routeTable) # Route cleanup is done; update list of enabled plugins. return setting.set(SettingKey.PLUGINS_ENABLED, plugins)
def testLdapLogin(self): settings = Setting() self.assertEqual(settings.get(PluginSettings.SERVERS), []) with self.assertRaises(ValidationException): settings.set(PluginSettings.SERVERS, {}) settings.set(PluginSettings.SERVERS, [{ 'baseDn': 'cn=Users,dc=foo,dc=bar,dc=org', 'bindName': 'cn=foo,cn=Users,dc=foo,dc=bar,dc=org', 'password': '******', 'searchField': 'mail', 'uri': 'foo.bar.org:389' }]) with mock.patch('ldap.initialize', return_value=MockLdap()) as ldapInit: resp = self.request('/user/authentication', basicAuth='hello:world') self.assertEqual(len(ldapInit.mock_calls), 1) self.assertStatusOk(resp) # Register a new user user = resp.json['user'] self.assertEqual(user['email'], '*****@*****.**') self.assertEqual(user['firstName'], 'Foo') self.assertEqual(user['lastName'], 'Bar') self.assertEqual(user['login'], 'foobar') # Login as an existing user resp = self.request('/user/authentication', basicAuth='hello:world') self.assertStatusOk(resp) self.assertEqual(resp.json['user']['_id'], user['_id']) with mock.patch('ldap.initialize', return_value=MockLdap(bindFail=True)): resp = self.request('/user/authentication', basicAuth='hello:world') self.assertStatus(resp, 401) with mock.patch('ldap.initialize', return_value=MockLdap(searchFail=True)): resp = self.request('/user/authentication', basicAuth='hello:world') self.assertStatus(resp, 401) # Test fallback to logging in with core auth normalUser = User().createUser( login='******', firstName='Normal', lastName='User', email='*****@*****.**', password='******') with mock.patch('ldap.initialize', return_value=MockLdap(searchFail=True)): resp = self.request('/user/authentication', basicAuth='normal:normaluser') self.assertStatusOk(resp) self.assertEqual(str(normalUser['_id']), resp.json['user']['_id']) # Test registering from a record that only has a cn, no sn/givenName record = { 'cn': [b'Fizz Buzz'], 'mail': [b'*****@*****.**'], 'distinguishedName': [b'shouldbeignored'] } with mock.patch('ldap.initialize', return_value=MockLdap(record=record)): resp = self.request('/user/authentication', basicAuth='fizzbuzz:foo') self.assertStatusOk(resp) self.assertEqual(resp.json['user']['login'], 'fizz') self.assertEqual(resp.json['user']['firstName'], 'Fizz') self.assertEqual(resp.json['user']['lastName'], 'Buzz') # Test falling back to other name generation behavior (first+last name) record = { 'cn': [b'Fizz Buzz'], 'mail': [b'*****@*****.**'], 'distinguishedName': [b'shouldbeignored'] } with mock.patch('ldap.initialize', return_value=MockLdap(record=record)): resp = self.request('/user/authentication', basicAuth='fizzbuzz:foo') self.assertStatusOk(resp) self.assertEqual(resp.json['user']['login'], 'fizzbuzz') self.assertEqual(resp.json['user']['firstName'], 'Fizz') self.assertEqual(resp.json['user']['lastName'], 'Buzz')
def testRegisterAndLoginBcrypt(self): """ Test user registration and logging in. """ cherrypy.config['auth']['hash_alg'] = 'bcrypt' # Set this to minimum so test runs faster. cherrypy.config['auth']['bcrypt_rounds'] = 4 params = { 'email': 'bad_email', 'login': '******', 'firstName': 'First', 'lastName': 'Last', 'password': '******' } # First test all of the required parameters. self.ensureRequiredParams(path='/user', method='POST', required=six.viewkeys(params)) # Now test parameter validation resp = self.request(path='/user', method='POST', params=params) self.assertValidationError(resp, 'password') self.assertEqual(cherrypy.config['users']['password_description'], resp.json['message']) params['password'] = '******' resp = self.request(path='/user', method='POST', params=params) self.assertValidationError(resp, 'login') # Make login something that violates the regex but doesn't contain @ params['login'] = '******' resp = self.request(path='/user', method='POST', params=params) self.assertValidationError(resp, 'login') self.assertEqual(cherrypy.config['users']['login_description'], resp.json['message']) params['login'] = '******' resp = self.request(path='/user', method='POST', params=params) self.assertValidationError(resp, 'email') # Now successfully create the user params['email'] = '*****@*****.**' 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'], 'bcrypt') # Try logging in without basic auth, should get 401 resp = self.request(path='/user/authentication', method='GET') self.assertStatus(resp, 401) # Bad authentication header resp = self.request(path='/user/authentication', method='GET', additionalHeaders=[('Girder-Authorization', 'Basic Not-Valid-64')]) self.assertStatus(resp, 401) self.assertEqual('Invalid HTTP Authorization header', resp.json['message']) resp = self.request(path='/user/authentication', method='GET', additionalHeaders=[('Girder-Authorization', 'Basic NotValid')]) self.assertStatus(resp, 401) self.assertEqual('Invalid HTTP Authorization header', resp.json['message']) # Login with unregistered email resp = self.request(path='/user/authentication', method='GET', basicAuth='[email protected]:badpassword') self.assertStatus(resp, 401) self.assertEqual('Login failed.', resp.json['message']) # Correct email, but wrong password resp = self.request(path='/user/authentication', method='GET', basicAuth='[email protected]:badpassword') self.assertStatus(resp, 401) self.assertEqual('Login failed.', resp.json['message']) # Login successfully with email resp = self.request(path='/user/authentication', method='GET', basicAuth='[email protected]:good:password') self.assertStatusOk(resp) self.assertHasKeys(resp.json, ['authToken']) self.assertHasKeys(resp.json['authToken'], ['token', 'expires']) self._verifyAuthCookie(resp) # Invalid login resp = self.request(path='/user/authentication', method='GET', basicAuth='badlogin:good:password') self.assertStatus(resp, 401) self.assertEqual('Login failed.', resp.json['message']) # Login successfully with fallback Authorization header resp = self.request(path='/user/authentication', method='GET', basicAuth='goodlogin:good:password', authHeader='Authorization') self.assertStatusOk(resp) # Test secure cookie validation with self.assertRaises(ValidationException): Setting().set(SettingKey.SECURE_COOKIE, 'bad value') # Set secure cookie value Setting().set(SettingKey.SECURE_COOKIE, True) # Login successfully with login resp = self.request(path='/user/authentication', method='GET', basicAuth='goodlogin:good:password') self.assertStatusOk(resp) # Make sure we got a nice (secure) cookie self._verifyAuthCookie(resp, secure=True) # Test user/me resp = self.request(path='/user/me', method='GET', user=user) self.assertStatusOk(resp) self.assertEqual(resp.json['login'], user['login'])
def _renderHTML(self): from girder.utility import server self.vars['apiRoot'] = server.getApiRoot() self.vars['staticPublicPath'] = server.getStaticPublicPath() self.vars['brandName'] = Setting().get(SettingKey.BRAND_NAME) return super(ApiDocs, self)._renderHTML()
class HistogramResource(Resource): def __init__(self): super(HistogramResource, self).__init__() self.resourceName = 'histogram' self.route('GET', (), self.find) self.route('POST', (), self.createHistogram) self.route('DELETE', (':id', ), self.deleteHistogram) self.route('GET', (':id', ), self.getHistogram) self.route('GET', (':id', 'access'), self.getHistogramAccess) self.route('PUT', (':id', 'access'), self.updateHistogramAccess) self.route('GET', ('settings', ), self.getSettings) self.histogram = Histogram() @access.public(scope=TokenScope.DATA_READ) @filtermodel(Histogram) @autoDescribeRoute( Description('Search for histograms.').responseClass( Histogram, array=True).param( 'itemId', 'The item ID of the histogram source.', required=False).param('bins', 'Number of bins in in the histogram.', required=False, dataType='integer'). param('label', 'Histogram is of a label image.', required=False, dataType='boolean').param( 'bitmask', 'Histogram is of a image with bitmask values.', required=False, dataType='boolean').param( 'jobId', 'The job ID of the task generating the histogram.', required=False).param( 'fileId', 'The file ID of the histogram file.', required=False).pagingParams( defaultSort='_id').errorResponse().errorResponse( 'No matching histograms were found.', 404)) def find(self, itemId, bins, label, bitmask, jobId, fileId, limit, offset, sort): user = self.getCurrentUser() query = {} if itemId is not None: query['itemId'] = ObjectId(itemId) if bins is not None: query['bins'] = bins if label is not None: query['label'] = label if bitmask is not None: query['bitmask'] = bitmask if jobId is not None: query['jobId'] = ObjectId(jobId) if fileId is not None: query['fileId'] = ObjectId(fileId) return list( self.histogram.filterResultsByPermission( cursor=self.histogram.find(query, sort=sort), user=user, level=AccessType.READ, limit=limit, offset=offset)) @access.user(scope=TokenScope.DATA_WRITE) # @filtermodel(model='job', plugin='jobs') @filtermodel(Histogram) @autoDescribeRoute( Description('Create a new histogram from an item.').modelParam( 'itemId', 'The ID of the source item.', paramType='formData', model=Item, level=AccessType.WRITE).param( 'fileId', 'The ID of the source file.', required=False).param( 'notify', 'Trigger a notification when completed', required=False, dataType='boolean', default=False).param( 'bins', 'Number of bins in the histogram', required=False, dataType='integer', # FIXME: update default=Setting().get( PluginSettings.DEFAULT_BINS)).param( 'label', 'Image is a label (ignore zero values)', required=False, dataType='boolean', default=False).param( 'bitmask', 'Image label values are bitmasks', required=False, dataType='boolean', default=False)) def createHistogram(self, item, fileId, notify, bins, label, bitmask): user = self.getCurrentUser() token = self.getCurrentToken() if fileId is None: # files = list(Item().childFiles(item=item, limit=2)) query = { 'itemId': item['_id'], # 'mimeType': {'$regex': '^image/tiff'} # query should find the same file(tiff) used for creating histogram # but this will always find most recent json histogram '$or': [{ 'mimeType': { '$regex': '^image/' } }, { 'mimeType': 'application/octet-stream' }, { 'exts': ['tif'] }], } files = list(File().find(query, limit=2)) if len(files) >= 1: fileId = str(files[0]['_id']) if not fileId: raise RestException('Missing "fileId" parameter.') file_ = File().load(fileId, user=user, level=AccessType.READ, exc=True) return self.histogram.createHistogramJob(item, file_, user=user, token=token, notify=notify, bins=bins, label=label, bitmask=bitmask) @access.user(scope=TokenScope.DATA_OWN) @filtermodel(Histogram) @autoDescribeRoute( Description('Delete a histogram.').modelParam( 'id', model=Histogram, level=AccessType.WRITE).errorResponse( 'ID was invalid.').errorResponse( 'Write access was denied for the histogram.', 403)) def deleteHistogram(self, histogram): self.histogram.remove(histogram) @access.public(scope=TokenScope.DATA_READ) @filtermodel(Histogram) @autoDescribeRoute( Description('Get histogram by ID.').responseClass( Histogram).modelParam( 'id', model=Histogram, level=AccessType.READ).errorResponse( 'ID was invalid.').errorResponse( 'Read access was denied for the histogram.', 403)) def getHistogram(self, histogram): return histogram @access.user(scope=TokenScope.DATA_OWN) @filtermodel(Histogram) @autoDescribeRoute( Description('Get the access control list for a histogram.').modelParam( 'id', model=Histogram, level=AccessType.ADMIN).errorResponse( 'ID was invalid.').errorResponse( 'Admin access was denied for the histogram.', 403)) def getHistogramAccess(self, histogram): return self.histogram.getFullAccessList(histogram) @access.user(scope=TokenScope.DATA_OWN) @filtermodel(Histogram) @autoDescribeRoute( Description('Update the access control list for a histogram.'). responseClass(Histogram).modelParam('id', model=Histogram, level=AccessType.ADMIN). jsonParam('access', 'The JSON-encoded access control list.').param( 'public', 'Whether the histogram should be publicly visible.', dataType='boolean', required=False).errorResponse('ID was invalid.').errorResponse( 'Admin access was denied for the histogram.', 403)) def updateHistogramAccess(self, histogram, access, public): self.histogram.setPublic(histogram, public) return self.histogram.setAccessList(histogram, access, save=True, user=self.getCurrentUser()) @access.public @autoDescribeRoute(Description('Getting histogram settings.')) def getSettings(self): settings = Setting() return { PluginSettings.DEFAULT_BINS: settings.get(PluginSettings.DEFAULT_BINS), }
def getClientSecretSetting(self): return Setting().get(constants.PluginSettings.GLOBUS_CLIENT_SECRET)
def getClientSecretSetting(self): return Setting().get(PluginSettings.LINKEDIN_CLIENT_SECRET)
def testCORS(self): testServer.root.api.v1.dummy = DummyResource() # When no origin header is passed, we shouldn't receive CORS headers resp = self.request(path='/dummy/test') self.assertStatusOk(resp) self.assertFalse('Access-Control-Allow-Origin' in resp.headers) self.assertFalse('Access-Control-Allow-Credentials' in resp.headers) # If no origins are allowed, we should not get an allow origin header resp = self.request(path='/dummy/test', additionalHeaders=[ ('Origin', 'http://foo.com') ]) self.assertStatusOk(resp) self.assertFalse('Access-Control-Allow-Origin' in resp.headers) # Request from a non-allowed Origin Setting().set(SettingKey.CORS_ALLOW_ORIGIN, 'http://kitware.com') resp = self.request(path='/dummy/test', additionalHeaders=[ ('Origin', 'http://foo.com') ]) self.assertNotIn('Access-Control-Allow-Origin', resp.headers) self.assertEqual(resp.headers['Access-Control-Allow-Credentials'], 'true') # Simulate a preflight request; we should get back several headers Setting().set(SettingKey.CORS_ALLOW_METHODS, 'POST') resp = self.request( path='/dummy/test', method='OPTIONS', additionalHeaders=[ ('Origin', 'http://foo.com') ], isJson=False ) self.assertStatusOk(resp) self.assertEqual(self.getBody(resp), '') self.assertNotIn('Access-Control-Allow-Origin', resp.headers) self.assertEqual(resp.headers['Access-Control-Allow-Credentials'], 'true') self.assertEqual(resp.headers['Access-Control-Allow-Headers'], SettingDefault.defaults[SettingKey.CORS_ALLOW_HEADERS]) self.assertEqual(resp.headers['Access-Control-Allow-Methods'], 'POST') # Make an actual preflight request with query parameters; CherryPy 11.1 # introduced a bug where this would fail with a 405. resp = requests.options( 'http://127.0.0.1:%s/api/v1/folder?key=value' % os.environ['GIRDER_TEST_PORT']) self.assertEqual(resp.status_code, 200) # Set multiple allowed origins Setting().set(SettingKey.CORS_ALLOW_ORIGIN, 'http://foo.com, http://bar.com') resp = self.request( path='/dummy/test', method='GET', additionalHeaders=[ ('Origin', 'http://bar.com') ], isJson=False) self.assertEqual(resp.headers['Access-Control-Allow-Origin'], 'http://bar.com') resp = self.request( path='/dummy/test', method='GET', additionalHeaders=[ ('Origin', 'http://invalid.com') ], isJson=False) self.assertNotIn('Access-Control-Allow-Origin', resp.headers) # Test behavior of '*' allowed origin Setting().set(SettingKey.CORS_ALLOW_ORIGIN, 'http://foo.com,*') resp = self.request( path='/dummy/test', method='GET', additionalHeaders=[ ('Origin', 'http://bar.com') ], isJson=False) self.assertEqual(resp.headers['Access-Control-Allow-Origin'], '*') resp = self.request( path='/dummy/test', method='GET', additionalHeaders=[ ('Origin', 'http://foo.com') ], isJson=False) self.assertEqual(resp.headers['Access-Control-Allow-Origin'], 'http://foo.com')
def getTCGACollection(self): """Get the unique TCGA collection from the settings collection.""" tcga = Setting().get(TCGACollectionSettingKey) if tcga is None: raise Exception('TCGA collection id not initialized in settings') return Collection().load(tcga, force=True)
def defaultMaxSize(self): return int(Setting().get( PluginSettings.LARGE_IMAGE_MAX_SMALL_IMAGE_SIZE))
def testSettings(self): users = self.users # Only admins should be able to get or set settings for method in ('GET', 'PUT', 'DELETE'): resp = self.request(path='/system/setting', method=method, params={ 'key': 'foo', 'value': 'bar' }, user=users[1]) self.assertStatus(resp, 403) # Only valid setting keys should be allowed resp = self.request(path='/system/setting', method='PUT', params={ 'key': 'foo', 'value': 'bar' }, user=users[0]) self.assertStatus(resp, 400) self.assertEqual(resp.json['field'], 'key') # Only a valid JSON list is permitted resp = self.request(path='/system/setting', method='GET', params={'list': json.dumps('not_a_list')}, user=users[0]) self.assertStatus(resp, 400) resp = self.request(path='/system/setting', method='PUT', params={'list': json.dumps('not_a_list')}, user=users[0]) self.assertStatus(resp, 400) # Set an invalid setting value, should fail resp = self.request(path='/system/setting', method='PUT', params={ 'key': SettingKey.BANNER_COLOR, 'value': 'bar' }, user=users[0]) self.assertStatus(resp, 400) self.assertEqual(resp.json['message'], 'The banner color must be a hex color triplet') # Set a valid value resp = self.request(path='/system/setting', method='PUT', params={ 'key': SettingKey.BANNER_COLOR, 'value': '#121212' }, user=users[0]) self.assertStatusOk(resp) # We should now be able to retrieve it resp = self.request(path='/system/setting', method='GET', params={'key': SettingKey.BANNER_COLOR}, user=users[0]) self.assertStatusOk(resp) self.assertEqual(resp.json, '#121212') # We should now clear the setting resp = self.request(path='/system/setting', method='DELETE', params={'key': SettingKey.BANNER_COLOR}, user=users[0]) self.assertStatusOk(resp) # Setting should now be default setting = Setting().get(SettingKey.BANNER_COLOR) self.assertEqual(setting, SettingDefault.defaults[SettingKey.BANNER_COLOR]) # We should also be able to put several setting using a JSON list resp = self.request(path='/system/setting', method='PUT', params={ 'list': json.dumps([ { 'key': SettingKey.BANNER_COLOR, 'value': '#121212' }, { 'key': SettingKey.COOKIE_LIFETIME, 'value': None }, ]) }, user=users[0]) self.assertStatusOk(resp) # We can get a list as well resp = self.request(path='/system/setting', method='GET', params={ 'list': json.dumps([ SettingKey.BANNER_COLOR, SettingKey.COOKIE_LIFETIME, ]) }, user=users[0]) self.assertStatusOk(resp) self.assertEqual(resp.json[SettingKey.BANNER_COLOR], '#121212') # Try to set each key in turn to test the validation. First test with # am invalid value, then test with the default value. If the value # 'bad' won't trigger a validation error, the key should be present in # the badValues table. badValues = { SettingKey.BRAND_NAME: '', SettingKey.BANNER_COLOR: '', SettingKey.EMAIL_FROM_ADDRESS: '', SettingKey.PRIVACY_NOTICE: '', SettingKey.CONTACT_EMAIL_ADDRESS: '', SettingKey.EMAIL_HOST: {}, SettingKey.SMTP_HOST: '', SettingKey.SMTP_PASSWORD: {}, SettingKey.SMTP_USERNAME: {}, SettingKey.CORS_ALLOW_ORIGIN: {}, SettingKey.CORS_ALLOW_METHODS: {}, SettingKey.CORS_ALLOW_HEADERS: {}, SettingKey.CORS_EXPOSE_HEADERS: {}, } allKeys = dict.fromkeys(six.viewkeys(SettingDefault.defaults)) allKeys.update(badValues) for key in allKeys: resp = self.request(path='/system/setting', method='PUT', params={ 'key': key, 'value': badValues.get(key, 'bad') }, user=users[0]) self.assertStatus(resp, 400) resp = self.request(path='/system/setting', method='PUT', params={ 'key': key, 'value': json.dumps( SettingDefault.defaults.get(key, '')) }, user=users[0]) self.assertStatusOk(resp) resp = self.request( path='/system/setting', method='PUT', params={'list': json.dumps([{ 'key': key, 'value': None }])}, user=users[0]) self.assertStatusOk(resp)
def testAnnotationHistoryEndpoints(self, server, user, admin): privateFolder = utilities.namedFolder(admin, 'Private') Setting().set(constants.PluginSettings.LARGE_IMAGE_ANNOTATION_HISTORY, True) item = Item().createItem('sample', admin, privateFolder) # Create an annotation with some history annot = Annotation().createAnnotation(item, admin, copy.deepcopy(sampleAnnotation)) annot['annotation']['name'] = 'First Change' annot['annotation']['elements'].extend([ { 'type': 'point', 'center': [20.0, 25.0, 0] }, { 'type': 'point', 'center': [10.0, 24.0, 0] }, { 'type': 'point', 'center': [25.5, 23.0, 0] }, ]) annot = Annotation().save(annot) # simulate a concurrent save dup = Annotation().findOne({'_id': annot['_id']}) dup['_annotationId'] = dup.pop('_id') dup['_active'] = False Annotation().collection.insert_one(dup) # Save again annot['annotation']['name'] = 'Second Change' annot['annotation']['elements'].pop(2) annot = Annotation().save(annot) # Test the list of versions resp = server.request('/annotation/%s/history' % annot['_id'], user=user) assert utilities.respStatus(resp) == 200 assert resp.json == [] resp = server.request('/annotation/%s/history' % annot['_id'], user=admin) assert utilities.respStatus(resp) == 200 assert len(resp.json) == 3 versions = resp.json # Test getting a specific version resp = server.request('/annotation/%s/history/%s' % (annot['_id'], versions[1]['_version']), user=user) assert utilities.respStatus(resp) == 403 resp = server.request('/annotation/%s/history/%s' % (annot['_id'], versions[1]['_version']), user=admin) assert utilities.respStatus(resp) == 200 assert resp.json['_annotationId'] == str(annot['_id']) assert len(resp.json['annotation']['elements']) == 4 resp = server.request('/annotation/%s/history/%s' % (annot['_id'], versions[0]['_version'] + 1), user=admin) assert utilities.respStatus(resp) == 400 # Test revert resp = server.request('/annotation/%s/history/revert' % (annot['_id']), method='PUT', user=user) assert utilities.respStatus(resp) == 403 resp = server.request('/annotation/%s/history/revert' % (annot['_id']), method='PUT', user=admin, params={'version': versions[0]['_version'] + 1}) assert utilities.respStatus(resp) == 400 resp = server.request('/annotation/%s/history/revert' % (annot['_id']), method='PUT', user=admin, params={'version': versions[1]['_version']}) assert utilities.respStatus(resp) == 200 loaded = Annotation().load(annot['_id'], user=admin) assert len(loaded['annotation']['elements']) == 4
def get_extra_hosts_setting(): return Setting().get(constants.PluginSettings.DATAVERSE_EXTRA_HOSTS)
def get_base_url_setting(): return Setting().get(constants.PluginSettings.DATAVERSE_URL)
def _onSettingRemove(self, event): settingDoc = event.info if settingDoc['key'] == SettingKey.BRAND_NAME: self.updateHtmlVars( {'brandName': Setting().getDefault(SettingKey.BRAND_NAME)})
def getSetting(self, key, list): if list is not None: return {k: Setting().get(k) for k in list} else: self.requireParams({'key': key}) return Setting().get(key)
def getClientIdSetting(self): return Setting().get(constants.PluginSettings.GLOBUS_CLIENT_ID)
def unsetSetting(self, key): return Setting().unset(key)
def getClientIdSetting(self): return Setting().get(PluginSettings.LINKEDIN_CLIENT_ID)
def get(self): config = { 'deployment': Setting().get(constants.CONFIGURATION_DEPLOYMENT), 'license': Setting().get(constants.CONFIGURATION_LICENSE), 'privacy': Setting().get(constants.CONFIGURATION_PRIVACY), 'showMenu': Setting().get(constants.CONFIGURATION_SHOW_MENU, True), 'showSearch': Setting().get(constants.CONFIGURATION_SHOW_SEARCH, True) } if Setting().get( constants.CONFIGURATION_HEADER_LEFT_LOGO_ID) is not None: config['headerLeftLogoFileId'] = Setting().get( constants.CONFIGURATION_HEADER_LEFT_LOGO_ID) if Setting().get( constants.CONFIGURATION_HEADER_RIGHT_LOGO_ID) is not None: config['headerRightLogoFileId'] = Setting().get( constants.CONFIGURATION_HEADER_RIGHT_LOGO_ID) if Setting().get( constants.CONFIGURATION_HEADER_RIGHT_LOGO_URL) is not None: config['headerRightLogoUrl'] = Setting().get( constants.CONFIGURATION_HEADER_RIGHT_LOGO_URL) if Setting().get(constants.CONFIGURATION_FAVICON_ID) is not None: config['faviconFileId'] = Setting().get( constants.CONFIGURATION_FAVICON_ID) if Setting().get(constants.CONFIGURATION_FOOTER_LOGO_ID) is not None: config['footerLogoFileId'] = Setting().get( constants.CONFIGURATION_FOOTER_LOGO_ID) if Setting().get(constants.CONFIGURATION_FOOTER_LOGO_URL) is not None: config['footerLogoUrl'] = Setting().get( constants.CONFIGURATION_FOOTER_LOGO_URL) return config
def testAccountApproval(self): admin = User().createUser('admin', 'password', 'Admin', 'Admin', '*****@*****.**') Setting().set(SettingKey.REGISTRATION_POLICY, 'approve') self.assertTrue(base.mockSmtp.isMailQueueEmpty()) user = User().createUser('user', 'password', 'User', 'User', '*****@*****.**') # pop email self.assertTrue(base.mockSmtp.waitForMail()) base.mockSmtp.getMail(parse=True) # cannot login without being approved resp = self.request('/user/authentication', basicAuth='user:password') self.assertStatus(resp, 401) self.assertTrue(resp.json['extra'] == 'accountApproval') # ensure only admins can change status path = '/user/%s' % user['_id'] resp = self.request(path=path, method='PUT', user=user, params={ 'firstName': user['firstName'], 'lastName': user['lastName'], 'email': user['email'], 'status': 'enabled' }) self.assertStatus(resp, 403) self.assertEqual(resp.json['message'], 'Only admins may change status.') # approve account path = '/user/%s' % user['_id'] resp = self.request(path=path, method='PUT', user=admin, params={ 'firstName': user['firstName'], 'lastName': user['lastName'], 'email': user['email'], 'status': 'enabled' }) self.assertStatusOk(resp) # pop email self.assertTrue(base.mockSmtp.waitForMail()) base.mockSmtp.getMail(parse=True) # can now login resp = self.request('/user/authentication', basicAuth='user:password') self.assertStatusOk(resp) # disable account path = '/user/%s' % user['_id'] resp = self.request(path=path, method='PUT', user=admin, params={ 'firstName': user['firstName'], 'lastName': user['lastName'], 'email': user['email'], 'status': 'disabled' }) self.assertStatusOk(resp) # cannot login again resp = self.request('/user/authentication', basicAuth='user:password') self.assertStatus(resp, 401) self.assertEqual(resp.json['extra'], 'disabled')
def testGeneralSettings(self, server, admin, user): self.makeResources(admin) settings = [{ 'key': PluginSettings.HUI_WEBROOT_PATH, 'initial': 'histomics', 'bad': { 'girder': 'not be "girder"', '': 'not be empty' }, 'good': { 'alternate1': 'alternate1' }, }, { 'key': PluginSettings.HUI_BRAND_NAME, 'initial': 'HistomicsUI', 'bad': { '': 'not be empty' }, 'good': { 'Alternate': 'Alternate' }, }, { 'key': PluginSettings.HUI_BRAND_COLOR, 'initial': '#777777', 'bad': { '': 'not be empty', 'white': 'be a hex color', '#777': 'be a hex color' }, 'good': { '#000000': '#000000' }, }, { 'key': PluginSettings.HUI_BANNER_COLOR, 'initial': '#f8f8f8', 'bad': { '': 'not be empty', 'white': 'be a hex color', '#777': 'be a hex color' }, 'good': { '#000000': '#000000' }, }] for setting in settings: key = setting['key'] assert Setting().get(key) == setting['initial'] for badval in setting.get('bad', {}): with pytest.raises(ValidationException, match=setting['bad'][badval]): Setting().set(key, badval) for badval in setting.get('badjson', []): with pytest.raises(ValidationException, match=badval['return']): Setting().set(key, badval['value']) for goodval in setting.get('good', {}): assert Setting().set( key, goodval)['value'] == setting['good'][goodval] for goodval in setting.get('goodjson', []): assert Setting().set( key, goodval['value'])['value'] == goodval['return']
def getSettings(self): settings = Setting() return { PluginSettings.DEFAULT_BINS: settings.get(PluginSettings.DEFAULT_BINS), }
def testQuarantine(self, server, admin, user): publicFolder = Folder().childFolders( # noqa: B305 user, 'user', filters={ 'name': 'Public' }).next() adminFolder = Folder().childFolders( # noqa: B305 admin, 'user', filters={ 'name': 'Public' }).next() privateFolder = Folder().childFolders( # noqa: B305 admin, 'user', filters={ 'name': 'Private' }, user=admin).next() items = [ Item().createItem(name, creator, folder) for name, creator, folder in [ ('userPublic1', user, publicFolder), ('userPublic2', user, publicFolder), ('adminPublic1', admin, adminFolder), ('adminPublic2', admin, adminFolder), ('adminPrivate1', admin, privateFolder), ('adminPrivate2', admin, privateFolder), ] ] resp = server.request(method='PUT', path='/histomicsui/quarantine/%s' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 401 assert 'Write access denied' in resp.json['message'] resp = server.request(method='PUT', user=user, path='/histomicsui/quarantine/%s' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 400 assert 'The quarantine folder is not configure' in resp.json['message'] key = PluginSettings.HUI_QUARANTINE_FOLDER Setting().set(key, str(privateFolder['_id'])) resp = server.request(method='PUT', user=user, path='/histomicsui/quarantine/%s' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 200 resp = server.request(method='PUT', user=user, path='/histomicsui/quarantine/%s' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 403 assert 'Write access denied' in resp.json['message'] resp = server.request(method='PUT', user=user, path='/histomicsui/quarantine/%s' % str(items[2]['_id'])) assert utilities.respStatus(resp) == 403 assert 'Write access denied' in resp.json['message'] resp = server.request(method='PUT', user=admin, path='/histomicsui/quarantine/%s' % str(items[2]['_id'])) assert utilities.respStatus(resp) == 200 resp = server.request(method='PUT', user=admin, path='/histomicsui/quarantine/%s' % str(items[4]['_id'])) assert utilities.respStatus(resp) == 400 assert 'already in the quarantine' in resp.json['message'] # Restore resp = server.request(method='PUT', user=admin, path='/histomicsui/quarantine/%s/restore' % str(items[1]['_id'])) assert utilities.respStatus(resp) == 400 assert 'no quarantine record' in resp.json['message'] resp = server.request(method='PUT', path='/histomicsui/quarantine/%s/restore' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 401 assert 'Write access denied' in resp.json['message'] resp = server.request(method='PUT', user=user, path='/histomicsui/quarantine/%s/restore' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 403 assert 'Write access denied' in resp.json['message'] resp = server.request(method='PUT', user=admin, path='/histomicsui/quarantine/%s/restore' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 200 resp = server.request(method='PUT', user=admin, path='/histomicsui/quarantine/%s/restore' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 400 assert 'no quarantine record' in resp.json['message'] resp = server.request(method='PUT', user=user, path='/histomicsui/quarantine/%s' % str(items[0]['_id'])) assert utilities.respStatus(resp) == 200
def testSettingsCache(db, enabledCache): setting = Setting() # 'foo' should be cached as the brand name setting.set(SettingKey.BRAND_NAME, 'foo') # change the brand name bypassing the cache via mongo returnedSetting = setting.findOne({'key': SettingKey.BRAND_NAME}) returnedSetting['value'] = 'bar' # verify the cache still gives us the old brand name assert setting.get(SettingKey.BRAND_NAME) == 'foo' # change the brand name through .set (which updates the cache) setting.set(SettingKey.BRAND_NAME, 'bar') # verify retrieving gives us the new value with mock.patch.object(setting, 'findOne') as findOneMock: assert setting.get(SettingKey.BRAND_NAME) == 'bar' # findOne shouldn't be called since the cache is returning the setting findOneMock.assert_not_called() # unset the setting, invalidating the cache setting.unset(SettingKey.BRAND_NAME) # verify the database needs to be accessed to retrieve the setting now with mock.patch.object(setting, 'findOne') as findOneMock: setting.get(SettingKey.BRAND_NAME) findOneMock.assert_called_once()
def testGetLicenses(self): """ Test getting list of licenses. """ # Get default settings resp = self.request(path='/item/licenses', user=self.user, params={'default': True}) self.assertStatusOk(resp) self.assertGreater(len(resp.json), 1) self.assertIn('category', resp.json[0]) self.assertIn('licenses', resp.json[0]) self.assertGreater(len(resp.json[0]['licenses']), 8) self.assertIn('name', resp.json[0]['licenses'][0]) self.assertGreater(len(resp.json[0]['licenses'][0]['name']), 0) self.assertIn('name', resp.json[0]['licenses'][1]) self.assertGreater(len(resp.json[0]['licenses'][1]['name']), 0) # Get current settings resp = self.request(path='/item/licenses', user=self.user) self.assertStatusOk(resp) self.assertGreater(len(resp.json), 1) self.assertIn('category', resp.json[0]) self.assertIn('licenses', resp.json[0]) self.assertGreater(len(resp.json[0]['licenses']), 8) self.assertIn('name', resp.json[0]['licenses'][0]) self.assertGreater(len(resp.json[0]['licenses'][0]['name']), 0) self.assertIn('name', resp.json[0]['licenses'][1]) self.assertGreater(len(resp.json[0]['licenses'][1]['name']), 0) # Change licenses Setting().set(PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [{ 'name': '1' }] }, { 'category': 'B', 'licenses': [{ 'name': '2' }, { 'name': '3' }] }]) # Get default settings after changing licenses resp = self.request(path='/item/licenses', user=self.user, params={'default': True}) self.assertStatusOk(resp) self.assertStatusOk(resp) self.assertGreater(len(resp.json), 1) self.assertIn('category', resp.json[0]) self.assertIn('licenses', resp.json[0]) self.assertGreater(len(resp.json[0]['licenses']), 8) self.assertIn('name', resp.json[0]['licenses'][0]) self.assertGreater(len(resp.json[0]['licenses'][0]['name']), 0) self.assertIn('name', resp.json[0]['licenses'][1]) self.assertGreater(len(resp.json[0]['licenses'][1]['name']), 0) # Get current settings after changing licenses resp = self.request(path='/item/licenses', user=self.user) self.assertStatusOk(resp) six.assertCountEqual(self, resp.json, [{ 'category': 'A', 'licenses': [{ 'name': '1' }] }, { 'category': 'B', 'licenses': [{ 'name': '2' }, { 'name': '3' }] }])
def testRouteTableValidationSuccess(value, db): Setting().validate({'key': SettingKey.ROUTE_TABLE, 'value': value})
def testLicensesSettingValidation(self): """ Test validation of licenses setting. """ # Test valid settings Setting().set(PluginSettings.LICENSES, []) Setting().set(PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [] }]) Setting().set(PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [{ 'name': '1' }] }]) Setting().set(PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [{ 'name': '1' }, { 'name': '2' }] }]) Setting().set(PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [] }, { 'category': 'B', 'licenses': [{ 'name': '1' }] }]) Setting().set(PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [] }, { 'category': 'B', 'licenses': [{ 'name': '1' }, { 'name': '2' }] }]) # Test invalid top-level types for val in (None, 1, '', {}, [{}]): self.assertRaises(ValidationException, Setting().set, PluginSettings.LICENSES, val) # Test invalid category types for category, licenses in ((None, []), (1, []), ('', []), ({}, [])): self.assertRaises(ValidationException, Setting().set, PluginSettings.LICENSES, [{ 'category': category, 'licenses': licenses }]) # Test invalid licenses types for val in (None, {}, [1], ['']): self.assertRaises(ValidationException, Setting().set, PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': val }]) # Test invalid license names for val in (None, 1, '', {}, []): self.assertRaises(ValidationException, Setting().set, PluginSettings.LICENSES, [{ 'category': 'A', 'licenses': [{ 'name': val }] }])
def testRouteTableValidationFailure(value, err, db): with pytest.raises(ValidationException, match=err): Setting().validate({'key': SettingKey.ROUTE_TABLE, 'value': value})
def testLdapLogin(self): settings = Setting() self.assertEqual(settings.get(PluginSettings.LDAP_SERVERS), []) with self.assertRaises(ValidationException): settings.set(PluginSettings.LDAP_SERVERS, {}) settings.set(PluginSettings.LDAP_SERVERS, [{ 'baseDn': 'cn=Users,dc=foo,dc=bar,dc=org', 'bindName': 'cn=foo,cn=Users,dc=foo,dc=bar,dc=org', 'password': '******', 'searchField': 'mail', 'uri': 'foo.bar.org:389' }]) with mock.patch('ldap.initialize', return_value=MockLdap()) as ldapInit: resp = self.request('/user/authentication', basicAuth='hello:world') self.assertEqual(len(ldapInit.mock_calls), 1) self.assertStatusOk(resp) # Register a new user user = resp.json['user'] self.assertEqual(user['email'], '*****@*****.**') self.assertEqual(user['firstName'], 'Foo') self.assertEqual(user['lastName'], 'Bar') self.assertEqual(user['login'], 'foobar') # Login as an existing user resp = self.request('/user/authentication', basicAuth='hello:world') self.assertStatusOk(resp) self.assertEqual(resp.json['user']['_id'], user['_id']) with mock.patch('ldap.initialize', return_value=MockLdap(bindFail=True)): resp = self.request('/user/authentication', basicAuth='hello:world') self.assertStatus(resp, 401) with mock.patch('ldap.initialize', return_value=MockLdap(searchFail=True)): resp = self.request('/user/authentication', basicAuth='hello:world') self.assertStatus(resp, 401) # Test fallback to logging in with core auth normalUser = User().createUser(login='******', firstName='Normal', lastName='User', email='*****@*****.**', password='******') with mock.patch('ldap.initialize', return_value=MockLdap(searchFail=True)): resp = self.request('/user/authentication', basicAuth='normal:normaluser') self.assertStatusOk(resp) self.assertEqual(str(normalUser['_id']), resp.json['user']['_id']) # Test registering from a record that only has a cn, no sn/givenName record = { 'cn': [b'Fizz Buzz'], 'mail': [b'*****@*****.**'], 'distinguishedName': [b'shouldbeignored'] } with mock.patch('ldap.initialize', return_value=MockLdap(record=record)): resp = self.request('/user/authentication', basicAuth='fizzbuzz:foo') self.assertStatusOk(resp) self.assertEqual(resp.json['user']['login'], 'fizz') self.assertEqual(resp.json['user']['firstName'], 'Fizz') self.assertEqual(resp.json['user']['lastName'], 'Buzz') # Test falling back to other name generation behavior (first+last name) record = { 'cn': [b'Fizz Buzz'], 'mail': [b'*****@*****.**'], 'distinguishedName': [b'shouldbeignored'] } with mock.patch('ldap.initialize', return_value=MockLdap(record=record)): resp = self.request('/user/authentication', basicAuth='fizzbuzz:foo') self.assertStatusOk(resp) self.assertEqual(resp.json['user']['login'], 'fizzbuzz') self.assertEqual(resp.json['user']['firstName'], 'Fizz') self.assertEqual(resp.json['user']['lastName'], 'Buzz')
def has_task_folder(): return Setting().get( PluginSettings.SLICER_CLI_WEB_TASK_FOLDER) is not None
def _testQuota(self, model, resource, user): """ Test quota policies for a specified resource. :param model: either 'user' or 'collection'. :param resource: the document for the resource to test. :param user: user to use for authorization. """ Setting().set(SettingKey.UPLOAD_MINIMUM_CHUNK_SIZE, 0) resp = self.request(path='/folder', method='GET', user=user, params={ 'parentType': model, 'parentId': resource['_id'] }) self.assertStatusOk(resp) self.assertGreaterEqual(len(resp.json), 1) folder = resp.json[0] # Start by uploading one file so that there is some use self._uploadFile('First upload', folder, size=1024) # Set a policy limiting things to 4 kb, then a 4 kb file should fail self._setPolicy({ 'fileSizeQuota': 4096, 'useQuotaDefault': False }, model, resource, user) self._uploadFile( 'File too large', folder, size=4096, validationError='Upload would exceed file storage quota') # But a 2 kb file will succeed file = self._uploadFile('Second upload', folder, size=2048) # And a second 2 kb file will fail self._uploadFile( 'File too large', folder, size=2048, validationError='Upload would exceed file storage quota') # If we start uploading two files, only one should complete file1kwargs = self._uploadFile('First partial', folder, size=768, partial=True) file2kwargs = self._uploadFile('Second partial', folder, size=768, partial=True) resp = self.multipartRequest(**file1kwargs) self.assertStatusOk(resp) try: resp = self.multipartRequest(**file2kwargs) self.assertStatus(resp, 400) except AssertionError as exc: self.assertTrue('Upload exceeded' in exc.args[0]) # Shrink the quota to smaller than all of our files. Replacing an # existing file should still work, though self._setPolicy({'fileSizeQuota': 2048}, model, resource, user) self._uploadFile('Second upload', file, 'file', size=1536) # Now test again using default quotas. We have 1024+1536+768 = 3328 # bytes currently uploaded self._setPolicy({'useQuotaDefault': True}, model, resource, user) # Upload should now be unlimited, so anything will work self._uploadFile('Fourth upload', folder, size=1792) # Set a policy limiting things to 8 kb, then an additional 4 kb file # should fail self._setQuotaDefault(model, 8192) self._uploadFile( 'File too large', folder, size=4096, validationError='Upload would exceed file storage quota') # But a 2 kb file will succeed file = self._uploadFile('Fifth upload', folder, size=2048) # And a second 2 kb file will fail self._uploadFile( 'File too large', folder, size=2048, validationError='Upload would exceed file storage quota') # Set a policy with a large quota to test using NumberLong in the # mongo settings. self._setQuotaDefault(model, 5 * 1024**3) # A small file should now upload file = self._uploadFile('Six upload', folder, size=2048) # But a huge one will fail self._uploadFile( 'File too large', folder, size=6 * 1024**3, validationError='Upload would exceed file storage quota')