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 _do_login(self) -> None: """handle the sent login form""" if not html.request.var('_login'): return try: if not config.user_login: raise MKUserError(None, _('Login is not allowed on this site.')) username_var = html.request.get_unicode_input('_username', '') assert username_var is not None username = UserId(username_var.rstrip()) if not username: raise MKUserError('_username', _('No username given.')) password = html.request.var('_password', '') if not password: raise MKUserError('_password', _('No password given.')) default_origtarget = config.url_prefix() + "check_mk/" origtarget = html.get_url_input("_origtarget", default_origtarget) # Disallow redirections to: # - logout.py: Happens after login # - side.py: Happens when invalid login is detected during sidebar refresh if "logout.py" in origtarget or 'side.py' in origtarget: origtarget = default_origtarget result = userdb.check_credentials(username, password) if result: # use the username provided by the successful login function, this function # might have transformed the username provided by the user. e.g. switched # from mixed case to lower case. username = result session_id = userdb.on_succeeded_login(username) # The login succeeded! Now: # a) Set the auth cookie # b) Unset the login vars in further processing # c) Redirect to really requested page _create_auth_session(username, session_id) # Never use inplace redirect handling anymore as used in the past. This results # in some unexpected situations. We simpy use 302 redirects now. So we have a # clear situation. # userdb.need_to_change_pw returns either False or the reason description why the # password needs to be changed change_pw_result = userdb.need_to_change_pw(username) if change_pw_result: raise HTTPRedirect( 'user_change_pw.py?_origtarget=%s&reason=%s' % (html.urlencode(origtarget), change_pw_result)) raise HTTPRedirect(origtarget) userdb.on_failed_login(username) raise MKUserError(None, _('Invalid credentials.')) except MKUserError as e: html.add_user_error(e.varname, e)
def _check_auth_cookie(cookie_name: str) -> Optional[UserId]: username, issue_time, cookie_hash = _parse_auth_cookie(cookie_name) _check_parsed_auth_cookie(username, issue_time, cookie_hash) # Check whether or not there is an idle timeout configured, delete cookie and # require the user to renew the log when the timeout exceeded. if userdb.login_timed_out(username, issue_time): del_auth_cookie() return None # Check whether or not a single user session is allowed at a time and the user # is doing this request with the currently active session. if config.single_user_session is not None: session_id = _get_session_id_from_cookie(username) if not userdb.is_valid_user_session(username, session_id): del_auth_cookie() return None # Once reached this the cookie is a good one. Renew it! _renew_cookie(cookie_name, username) if html.myfile != 'user_change_pw': result = userdb.need_to_change_pw(username) if result: raise HTTPRedirect('user_change_pw.py?_origtarget=%s&reason=%s' % (html.urlencode(html.makeuri([])), result)) # Return the authenticated username return username
def _check_auth_cookie(cookie_name: str) -> Optional[UserId]: username, session_id, cookie_hash = _parse_auth_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 html.myfile != 'user_change_pw': result = userdb.need_to_change_pw(username) if result: raise HTTPRedirect('user_change_pw.py?_origtarget=%s&reason=%s' % (html.urlencode(html.makeuri([])), result)) # Return the authenticated username return username
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 do_login(): # handle the sent login form if html.request.var('_login'): try: username = html.get_unicode_input('_username', '').rstrip() if username == '': raise MKUserError('_username', _('No username given.')) password = html.request.var('_password', '') if password == '': raise MKUserError('_password', _('No password given.')) default_origtarget = config.url_prefix() + "check_mk/" origtarget = html.get_url_input("_origtarget", default_origtarget) # Disallow redirections to: # - logout.py: Happens after login # - side.py: Happens when invalid login is detected during sidebar refresh if "logout.py" in origtarget or 'side.py' in origtarget: origtarget = default_origtarget # None -> User unknown, means continue with other connectors # '<user_id>' -> success # False -> failed result = userdb.hook_login(username, password) if result: # use the username provided by the successful login function, this function # might have transformed the username provided by the user. e.g. switched # from mixed case to lower case. username = result # When single user session mode is enabled, check that there is not another # active session userdb.ensure_user_can_init_session(username) # reset failed login counts userdb.on_succeeded_login(username) # The login succeeded! Now: # a) Set the auth cookie # b) Unset the login vars in further processing # c) Redirect to really requested page create_auth_session(username) # Never use inplace redirect handling anymore as used in the past. This results # in some unexpected situations. We simpy use 302 redirects now. So we have a # clear situation. # userdb.need_to_change_pw returns either False or the reason description why the # password needs to be changed result = userdb.need_to_change_pw(username) if result: raise HTTPRedirect('user_change_pw.py?_origtarget=%s&reason=%s' % (html.urlencode(origtarget), result)) else: raise HTTPRedirect(origtarget) else: userdb.on_failed_login(username) raise MKUserError(None, _('Invalid credentials.')) except MKUserError as e: html.add_user_error(e.varname, e) return "%s" % e
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))
def _do_login(self) -> None: """handle the sent login form""" if not request.var("_login"): return try: if not active_config.user_login: raise MKUserError(None, _("Login is not allowed on this site.")) username_var = request.get_str_input("_username", "") assert username_var is not None username = UserId(username_var.rstrip()) if not username: raise MKUserError("_username", _("Missing username")) password = request.var("_password", "") if not password: raise MKUserError("_password", _("Missing password")) default_origtarget = url_prefix() + "check_mk/" origtarget = request.get_url_input("_origtarget", default_origtarget) # Disallow redirections to: # - logout.py: Happens after login # - side.py: Happens when invalid login is detected during sidebar refresh if "logout.py" in origtarget or "side.py" in origtarget: origtarget = default_origtarget result = userdb.check_credentials(username, password) if result: # use the username provided by the successful login function, this function # might have transformed the username provided by the user. e.g. switched # from mixed case to lower case. username = result session_id = userdb.on_succeeded_login(username) # The login succeeded! Now: # a) Set the auth cookie # b) Unset the login vars in further processing # c) Redirect to really requested page _create_auth_session(username, session_id) # Never use inplace redirect handling anymore as used in the past. This results # in some unexpected situations. We simpy use 302 redirects now. So we have a # clear situation. # userdb.need_to_change_pw returns either False or the reason description why the # password needs to be changed change_pw_result = userdb.need_to_change_pw(username) if change_pw_result: raise HTTPRedirect( "user_change_pw.py?_origtarget=%s&reason=%s" % (urlencode(origtarget), change_pw_result)) if userdb.is_two_factor_login_enabled(username): raise HTTPRedirect( "user_login_two_factor.py?_origtarget=%s" % urlencode(makeuri(request, []))) raise HTTPRedirect(origtarget) userdb.on_failed_login(username) raise MKUserError(None, _("Invalid login")) except MKUserError as e: user_errors.add(e)