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()

```

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):

{"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"}]}