def setUp(self): self.plugin = BSONBottlePlugin() self.ip = "84.34.13.122" self.callback = Mock(wraps=self._callback) self.callbacknobson = Mock(wraps=self._callbackno) bottle.request.environ['REMOTE_ADDR'] = self.ip bottle.request.environ['CONTENT_TYPE'] = 'application/bson' self.context = Mock() self.context.callback = self._callback self.contextnobson = Mock(wraps=self._callbackno) self.contextnobson.callback = self._callbackno self.__set_bson_content({"therivermen": "ehhhhhmacarena"})
class BsonBottleTest(unittest.TestCase): """Bottle plugin for automatic parse a BSON request and pass a """ def setUp(self): self.plugin = BSONBottlePlugin() self.ip = "84.34.13.122" self.callback = Mock(wraps=self._callback) self.callbacknobson = Mock(wraps=self._callbackno) bottle.request.environ['REMOTE_ADDR'] = self.ip bottle.request.environ['CONTENT_TYPE'] = 'application/bson' self.context = Mock() self.context.callback = self._callback self.contextnobson = Mock(wraps=self._callbackno) self.contextnobson.callback = self._callbackno self.__set_bson_content({"therivermen": "ehhhhhmacarena"}) def tearDown(self): pass def testAddOtherPluginWithSameKeywork(self): app = Mock() bad_plugin = Mock() bad_plugin.keyword = "bson_data" app.plugins = set([bad_plugin]) self.assertRaises(PluginError, self.plugin.setup, app) def testCallbackCalled(self): self.plugin.apply(self.callback, self.context)() self.assertTrue(self.callback.called) def testNotBsonRequest(self): bottle.request.environ['CONTENT_TYPE'] = 'mouse/mikey' self.assertRaises(BSONBottlePluginException, self.plugin.apply(self.callback, self.context)) def testNotBsonRequestWithNoBonDataParameter(self): bottle.request.environ['CONTENT_TYPE'] = 'mouse/mikey' # If there is not bson_data parameter callback will be called correctly and without bson_data parameter self.plugin.apply(self.callbacknobson, self.contextnobson)() self.callbacknobson.assert_called_once_with() def testNoContent(self): bottle.request.environ["CONTENT_LENGTH"] = 0 self.assertRaises(BSONBottlePluginException, self.plugin.apply(self.callback, self.context)) def testMaxContent(self): bottle.request.environ["CONTENT_LENGTH"] = ( BII_MAX_MEMORY_PER_REQUEST) + 1 self.assertRaises(BSONBottlePluginException, self.plugin.apply(self.callback, self.context)) def testAbortWithBSON(self): tmp = self.plugin.abort_with_bson(401, {"kk": 2}) self.assertIsInstance(tmp, HTTPResponse) self.assertEquals("application/bson", tmp.content_type) self.assertEquals(401, tmp.status_code) self.assertEquals(str(BSON.encode({"kk": 2})), tmp.body) def _callback(self, bson_data=""): logger.debug("Bson: " + str(bson_data)) pass def _callbackno(self): pass def __set_bson_content(self, data): bottle.request.environ['wsgi.input'] = str(BSON.encode(data)) bottle.request.environ["CONTENT_LENGTH"] = len( bottle.request.environ['wsgi.input']) bottle.request.body = Mock bottle.request.body.read = Mock( return_value=bottle.request.environ['wsgi.input'])
def install_plugins(self): self.bsonplugin = BSONBottlePlugin() # BiiResponse plugin. All rest methods has to return # (data serializable | None, biiresponse) or throw BiiServiceException subclass logger.info("Installing BiiReturnHandlerPlugin plugin...") self.biiresponseplugin = BiiReturnHandlerPlugin(self.bsonplugin) self.install(self.biiresponseplugin) # Very first of all, check SSL or die if BII_SSL_ENABLED: # In heroku true for all environments logger.info("Installing NonSSLBlockerBottlePlugin plugin...") nonsslblock = NonSSLBlockerBottlePlugin() self.install(nonsslblock) # First of all, check DOS attacks by IP to the API # Counts IP request, raise 401 if banned if getattr(self.store, 'ip_mc_collection', False): logger.info("Installing massive DOS blocker...") doslogin = DOSBlockerBottlePlugin(self.store.ip_mc_collection, delta=BII_DOS_ATTACK_DELTA_TIME, max_events=BII_DOS_ATTACK_MAX_REQUEST, bantime=BII_DOS_ATTACK_BAN_TIME, callback_ip_banned=self.callback_ip_banned_for_DOS, banned_http_response=self.banned_http_response_for_DOS) # TODO: Maybe configure a log alert (heroku) if we return 401 banned # to analyze the case and adjust limits? self.install(doslogin) # Second, check Http Basic auth logger.info("Installing http basic authentication plugin...") httpplugin = HttpBasicAuthenticationBottlePlugin() self.install(httpplugin) # And check auth JWT logger.info("Installing JWT authentication plugin...") jwt_manager = JWTCredentialsManagerFactory.new(self.store) jwt_plugin = JWTAuthenticationBottlePlugin(jwt_manager) self.install(jwt_plugin) # Third check excess of login error for an IP # Catch generic 401 (or 404 or other) error from authentication and stores IP, # raise 401 if already banned if getattr(self.store, 'ip_mc_collection', False): logger.info("Installing massive error blocker...") massiveerrorplugin = MassiveErrorBlockerBottlePlugin( self.store.ip_mc_collection, delta=BII_ERROR_ATTACK_DELTA_TIME, max_events=BII_ERROR_ATTACK_MAX_ATTEMPTS, bantime=BII_ERROR_ATTACK_BAN_TIME, callback_ip_banned=self.callback_ip_banned_for_many_errors, banned_http_response=self.banned_http_response_for_many_errors) self.install(massiveerrorplugin) # Last, parse BSON data logger.info("Installing bson plugin...") self.install(self.bsonplugin) # Logging actions if BII_ENABLED_BII_USER_TRACE: self.tracebottleplugin = BiiUserTraceBottlePlugin() logger.info("Installing BiiUserTraceBottlePlugin plugin...") self.install(self.tracebottleplugin)
class BsonBottleTest(unittest.TestCase): """Bottle plugin for automatic parse a BSON request and pass a """ def setUp(self): self.plugin = BSONBottlePlugin() self.ip = "84.34.13.122" self.callback = Mock(wraps=self._callback) self.callbacknobson = Mock(wraps=self._callbackno) bottle.request.environ['REMOTE_ADDR'] = self.ip bottle.request.environ['CONTENT_TYPE'] = 'application/bson' self.context = Mock() self.context.callback = self._callback self.contextnobson = Mock(wraps=self._callbackno) self.contextnobson.callback = self._callbackno self.__set_bson_content({"therivermen": "ehhhhhmacarena"}) def tearDown(self): pass def testAddOtherPluginWithSameKeywork(self): app = Mock() bad_plugin = Mock() bad_plugin.keyword = "bson_data" app.plugins = set([bad_plugin]) self.assertRaises(PluginError, self.plugin.setup, app) def testCallbackCalled(self): self.plugin.apply(self.callback, self.context)() self.assertTrue(self.callback.called) def testNotBsonRequest(self): bottle.request.environ['CONTENT_TYPE'] = 'mouse/mikey' self.assertRaises(BSONBottlePluginException, self.plugin.apply(self.callback, self.context)) def testNotBsonRequestWithNoBonDataParameter(self): bottle.request.environ['CONTENT_TYPE'] = 'mouse/mikey' # If there is not bson_data parameter callback will be called correctly and without bson_data parameter self.plugin.apply(self.callbacknobson, self.contextnobson)() self.callbacknobson.assert_called_once_with() def testNoContent(self): bottle.request.environ["CONTENT_LENGTH"] = 0 self.assertRaises(BSONBottlePluginException, self.plugin.apply(self.callback, self.context)) def testMaxContent(self): bottle.request.environ["CONTENT_LENGTH"] = (BII_MAX_MEMORY_PER_REQUEST) + 1 self.assertRaises(BSONBottlePluginException, self.plugin.apply(self.callback, self.context)) def testAbortWithBSON(self): tmp = self.plugin.abort_with_bson(401, {"kk": 2}) self.assertIsInstance(tmp, HTTPResponse) self.assertEquals("application/bson", tmp.content_type) self.assertEquals(401, tmp.status_code) self.assertEquals(str(BSON.encode({"kk": 2})), tmp.body) def _callback(self, bson_data=""): logger.debug("Bson: " + str(bson_data)) pass def _callbackno(self): pass def __set_bson_content(self, data): bottle.request.environ['wsgi.input'] = str(BSON.encode(data)) bottle.request.environ["CONTENT_LENGTH"] = len(bottle.request.environ['wsgi.input']) bottle.request.body = Mock bottle.request.body.read = Mock(return_value=bottle.request.environ['wsgi.input'])