From 42274b9eee11d0633b24898154bca44dc8f91518 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Thu, 10 Apr 2025 16:22:03 -0300 Subject: [PATCH] MM-63200: unrestricted local admin (#30295) * use SessionHasPermissionToCheckRestrictedAdmin * allow unrestricted config edits from localmode * check model.PermissionManageSystem for getLatestVersion * simplify/clarify RequestTrialLicense semantics * rename for clarity * whitespace from linter --------- Co-authored-by: Mattermost Build --- server/channels/api4/bleve.go | 7 +- server/channels/api4/cluster.go | 7 +- server/channels/api4/config.go | 25 +++--- server/channels/api4/elasticsearch.go | 14 +--- server/channels/api4/license.go | 21 +---- server/channels/api4/system.go | 61 +++----------- server/channels/app/authorization.go | 14 ++++ server/channels/app/authorization_test.go | 96 +++++++++++++++++++++++ server/channels/app/license.go | 8 -- server/channels/app/plugin_api.go | 3 + server/public/model/config.go | 3 +- 11 files changed, 142 insertions(+), 117 deletions(-) diff --git a/server/channels/api4/bleve.go b/server/channels/api4/bleve.go index 37dbd84472..88c6e01dc6 100644 --- a/server/channels/api4/bleve.go +++ b/server/channels/api4/bleve.go @@ -18,16 +18,11 @@ func purgeBleveIndexes(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("purgeBleveIndexes", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionPurgeBleveIndexes) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionPurgeBleveIndexes) { c.SetPermissionError(model.PermissionPurgeBleveIndexes) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("purgeBleveIndexes", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - if err := c.App.PurgeBleveIndexes(c.AppContext); err != nil { c.Err = err return diff --git a/server/channels/api4/cluster.go b/server/channels/api4/cluster.go index 7d4ad51b9c..f2b246d832 100644 --- a/server/channels/api4/cluster.go +++ b/server/channels/api4/cluster.go @@ -15,16 +15,11 @@ func (api *API) InitCluster() { } func getClusterStatus(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadEnvironmentHighAvailability) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionSysconsoleReadEnvironmentHighAvailability) { c.SetPermissionError(model.PermissionSysconsoleReadEnvironmentHighAvailability) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("getClusterStatus", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - infos := c.App.GetClusterStatus(c.AppContext) js, err := json.Marshal(infos) if err != nil { diff --git a/server/channels/api4/config.go b/server/channels/api4/config.go index 1d7abbadfe..f88768e605 100644 --- a/server/channels/api4/config.go +++ b/server/channels/api4/config.go @@ -19,9 +19,11 @@ import ( "github.com/mattermost/mattermost/server/v8/config" ) -var writeFilter func(c *Context, structField reflect.StructField) bool -var readFilter func(c *Context, structField reflect.StructField) bool -var permissionMap map[string]*model.Permission +var ( + writeFilter func(c *Context, structField reflect.StructField) bool + readFilter func(c *Context, structField reflect.StructField) bool + permissionMap map[string]*model.Permission +) type filterType string @@ -100,16 +102,11 @@ func configReload(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("configReload", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionReloadConfig) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionReloadConfig) { c.SetPermissionError(model.PermissionReloadConfig) return } - if !c.AppContext.Session().IsUnrestricted() && *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("configReload", "api.restricted_system_admin", nil, "", http.StatusBadRequest) - return - } - if err := c.App.ReloadConfig(); err != nil { c.Err = model.NewAppError("configReload", "api.config.reload_config.app_error", nil, "", http.StatusInternalServerError).Wrap(err) return @@ -230,7 +227,7 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { return } - //auditRec.AddEventResultState(cfg) // TODO we can do this too but do we want to? the config object is huge + // auditRec.AddEventResultState(cfg) // TODO we can do this too but do we want to? the config object is huge auditRec.AddEventObjectType("config") auditRec.Success() c.LogAudit("updateConfig") @@ -406,12 +403,8 @@ func makeFilterConfigByPermission(accessType filterType) func(c *Context, struct tagPermissions := strings.Split(structField.Tag.Get("access"), ",") - // If there are no access tag values and the role has manage_system, no need to continue - // checking permissions. - if len(tagPermissions) == 0 { - if c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) { - return true - } + if c.AppContext.Session().IsUnrestricted() { + return true } // one iteration for write_restrictable value, it could be anywhere in the order of values diff --git a/server/channels/api4/elasticsearch.go b/server/channels/api4/elasticsearch.go index 763eaf6e46..a247a74a55 100644 --- a/server/channels/api4/elasticsearch.go +++ b/server/channels/api4/elasticsearch.go @@ -39,16 +39,11 @@ func testElasticsearch(c *Context, w http.ResponseWriter, r *http.Request) { // PERMISSION_TEST_ELASTICSEARCH is an ancillary permission of PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH, // which should prevent read-only managers from password sniffing - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionTestElasticsearch) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionTestElasticsearch) { c.SetPermissionError(model.PermissionTestElasticsearch) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("testElasticsearch", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - if err := c.App.TestElasticsearch(c.AppContext, cfg); err != nil { c.Err = err return @@ -61,16 +56,11 @@ func purgeElasticsearchIndexes(c *Context, w http.ResponseWriter, r *http.Reques auditRec := c.MakeAuditRecord("purgeElasticsearchIndexes", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionPurgeElasticsearchIndexes) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionPurgeElasticsearchIndexes) { c.SetPermissionError(model.PermissionPurgeElasticsearchIndexes) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("purgeElasticsearchIndexes", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - specifiedIndexesQuery := r.URL.Query()["index"] if err := c.App.PurgeElasticsearchIndexes(c.AppContext, specifiedIndexesQuery); err != nil { c.Err = err diff --git a/server/channels/api4/license.go b/server/channels/api4/license.go index 3377f43017..3bef081456 100644 --- a/server/channels/api4/license.go +++ b/server/channels/api4/license.go @@ -55,16 +55,11 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) c.LogAudit("attempt") - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionManageLicenseInformation) { c.SetPermissionError(model.PermissionManageLicenseInformation) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("addLicense", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -162,16 +157,11 @@ func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) c.LogAudit("attempt") - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionManageLicenseInformation) { c.SetPermissionError(model.PermissionManageLicenseInformation) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("removeLicense", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - if err := c.App.Srv().RemoveLicense(); err != nil { c.Err = err return @@ -188,16 +178,11 @@ func requestTrialLicense(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) c.LogAudit("attempt") - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionManageLicenseInformation) { c.SetPermissionError(model.PermissionManageLicenseInformation) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("requestTrialLicense", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - if c.App.Srv().Platform().LicenseManager() == nil { c.Err = model.NewAppError("requestTrialLicense", "api.license.upgrade_needed.app_error", nil, "", http.StatusForbidden) return diff --git a/server/channels/api4/system.go b/server/channels/api4/system.go index dc57191582..592e9554e6 100644 --- a/server/channels/api4/system.go +++ b/server/channels/api4/system.go @@ -83,13 +83,8 @@ func generateSupportPacket(c *Context, w http.ResponseWriter, r *http.Request) { const FileMime = "application/zip" const OutputDirectory = "support_packet" - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("generateSupportPacket", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - // Support Packet generation is limited to system admins (MM-42271). - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionManageSystem) { c.SetPermissionError(model.PermissionManageSystem) return } @@ -262,16 +257,11 @@ func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionTestEmail) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionTestEmail) { c.SetPermissionError(model.PermissionTestEmail) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("testEmail", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - appErr := c.App.TestEmail(c.AppContext, c.AppContext.Session().UserId, cfg) if appErr != nil { c.Err = appErr @@ -282,16 +272,11 @@ func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { } func testSiteURL(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionTestSiteURL) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionTestSiteURL) { c.SetPermissionError(model.PermissionTestSiteURL) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("testSiteURL", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - props := model.MapFromJSON(r.Body) siteURL := props["site_url"] if siteURL == "" { @@ -333,7 +318,7 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { } func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionRecycleDatabaseConnections) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionRecycleDatabaseConnections) { c.SetPermissionError(model.PermissionRecycleDatabaseConnections) return } @@ -341,11 +326,6 @@ func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("databaseRecycle", audit.Fail) defer c.LogAuditRec(auditRec) - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("databaseRecycle", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - c.App.RecycleDatabaseConnection(c.AppContext) auditRec.Success() @@ -353,7 +333,7 @@ func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { } func invalidateCaches(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionInvalidateCaches) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionInvalidateCaches) { c.SetPermissionError(model.PermissionInvalidateCaches) return } @@ -361,11 +341,6 @@ func invalidateCaches(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("invalidateCaches", audit.Fail) defer c.LogAuditRec(auditRec) - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("invalidateCaches", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - appErr := c.App.Srv().InvalidateAllCaches() if appErr != nil { c.Err = appErr @@ -382,12 +357,7 @@ func queryLogs(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("queryLogs", audit.Fail) defer c.LogAuditRec(auditRec) - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("queryLogs", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionGetLogs) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionGetLogs) { c.SetPermissionError(model.PermissionGetLogs) return } @@ -430,12 +400,7 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("getLogs", audit.Fail) defer c.LogAuditRec(auditRec) - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("getLogs", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionGetLogs) { + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionGetLogs) { c.SetPermissionError(model.PermissionGetLogs) return } @@ -457,11 +422,8 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { func downloadLogs(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("downloadLogs", audit.Fail) defer c.LogAuditRec(auditRec) - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("downloadLogs", "api.restricted_system_admin", nil, "", http.StatusForbidden) - return - } - if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionGetLogs) { + + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionGetLogs) { c.SetPermissionError(model.PermissionGetLogs) return } @@ -563,8 +525,8 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { } func getLatestVersion(c *Context, w http.ResponseWriter, r *http.Request) { - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - c.Err = model.NewAppError("latestVersion", "api.restricted_system_admin", nil, "", http.StatusForbidden) + if !c.App.SessionHasPermissionToAndNotRestrictedAdmin(*c.AppContext.Session(), model.PermissionManageSystem) { + c.SetPermissionError(model.PermissionManageSystem) return } @@ -1034,7 +996,6 @@ func getOnboarding(c *Context, w http.ResponseWriter, r *http.Request) { } firstAdminCompleteSetupObj, err := c.App.GetOnboarding() - if err != nil { c.Err = model.NewAppError("getOnboarding", "app.system.get_onboarding_request.app_error", nil, "", http.StatusInternalServerError).Wrap(err) return diff --git a/server/channels/app/authorization.go b/server/channels/app/authorization.go index 2a5d2af60c..70669fd2be 100644 --- a/server/channels/app/authorization.go +++ b/server/channels/app/authorization.go @@ -21,6 +21,20 @@ func (a *App) SessionHasPermissionTo(session model.Session, permission *model.Pe return a.RolesGrantPermission(session.GetUserRoles(), permission.Id) } +// SessionHasPermissionToAndNotRestrictedAdmin is a variant of [App.SessionHasPermissionTo] that +// denies access to restricted system admins. Note that a local session is always unrestricted. +func (a *App) SessionHasPermissionToAndNotRestrictedAdmin(session model.Session, permission *model.Permission) bool { + if session.IsUnrestricted() { + return true + } + + if *a.Config().ExperimentalSettings.RestrictSystemAdmin { + return false + } + + return a.RolesGrantPermission(session.GetUserRoles(), permission.Id) +} + func (a *App) SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool { for _, perm := range permissions { if a.SessionHasPermissionTo(session, perm) { diff --git a/server/channels/app/authorization_test.go b/server/channels/app/authorization_test.go index b935e59fcc..ac3228ec31 100644 --- a/server/channels/app/authorization_test.go +++ b/server/channels/app/authorization_test.go @@ -21,6 +21,102 @@ import ( "github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks" ) +func TestSessionHasPermissionTo(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + localSession := model.Session{ + UserId: th.BasicUser.Id, + Roles: model.SystemUserRoleId, + Local: true, + } + + adminSession := model.Session{ + UserId: th.SystemAdminUser.Id, + Roles: model.SystemAdminRoleId, + } + + session := model.Session{ + UserId: th.BasicUser.Id, + Roles: model.SystemUserRoleId, + } + + t.Run("basic user cannot manage system", func(t *testing.T) { + require.False(t, th.App.SessionHasPermissionTo(session, model.PermissionManageSystem)) + }) + + t.Run("basic user generally has no global permissions", func(t *testing.T) { + require.False(t, th.App.SessionHasPermissionTo(session, model.PermissionReadPublicChannel)) + }) + + t.Run("system admin can manage system", func(t *testing.T) { + require.True(t, th.App.SessionHasPermissionTo(adminSession, model.PermissionManageSystem)) + }) + + t.Run("unrestricted session has all permissions", func(t *testing.T) { + require.True(t, th.App.SessionHasPermissionTo(localSession, model.PermissionManageSystem)) + require.True(t, th.App.SessionHasPermissionTo(localSession, model.PermissionCreateBot)) + require.True(t, th.App.SessionHasPermissionTo(localSession, model.PermissionReadPublicChannel)) + }) +} + +func TestSessionHasPermissionToAndNotRestrictedAdmin(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + localSession := model.Session{ + UserId: th.BasicUser.Id, + Roles: model.SystemUserRoleId, + Local: true, + } + + adminSession := model.Session{ + UserId: th.SystemAdminUser.Id, + Roles: model.SystemAdminRoleId, + } + + session := model.Session{ + UserId: th.BasicUser.Id, + Roles: model.SystemUserRoleId, + } + + t.Run("basic user cannot manage system", func(t *testing.T) { + require.False(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(session, model.PermissionManageSystem)) + }) + + t.Run("allow system admin when not restricted", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ExperimentalSettings.RestrictSystemAdmin = false + }) + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(adminSession, model.PermissionManageSystem)) + }) + + t.Run("reject system admin when restricted", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ExperimentalSettings.RestrictSystemAdmin = true + }) + require.False(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(adminSession, model.PermissionManageSystem)) + }) + + t.Run("always allow unrestricted session", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ExperimentalSettings.RestrictSystemAdmin = false + }) + + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(localSession, model.PermissionManageSystem)) + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(localSession, model.PermissionCreateBot)) + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(localSession, model.PermissionReadPublicChannel)) + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ExperimentalSettings.RestrictSystemAdmin = true + }) + + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(localSession, model.PermissionManageSystem)) + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(localSession, model.PermissionCreateBot)) + require.True(t, th.App.SessionHasPermissionToAndNotRestrictedAdmin(localSession, model.PermissionReadPublicChannel)) + }) +} + func TestCheckIfRolesGrantPermission(t *testing.T) { th := Setup(t) defer th.TearDown() diff --git a/server/channels/app/license.go b/server/channels/app/license.go index 20c3b356c6..aee10644ec 100644 --- a/server/channels/app/license.go +++ b/server/channels/app/license.go @@ -18,10 +18,6 @@ func (ch *Channels) License() *model.License { } func (ch *Channels) RequestTrialLicenseWithExtraFields(requesterID string, trialRequest *model.TrialLicenseRequest) *model.AppError { - if *ch.srv.platform.Config().ExperimentalSettings.RestrictSystemAdmin { - return model.NewAppError("RequestTrialLicense", "api.restricted_system_admin", nil, "", http.StatusForbidden) - } - requester, err := ch.srv.userService.GetUser(requesterID) if err != nil { var nfErr *store.ErrNotFound @@ -63,10 +59,6 @@ func (ch *Channels) RequestTrialLicenseWithExtraFields(requesterID string, trial // Deprecated: Use RequestTrialLicenseWithExtraFields instead. This function remains to support the Plugin API. func (ch *Channels) RequestTrialLicense(requesterID string, users int, termsAccepted bool, receiveEmailsAccepted bool) *model.AppError { - if *ch.srv.platform.Config().ExperimentalSettings.RestrictSystemAdmin { - return model.NewAppError("RequestTrialLicense", "api.restricted_system_admin", nil, "", http.StatusForbidden) - } - if !termsAccepted { return model.NewAppError("RequestTrialLicense", "api.license.request-trial.bad-request.terms-not-accepted", nil, "", http.StatusBadRequest) } diff --git a/server/channels/app/plugin_api.go b/server/channels/app/plugin_api.go index 86c48ece88..ec6385cfcd 100644 --- a/server/channels/app/plugin_api.go +++ b/server/channels/app/plugin_api.go @@ -1354,6 +1354,9 @@ func (api *PluginAPI) PublishPluginClusterEvent(ev model.PluginClusterEvent, // RequestTrialLicense requests a trial license and installs it in the server func (api *PluginAPI) RequestTrialLicense(requesterID string, users int, termsAccepted bool, receiveEmailsAccepted bool) *model.AppError { + // Normally, plugins are unrestricted in their abilities, but to maintain backwards compatbilibity with plugins + // that were unaware of the nuances of ExperimentalSettings.RestrictSystemAdmin, we restrict the trial license + // unconditionally. if *api.app.Config().ExperimentalSettings.RestrictSystemAdmin { return model.NewAppError("RequestTrialLicense", "api.restricted_system_admin", nil, "", http.StatusForbidden) } diff --git a/server/public/model/config.go b/server/public/model/config.go index acf727e757..814f5c31ac 100644 --- a/server/public/model/config.go +++ b/server/public/model/config.go @@ -3677,7 +3677,8 @@ const ConfigAccessTagAnySysConsoleRead = "*_read" // 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 PermissionManageSystem, but if ExperimentalSettings.RestrictSystemAdmin is true -// and the access tag contains the value 'write_restrictable', then even PermissionManageSystem, does not grant write access. +// and the access tag contains the value 'write_restrictable', then even PermissionManageSystem, does not grant write access +// unless the request is made using local mode. // // PermissionManageSystem always grants read access. //