From 2cb82965b05c66a3f3d7732e607a5a324654a7dd Mon Sep 17 00:00:00 2001 From: Scott Bishel Date: Tue, 6 Apr 2021 08:39:36 -0600 Subject: [PATCH] MM-33905 -always add FeatureFlags to config (#17163) * always add FeatureFlags to config * update const to TitleCase * gofmt * update method to use 'access:all' * update method to use 'access:all' * fix lint * gofmt * added comments * update name of access tag for any * fix bad save Co-authored-by: Mattermod --- api4/config.go | 17 ++++++++++++----- api4/config_test.go | 26 ++++++++++++++++++++++++++ model/config.go | 7 ++++++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/api4/config.go b/api4/config.go index fdc30e2828..ebc56bc2d9 100644 --- a/api4/config.go +++ b/api4/config.go @@ -22,8 +22,10 @@ var permissionMap map[string]*model.Permission type filterType string -const filterTypeWrite filterType = "write" -const filterTypeRead filterType = "read" +const ( + FilterTypeWrite filterType = "write" + FilterTypeRead filterType = "read" +) func (api *API) InitConfig() { api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(getConfig)).Methods("GET") @@ -36,8 +38,8 @@ func (api *API) InitConfig() { } func init() { - writeFilter = makeFilterConfigByPermission(filterTypeWrite) - readFilter = makeFilterConfigByPermission(filterTypeRead) + writeFilter = makeFilterConfigByPermission(FilterTypeWrite) + readFilter = makeFilterConfigByPermission(FilterTypeRead) permissionMap = map[string]*model.Permission{} for _, p := range model.AllPermissions { permissionMap[p.Id] = p @@ -301,7 +303,7 @@ func makeFilterConfigByPermission(accessType filterType) func(c *Context, struct } // ConfigAccessTagWriteRestrictable trumps all other permissions if tagValue == model.ConfigAccessTagWriteRestrictable || tagValue == model.ConfigAccessTagCloudRestrictable { - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin && accessType == filterTypeWrite { + if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin && accessType == FilterTypeWrite { return false } continue @@ -320,6 +322,11 @@ func makeFilterConfigByPermission(accessType filterType) func(c *Context, struct if tagValue == model.ConfigAccessTagCloudRestrictable { continue } + if tagValue == model.ConfigAccessTagAnySysConsoleRead && accessType == FilterTypeRead && + c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleReadPermissions) { + return true + } + permissionID := fmt.Sprintf("sysconsole_%s_%s", accessType, tagValue) if permission, ok := permissionMap[permissionID]; ok { if c.App.SessionHasPermissionTo(*c.App.Session(), permission) { diff --git a/api4/config_test.go b/api4/config_test.go index 3d3a5f0d24..3ab59eeba0 100644 --- a/api4/config_test.go +++ b/api4/config_test.go @@ -90,6 +90,32 @@ func TestGetConfigWithAccessTag(t *testing.T) { t.Run("Can read value with permission", func(t *testing.T) { assert.Equal(t, mockVaryByHeader, cfg.RateLimitSettings.VaryByHeader) }) + + t.Run("Contains Feature Flags", func(t *testing.T) { + assert.NotNil(t, cfg.FeatureFlags) + }) +} + +func TestGetConfigAnyFlagsAccess(t *testing.T) { + th := Setup(t) + defer th.TearDown() + + th.Client.Login(th.BasicUser.Username, th.BasicUser.Password) + cfg, resp := th.Client.GetConfig() + + t.Run("Check permissions error with no sysconsole read permission", func(t *testing.T) { + CheckForbiddenStatus(t, resp) + }) + + // add read sysconsole environment config + th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, model.SYSTEM_USER_ROLE_ID) + defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, model.SYSTEM_USER_ROLE_ID) + + cfg, resp = th.Client.GetConfig() + CheckNoError(t, resp) + t.Run("Can read value with permission", func(t *testing.T) { + assert.NotNil(t, cfg.FeatureFlags) + }) } func TestReloadConfig(t *testing.T) { diff --git a/model/config.go b/model/config.go index d63ccb04ec..5a06ed5ba3 100644 --- a/model/config.go +++ b/model/config.go @@ -3050,6 +3050,9 @@ const ConfigAccessTagType = "access" const ConfigAccessTagWriteRestrictable = "write_restrictable" const ConfigAccessTagCloudRestrictable = "cloud_restrictable" +// Allows read access if any PERMISSION_SYSCONSOLE_READ_* is allowed +const ConfigAccessTagAnySysConsoleRead = "*_read" + // Config fields support the 'access' tag with the following values corresponding to the suffix of the associated // PERMISSION_SYSCONSOLE_*_* permission Id: 'about', 'reporting', 'user_management_users', // 'user_management_groups', 'user_management_teams', 'user_management_channels', @@ -3057,6 +3060,8 @@ const ConfigAccessTagCloudRestrictable = "cloud_restrictable" // 'integrations', 'compliance', 'plugins', and 'experimental'. They grant read and/or write access to the config field // to roles without PERMISSION_MANAGE_SYSTEM. // +// The 'access' tag '*_read' checks for any SYSCONSOLE read permission and grants access if any read permission is allowed. +// // By default config values can be written with PERMISSION_MANAGE_SYSTEM, but if ExperimentalSettings.RestrictSystemAdmin is true // and the access tag contains the value 'write_restrictable', then even PERMISSION_MANAGE_SYSTEM does not grant write access. // @@ -3119,7 +3124,7 @@ type Config struct { GuestAccountsSettings GuestAccountsSettings ImageProxySettings ImageProxySettings CloudSettings CloudSettings // telemetry: none - FeatureFlags *FeatureFlags `json:",omitempty"` // telemetry: none + FeatureFlags *FeatureFlags `access:"*_read" json:",omitempty"` // telemetry: none ImportSettings ImportSettings // telemetry: none ExportSettings ExportSettings }