Exemple #1
0
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}).")
Exemple #2
0
    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)
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
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))
Exemple #8
0
    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)