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 <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ca9fd45408
Коммит
42274b9eee
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user