diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e14c784128..316c401cca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,8 @@ Added * Added a joint index to solve the problem of slow mongo queries for scheduled executions. #5805 +* Added a flag in config for a feature where non-admin users can manage their own keys. #5859 + Contributed by @bharath-orchestral 3.8.0 - November 18, 2022 ------------------------- diff --git a/conf/st2.dev.conf b/conf/st2.dev.conf index cf2b5b6596..92a873cf66 100644 --- a/conf/st2.dev.conf +++ b/conf/st2.dev.conf @@ -43,6 +43,7 @@ stream_output = True [rbac] enable = False +personal_keys = False [auth] host = 127.0.0.1 diff --git a/st2api/st2api/controllers/v1/auth.py b/st2api/st2api/controllers/v1/auth.py index d4741c4bf1..5a13b22818 100644 --- a/st2api/st2api/controllers/v1/auth.py +++ b/st2api/st2api/controllers/v1/auth.py @@ -74,11 +74,21 @@ def get_one(self, api_key_id_or_key, requester_user, show_secrets=None): permission_type = PermissionType.API_KEY_VIEW rbac_utils = get_rbac_backend().get_utils_class() - rbac_utils.assert_user_has_resource_db_permission( - user_db=requester_user, - resource_db=api_key_db, - permission_type=permission_type, - ) + if cfg.CONF.rbac.personal_keys: + isKeyCreationAllowed = self.checkPersonalAPIKeyPermission( + api_key_db, requester_user + ) + if not isKeyCreationAllowed: + LOG.exception( + "User does not have permission to view apikey=%s.", api_key_db + ) + abort(http_client.BAD_REQUEST, "") + else: + rbac_utils.assert_user_has_resource_db_permission( + user_db=requester_user, + resource_db=api_key_db, + permission_type=permission_type, + ) try: mask_secrets = self._get_mask_secrets( @@ -126,18 +136,39 @@ def get_all(self, requester_user, show_secrets=None, limit=None, offset=0): return resp + def checkPersonalAPIKeyPermission(self, api_key_api, requester_user): + """ + Checks whether requested user is creating/updating/fetching/deleting the api key. This is used when + 'personal_keys' flag is set in 'rbac' group in conf file. + """ + if not api_key_api or not requester_user: + return False + rbac_utils = get_rbac_backend().get_utils_class() + user_is_admin = rbac_utils.user_is_admin(user_db=requester_user) + is_same_user = requester_user.name == api_key_api.user + return (user_is_admin) or (is_same_user or api_key_api.user == "") + def post(self, api_key_api, requester_user): """ Create a new entry. """ - permission_type = PermissionType.API_KEY_CREATE rbac_utils = get_rbac_backend().get_utils_class() - rbac_utils.assert_user_has_resource_api_permission( - user_db=requester_user, - resource_api=api_key_api, - permission_type=permission_type, - ) + if cfg.CONF.rbac.personal_keys: + isKeyCreationAllowed = self.checkPersonalAPIKeyPermission( + api_key_api, requester_user + ) + if not isKeyCreationAllowed: + LOG.exception( + "User does not have permission to create apikey=%s.", api_key_api + ) + abort(http_client.BAD_REQUEST, "") + else: + rbac_utils.assert_user_has_resource_api_permission( + user_db=requester_user, + resource_api=api_key_api, + permission_type=permission_type, + ) api_key_db = None api_key = None @@ -184,11 +215,21 @@ def put(self, api_key_api, api_key_id_or_key, requester_user): permission_type = PermissionType.API_KEY_MODIFY rbac_utils = get_rbac_backend().get_utils_class() - rbac_utils.assert_user_has_resource_db_permission( - user_db=requester_user, - resource_db=api_key_db, - permission_type=permission_type, - ) + if cfg.CONF.rbac.personal_keys: + isKeyCreationAllowed = self.checkPersonalAPIKeyPermission( + api_key_db, requester_user + ) + if not isKeyCreationAllowed: + LOG.exception( + "User does not have permission to update apikey=%s.", api_key_db + ) + abort(http_client.BAD_REQUEST, "") + else: + rbac_utils.assert_user_has_resource_db_permission( + user_db=requester_user, + resource_db=api_key_db, + permission_type=permission_type, + ) old_api_key_db = api_key_db api_key_db = ApiKeyAPI.to_model(api_key_api) @@ -233,11 +274,21 @@ def delete(self, api_key_id_or_key, requester_user): permission_type = PermissionType.API_KEY_DELETE rbac_utils = get_rbac_backend().get_utils_class() - rbac_utils.assert_user_has_resource_db_permission( - user_db=requester_user, - resource_db=api_key_db, - permission_type=permission_type, - ) + if cfg.CONF.rbac.personal_keys: + isKeyCreationAllowed = self.checkPersonalAPIKeyPermission( + api_key_db, requester_user + ) + if not isKeyCreationAllowed: + LOG.exception( + "User does not have permission to delete apikey=%s.", api_key_db + ) + abort(http_client.BAD_REQUEST, "") + else: + rbac_utils.assert_user_has_resource_db_permission( + user_db=requester_user, + resource_db=api_key_db, + permission_type=permission_type, + ) ApiKey.delete(api_key_db) diff --git a/st2api/tests/unit/controllers/v1/test_auth_api_keys.py b/st2api/tests/unit/controllers/v1/test_auth_api_keys.py index ad2e0e5bc4..594ffd608b 100644 --- a/st2api/tests/unit/controllers/v1/test_auth_api_keys.py +++ b/st2api/tests/unit/controllers/v1/test_auth_api_keys.py @@ -51,6 +51,7 @@ def setUpClass(cls): cfg.CONF.set_override(name="mask_secrets", override=True, group="api") cfg.CONF.set_override(name="mask_secrets", override=True, group="log") + cfg.CONF.set_override(name="personal_keys", override=False, group="rbac") models = FixturesLoader().save_fixtures_to_db( fixtures_pack=FIXTURES_PACK, fixtures_dict=TEST_MODELS diff --git a/st2auth/conf/htpasswd_dev b/st2auth/conf/htpasswd_dev index 09e3701940..a7ed367b86 100644 --- a/st2auth/conf/htpasswd_dev +++ b/st2auth/conf/htpasswd_dev @@ -1 +1 @@ -testu:{SHA}V1t6eZLxnehb7CTBuj61Nq3lIh4= +testu:{SHA}V1t6eZLxnehb7CTBuj61Nq3lIh4= \ No newline at end of file diff --git a/st2common/st2common/config.py b/st2common/st2common/config.py index c88955e4bb..6e62ba1d6f 100644 --- a/st2common/st2common/config.py +++ b/st2common/st2common/config.py @@ -72,6 +72,11 @@ def register_opts(ignore_errors=False): "executions. All resources can only be viewed or executed by the owning user " "except the admin and system_user who can view or run everything.", ), + cfg.BoolOpt( + "personal_keys", + default=False, + help="Enable all non-admin users to create/update/delete their own keys. They cannot create/update/delete other's keys.", + ), ] do_register_opts(rbac_opts, "rbac", ignore_errors)