def test_logged_in_nobody_permissions(mocker): user = LoggedInNobody() mocker.patch.object(config, "roles", {}) mocker.patch.object(permissions, "permission_registry") assert user.may("any_permission") is False with pytest.raises(MKAuthException): user.need_permission("any_permission")
def test_dcd_not_found_if_not_super_user( self, monkeypatch: MonkeyPatch, mock_livestatus: MockLiveStatusConnection, ): """ This test ensures that test_index_is_built_as_super_user makes sense, ie. that if we do not build as a super user, the entry "Custom host attributes" is not found. """ @contextmanager def SuperUserContext() -> Iterator[None]: yield monkeypatch.setattr( search, "SuperUserContext", SuperUserContext, ) with _UserContext(LoggedInNobody()): builder = IndexBuilder(real_match_item_generator_registry) with self._livestatus_mock(mock_livestatus): builder.build_full_index() searcher = IndexSearcher() searcher._redis_client = builder._redis_client assert not list(searcher.search("custom host attributes"))
def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> WSGIResponse: req = http.Request(environ) output_format = get_output_format( req.get_ascii_input_mandatory("output_format", "html").lower()) mime_type = get_mime_type_from_output_format(output_format) resp = Response(headers=default_response_headers(req), mimetype=mime_type) funnel = OutputFunnel(resp) timeout_manager = TimeoutManager() timeout_manager.enable_timeout(req.request_timeout) theme = Theme() config_obj = config_module.make_config_object( config_module.get_default_config()) with AppContext(self), RequestContext( req=req, resp=resp, funnel=funnel, config_obj=config_obj, user=LoggedInNobody(), html_obj=htmllib.html(req, resp, funnel, output_format), timeout_manager=timeout_manager, display_options=DisplayOptions(), theme=theme, ), patch_json(json): config_module.initialize() theme.from_config(config.ui_theme) return self.wsgi_app(environ, start_response)
def __init__( self, req: http.Request, resp: http.Response, funnel: OutputFunnel, config_obj: Config, html_obj: Optional[htmllib.html] = None, timeout_manager: Optional[TimeoutManager] = None, # pylint: disable=redefined-outer-name theme: Optional[Theme] = None, # pylint: disable=redefined-outer-name display_options: Optional[DisplayOptions] = None, # pylint: disable=redefined-outer-name prefix_logs_with_url: bool = True, ): self.html = html_obj self.auth_type: Optional[str] = None self.timeout_manager = timeout_manager self.theme = theme self.display_options = display_options self.session: Optional[userdb.Session] = None self.flashes: Optional[List[str]] = None self._prefix_logs_with_url = prefix_logs_with_url self.request = req self.response = resp self.output_funnel = funnel self.config = config_obj # TODO: cyclical import with config -> globals -> config -> ... from cmk.gui.utils.logged_in import LoggedInNobody self._user: LoggedInUser = LoggedInNobody() # TODO: This needs to be a helper of LoggedInUser self.transactions = TransactionManager(req, self._user) self.user_errors = UserErrors() self._prepend_url_filter = _PrependURLFilter() self._web_log_handler: Optional[logging.Handler] = None
def mock_livestatus( with_context: bool = False, with_html: bool = False ) -> Generator[MockLiveStatusConnection, None, None]: live = MockLiveStatusConnection() env = EnvironBuilder().get_environ() req = http.Request(env) resp = http.Response() app_context: ContextManager req_context: ContextManager if with_html: html_obj = None else: html_obj = html( request=req, response=resp, output_funnel=OutputFunnel(resp), output_format="html", ) if with_context: app_context = AppContext(None) req_context = RequestContext( html_obj=html_obj, req=req, resp=resp, funnel=OutputFunnel(resp), config_obj=make_config_object(get_default_config()), user=LoggedInNobody(), display_options=DisplayOptions(), prefix_logs_with_url=False, ) else: app_context = contextlib.nullcontext() req_context = contextlib.nullcontext() with app_context, req_context, mock.patch( "cmk.gui.sites._get_enabled_and_disabled_sites", new=live.enabled_and_disabled_sites), mock.patch( "livestatus.MultiSiteConnection.expect_query", new=live.expect_query, create=True), mock.patch( "livestatus.SingleSiteConnection._create_socket", new=live.create_socket), mock.patch.dict( os.environ, { "OMD_ROOT": "/", "OMD_SITE": "NO_SITE" }): # We don't want to be polluted by other tests. omd_site.cache_clear() yield live # We don't want to pollute other tests. omd_site.cache_clear()
def with_request_context(): environ = create_environ() resp = Response() with AppContext(session_wsgi_app(debug=False)), RequestContext( req=Request(environ), resp=resp, funnel=OutputFunnel(resp), config_obj=make_config_object(get_default_config()), user=LoggedInNobody(), display_options=DisplayOptions(), ): yield
def with_context(environ, start_response): req = http.Request(environ) resp = http.Response() with AppContext(app), RequestContext( req=req, resp=resp, funnel=OutputFunnel(resp), config_obj=config.make_config_object( config.get_default_config()), user=LoggedInNobody(), display_options=DisplayOptions(), ), cmk.utils.store.cleanup_locks(), sites.cleanup_connections(): config.initialize() return app(environ, start_response)
def make_request_context( environ: Optional[Mapping[str, Any]] = None) -> RequestContext: req = Request( dict(create_environ(), REQUEST_URI="") if environ is None else environ) resp = Response(mimetype="text/html") funnel = OutputFunnel(resp) return RequestContext( req=req, resp=resp, funnel=funnel, config_obj=make_config_object(get_default_config()), user=LoggedInNobody(), html_obj=html(req, resp, funnel, output_format="html"), display_options=DisplayOptions(), timeout_manager=TimeoutManager(), theme=Theme(), prefix_logs_with_url=False, )
def test_index_is_built_as_super_user( self, mock_livestatus: MockLiveStatusConnection, ): """ We test that the index is always built as a super user. """ with _UserContext(LoggedInNobody()): builder = IndexBuilder(real_match_item_generator_registry) with self._livestatus_mock(mock_livestatus): builder.build_full_index() searcher = IndexSearcher() searcher._redis_client = builder._redis_client # if the search index did not internally use the super user while building, this item would # be missing, because the match item generator for the setup menu only yields entries which # the current user is allowed to see assert list(searcher.search("custom host attributes"))
with UserContext(first_user_id): assert global_user.id == first_user_id with UserContext(second_user_id): assert global_user.id == second_user_id assert global_user.id == first_user_id assert global_user.id is None @pytest.mark.parametrize( "user, alias, email, role_ids, baserole_id", [ ( LoggedInNobody(), "Unauthenticated user", "nobody", [], "guest", # TODO: Why is this guest "guest"? ), ( LoggedInSuperUser(), "Superuser for unauthenticated pages", "admin", ["admin"], "admin", ), ], ) def test_unauthenticated_users(user, alias, email, role_ids, baserole_id):
def _wsgi_app(self, environ: WSGIEnvironment, start_response: StartResponse) -> WSGIResponse: urls = self.url_map.bind_to_environ(environ) endpoint: Optional[Endpoint] = None try: result: Tuple[str, Mapping[str, Any]] = urls.match(return_rule=False) endpoint_ident, matched_path_args = result # pylint: disable=unpacking-non-sequence wsgi_app = self.endpoints[endpoint_ident] if isinstance(wsgi_app, Authenticate): endpoint = wsgi_app.endpoint # Remove _path again (see Submount above), so the validators don't go crazy. path_args = {key: value for key, value in matched_path_args.items() if key != "_path"} # This is an implicit dependency, as we only know the args at runtime, but the # function at setup-time. environ[ARGS_KEY] = path_args req = Request(environ) resp = Response() with AppContext(self), RequestContext( req=req, resp=resp, funnel=OutputFunnel(resp), config_obj=config.make_config_object(config.get_default_config()), endpoint=endpoint, user=LoggedInNobody(), display_options=DisplayOptions(), ), cmk.utils.store.cleanup_locks(), sites.cleanup_connections(): config.initialize() load_dynamic_permissions() return wsgi_app(environ, start_response) except ProblemException as exc: return exc(environ, start_response) except HTTPException as exc: # We don't want to log explicit HTTPExceptions as these are intentional. assert isinstance(exc.code, int) return problem( status=exc.code, title=http.client.responses[exc.code], detail=str(exc), )(environ, start_response) except MKException as exc: if self.debug: raise return problem( status=EXCEPTION_STATUS.get(type(exc), 500), title="An exception occurred.", detail=str(exc), )(environ, start_response) except Exception as exc: crash = APICrashReport.from_exception() crash_reporting.CrashReportStore().save(crash) logger.exception("Unhandled exception (Crash-ID: %s)", crash.ident_to_text()) if self.debug: raise request = Request(environ) site = config.omd_site() query_string = urllib.parse.urlencode( [ ("crash_id", (crash.ident_to_text())), ("site", site), ] ) crash_url = f"{request.host_url}{site}/check_mk/crash.py?{query_string}" crash_details = { "crash_id": (crash.ident_to_text()), "crash_report": { "href": crash_url, "method": "get", "rel": "cmk/crash-report", "type": "text/html", }, } if user.may("general.see_crash_reports"): crash_details["stack_trace"] = traceback.format_exc().split("\n") return problem( status=500, title=http.client.responses[500], detail=str(exc), ext=crash_details, )(environ, start_response)