prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Error 904 is still shown with policy Action login_mode: privacyIDEA 
  
  privacyidea 3.8
  ubuntu 20
  
  Since 3.7 the error message :´ERR904: The user can not be found in any resolver in this realm!¨ is deactivated when you enter a wrong username.
  
  But this is still true if you have a policy :
  Scope webui
  Action login_mode: privacyIDEA 
  
  if you have a policy:
  Scope webui
  login_mode: userstore 
  Then the error (ERR904: The user can not be found in any resolver in this realm!)  Is deactivated.
  
  Kind regards
  Sebastien
  
  
  
  
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `privacyidea/lib/auth.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 #
  3 # 2015-11-03 Cornelius Kölbel <cornelius@privacyidea.org>
  4 #            Add check if an admin user exists
  5 # 2014-12-15 Cornelius Kölbel, info@privacyidea.org
  6 #            Initial creation
  7 #
  8 # (c) Cornelius Kölbel
  9 # Info: http://www.privacyidea.org
  10 #
  11 # This code is free software; you can redistribute it and/or
  12 # modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  13 # License as published by the Free Software Foundation; either
  14 # version 3 of the License, or any later version.
  15 #
  16 # This code is distributed in the hope that it will be useful,
  17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 # GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  20 #
  21 # You should have received a copy of the GNU Affero General Public
  22 # License along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 #
  24 from privacyidea.models import Admin
  25 from privacyidea.lib.token import check_user_pass
  26 from privacyidea.lib.policydecorators import libpolicy, login_mode
  27 from privacyidea.lib.crypto import hash_with_pepper, verify_with_pepper
  28 from privacyidea.lib.utils import fetch_one_resource
  29 
  30 
  31 class ROLE(object):
  32     ADMIN = "admin"
  33     USER = "user"
  34     VALIDATE = "validate"
  35 
  36 
  37 def verify_db_admin(username, password):
  38     """
  39     This function is used to verify the username and the password against the
  40     database table "Admin".
  41     :param username: The administrator username
  42     :param password: The password
  43     :return: True if password is correct for the admin
  44     :rtype: bool
  45     """
  46     success = False
  47     qa = Admin.query.filter(Admin.username == username).first()
  48     if qa:
  49         success = verify_with_pepper(qa.password, password)
  50 
  51     return success
  52 
  53 
  54 def db_admin_exist(username):
  55     """
  56     Checks if a local admin in the database exists
  57 
  58     :param username: The username of the admin
  59     :return: True, if exist
  60     """
  61     return bool(get_db_admin(username))
  62 
  63 
  64 def create_db_admin(app, username, email=None, password=None):
  65     pw_dig = None
  66     if password:
  67         pw_dig = hash_with_pepper(password)
  68     user = Admin(email=email, username=username, password=pw_dig)
  69     user.save()
  70 
  71 
  72 def list_db_admin():
  73     admins = Admin.query.all()
  74     print("Name \t email")
  75     print(30*"=")
  76     for admin in admins:
  77         print("{0!s} \t {1!s}".format(admin.username, admin.email))
  78 
  79 
  80 def get_db_admins():
  81     admins = Admin.query.all()
  82     return admins
  83 
  84 
  85 def get_db_admin(username):
  86     return Admin.query.filter(Admin.username == username).first()
  87 
  88 
  89 def delete_db_admin(username):
  90     print("Deleting admin {0!s}".format(username))
  91     fetch_one_resource(Admin, username=username).delete()
  92 
  93 
  94 @libpolicy(login_mode)
  95 def check_webui_user(user_obj,
  96                      password,
  97                      options=None,
  98                      superuser_realms=None,
  99                      check_otp=False):
  100     """
  101     This function is used to authenticate the user at the web ui.
  102     It checks against the userstore or against OTP/privacyidea (check_otp).
  103     It returns a tuple of
  104 
  105     * true/false if the user authenticated successfully
  106     * the role of the user
  107     * the "detail" dictionary of the response
  108 
  109     :param user_obj: The user who tries to authenticate
  110     :type user_obj: User Object
  111     :param password: Password, static and or OTP
  112     :param options: additional options like g and clientip
  113     :type options: dict
  114     :param superuser_realms: list of realms, that contain admins
  115     :type superuser_realms: list
  116     :param check_otp: If set, the user is not authenticated against the
  117          userstore but against privacyidea
  118     :return: tuple of bool, string and dict/None
  119     """
  120     options = options or {}
  121     superuser_realms = superuser_realms or []
  122     user_auth = False
  123     role = ROLE.USER
  124     details = None
  125 
  126     if check_otp:
  127         # check if the given password matches an OTP token
  128         check, details = check_user_pass(user_obj, password, options=options)
  129         details["loginmode"] = "privacyIDEA"
  130         if check:
  131             user_auth = True
  132     else:
  133         # check the password of the user against the userstore
  134         if user_obj.check_password(password):
  135             user_auth = True
  136 
  137     # If the realm is in the SUPERUSER_REALM then the authorization role
  138     # is risen to "admin".
  139     if user_obj.realm in superuser_realms:
  140         role = ROLE.ADMIN
  141 
  142     return user_auth, role, details
  143
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/privacyidea/lib/auth.py b/privacyidea/lib/auth.py
  --- a/privacyidea/lib/auth.py
  +++ b/privacyidea/lib/auth.py
  @@ -26,6 +26,10 @@
   from privacyidea.lib.policydecorators import libpolicy, login_mode
   from privacyidea.lib.crypto import hash_with_pepper, verify_with_pepper
   from privacyidea.lib.utils import fetch_one_resource
  +import logging
  +
  +log = logging.getLogger(__name__)
  +
   
   
   class ROLE(object):
  @@ -125,10 +129,13 @@
   
       if check_otp:
           # check if the given password matches an OTP token
  -        check, details = check_user_pass(user_obj, password, options=options)
  -        details["loginmode"] = "privacyIDEA"
  -        if check:
  -            user_auth = True
  +        try:
  +            check, details = check_user_pass(user_obj, password, options=options)
  +            details["loginmode"] = "privacyIDEA"
  +            if check:
  +                user_auth = True
  +        except Exception as e:
  +            log.debug("Error authenticating user against privacyIDEA: {0!r}".format(e))
       else:
           # check the password of the user against the userstore
           if user_obj.check_password(password):
  
verification_info: {"golden_diff": "diff --git a/privacyidea/lib/auth.py b/privacyidea/lib/auth.py\n--- a/privacyidea/lib/auth.py\n+++ b/privacyidea/lib/auth.py\n@@ -26,6 +26,10 @@\n from privacyidea.lib.policydecorators import libpolicy, login_mode\n from privacyidea.lib.crypto import hash_with_pepper, verify_with_pepper\n from privacyidea.lib.utils import fetch_one_resource\n+import logging\n+\n+log = logging.getLogger(__name__)\n+\n \n \n class ROLE(object):\n@@ -125,10 +129,13 @@\n \n     if check_otp:\n         # check if the given password matches an OTP token\n-        check, details = check_user_pass(user_obj, password, options=options)\n-        details[\"loginmode\"] = \"privacyIDEA\"\n-        if check:\n-            user_auth = True\n+        try:\n+            check, details = check_user_pass(user_obj, password, options=options)\n+            details[\"loginmode\"] = \"privacyIDEA\"\n+            if check:\n+                user_auth = True\n+        except Exception as e:\n+            log.debug(\"Error authenticating user against privacyIDEA: {0!r}\".format(e))\n     else:\n         # check the password of the user against the userstore\n         if user_obj.check_password(password):\n", "issue": "Error 904 is still shown with policy Action login_mode: privacyIDEA \n\r\nprivacyidea 3.8\r\nubuntu 20\r\n\r\nSince 3.7 the error message :\u00b4ERR904: The user can not be found in any resolver in this realm!\u00a8 is deactivated when you enter a wrong username.\r\n\r\nBut this is still true if you have a policy :\r\nScope webui\r\nAction login_mode: privacyIDEA \r\n\r\nif you have a policy:\r\nScope webui\r\nlogin_mode: userstore \r\nThen the error (ERR904: The user can not be found in any resolver in this realm!)  Is deactivated.\r\n\r\nKind regards\r\nSebastien\r\n\r\n\r\n\r\n\r\n\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# 2015-11-03 Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n#            Add check if an admin user exists\n# 2014-12-15 Cornelius K\u00f6lbel, info@privacyidea.org\n#            Initial creation\n#\n# (c) Cornelius K\u00f6lbel\n# Info: http://www.privacyidea.org\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\nfrom privacyidea.models import Admin\nfrom privacyidea.lib.token import check_user_pass\nfrom privacyidea.lib.policydecorators import libpolicy, login_mode\nfrom privacyidea.lib.crypto import hash_with_pepper, verify_with_pepper\nfrom privacyidea.lib.utils import fetch_one_resource\n\n\nclass ROLE(object):\n    ADMIN = \"admin\"\n    USER = \"user\"\n    VALIDATE = \"validate\"\n\n\ndef verify_db_admin(username, password):\n    \"\"\"\n    This function is used to verify the username and the password against the\n    database table \"Admin\".\n    :param username: The administrator username\n    :param password: The password\n    :return: True if password is correct for the admin\n    :rtype: bool\n    \"\"\"\n    success = False\n    qa = Admin.query.filter(Admin.username == username).first()\n    if qa:\n        success = verify_with_pepper(qa.password, password)\n\n    return success\n\n\ndef db_admin_exist(username):\n    \"\"\"\n    Checks if a local admin in the database exists\n\n    :param username: The username of the admin\n    :return: True, if exist\n    \"\"\"\n    return bool(get_db_admin(username))\n\n\ndef create_db_admin(app, username, email=None, password=None):\n    pw_dig = None\n    if password:\n        pw_dig = hash_with_pepper(password)\n    user = Admin(email=email, username=username, password=pw_dig)\n    user.save()\n\n\ndef list_db_admin():\n    admins = Admin.query.all()\n    print(\"Name \\t email\")\n    print(30*\"=\")\n    for admin in admins:\n        print(\"{0!s} \\t {1!s}\".format(admin.username, admin.email))\n\n\ndef get_db_admins():\n    admins = Admin.query.all()\n    return admins\n\n\ndef get_db_admin(username):\n    return Admin.query.filter(Admin.username == username).first()\n\n\ndef delete_db_admin(username):\n    print(\"Deleting admin {0!s}\".format(username))\n    fetch_one_resource(Admin, username=username).delete()\n\n\n@libpolicy(login_mode)\ndef check_webui_user(user_obj,\n                     password,\n                     options=None,\n                     superuser_realms=None,\n                     check_otp=False):\n    \"\"\"\n    This function is used to authenticate the user at the web ui.\n    It checks against the userstore or against OTP/privacyidea (check_otp).\n    It returns a tuple of\n\n    * true/false if the user authenticated successfully\n    * the role of the user\n    * the \"detail\" dictionary of the response\n\n    :param user_obj: The user who tries to authenticate\n    :type user_obj: User Object\n    :param password: Password, static and or OTP\n    :param options: additional options like g and clientip\n    :type options: dict\n    :param superuser_realms: list of realms, that contain admins\n    :type superuser_realms: list\n    :param check_otp: If set, the user is not authenticated against the\n         userstore but against privacyidea\n    :return: tuple of bool, string and dict/None\n    \"\"\"\n    options = options or {}\n    superuser_realms = superuser_realms or []\n    user_auth = False\n    role = ROLE.USER\n    details = None\n\n    if check_otp:\n        # check if the given password matches an OTP token\n        check, details = check_user_pass(user_obj, password, options=options)\n        details[\"loginmode\"] = \"privacyIDEA\"\n        if check:\n            user_auth = True\n    else:\n        # check the password of the user against the userstore\n        if user_obj.check_password(password):\n            user_auth = True\n\n    # If the realm is in the SUPERUSER_REALM then the authorization role\n    # is risen to \"admin\".\n    if user_obj.realm in superuser_realms:\n        role = ROLE.ADMIN\n\n    return user_auth, role, details\n", "path": "privacyidea/lib/auth.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# 2015-11-03 Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n#            Add check if an admin user exists\n# 2014-12-15 Cornelius K\u00f6lbel, info@privacyidea.org\n#            Initial creation\n#\n# (c) Cornelius K\u00f6lbel\n# Info: http://www.privacyidea.org\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\nfrom privacyidea.models import Admin\nfrom privacyidea.lib.token import check_user_pass\nfrom privacyidea.lib.policydecorators import libpolicy, login_mode\nfrom privacyidea.lib.crypto import hash_with_pepper, verify_with_pepper\nfrom privacyidea.lib.utils import fetch_one_resource\nimport logging\n\nlog = logging.getLogger(__name__)\n\n\n\nclass ROLE(object):\n    ADMIN = \"admin\"\n    USER = \"user\"\n    VALIDATE = \"validate\"\n\n\ndef verify_db_admin(username, password):\n    \"\"\"\n    This function is used to verify the username and the password against the\n    database table \"Admin\".\n    :param username: The administrator username\n    :param password: The password\n    :return: True if password is correct for the admin\n    :rtype: bool\n    \"\"\"\n    success = False\n    qa = Admin.query.filter(Admin.username == username).first()\n    if qa:\n        success = verify_with_pepper(qa.password, password)\n\n    return success\n\n\ndef db_admin_exist(username):\n    \"\"\"\n    Checks if a local admin in the database exists\n\n    :param username: The username of the admin\n    :return: True, if exist\n    \"\"\"\n    return bool(get_db_admin(username))\n\n\ndef create_db_admin(app, username, email=None, password=None):\n    pw_dig = None\n    if password:\n        pw_dig = hash_with_pepper(password)\n    user = Admin(email=email, username=username, password=pw_dig)\n    user.save()\n\n\ndef list_db_admin():\n    admins = Admin.query.all()\n    print(\"Name \\t email\")\n    print(30*\"=\")\n    for admin in admins:\n        print(\"{0!s} \\t {1!s}\".format(admin.username, admin.email))\n\n\ndef get_db_admins():\n    admins = Admin.query.all()\n    return admins\n\n\ndef get_db_admin(username):\n    return Admin.query.filter(Admin.username == username).first()\n\n\ndef delete_db_admin(username):\n    print(\"Deleting admin {0!s}\".format(username))\n    fetch_one_resource(Admin, username=username).delete()\n\n\n@libpolicy(login_mode)\ndef check_webui_user(user_obj,\n                     password,\n                     options=None,\n                     superuser_realms=None,\n                     check_otp=False):\n    \"\"\"\n    This function is used to authenticate the user at the web ui.\n    It checks against the userstore or against OTP/privacyidea (check_otp).\n    It returns a tuple of\n\n    * true/false if the user authenticated successfully\n    * the role of the user\n    * the \"detail\" dictionary of the response\n\n    :param user_obj: The user who tries to authenticate\n    :type user_obj: User Object\n    :param password: Password, static and or OTP\n    :param options: additional options like g and clientip\n    :type options: dict\n    :param superuser_realms: list of realms, that contain admins\n    :type superuser_realms: list\n    :param check_otp: If set, the user is not authenticated against the\n         userstore but against privacyidea\n    :return: tuple of bool, string and dict/None\n    \"\"\"\n    options = options or {}\n    superuser_realms = superuser_realms or []\n    user_auth = False\n    role = ROLE.USER\n    details = None\n\n    if check_otp:\n        # check if the given password matches an OTP token\n        try:\n            check, details = check_user_pass(user_obj, password, options=options)\n            details[\"loginmode\"] = \"privacyIDEA\"\n            if check:\n                user_auth = True\n        except Exception as e:\n            log.debug(\"Error authenticating user against privacyIDEA: {0!r}\".format(e))\n    else:\n        # check the password of the user against the userstore\n        if user_obj.check_password(password):\n            user_auth = True\n\n    # If the realm is in the SUPERUSER_REALM then the authorization role\n    # is risen to \"admin\".\n    if user_obj.realm in superuser_realms:\n        role = ROLE.ADMIN\n\n    return user_auth, role, details\n", "path": "privacyidea/lib/auth.py"}]}