Repository: privacyidea/privacyidea

Issue:
Add resolvers to some policies
The resolver of the user should be added to the following policies:

* api/lib/prepolicy.py:check_token_init
* api/lib/prepolicy.py:check_max_token_user


Discussion:

Resolving patch:
diff --git a/privacyidea/api/lib/prepolicy.py b/privacyidea/api/lib/prepolicy.py
--- a/privacyidea/api/lib/prepolicy.py
+++ b/privacyidea/api/lib/prepolicy.py
@@ -697,6 +697,7 @@ def check_max_token_user(request=None, action=None):
         limit_list = policy_object.get_action_values(ACTION.MAXTOKENUSER,
                                                      scope=SCOPE.ENROLL,
                                                      realm=user_object.realm,
+                                                     resolver=user_object.resolver,
                                                      user=user_object.login,
                                                      client=g.client_ip)
         if limit_list:
@@ -1085,14 +1086,24 @@ def check_token_init(request=None, action=None):
     role = g.logged_in_user.get("role")
     admin_realm = g.logged_in_user.get("realm")
     scope = SCOPE.ADMIN
+    # We need this user, if an admin enrolls a token for a user
+    user_obj = get_user_from_param(params)
+    resolver = realm = None
     if role == ROLE.USER:
         scope = SCOPE.USER
+        realm = admin_realm
         admin_realm = None
+        resolver = User(username, realm).resolver
+    elif role == ROLE.ADMIN and user_obj:
+        resolver = user_obj.resolver
+        realm = user_obj.realm
+
     tokentype = params.get("type", "HOTP")
     action = "enroll{0!s}".format(tokentype.upper())
     action = policy_object.get_policies(action=action,
                                         user=username,
-                                        realm=params.get("realm"),
+                                        realm=realm,
+                                        resolver=resolver,
                                         scope=scope,
                                         client=g.client_ip,
                                         adminrealm=admin_realm,


Test patch:
diff --git a/tests/test_api_lib_policy.py b/tests/test_api_lib_policy.py
--- a/tests/test_api_lib_policy.py
+++ b/tests/test_api_lib_policy.py
@@ -27,6 +27,8 @@
                                            u2ftoken_verify_cert,
                                            tantoken_count, sms_identifiers,
                                            pushtoken_add_config)
+from privacyidea.lib.realm import set_realm as create_realm
+from privacyidea.lib.realm import delete_realm
 from privacyidea.api.lib.postpolicy import (check_serial, check_tokentype,
                                             check_tokeninfo,
                                             no_detail_on_success,
@@ -1372,6 +1374,76 @@ def test_22_push_firebase_config(self):
         delete_policy("push_pol")
         delete_policy("push_pol2")
 
+    def test_23_enroll_different_tokentypes_in_different_resolvers(self):
+        # One realm has different resolvers.
+        # The different users are allowed to enroll different tokentypes.
+        realm = "myrealm"
+        # We need this, to create the resolver3
+        self.setUp_user_realm3()
+        (added, failed) = create_realm(realm,
+                                       [self.resolvername1, self.resolvername3])
+        self.assertEqual(0, len(failed))
+        self.assertEqual(2, len(added))
+        # We have cornelius@myRealm in self.resolvername1
+        # We have corny@myRealm in self.resolvername3
+        set_policy("reso1pol", scope=SCOPE.USER, action="enrollTOTP", realm=realm, resolver=self.resolvername1)
+        set_policy("reso3pol", scope=SCOPE.USER, action="enrollHOTP", realm=realm, resolver=self.resolvername3)
+
+        # Cornelius is allowed to enroll TOTP
+        g.logged_in_user = {"username": "cornelius",
+                            "realm": realm,
+                            "role": "user"}
+        builder = EnvironBuilder(method='POST',
+                                 data={'serial': "OATH123456"},
+                                 headers={})
+        env = builder.get_environ()
+        # Set the remote address so that we can filter for it
+        env["REMOTE_ADDR"] = "10.0.0.1"
+        g.client_ip = env["REMOTE_ADDR"]
+        req = Request(env)
+        req.all_data = {"type": "totp"}
+        g.policy_object = PolicyClass()
+        r = check_token_init(req)
+        self.assertTrue(r)
+
+        # Cornelius is not allowed to enroll HOTP
+        req.all_data = {"type": "hotp"}
+        self.assertRaises(PolicyError,
+                          check_token_init, req)
+
+        # Corny is allowed to enroll HOTP
+        g.logged_in_user = {"username": "corny",
+                            "realm": realm,
+                            "role": "user"}
+        builder = EnvironBuilder(method='POST',
+                                 data={'serial': "OATH123456"},
+                                 headers={})
+        env = builder.get_environ()
+        # Set the remote address so that we can filter for it
+        env["REMOTE_ADDR"] = "10.0.0.1"
+        g.client_ip = env["REMOTE_ADDR"]
+        req = Request(env)
+        req.all_data = {"type": "hotp"}
+        g.policy_object = PolicyClass()
+        r = check_token_init(req)
+        self.assertTrue(r)
+
+        # Corny is not allowed to enroll TOTP
+        req.all_data = {"type": "totp"}
+        self.assertRaises(PolicyError,
+                          check_token_init, req)
+
+        delete_policy("reso3pol")
+        g.policy_object = PolicyClass()
+        # Now Corny is not allowed to enroll anything! Also not hotp anymore,
+        # since there is no policy for his resolver.
+        req.all_data = {"type": "hotp"}
+        self.assertRaises(PolicyError,
+                          check_token_init, req)
+
+        delete_policy("reso1pol")
+        delete_realm(realm)
+
 
 class PostPolicyDecoratorTestCase(MyApiTestCase):