From e1cd64613591cf5a990442a69ebf188258bd0cb5 Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Tue, 6 Feb 2018 15:34:08 +0000 Subject: XYZ-37: Advanced Permissions Phase 1 Backend. (#8159) * XYZ-13: Update Permission and Role structs to new design. * XYZ-10: Role store. * XYZ-9/XYZ-44: Roles API endpoints and WebSocket message. * XYZ-8: Switch server permissions checks to store backed roles. * XYZ-58: Proper validation of roles where required. * XYZ-11/XYZ-55: Migration to store backed roles from policy config. * XYZ-37: Update unit tests to work with database roles. * XYZ-56: Remove the "guest" role. * Changes to SetDefaultRolesFromConfig. * Short-circuit the store if nothing has changed. * Address first round of review comments. * Address second round of review comments. --- app/app.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) (limited to 'app/app.go') diff --git a/app/app.go b/app/app.go index 1e46d29d0..4cc9ff7df 100644 --- a/app/app.go +++ b/app/app.go @@ -7,6 +7,7 @@ import ( "html/template" "net" "net/http" + "reflect" "strings" "sync" "sync/atomic" @@ -25,6 +26,8 @@ import ( "github.com/mattermost/mattermost-server/utils" ) +const ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete" + type App struct { goroutineCount int32 goroutineExitSignal chan struct{} @@ -62,7 +65,6 @@ type App struct { htmlTemplateWatcher *utils.HTMLTemplateWatcher sessionCache *utils.Cache - roles map[string]*model.Role configListenerId string licenseListenerId string disableConfigWatch bool @@ -120,7 +122,6 @@ func New(options ...Option) (*App, error) { }) app.licenseListenerId = utils.AddLicenseListener(app.configOrLicenseListener) app.regenerateClientConfig() - app.SetDefaultRolesBasedOnConfig() l4g.Info(utils.T("api.server.new_server.init.info")) @@ -157,7 +158,6 @@ func New(options ...Option) (*App, error) { func (a *App) configOrLicenseListener() { a.regenerateClientConfig() - a.SetDefaultRolesBasedOnConfig() } func (a *App) Shutdown() { @@ -450,3 +450,57 @@ func (a *App) Handle404(w http.ResponseWriter, r *http.Request) { utils.RenderWebError(err, w, r) } + +// This function migrates the default built in roles from code/config to the database. +func (a *App) DoAdvancedPermissionsMigration() { + // If the migration is already marked as completed, don't do it again. + if result := <-a.Srv.Store.System().GetByName(ADVANCED_PERMISSIONS_MIGRATION_KEY); result.Err == nil { + return + } + + l4g.Info("Migrating roles to database.") + roles := model.MakeDefaultRoles() + roles = utils.SetRolePermissionsFromConfig(roles, a.Config()) + + allSucceeded := true + + for _, role := range roles { + if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { + // If this failed for reasons other than the role already existing, don't mark the migration as done. + if result2 := <-a.Srv.Store.Role().GetByName(role.Name); result2.Err != nil { + l4g.Critical("Failed to migrate role to database.") + l4g.Critical(result.Err) + allSucceeded = false + } else { + // If the role already existed, check it is the same and update if not. + fetchedRole := result.Data.(*model.Role) + if !reflect.DeepEqual(fetchedRole.Permissions, role.Permissions) || + fetchedRole.DisplayName != role.DisplayName || + fetchedRole.Description != role.Description || + fetchedRole.SchemeManaged != role.SchemeManaged { + role.Id = fetchedRole.Id + if result := <-a.Srv.Store.Role().Save(role); result.Err != nil { + // Role is not the same, but failed to update. + l4g.Critical("Failed to migrate role to database.") + l4g.Critical(result.Err) + allSucceeded = false + } + } + } + } + } + + if !allSucceeded { + return + } + + system := model.System{ + Name: ADVANCED_PERMISSIONS_MIGRATION_KEY, + Value: "true", + } + + if result := <-a.Srv.Store.System().Save(&system); result.Err != nil { + l4g.Critical("Failed to mark advanced permissions migration as completed.") + l4g.Critical(result.Err) + } +} -- cgit v1.2.3-1-g7c22