Repository: StackStorm/st2

Issue:
Default RBAC configuration does not allow use of st2 pack config
Steps to reproduce:

1. Install new BWC system using one-line install. Note that RBAC is now enabled by default
2. Authenticate as st2admin
3. Install a pack - e.g. `st2 pack install zendesk` - this will succeed
4. Attempt to configure the pack with `st2 pack config zendesk`. Result: 500 Server error.

Output:
```
ubuntu@bwcxenial:/opt/stackstorm/packs/dcfabric$ st2 pack config zendesk
subdomain: bwc
email: lindsay@brocade.com
api_token (secret): ***************
---
Do you want to preview the config in an editor before saving? [y]: n
---
Do you want me to save it? [y]: y
ERROR: 500 Server Error: Internal Server Error
MESSAGE: Internal Server Error for url: http://127.0.0.1:9101/v1/configs/zendesk
```

This is an example of typical st2api.log output https://gist.github.com/anonymous/e71026f96062bb1f5c8f0eeae145de50

Wonder if there's a connection to https://github.com/StackStorm/st2/pull/3235 ?


Discussion:
Yeah #3235 should have fixed that (from the API looks looks like it's indeed an issue which has been fixed by that PR).

Are they using v2.2.0?
Yes, v2.2.0, from what it looked like to me pack_config in API checks for PACK_CREATE permissions.  However, that permission is not in the resolver assert list:

https://github.com/StackStorm/st2/blob/master/st2api/st2api/controllers/v1/pack_configs.py#L82
https://github.com/StackStorm/st2/blob/master/st2common/st2common/rbac/resolvers.py#L339

If I change the line in pack_config.py to PACK_INSTALL instead of PACK_CREATE and then restart services then it seems to work for me.

@efenian Thanks again for confirming.

I just checked the code and I see the issue (similar to #3235, but a different issue). Will work on a fix shortly.

Resolving patch:
diff --git a/st2api/st2api/controllers/v1/pack_configs.py b/st2api/st2api/controllers/v1/pack_configs.py
--- a/st2api/st2api/controllers/v1/pack_configs.py
+++ b/st2api/st2api/controllers/v1/pack_configs.py
@@ -79,11 +79,11 @@ def get_one(self, pack_ref):
         # TODO: Make sure secret values are masked
         return self._get_one_by_pack_ref(pack_ref=pack_ref)
 
-    @request_user_has_permission(permission_type=PermissionType.PACK_CREATE)
+    @request_user_has_permission(permission_type=PermissionType.PACK_CONFIG)
     @jsexpose(body_cls=ConfigUpdateRequestAPI, arg_types=[str])
     def put(self, pack_uninstall_request, pack_ref):
         """
-            Create a new config for the action.
+            Create a new config for a pack.
 
             Handles requests:
                 POST /configs/<pack_ref>
diff --git a/st2common/st2common/rbac/resolvers.py b/st2common/st2common/rbac/resolvers.py
--- a/st2common/st2common/rbac/resolvers.py
+++ b/st2common/st2common/rbac/resolvers.py
@@ -29,6 +29,7 @@
 from st2common.rbac.types import PermissionType
 from st2common.rbac.types import ResourceType
 from st2common.rbac.types import SystemRole
+from st2common.rbac.types import GLOBAL_PACK_PERMISSION_TYPES
 from st2common.services.rbac import get_roles_for_user
 from st2common.services.rbac import get_all_permission_grants_for_user
 
@@ -336,10 +337,7 @@ class PackPermissionsResolver(PermissionsResolver):
     resource_type = ResourceType.PACK
 
     def user_has_permission(self, user_db, permission_type):
-        assert permission_type in [PermissionType.PACK_LIST, PermissionType.PACK_INSTALL,
-                                   PermissionType.PACK_UNINSTALL, PermissionType.PACK_REGISTER,
-                                   PermissionType.PACK_SEARCH,
-                                   PermissionType.PACK_VIEW_INDEX_HEALTH]
+        assert permission_type in GLOBAL_PACK_PERMISSION_TYPES
 
         if permission_type == PermissionType.PACK_LIST:
             return self._user_has_list_permission(user_db=user_db, permission_type=permission_type)
diff --git a/st2common/st2common/rbac/types.py b/st2common/st2common/rbac/types.py
--- a/st2common/st2common/rbac/types.py
+++ b/st2common/st2common/rbac/types.py
@@ -28,6 +28,7 @@
 
     'ALL_PERMISSION_TYPES',
     'GLOBAL_PERMISSION_TYPES',
+    'GLOBAL_PACK_PERMISSION_TYPES',
     'LIST_PERMISSION_TYPES'
 ]
 
@@ -55,6 +56,7 @@ class PermissionType(Enum):
     PACK_INSTALL = 'pack_install'
     PACK_UNINSTALL = 'pack_uninstall'
     PACK_REGISTER = 'pack_register'
+    PACK_CONFIG = 'pack_config'
     PACK_SEARCH = 'pack_search'
     PACK_VIEW_INDEX_HEALTH = 'pack_view_index_health'
 
@@ -236,6 +238,7 @@ class SystemRole(Enum):
         PermissionType.PACK_INSTALL,
         PermissionType.PACK_UNINSTALL,
         PermissionType.PACK_REGISTER,
+        PermissionType.PACK_CONFIG,
         PermissionType.PACK_SEARCH,
         PermissionType.PACK_VIEW_INDEX_HEALTH,
         PermissionType.PACK_ALL,
@@ -340,6 +343,7 @@ class SystemRole(Enum):
     PermissionType.PACK_UNINSTALL,
     PermissionType.PACK_CREATE,
     PermissionType.PACK_REGISTER,
+    PermissionType.PACK_CONFIG,
     PermissionType.PACK_SEARCH,
     PermissionType.PACK_VIEW_INDEX_HEALTH,
 
@@ -348,6 +352,9 @@ class SystemRole(Enum):
     PermissionType.ACTION_ALIAS_HELP
 ] + LIST_PERMISSION_TYPES
 
+GLOBAL_PACK_PERMISSION_TYPES = [permission_type for permission_type in GLOBAL_PERMISSION_TYPES if
+                                permission_type.startswith('pack_')]
+
 
 # Maps a permission type to the corresponding description
 PERMISION_TYPE_TO_DESCRIPTION_MAP = {
@@ -359,6 +366,7 @@ class SystemRole(Enum):
     PermissionType.PACK_INSTALL: 'Ability to install packs.',
     PermissionType.PACK_UNINSTALL: 'Ability to uninstall packs.',
     PermissionType.PACK_REGISTER: 'Ability to register packs and corresponding resources.',
+    PermissionType.PACK_CONFIG: 'Ability to configure a pack.',
     PermissionType.PACK_SEARCH: 'Ability to query registry and search packs.',
     PermissionType.PACK_VIEW_INDEX_HEALTH: 'Ability to query health of pack registries.',
     PermissionType.PACK_ALL: ('Ability to perform all the supported operations on a particular '


Test patch:
diff --git a/st2api/tests/unit/controllers/v1/test_rbac_for_supported_endpoints.py b/st2api/tests/unit/controllers/v1/test_rbac_for_supported_endpoints.py
--- a/st2api/tests/unit/controllers/v1/test_rbac_for_supported_endpoints.py
+++ b/st2api/tests/unit/controllers/v1/test_rbac_for_supported_endpoints.py
@@ -185,6 +185,22 @@ def test_api_endpoints_behind_rbac_wall(self):
                 'path': '/v1/packs/views/file/dummy_pack_1/pack.yaml',
                 'method': 'GET'
             },
+            # Pack configs
+            {
+                'path': '/v1/configs/',
+                'method': 'GET'
+            },
+            {
+                'path': '/v1/configs/dummy_pack_1',
+                'method': 'GET'
+            },
+            {
+                'path': '/v1/configs/dummy_pack_1',
+                'method': 'PUT',
+                'payload': {
+                    'foo': 'bar'
+                }
+            },
             # Sensors
             {
                 'path': '/v1/sensortypes',