def _handle_not_authenticated() -> Response: if fail_silently(): # While api call don't show the login dialog raise MKUnauthenticatedException(_("You are not authenticated.")) # Redirect to the login-dialog with the current url as original target # Never render the login form directly when accessing urls like "index.py" # or "dashboard.py". This results in strange problems. requested_file = requested_file_name(request) if requested_file != "login": post_login_url = makeuri(request, []) if requested_file != "index": # Ensure that users start with a navigation after they have logged in post_login_url = makeuri_contextless( request, [("start_url", post_login_url)], filename="index.py" ) raise HTTPRedirect( "%scheck_mk/login.py?_origtarget=%s" % (url_prefix(), urlencode(post_login_url)) ) # This either displays the login page or validates the information submitted # to the login form. After successful login a http redirect to the originally # requested page is performed. login_page = login.LoginPage() login_page.set_no_html_output(plain_error()) login_page.handle_page() return response
def page_login() -> None: title = _("Checkmk Mobile") mobile_html_head(title) jqm_page_header(title, id_="login") html.div(_("Welcome to Checkmk Mobile."), id_="loginhead") html.begin_form("login", method='POST', add_transid=False) # Keep information about original target URL default_origtarget = "index.py" if requested_file_name(request) in ["login", "logout" ] else makeuri(request, []) origtarget = request.get_url_input("_origtarget", default_origtarget) html.hidden_field('_origtarget', escaping.escape_attribute(origtarget)) html.text_input("_username", label=_("Username:"******"username", id_="input_user") html.password_input( "_password", size=None, label=_("Password:"******"current-password", id_="input_pass", ) html.br() html.button("_login", _('Login')) html.set_focus("_username") html.end_form() html.open_div(id_="loginfoot") html.img("themes/facelift/images/logo_cmk_small.png", class_="logomk") html.div(HTML(_("© <a target=\"_blank\" href=\"https://checkmk.com\">tribe29 GmbH</a>")), class_="copyright") html.close_div() # close content-div html.close_div() html.close_div() # close page-div mobile_html_foot()
def begin_form( self, name: str, action: Optional[str] = None, method: str = "GET", onsubmit: Optional[str] = None, add_transid: bool = True, ) -> None: self.form_name = name self.form_vars = [] self.form_has_submit_button = False if action is None: action = requested_file_name(self.request) + ".py" self.open_form( id_="form_%s" % name, name=name, class_=name, action=action, method=method, onsubmit=onsubmit, enctype="multipart/form-data" if method.lower() == "post" else None, ) session = request_local_attr("session") if hasattr(session, "session_info"): self.hidden_field("csrf_token", session.session_info.csrf_token) self.hidden_field("filled_in", name, add_var=True) if add_transid: self.hidden_field( "_transid", str(transactions.get()), add_var=True, )
def __init__( self, table_id: Optional[str] = None, title: Optional["HTMLContent"] = None, searchable: bool = True, sortable: bool = True, foldable: Foldable = Foldable.NOT_FOLDABLE, limit: Union[None, int, Literal[False]] = None, output_format: str = "html", omit_if_empty: bool = False, omit_empty_columns: bool = False, omit_headers: bool = False, omit_update_header: bool = False, empty_text: Optional[str] = None, help: Optional[str] = None, # pylint: disable=redefined-builtin css: Optional[str] = None, isopen: bool = True, ): super().__init__() self.next_func = lambda: None self.next_header: Optional[str] = None # Use our pagename as table id if none is specified table_id = table_id if table_id is not None else requested_file_name( request) assert table_id is not None # determine row limit if limit is None: limit = config.table_row_limit if request.get_ascii_input( "limit") == "none" or output_format != "html": limit = None self.id = table_id self.title = title self.rows: TableRows = [] self.limit = limit self.limit_reached = False self.limit_hint: Optional[int] = None self.headers: List[TableHeader] = [] self.options = { "collect_headers": False, # also: True, "finished" "omit_if_empty": omit_if_empty, "omit_empty_columns": omit_empty_columns, "omit_headers": omit_headers, "omit_update_header": omit_update_header, "searchable": searchable, "sortable": sortable, "foldable": foldable, "output_format": output_format, # possible: html, csv, fetch } self.empty_text = empty_text if empty_text is not None else _( "No entries.") self.help = help self.css = css self.mode = "row" self.isopen: Final = isopen
def _page_menu(self, breadcrumb) -> PageMenu: menu = make_simple_form_page_menu(_("Profile"), breadcrumb, form_name="profile", button_name="_save") menu.dropdowns.insert( 1, page_menu_dropdown_user_related(requested_file_name(request))) return menu
def load_all_plugins() -> None: # Optimization: in case of the graph ajax call only check the metrics module. This # improves the performance for these requests. # TODO: CLEANUP: Move this to the pagehandlers if this concept works out. # werkzeug.wrappers.Request.script_root would be helpful here, but we don't have that yet. only_modules = ["metrics" ] if requested_file_name(request) == "ajax_graph" else None modules.load_all_plugins(only_modules=only_modules)
def infos(self): # Hack for create mode of dashlet editor. The user first selects a datasource and then the # single contexts, the dashlet editor needs to use these information. if requested_file_name(request) == "edit_dashlet" and request.has_var( "datasource"): ds_name = request.get_str_input_mandatory("datasource") return views.data_source_registry[ds_name]().infos return self._get_infos_from_view_spec(self._dashlet_spec)
def _process_request( environ: WSGIEnvironment, start_response: StartResponse, debug: bool = False, ) -> WSGIResponse: # pylint: disable=too-many-branches resp: Response try: page_handler = get_and_wrap_page(requested_file_name(request)) resp = page_handler() except HTTPRedirect as e: # This can't be a new Response as it can have already cookies set/deleted by the pages. # We can't return the response because the Exception has been raised instead. # TODO: Remove all HTTPRedirect exceptions from all pages. Making the Exception a subclass # of Response may also work as it can then be directly returned from here. resp = response resp.status_code = e.status resp.headers["Location"] = e.url except FinalizeRequest as e: # TODO: Remove all FinalizeRequest exceptions from all pages and replace it with a `return`. # It may be necessary to rewire the control-flow a bit as this exception could have # been used to short-circuit some code and jump directly to the response. This # needs to be changed as well. resp = response resp.status_code = e.status except livestatus.MKLivestatusNotFoundError as e: resp = _render_exception(e, title=_("Data not found")) except MKUserError as e: resp = _render_exception(e, title=_("Invalid user input")) except MKAuthException as e: resp = _render_exception(e, title=_("Permission denied")) except livestatus.MKLivestatusException as e: resp = _render_exception(e, title=_("Livestatus problem")) resp.status_code = http_client.BAD_GATEWAY except MKUnauthenticatedException as e: resp = _render_exception(e, title=_("Not authenticated")) resp.status_code = http_client.UNAUTHORIZED except MKConfigError as e: resp = _render_exception(e, title=_("Configuration error")) logger.error("MKConfigError: %s", e) except (MKGeneralException, cmk.utils.store.MKConfigLockTimeout) as e: resp = _render_exception(e, title=_("General error")) logger.error("%s: %s", e.__class__.__name__, e) except Exception: resp = handle_unhandled_exception() if debug: raise return resp(environ, start_response)
def _renew_cookie(cookie_name: str, username: UserId, session_id: str) -> None: # Do not renew if: # a) The _ajaxid var is set # b) A logout is requested requested_file = requested_file_name(request) if (requested_file != "logout" and not request.has_var("_ajaxid") ) and cookie_name == auth_cookie_name(): auth_logger.debug("Renewing auth cookie (%s.py, vars: %r)" % (requested_file, dict(request.itervars()))) _renew_auth_session(username, session_id)
def _redirect_for_two_factor_authentication(user_id: UserId) -> None: if requested_file_name(request) in ( "user_login_two_factor", "user_webauthn_login_begin", "user_webauthn_login_complete", ): return if userdb.is_two_factor_login_enabled( user_id) and not userdb.is_two_factor_completed(): raise HTTPRedirect("user_login_two_factor.py?_origtarget=%s" % urlencode(makeuri(request, [])))
def default_response_headers(req: http.Request) -> Dict[str, str]: headers = { # Disable caching for all our pages as they are mostly dynamically generated, # user related and are required to be up-to-date on every refresh "Cache-Control": "no-cache", } # Would be better to put this to page individual code, but we currently have # no mechanism for a page to set do this before the authentication is made. if requested_file_name(req) == "webapi": headers["Access-Control-Allow-Origin"] = "*" return headers
def from_exception(cls, details=None, type_specific_attributes=None): return super().from_exception( details={ "page": requested_file_name(request) + ".py", "vars": { key: "***" if value in ["password", "_password"] else value for key, value in request.itervars() }, "username": user.id, "user_agent": request.user_agent.string, "referer": request.referer, "is_mobile": is_mobile(request, response), "is_ssl_request": request.is_ssl_request, "language": cmk.gui.i18n.get_current_language(), "request_method": request.request_method, }, )
def _check_auth_cookie(cookie_name: str) -> Optional[UserId]: username, session_id, cookie_hash = user_from_cookie( _fetch_cookie(cookie_name)) check_parsed_auth_cookie(username, session_id, cookie_hash) try: userdb.on_access(username, session_id) except MKAuthException: del_auth_cookie() raise # Once reached this the cookie is a good one. Renew it! _renew_cookie(cookie_name, username, session_id) if requested_file_name(request) != "user_change_pw": result = userdb.need_to_change_pw(username) if result: raise HTTPRedirect("user_change_pw.py?_origtarget=%s&reason=%s" % (urlencode(makeuri(request, [])), result)) # Return the authenticated username return username
def plain_error() -> bool: """Webservice functions may decide to get a normal result code but a text with an error message in case of an error""" return request.has_var("_plain_error") or requested_file_name(request) == "webapi"
def _show_login_page(self) -> None: html.set_render_headfoot(False) html.add_body_css_class("login") html.header(get_page_heading(), Breadcrumb(), javascripts=[]) default_origtarget = ("index.py" if requested_file_name(request) in ["login", "logout"] else makeuri(request, [])) origtarget = request.get_url_input("_origtarget", default_origtarget) # Never allow the login page to be opened in the iframe. Redirect top page to login page. # This will result in a full screen login page. html.javascript("""if(top != self) { window.top.location.href = location; }""") # When someone calls the login page directly and is already authed redirect to main page if requested_file_name(request) == "login" and _check_auth(request): raise HTTPRedirect(origtarget) html.open_div(id_="login") html.open_div(id_="login_window") html.open_a(href="https://checkmk.com") html.img( src=theme.detect_icon_path(icon_name="logo", prefix="mk-"), id_="logo", class_="custom" if theme.has_custom_logo() else None, ) html.close_a() html.begin_form("login", method="POST", add_transid=False, action="login.py") html.hidden_field("_login", "1") html.hidden_field("_origtarget", origtarget) html.label("%s:" % _("Username"), id_="label_user", class_=["legend"], for_="_username") html.br() html.text_input("_username", id_="input_user") html.label("%s:" % _("Password"), id_="label_pass", class_=["legend"], for_="_password") html.br() html.password_input("_password", id_="input_pass", size=None) if user_errors: html.open_div(id_="login_error") html.show_user_errors() html.close_div() html.open_div(id_="button_text") html.button("_login", _("Login"), cssclass="hot") html.close_div() html.close_div() html.open_div(id_="foot") if config.login_screen.get("login_message"): html.open_div(id_="login_message") html.show_message(config.login_screen["login_message"]) html.close_div() footer: List[HTML] = [] for title, url, target in config.login_screen.get("footer_links", []): footer.append(html.render_a(title, href=url, target=target)) if "hide_version" not in config.login_screen: footer.append(escape_html("Version: %s" % cmk_version.__version__)) footer.append( HTML("© %s" % html.render_a( "tribe29 GmbH", href="https://tribe29.com", target="_blank"))) html.write_html(HTML(" - ").join(footer)) if cmk_version.is_raw_edition(): html.br() html.br() html.write_text( _('You can use, modify and distribute Check_MK under the terms of the <a href="%s" target="_blank">' "GNU GPL Version 2</a>.") % "https://checkmk.com/gpl.html") html.close_div() html.set_focus("_username") html.hidden_fields() html.end_form() html.close_div() html.footer()
def _redirect_for_password_change(user_id: UserId) -> None: if requested_file_name(request) != "user_change_pw": result = userdb.need_to_change_pw(user_id) if result: raise HTTPRedirect("user_change_pw.py?_origtarget=%s&reason=%s" % (urlencode(makeuri(request, [])), result))