def load(cls): cls.clear_instances() # First load builtin pages. Set username to '' for name, page_dict in cls.builtin_pages().items(): page_dict["owner"] = UserId(u'') # might have been forgotten on copy action page_dict["public"] = True page_dict["name"] = name new_page = cls(page_dict) cls.add_instance(("", name), new_page) # Now scan users subdirs for files "user_$type_name.mk" for user_dir in os.listdir(config.config_dir): user = UserId(ensure_unicode(user_dir)) try: path = "%s/%s/user_%ss.mk" % (config.config_dir, six.ensure_str(user), cls.type_name()) if not os.path.exists(path): continue if not userdb.user_exists(user): continue user_pages = store.load_object_from_file(path, default={}) for name, page_dict in user_pages.items(): page_dict["owner"] = user page_dict["name"] = name cls.add_instance((user, name), cls(page_dict)) except SyntaxError as e: raise MKGeneralException( _("Cannot load %s from %s: %s") % (cls.type_name(), path, e)) cls._load() cls._declare_instance_permissions()
def _check_parsed_auth_cookie(username: UserId, session_id: str, cookie_hash: str) -> None: if not userdb.user_exists(username): raise MKAuthException(_('Username is unknown')) if cookie_hash != _generate_auth_hash(username, session_id): raise MKAuthException(_('Invalid credentials'))
def _check_parsed_auth_cookie(username, issue_time, cookie_hash): # type: (UserId, float, str) -> None if not userdb.user_exists(username): raise MKAuthException(_('Username is unknown')) if cookie_hash != _generate_auth_hash(username, issue_time): raise MKAuthException(_('Invalid credentials'))
def _verify_user(environ: WSGIEnvironment, now: datetime) -> RFC7662: verified: List[RFC7662] = [] auth_header = environ.get("HTTP_AUTHORIZATION", "") basic_user = None if auth_header: auth_type, _ = auth_header.split(None, 1) if auth_type == "Bearer": user_id, secret = user_from_bearer_header(auth_header) automation_user = automation_auth(user_id, secret) if automation_user: verified.append(automation_user) else: # GUI user and Automation users are mutually exclusive. Checking only once is less # work for the system. gui_user = gui_user_auth(user_id, secret, now) if gui_user: verified.append(gui_user) elif auth_type == "Basic": # We store this for sanity checking below, once we get a REMOTE_USER key. # If we don't get a REMOTE_USER key, this value will be ignored. basic_user = user_from_basic_header(auth_header) else: raise MKAuthException(f"Unsupported Auth Type: {auth_type}") remote_user = environ.get("REMOTE_USER", "") if remote_user and userdb.user_exists(UserId(remote_user)): if basic_user and basic_user[0] != remote_user: raise MKAuthException("Mismatch in authentication headers.") verified.append(rfc7662_subject(UserId(remote_user), "web_server")) cookie = Request(environ).cookies.get(f"auth_{omd_site()}") if cookie: user_id, session_id, cookie_hash = user_from_cookie(cookie) check_parsed_auth_cookie(user_id, session_id, cookie_hash) verified.append(rfc7662_subject(user_id, "cookie")) if not verified: raise MKAuthException( "You need to be authenticated to use the REST API.") # We pick the first successful authentication method, which means the precedence is the same # as the order in the code. final_candidate = verified[0] user_id = final_candidate["sub"] if not userdb.is_customer_user_allowed_to_login(user_id): raise MKAuthException(f"{user_id} may not log in here.") if userdb.user_locked(user_id): raise MKAuthException(f"{user_id} not authorized.") if change_reason := userdb.need_to_change_pw(user_id, now): raise MKAuthException( f"{user_id} needs to change the password ({change_reason}).")
def test_check_credentials_local_user_create_htpasswd_user_ad_hoc() -> None: user_id = UserId("someuser") assert userdb.user_exists(user_id) is False assert userdb._user_exists_according_to_profile(user_id) is False assert user_id not in _load_users_uncached(lock=False) htpasswd.Htpasswd(Path(cmk.utils.paths.htpasswd_file)).save( {user_id: htpasswd.hash_password("cmk")}) # Once a user exists in the htpasswd, the GUI treats the user as existing user and will # automatically initialize the missing data structures assert userdb.user_exists(user_id) is True assert userdb._user_exists_according_to_profile(user_id) is False assert str(user_id) in _load_users_uncached(lock=False) assert userdb.check_credentials(user_id, "cmk") == user_id # Nothing changes during regular access assert userdb.user_exists(user_id) is True assert userdb._user_exists_according_to_profile(user_id) is False assert str(user_id) in _load_users_uncached(lock=False)
def _verify_user(environ) -> RFC7662: verified: List[RFC7662] = [] auth_header = environ.get('HTTP_AUTHORIZATION', '') basic_user = None if auth_header: auth_type, _ = auth_header.split(None, 1) if auth_type == 'Bearer': user_id, secret = user_from_bearer_header(auth_header) automation_user = automation_auth(user_id, secret) if automation_user: verified.append(automation_user) gui_user = gui_user_auth(user_id, secret) if gui_user: verified.append(gui_user) elif auth_type == 'Basic': # We store this for sanity checking below, once we get a REMOTE_USER key. # If we don't get a REMOTE_USER key, this value will be ignored. basic_user = user_from_basic_header(auth_header) else: raise MKAuthException(f"Unsupported Auth Type: {auth_type}") remote_user = environ.get('REMOTE_USER', '') if remote_user and userdb.user_exists(UserId(remote_user)): if basic_user and basic_user[0] != remote_user: raise MKAuthException("Mismatch in authentication headers.") verified.append(rfc7662_subject(UserId(remote_user), 'webserver')) cookie = Request(environ).cookies.get(f"auth_{omd_site()}") if cookie: user_id, session_id, cookie_hash = user_from_cookie(cookie) check_parsed_auth_cookie(user_id, session_id, cookie_hash) verified.append(rfc7662_subject(user_id, 'cookie')) if not verified: raise MKAuthException("You need to be authenticated to use the REST API.") # We pick the first successful authentication method, which means the precedence is the same # as the oder in the code. final_candidate = verified[0] if not userdb.is_customer_user_allowed_to_login(final_candidate['sub']): raise MKAuthException(f"{final_candidate['sub']} may not log in here.") if userdb.user_locked(final_candidate['sub']): raise MKAuthException(f"{final_candidate['sub']} not authorized.") return final_candidate
def _verify_user(environ) -> RFC7662: verified: List[RFC7662] = [] auth_header = environ.get('HTTP_AUTHORIZATION', '') if auth_header: user_id, secret = user_from_bearer_header(auth_header) automation_user = automation_auth(user_id, secret) gui_user = gui_user_auth(user_id, secret) if not (automation_user or gui_user): raise MKAuthException(f"{user_id} not authorized.") if automation_user: verified.append(automation_user) if gui_user: verified.append(gui_user) remote_user = environ.get('REMOTE_USER', '') if remote_user and userdb.user_exists(UserId(remote_user)): verified.append(rfc7662_subject(UserId(remote_user), 'webserver')) cookie = Request(environ).cookies.get(f"auth_{omd_site()}") if cookie: user_id, session_id, cookie_hash = user_from_cookie(cookie) check_parsed_auth_cookie(user_id, session_id, cookie_hash) verified.append(rfc7662_subject(user_id, 'cookie')) if not verified: raise MKAuthException( "You need to be authenticated to use the REST API.") # We pick the first successful authentication method, which means the precedence is the same # as the oder in the code. final_candidate = verified[0] if not userdb.is_customer_user_allowed_to_login(final_candidate['sub']): raise MKAuthException(f"{final_candidate['sub']} may not log in here.") if userdb.user_locked(final_candidate['sub']): raise MKAuthException(f"{final_candidate['sub']} not authorized.") return final_candidate
def is_relevant(self): return userdb.user_exists("omdadmin")
def is_relevant(self) -> bool: return userdb.user_exists(UserId("omdadmin"))
def check_parsed_auth_cookie(username, issue_time, cookie_hash): if not userdb.user_exists(username): raise MKAuthException(_('Username is unknown')) if cookie_hash != generate_auth_hash(username, issue_time): raise MKAuthException(_('Invalid credentials'))
def is_relevant(self): # type: () -> bool return userdb.user_exists(UserId("omdadmin"))
def execute_network_scan_job() -> None: init_wato_datastructures(with_wato_lock=True) if watolib.is_wato_slave_site(): return # Don't execute this job on slaves. folder = find_folder_to_scan() if not folder: return # Nothing to do. # We need to have the context of the user. The jobs are executed when # config.set_user_by_id() has not been executed yet. So there is no user context # available. Use the run_as attribute from the job config and revert # the previous state after completion. old_user = config.user.id run_as = folder.attribute("network_scan")["run_as"] if not userdb.user_exists(run_as): raise MKGeneralException( _("The user %s used by the network " "scan of the folder %s does not exist.") % (run_as, folder.title())) config.set_user_by_id(folder.attribute("network_scan")["run_as"]) result: NetworkScanResult = { "start": time.time(), "end": True, # means currently running "state": None, "output": "The scan is currently running.", } # Mark the scan in progress: Is important in case the request takes longer than # the interval of the cron job (1 minute). Otherwise the scan might be started # a second time before the first one finished. save_network_scan_result(folder, result) try: if config.site_is_local(folder.site_id()): found = cmk.gui.watolib.network_scan.do_network_scan(folder) else: found = watolib.do_remote_automation(config.site(folder.site_id()), "network-scan", [("folder", folder.path())]) if not isinstance(found, list): raise MKGeneralException(_("Received an invalid network scan result: %r") % found) add_scanned_hosts_to_folder(folder, found) result.update({ "state": True, "output": _("The network scan found %d new hosts.") % len(found), }) except Exception as e: result.update({ "state": False, "output": _("An exception occured: %s") % e, }) logger.error("Exception in network scan:\n%s", traceback.format_exc()) result["end"] = time.time() save_network_scan_result(folder, result) if old_user: config.set_user_by_id(old_user)
def execute_network_scan_job() -> None: """Executed by the multisite cron job once a minute. Is only executed in the central site. Finds the next folder to scan and starts it via WATO automation. The result is written to the folder in the master site.""" init_wato_datastructures(with_wato_lock=True) if is_wato_slave_site(): return # Don't execute this job on slaves. folder = _find_folder_to_scan() if not folder: return # Nothing to do. run_as = folder.attribute("network_scan")["run_as"] if not userdb.user_exists(run_as): raise MKGeneralException( _("The user %s used by the network " "scan of the folder %s does not exist.") % (run_as, folder.title())) with UserContext(run_as): result: NetworkScanResult = { "start": time.time(), "end": True, # means currently running "state": None, "output": "The scan is currently running.", } # Mark the scan in progress: Is important in case the request takes longer than # the interval of the cron job (1 minute). Otherwise the scan might be started # a second time before the first one finished. _save_network_scan_result(folder, result) try: if site_is_local(folder.site_id()): found = _do_network_scan(folder) else: found = do_remote_automation(get_site_config(folder.site_id()), "network-scan", [("folder", folder.path())]) if not isinstance(found, list): raise MKGeneralException( _("Received an invalid network scan result: %r") % found) _add_scanned_hosts_to_folder(folder, found) result.update({ "state": True, "output": _("The network scan found %d new hosts.") % len(found), }) except Exception as e: result.update({ "state": False, "output": _("An exception occured: %s") % e, }) logger.error("Exception in network scan:\n%s", traceback.format_exc()) result["end"] = time.time() _save_network_scan_result(folder, result)