Repository: privacyidea/privacyidea (Python)

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








Discussion:
Expected outcome: We should get the same error: Wrong Credentials.

The problem is, that the login_mode=privacyIDEA results in "check_otp=True" here:

https://github.com/privacyidea/privacyidea/blob/7ed27ada2f0bf93cca53ddbfb0df04c6faf23470/privacyidea/lib/auth.py#L126

in the if-branch the check_user_pass raises an error, if the user does not exist. here:
https://github.com/privacyidea/privacyidea/blob/7ed27ada2f0bf93cca53ddbfb0df04c6faf23470/privacyidea/lib/auth.py#L128

While in the else-branch the user_obj.check_password returns `False` if the user does not exist.

We need to catch the error in the if-branch:

~~~~Python
try: 
    details["loginmode"] = "privacyIDEA"
    check, details = check_user_pass(user_obj, password, options=options)
    if check:
          user_auth = True
except Exception ....
     pass

~~~~

     





Patch:
diff --git a/privacyidea/lib/auth.py b/privacyidea/lib/auth.py
index 64285c36a4..53e7b577cf 100644
--- 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 @@ def check_webui_user(user_obj,
 
     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):


Test patch:
diff --git a/tests/test_api_auth.py b/tests/test_api_auth.py
index fcb8d3f3ae..deb22a3093 100644
--- a/tests/test_api_auth.py
+++ b/tests/test_api_auth.py
@@ -635,6 +635,54 @@ def test_06_auth_user_not_in_defrealm(self):
             self.assertIn('token', result.get("value"), result)
             self.assertEqual('realm1', result['value']['realm'], result)
 
+    def test_07_user_not_in_userstore(self):
+        # If a user can not be found in the userstore we always get the response "Wrong Credentials"
+        # Setup realm
+        rid = save_resolver({"resolver": self.resolvername1,
+                             "type": "passwdresolver",
+                             "fileName": PWFILE})
+        self.assertTrue(rid > 0, rid)
+
+        (added, failed) = set_realm(self.realm1,
+                                    [self.resolvername1])
+        self.assertTrue(len(failed) == 0)
+        self.assertTrue(len(added) == 1)
+        set_default_realm(self.realm1)
+
+        # user authenticates against userstore but user does not exist
+        with self.app.test_request_context('/auth',
+                                           method='POST',
+                                           data={"username": "user-really-does-not-exist",
+                                                 "password": "test"}):
+            res = self.app.full_dispatch_request()
+            self.assertEqual(401, res.status_code, res)
+            result = res.json.get("result")
+            self.assertFalse(result.get("status"), result)
+            error = result.get("error")
+            self.assertEqual(4031, error.get("code"))
+            self.assertEqual("Authentication failure. Wrong credentials", error.get("message"))
+
+        # set a policy to authenticate against privacyIDEA
+        set_policy("piLogin", scope=SCOPE.WEBUI, action="{0!s}=privacyIDEA".format(ACTION.LOGINMODE))
+
+        # user authenticates against privacyidea but user does not exist
+        with self.app.test_request_context('/auth',
+                                           method='POST',
+                                           data={"username": "user-really-does-not-exist",
+                                                 "password": "test"}):
+            res = self.app.full_dispatch_request()
+            self.assertEqual(401, res.status_code, res)
+            result = res.json.get("result")
+            self.assertFalse(result.get("status"), result)
+            error = result.get("error")
+            self.assertEqual(4031, error.get("code"))
+            self.assertEqual("Authentication failure. Wrong credentials", error.get("message"))
+
+        # cleanup
+        delete_policy("piLogin")
+        delete_realm(self.realm1)
+        delete_resolver(self.resolvername1)
+
 
 class AdminFromUserstore(OverrideConfigTestCase):
     class Config(TestingConfig):