def test_ip_untrusted_identification_same_connection(self): identification = IpBasedIdentification([]) request_handler = mock_request_handler(ip='192.168.21.13') id1 = identification.identify(request_handler) id2 = identification.identify(request_handler) self.assertEqual(id1, id2)
def test_proxied_ip_behind_untrusted(self): identification = IpBasedIdentification([]) request_handler = mock_request_handler(ip='127.0.0.1', x_forwarded_for='192.168.21.13') id = identification.identify(request_handler) self.assertNotEqual('192.168.21.13', id) self.assertNotEqual('127.0.0.1', id)
def test_ip_untrusted_identification_for_different_connections(self): identification = IpBasedIdentification([]) ids = set() for _ in range(0, 100): ids.add(identification.identify(mock_request_handler(ip='192.168.21.13'))) self.assertEqual(100, len(ids))
def test_change_to_trusted(self): request_handler = mock_request_handler(ip='192.168.21.13') old_id = IpBasedIdentification([]).identify(request_handler) trusted_identification = IpBasedIdentification(['192.168.21.13']) new_id = trusted_identification.identify(request_handler) self.assertNotEqual(old_id, new_id) self.assertEqual(new_id, '192.168.21.13') self.assertIsNone(request_handler.get_cookie(COOKIE_KEY))
def test_refresh_old_cookie_with_same_id(self): request_handler = mock_request_handler(ip='192.168.21.13') identification = IpBasedIdentification([]) id = '1234567' token_expiry = str(date_utils.get_current_millis() + date_utils.days_to_ms(2)) old_token = id + '&' + token_expiry request_handler.set_secure_cookie(COOKIE_KEY, old_token) new_id = identification.identify(request_handler) new_token = request_handler.get_cookie(COOKIE_KEY) self.assertEqual(new_id, id) self.assertNotEqual(old_token, new_token)
def test_broken_token_structure(self): request_handler = mock_request_handler(ip='192.168.21.13') request_handler.set_secure_cookie(COOKIE_KEY, 'something') IpBasedIdentification([]).identify(request_handler) new_token = request_handler.get_cookie(COOKIE_KEY) self.assertNotEqual(new_token, 'something')
def test_old_token_timestamp(self): request_handler = mock_request_handler(ip='192.168.21.13') request_handler.set_secure_cookie(COOKIE_KEY, 'something&100000') id = IpBasedIdentification([]).identify(request_handler) new_token = request_handler.get_cookie(COOKIE_KEY) self.assertNotEqual('something', id) self.assertNotEqual(new_token, 'something&100000')
def test_broken_token_timestamp(self): request_handler = mock_request_handler(ip='192.168.21.13') request_handler.set_secure_cookie(COOKIE_KEY, 'something&hello') id = IpBasedIdentification(TrustedIpValidator([]), None).identify(request_handler) new_token = request_handler.get_cookie(COOKIE_KEY) self.assertNotEqual('something', id) self.assertNotEqual(new_token, 'something&hello')
def setUp(self): super().setUp() self.socket = None application = tornado.web.Application( [(r'/scripts/([^/]*)', ScriptConfigSocket)], login_url='/login.html', cookie_secret='12345') application.auth = TornadoAuth(None) application.authorizer = Authorizer(ANY_USER, [], [], EmptyGroupProvider()) application.identification = IpBasedIdentification( TrustedIpValidator(['127.0.0.1']), None) application.config_service = ConfigService(application.authorizer, test_utils.temp_folder) server = httpserver.HTTPServer(application) socket, self.port = testing.bind_unused_port() server.add_socket(socket) test_utils.setup() for dir in ['x', 'y', 'z']: for file in range(1, 4): filename = dir + str(file) + '.txt' test_utils.create_file( os.path.join('test1_files', dir, filename)) test1_files_path = os.path.join(test_utils.temp_folder, 'test1_files') test_utils.write_script_config( { 'name': 'Test script 1', 'script_path': 'ls', 'parameters': [ test_utils.create_script_param_config('text 1', required=True), test_utils.create_script_param_config( 'list 1', type='list', allowed_values=['A', 'B', 'C']), test_utils.create_script_param_config( 'file 1', type='server_file', file_dir=test1_files_path), test_utils.create_script_param_config( 'list 2', type='list', values_script='ls ' + test1_files_path + '/${file 1}') ] }, 'test_script_1')
def mock_request_handler(ip=None, x_forwarded_for=None, x_real_ip=None, saved_token=None, user_header_name=None, user_header_name_value=None): handler_mock = mock_object() handler_mock.application = mock_object() handler_mock.application.auth = TornadoAuth(None) handler_mock.application.identification = IpBasedIdentification( ['127.0.0.1'], user_header_name) handler_mock.request = mock_object() handler_mock.request.headers = {} handler_mock.request.remote_ip = ip if x_forwarded_for: handler_mock.request.headers['X-Forwarded-For'] = x_forwarded_for if x_real_ip: handler_mock.request.headers['X-Real-IP'] = x_real_ip if user_header_name and user_header_name_value: handler_mock.request.headers[user_header_name] = user_header_name_value cookies = {COOKIE_KEY: saved_token} def get_secure_cookie(name): values = cookies[name] if values is not None: return values.encode('utf8') return None def set_secure_cookie(key, value, expires_days=30): cookies[key] = value def clear_cookie(key): if cookies[key] is not None: cookies[key] = None handler_mock.get_cookie = lambda key: cookies[key] handler_mock.get_secure_cookie = get_secure_cookie handler_mock.set_secure_cookie = set_secure_cookie handler_mock.clear_cookie = clear_cookie return handler_mock
def test_no_cookie_change_for_same_user(self): request_handler = mock_request_handler(ip='192.168.21.13') identification = IpBasedIdentification([]) identification.identify(request_handler) cookie1 = request_handler.get_cookie(COOKIE_KEY) identification.identify(request_handler) cookie2 = request_handler.get_cookie(COOKIE_KEY) self.assertEqual(cookie1, cookie2)
def init(server_config: ServerConfig, authenticator, authorizer, execution_service: ExecutionService, execution_logging_service: ExecutionLoggingService, config_service: ConfigService, alerts_service: AlertsService, file_upload_feature: FileUploadFeature, file_download_feature: FileDownloadFeature, secret, server_version): ssl_context = None if server_config.is_ssl(): ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_context.load_cert_chain(server_config.get_ssl_cert_path(), server_config.get_ssl_key_path()) auth = TornadoAuth(authenticator) if auth.is_enabled(): identification = AuthBasedIdentification(auth) else: identification = IpBasedIdentification(server_config.trusted_ips, server_config.user_header_name) downloads_folder = file_download_feature.get_result_files_folder() handlers = [ (r'/conf', GetServerConf), (r'/scripts', GetScripts), (r'/scripts/([^/]*)', ScriptConfigSocket), (r'/scripts/([^/]*)/([^/]*)/list-files', ScriptParameterListFiles), (r'/executions/start', ScriptExecute), (r'/executions/stop/(.*)', ScriptStop), (r'/executions/kill/(.*)', ScriptKill), (r'/executions/io/(.*)', ScriptStreamSocket), (r'/executions/active', GetActiveExecutionIds), (r'/executions/config/(.*)', GetExecutingScriptConfig), (r'/executions/cleanup/(.*)', CleanupExecutingScript), (r'/executions/status/(.*)', GetExecutionStatus), (r'/admin/execution_log/short', GetShortHistoryEntriesHandler), (r'/admin/execution_log/long/(.*)', GetLongHistoryEntryHandler), (r'/auth/info', AuthInfoHandler), (r'/result_files/(.*)', DownloadResultFile, { 'path': downloads_folder }), (r"/", ProxiedRedirectHandler, { "url": "/index.html" }) ] if auth.is_enabled(): handlers.append((r'/login', LoginHandler)) handlers.append((r'/auth/config', AuthConfigHandler)) handlers.append((r'/logout', LogoutHandler)) handlers.append((r"/(.*)", AuthorizedStaticFileHandler, {"path": "web"})) settings = { "cookie_secret": secret, "login_url": "/login.html", 'websocket_ping_interval': 30, 'websocket_ping_timeout': 300 } application = tornado.web.Application(handlers, **settings) application.auth = auth application.server_config = server_config application.server_version = server_version application.authorizer = authorizer application.downloads_folder = downloads_folder application.file_download_feature = file_download_feature application.file_upload_feature = file_upload_feature application.execution_service = execution_service application.execution_logging_service = execution_logging_service application.config_service = config_service application.alerts_service = alerts_service application.identification = identification application.max_request_size_mb = server_config.max_request_size_mb io_loop = tornado.ioloop.IOLoop.current() http_server = httpserver.HTTPServer(application, ssl_options=ssl_context, max_buffer_size=10 * BYTES_IN_MB) http_server.listen(server_config.port, address=server_config.address) intercept_stop_when_running_scripts(io_loop, execution_service) http_protocol = 'https' if server_config.ssl else 'http' print('Server is running on: %s://%s:%s' % (http_protocol, server_config.address, server_config.port)) io_loop.start()
def init(server_config: ServerConfig, authenticator, authorizer, execution_service: ExecutionService, schedule_service: ScheduleService, execution_logging_service: ExecutionLoggingService, config_service: ConfigService, alerts_service: AlertsService, file_upload_feature: FileUploadFeature, file_download_feature: FileDownloadFeature, secret, server_version, conf_folder, *, start_server=True): ssl_context = None if server_config.is_ssl(): ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_context.load_cert_chain(server_config.get_ssl_cert_path(), server_config.get_ssl_key_path()) auth = TornadoAuth(authenticator) if auth.is_enabled(): identification = AuthBasedIdentification(auth) else: identification = IpBasedIdentification(server_config.ip_validator, server_config.user_header_name) downloads_folder = file_download_feature.get_result_files_folder() handlers = [(r'/conf', GetServerConf), (r'/scripts', GetScripts), (r'/scripts/([^/]*)', ScriptConfigSocket), (r'/scripts/([^/]*)/([^/]*)/list-files', ScriptParameterListFiles), (r'/executions/start', ScriptExecute), (r'/executions/stop/(.*)', ScriptStop), (r'/executions/kill/(.*)', ScriptKill), (r'/executions/io/(.*)', ScriptStreamSocket), (r'/executions/active', GetActiveExecutionIds), (r'/executions/config/(.*)', GetExecutingScriptConfig), (r'/executions/cleanup/(.*)', CleanupExecutingScript), (r'/executions/status/(.*)', GetExecutionStatus), (r'/history/execution_log/short', GetShortHistoryEntriesHandler), (r'/history/execution_log/long/(.*)', GetLongHistoryEntryHandler), (r'/schedule', AddSchedule), (r'/auth/info', AuthInfoHandler), (r'/result_files/(.*)', DownloadResultFile, {'path': downloads_folder}), (r'/admin/scripts', AdminUpdateScriptEndpoint), (r'/admin/scripts/(.*)', AdminGetScriptEndpoint), (r"/", ProxiedRedirectHandler, {"url": "/index.html"})] if auth.is_enabled(): handlers.append((r'/login', LoginHandler)) handlers.append((r'/auth/config', AuthConfigHandler)) handlers.append((r'/logout', LogoutHandler)) handlers.append((r'/theme/(.*)', ThemeStaticFileHandler, {'path': os.path.join(conf_folder, 'theme')})) handlers.append((r"/(.*)", AuthorizedStaticFileHandler, {"path": "web"})) settings = { "cookie_secret": secret, "login_url": "/login.html", 'websocket_ping_interval': 30, 'websocket_ping_timeout': 300, 'compress_response': True, 'xsrf_cookies': server_config.xsrf_protection != XSRF_PROTECTION_DISABLED, } application = tornado.web.Application(handlers, **settings) autoapply_xheaders(application) application.auth = auth application.server_config = server_config application.server_version = server_version application.authorizer = authorizer application.downloads_folder = downloads_folder application.file_download_feature = file_download_feature application.file_upload_feature = file_upload_feature application.execution_service = execution_service application.schedule_service = schedule_service application.execution_logging_service = execution_logging_service application.config_service = config_service application.alerts_service = alerts_service application.identification = identification application.max_request_size_mb = server_config.max_request_size_mb if os_utils.is_win() and env_utils.is_min_version('3.8'): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) io_loop = tornado.ioloop.IOLoop.current() global _http_server _http_server = httpserver.HTTPServer( application, ssl_options=ssl_context, max_buffer_size=10 * BYTES_IN_MB) _http_server.listen(server_config.port, address=server_config.address) intercept_stop_when_running_scripts(io_loop, execution_service) http_protocol = 'https' if server_config.ssl else 'http' print('Server is running on: %s://%s:%s' % (http_protocol, server_config.address, server_config.port)) if start_server: io_loop.start()
def test_some_ip_trusted_identification(self): identification = IpBasedIdentification(['192.168.21.13'], None) id = identification.identify(mock_request_handler(ip='192.168.21.13')) self.assertEqual('192.168.21.13', id)
def test_ip_untrusted_identification(self): identification = IpBasedIdentification([]) id = identification.identify(mock_request_handler(ip='192.168.21.13')) self.assertNotEqual('192.168.21.13', id)
def test_localhost_ip_trusted_identification(self): identification = IpBasedIdentification(['127.0.0.1']) id = identification.identify(mock_request_handler(ip='127.0.0.1')) self.assertEqual('127.0.0.1', id)
def test_proxied_ip_behind_trusted(self): identification = IpBasedIdentification(TrustedIpValidator(['127.0.0.1']), None) request_handler = mock_request_handler(ip='127.0.0.1', x_forwarded_for='192.168.21.13') id = identification.identify(request_handler) self.assertEqual('192.168.21.13', id)