Files
mattermost/app/permissions_migrations.go
Jesús Espino c8920588a0 Adding new "VIEW_MEMBERS" permissions restrict the scope of users visibility (#10487)
* MM-14138: Adding new "VIEW_MEMBERS" permissions restrict the scope of users visibility

* Fixing gofmt

* Fixing broken tests

* Addressing PR review comments from Miguel de la Cruz

* Removed hack

* A bit nicer and cleaner code in the UserBelongsToChannels function

* Adding cluster cache invalidation for user team ids

* Checking in the correct order permissions to not leek existency information

* Adding restrictions to TeamMembers and User status requests

* Fixing tests

* Fixing status endpoint permissions checks

* Adding more tests

* Fixing tests

* More tests and making the restrictions query based only on joins

* Adding more tests

* Adding more tests

* fixing merge problems

* Reverting status changes to avoid performance issues

* Adding more tests

* Fixing test

* i18n extract

* Adding extra method for get restrictions for a team

* Add the new elasticsearch functions to search users with restrictions

* Add missing translation string

* Rename restrictedChannelIds to restrictedToChannels

* Remove ToDo

* Adding the permission to the SystemAdmin role during permissions migrations
2019-04-29 16:56:56 +02:00

299 lines
11 KiB
Go

// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package app
import (
"github.com/mattermost/mattermost-server/model"
)
type permissionTransformation struct {
On func(string, map[string]map[string]bool) bool
Add []string
Remove []string
}
type permissionsMap []permissionTransformation
const (
MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT = "emoji_permissions_split"
MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT = "webhook_permissions_split"
MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS = "list_join_public_private_teams"
MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER = "remove_permanent_delete_user"
MIGRATION_KEY_ADD_BOT_PERMISSIONS = "add_bot_permissions"
MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER = "apply_channel_manage_delete_to_channel_user"
MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER = "remove_channel_manage_delete_from_team_user"
MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION = "view_members_new_permission"
PERMISSION_MANAGE_SYSTEM = "manage_system"
PERMISSION_MANAGE_EMOJIS = "manage_emojis"
PERMISSION_MANAGE_OTHERS_EMOJIS = "manage_others_emojis"
PERMISSION_CREATE_EMOJIS = "create_emojis"
PERMISSION_DELETE_EMOJIS = "delete_emojis"
PERMISSION_DELETE_OTHERS_EMOJIS = "delete_others_emojis"
PERMISSION_MANAGE_WEBHOOKS = "manage_webhooks"
PERMISSION_MANAGE_OTHERS_WEBHOOKS = "manage_others_webhooks"
PERMISSION_MANAGE_INCOMING_WEBHOOKS = "manage_incoming_webhooks"
PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = "manage_others_incoming_webhooks"
PERMISSION_MANAGE_OUTGOING_WEBHOOKS = "manage_outgoing_webhooks"
PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = "manage_others_outgoing_webhooks"
PERMISSION_LIST_PUBLIC_TEAMS = "list_public_teams"
PERMISSION_LIST_PRIVATE_TEAMS = "list_private_teams"
PERMISSION_JOIN_PUBLIC_TEAMS = "join_public_teams"
PERMISSION_JOIN_PRIVATE_TEAMS = "join_private_teams"
PERMISSION_PERMANENT_DELETE_USER = "permanent_delete_user"
PERMISSION_CREATE_BOT = "create_bot"
PERMISSION_READ_BOTS = "read_bots"
PERMISSION_READ_OTHERS_BOTS = "read_others_bots"
PERMISSION_MANAGE_BOTS = "manage_bots"
PERMISSION_MANAGE_OTHERS_BOTS = "manage_others_bots"
PERMISSION_DELETE_PUBLIC_CHANNEL = "delete_public_channel"
PERMISSION_DELETE_PRIVATE_CHANNEL = "delete_private_channel"
PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = "manage_public_channel_properties"
PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = "manage_private_channel_properties"
PERMISSION_VIEW_MEMBERS = "view_members"
)
func isRole(role string) func(string, map[string]map[string]bool) bool {
return func(roleName string, permissionsMap map[string]map[string]bool) bool {
return roleName == role
}
}
func permissionExists(permission string) func(string, map[string]map[string]bool) bool {
return func(roleName string, permissionsMap map[string]map[string]bool) bool {
val, ok := permissionsMap[roleName][permission]
return ok && val
}
}
func permissionNotExists(permission string) func(string, map[string]map[string]bool) bool {
return func(roleName string, permissionsMap map[string]map[string]bool) bool {
val, ok := permissionsMap[roleName][permission]
return !(ok && val)
}
}
func onOtherRole(otherRole string, function func(string, map[string]map[string]bool) bool) func(string, map[string]map[string]bool) bool {
return func(roleName string, permissionsMap map[string]map[string]bool) bool {
return function(otherRole, permissionsMap)
}
}
func permissionOr(funcs ...func(string, map[string]map[string]bool) bool) func(string, map[string]map[string]bool) bool {
return func(roleName string, permissionsMap map[string]map[string]bool) bool {
for _, f := range funcs {
if f(roleName, permissionsMap) {
return true
}
}
return false
}
}
func permissionAnd(funcs ...func(string, map[string]map[string]bool) bool) func(string, map[string]map[string]bool) bool {
return func(roleName string, permissionsMap map[string]map[string]bool) bool {
for _, f := range funcs {
if !f(roleName, permissionsMap) {
return false
}
}
return true
}
}
func applyPermissionsMap(roleName string, roleMap map[string]map[string]bool, migrationMap permissionsMap) []string {
var result []string
for _, transformation := range migrationMap {
if transformation.On(roleName, roleMap) {
for _, permission := range transformation.Add {
roleMap[roleName][permission] = true
}
for _, permission := range transformation.Remove {
roleMap[roleName][permission] = false
}
}
}
for key, active := range roleMap[roleName] {
if active {
result = append(result, key)
}
}
return result
}
func (a *App) doPermissionsMigration(key string, migrationMap permissionsMap) *model.AppError {
if result := <-a.Srv.Store.System().GetByName(key); result.Err == nil {
return nil
}
roles, err := a.GetAllRoles()
if err != nil {
return err
}
roleMap := make(map[string]map[string]bool)
for _, role := range roles {
roleMap[role.Name] = make(map[string]bool)
for _, permission := range role.Permissions {
roleMap[role.Name][permission] = true
}
}
for _, role := range roles {
role.Permissions = applyPermissionsMap(role.Name, roleMap, migrationMap)
if result := <-a.Srv.Store.Role().Save(role); result.Err != nil {
return result.Err
}
}
if result := <-a.Srv.Store.System().Save(&model.System{Name: key, Value: "true"}); result.Err != nil {
return result.Err
}
return nil
}
func getEmojisPermissionsSplitMigration() permissionsMap {
return permissionsMap{
permissionTransformation{
On: permissionExists(PERMISSION_MANAGE_EMOJIS),
Add: []string{PERMISSION_CREATE_EMOJIS, PERMISSION_DELETE_EMOJIS},
Remove: []string{PERMISSION_MANAGE_EMOJIS},
},
permissionTransformation{
On: permissionExists(PERMISSION_MANAGE_OTHERS_EMOJIS),
Add: []string{PERMISSION_DELETE_OTHERS_EMOJIS},
Remove: []string{PERMISSION_MANAGE_OTHERS_EMOJIS},
},
}
}
func getWebhooksPermissionsSplitMigration() permissionsMap {
return permissionsMap{
permissionTransformation{
On: permissionExists(PERMISSION_MANAGE_WEBHOOKS),
Add: []string{PERMISSION_MANAGE_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OUTGOING_WEBHOOKS},
Remove: []string{PERMISSION_MANAGE_WEBHOOKS},
},
permissionTransformation{
On: permissionExists(PERMISSION_MANAGE_OTHERS_WEBHOOKS),
Add: []string{PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS},
Remove: []string{PERMISSION_MANAGE_OTHERS_WEBHOOKS},
},
}
}
func getListJoinPublicPrivateTeamsPermissionsMigration() permissionsMap {
return permissionsMap{
permissionTransformation{
On: isRole(model.SYSTEM_ADMIN_ROLE_ID),
Add: []string{PERMISSION_LIST_PRIVATE_TEAMS, PERMISSION_JOIN_PRIVATE_TEAMS},
Remove: []string{},
},
permissionTransformation{
On: isRole(model.SYSTEM_USER_ROLE_ID),
Add: []string{PERMISSION_LIST_PUBLIC_TEAMS, PERMISSION_JOIN_PUBLIC_TEAMS},
Remove: []string{},
},
}
}
func removePermanentDeleteUserMigration() permissionsMap {
return permissionsMap{
permissionTransformation{
On: permissionExists(PERMISSION_PERMANENT_DELETE_USER),
Remove: []string{PERMISSION_PERMANENT_DELETE_USER},
},
}
}
func getAddBotPermissionsMigration() permissionsMap {
return permissionsMap{
permissionTransformation{
On: isRole(model.SYSTEM_ADMIN_ROLE_ID),
Add: []string{PERMISSION_CREATE_BOT, PERMISSION_READ_BOTS, PERMISSION_READ_OTHERS_BOTS, PERMISSION_MANAGE_BOTS, PERMISSION_MANAGE_OTHERS_BOTS},
Remove: []string{},
},
}
}
func applyChannelManageDeleteToChannelUser() permissionsMap {
return permissionsMap{
permissionTransformation{
On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES))),
Add: []string{PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES},
},
permissionTransformation{
On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_PRIVATE_CHANNEL))),
Add: []string{PERMISSION_DELETE_PRIVATE_CHANNEL},
},
permissionTransformation{
On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES))),
Add: []string{PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES},
},
permissionTransformation{
On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_PUBLIC_CHANNEL))),
Add: []string{PERMISSION_DELETE_PUBLIC_CHANNEL},
},
}
}
func removeChannelManageDeleteFromTeamUser() permissionsMap {
return permissionsMap{
permissionTransformation{
On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES)),
Remove: []string{PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES},
},
permissionTransformation{
On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_PRIVATE_CHANNEL)),
Remove: []string{model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id},
},
permissionTransformation{
On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES)),
Remove: []string{PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES},
},
permissionTransformation{
On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_PUBLIC_CHANNEL)),
Remove: []string{PERMISSION_DELETE_PUBLIC_CHANNEL},
},
}
}
func getViewMembersPermissionMigration() permissionsMap {
return permissionsMap{
permissionTransformation{
On: isRole(model.SYSTEM_USER_ROLE_ID),
Add: []string{PERMISSION_VIEW_MEMBERS},
},
permissionTransformation{
On: isRole(model.SYSTEM_ADMIN_ROLE_ID),
Add: []string{PERMISSION_VIEW_MEMBERS},
},
}
}
// DoPermissionsMigrations execute all the permissions migrations need by the current version.
func (a *App) DoPermissionsMigrations() *model.AppError {
PermissionsMigrations := []struct {
Key string
Migration func() permissionsMap
}{
{Key: MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT, Migration: getEmojisPermissionsSplitMigration},
{Key: MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT, Migration: getWebhooksPermissionsSplitMigration},
{Key: MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS, Migration: getListJoinPublicPrivateTeamsPermissionsMigration},
{Key: MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER, Migration: removePermanentDeleteUserMigration},
{Key: MIGRATION_KEY_ADD_BOT_PERMISSIONS, Migration: getAddBotPermissionsMigration},
{Key: MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER, Migration: applyChannelManageDeleteToChannelUser},
{Key: MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER, Migration: removeChannelManageDeleteFromTeamUser},
{Key: MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION, Migration: getViewMembersPermissionMigration},
}
for _, migration := range PermissionsMigrations {
if err := a.doPermissionsMigration(migration.Key, migration.Migration()); err != nil {
return err
}
}
return nil
}