github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/store/sqlstore/role_store.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "fmt" 9 "net/http" 10 "strings" 11 12 sq "github.com/Masterminds/squirrel" 13 "github.com/mattermost/gorp" 14 "github.com/vnforks/kid/v5/model" 15 "github.com/vnforks/kid/v5/store" 16 ) 17 18 type SqlRoleStore struct { 19 SqlStore 20 } 21 22 type Role struct { 23 Id string 24 Name string 25 DisplayName string 26 Description string 27 CreateAt int64 28 UpdateAt int64 29 DeleteAt int64 30 Permissions string 31 SchemeManaged bool 32 BuiltIn bool 33 } 34 35 type classRolesPermissions struct { 36 UserRoleName string 37 AdminRoleName string 38 HigherScopedUserPermissions string 39 HigherScopedAdminPermissions string 40 } 41 42 func NewRoleFromModel(role *model.Role) *Role { 43 permissionsMap := make(map[string]bool) 44 permissions := "" 45 46 for _, permission := range role.Permissions { 47 if !permissionsMap[permission] { 48 permissions += fmt.Sprintf(" %v", permission) 49 permissionsMap[permission] = true 50 } 51 } 52 53 return &Role{ 54 Id: role.Id, 55 Name: role.Name, 56 DisplayName: role.DisplayName, 57 Description: role.Description, 58 CreateAt: role.CreateAt, 59 UpdateAt: role.UpdateAt, 60 DeleteAt: role.DeleteAt, 61 Permissions: permissions, 62 SchemeManaged: role.SchemeManaged, 63 BuiltIn: role.BuiltIn, 64 } 65 } 66 67 func (role Role) ToModel() *model.Role { 68 return &model.Role{ 69 Id: role.Id, 70 Name: role.Name, 71 DisplayName: role.DisplayName, 72 Description: role.Description, 73 CreateAt: role.CreateAt, 74 UpdateAt: role.UpdateAt, 75 DeleteAt: role.DeleteAt, 76 Permissions: strings.Fields(role.Permissions), 77 SchemeManaged: role.SchemeManaged, 78 BuiltIn: role.BuiltIn, 79 } 80 } 81 82 func newSqlRoleStore(sqlStore SqlStore) store.RoleStore { 83 s := &SqlRoleStore{sqlStore} 84 85 for _, db := range sqlStore.GetAllConns() { 86 table := db.AddTableWithName(Role{}, "Roles").SetKeys(false, "Id") 87 table.ColMap("Id").SetMaxSize(26) 88 table.ColMap("Name").SetMaxSize(64).SetUnique(true) 89 table.ColMap("DisplayName").SetMaxSize(128) 90 table.ColMap("Description").SetMaxSize(1024) 91 table.ColMap("Permissions").SetMaxSize(4096) 92 } 93 return s 94 } 95 96 func (s *SqlRoleStore) Save(role *model.Role) (*model.Role, *model.AppError) { 97 // Check the role is valid before proceeding. 98 if !role.IsValidWithoutId() { 99 return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.invalid_role.app_error", nil, "", http.StatusBadRequest) 100 } 101 102 if len(role.Id) == 0 { 103 transaction, err := s.GetMaster().Begin() 104 if err != nil { 105 return nil, model.NewAppError("SqlRoleStore.RoleSave", "store.sql_role.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 106 } 107 defer finalizeTransaction(transaction) 108 createdRole, appErr := s.createRole(role, transaction) 109 if appErr != nil { 110 transaction.Rollback() 111 return nil, appErr 112 } else if err := transaction.Commit(); err != nil { 113 return nil, model.NewAppError("SqlRoleStore.RoleSave", "store.sql_role.save_role.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 114 } 115 return createdRole, nil 116 } 117 118 dbRole := NewRoleFromModel(role) 119 dbRole.UpdateAt = model.GetMillis() 120 if rowsChanged, err := s.GetMaster().Update(dbRole); err != nil { 121 return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.update.app_error", nil, err.Error(), http.StatusInternalServerError) 122 } else if rowsChanged != 1 { 123 return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.update.app_error", nil, "no record to update", http.StatusInternalServerError) 124 } 125 126 return dbRole.ToModel(), nil 127 } 128 129 func (s *SqlRoleStore) createRole(role *model.Role, transaction *gorp.Transaction) (*model.Role, *model.AppError) { 130 // Check the role is valid before proceeding. 131 if !role.IsValidWithoutId() { 132 return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.invalid_role.app_error", nil, "", http.StatusBadRequest) 133 } 134 135 dbRole := NewRoleFromModel(role) 136 137 dbRole.Id = model.NewId() 138 dbRole.CreateAt = model.GetMillis() 139 dbRole.UpdateAt = dbRole.CreateAt 140 141 if err := transaction.Insert(dbRole); err != nil { 142 return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.insert.app_error", nil, err.Error(), http.StatusInternalServerError) 143 } 144 145 return dbRole.ToModel(), nil 146 } 147 148 func (s *SqlRoleStore) Get(roleId string) (*model.Role, *model.AppError) { 149 var dbRole Role 150 151 if err := s.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Id = :Id", map[string]interface{}{"Id": roleId}); err != nil { 152 if err == sql.ErrNoRows { 153 return nil, model.NewAppError("SqlRoleStore.Get", "store.sql_role.get.app_error", nil, "Id="+roleId+", "+err.Error(), http.StatusNotFound) 154 } 155 return nil, model.NewAppError("SqlRoleStore.Get", "store.sql_role.get.app_error", nil, err.Error(), http.StatusInternalServerError) 156 } 157 158 return dbRole.ToModel(), nil 159 } 160 161 func (s *SqlRoleStore) GetAll() ([]*model.Role, *model.AppError) { 162 var dbRoles []Role 163 164 if _, err := s.GetReplica().Select(&dbRoles, "SELECT * from Roles", map[string]interface{}{}); err != nil { 165 if err == sql.ErrNoRows { 166 return nil, model.NewAppError("SqlRoleStore.GetAll", "store.sql_role.get_all.app_error", nil, err.Error(), http.StatusNotFound) 167 } 168 return nil, model.NewAppError("SqlRoleStore.GetAll", "store.sql_role.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 169 } 170 171 var roles []*model.Role 172 for _, dbRole := range dbRoles { 173 roles = append(roles, dbRole.ToModel()) 174 } 175 return roles, nil 176 } 177 178 func (s *SqlRoleStore) GetByName(name string) (*model.Role, *model.AppError) { 179 var dbRole Role 180 181 if err := s.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil { 182 if err == sql.ErrNoRows { 183 return nil, model.NewAppError("SqlRoleStore.GetByName", "store.sql_role.get_by_name.app_error", nil, "name="+name+",err="+err.Error(), http.StatusNotFound) 184 } 185 return nil, model.NewAppError("SqlRoleStore.GetByName", "store.sql_role.get_by_name.app_error", nil, "name="+name+",err="+err.Error(), http.StatusInternalServerError) 186 } 187 188 return dbRole.ToModel(), nil 189 } 190 191 func (s *SqlRoleStore) GetByNames(names []string) ([]*model.Role, *model.AppError) { 192 var dbRoles []*Role 193 194 if len(names) == 0 { 195 return []*model.Role{}, nil 196 } 197 198 var searchPlaceholders []string 199 var parameters = map[string]interface{}{} 200 for i, value := range names { 201 searchPlaceholders = append(searchPlaceholders, fmt.Sprintf(":Name%d", i)) 202 parameters[fmt.Sprintf("Name%d", i)] = value 203 } 204 205 searchTerm := "Name IN (" + strings.Join(searchPlaceholders, ", ") + ")" 206 207 if _, err := s.GetReplica().Select(&dbRoles, "SELECT * from Roles WHERE "+searchTerm, parameters); err != nil { 208 return nil, model.NewAppError("SqlRoleStore.GetByNames", "store.sql_role.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError) 209 } 210 211 var roles []*model.Role 212 for _, dbRole := range dbRoles { 213 roles = append(roles, dbRole.ToModel()) 214 } 215 216 return roles, nil 217 } 218 219 func (s *SqlRoleStore) Delete(roleId string) (*model.Role, *model.AppError) { 220 // Get the role. 221 var role *Role 222 if err := s.GetReplica().SelectOne(&role, "SELECT * from Roles WHERE Id = :Id", map[string]interface{}{"Id": roleId}); err != nil { 223 if err == sql.ErrNoRows { 224 return nil, model.NewAppError("SqlRoleStore.Delete", "store.sql_role.get.app_error", nil, "Id="+roleId+", "+err.Error(), http.StatusNotFound) 225 } 226 return nil, model.NewAppError("SqlRoleStore.Delete", "store.sql_role.get.app_error", nil, err.Error(), http.StatusInternalServerError) 227 } 228 229 time := model.GetMillis() 230 role.DeleteAt = time 231 role.UpdateAt = time 232 233 if rowsChanged, err := s.GetMaster().Update(role); err != nil { 234 return nil, model.NewAppError("SqlRoleStore.Delete", "store.sql_role.delete.update.app_error", nil, err.Error(), http.StatusInternalServerError) 235 } else if rowsChanged != 1 { 236 return nil, model.NewAppError("SqlRoleStore.Delete", "store.sql_role.delete.update.app_error", nil, "no record to update", http.StatusInternalServerError) 237 } 238 return role.ToModel(), nil 239 } 240 241 func (s *SqlRoleStore) PermanentDeleteAll() *model.AppError { 242 if _, err := s.GetMaster().Exec("DELETE FROM Roles"); err != nil { 243 return model.NewAppError("SqlRoleStore.PermanentDeleteAll", "store.sql_role.permanent_delete_all.app_error", nil, err.Error(), http.StatusInternalServerError) 244 } 245 246 return nil 247 } 248 249 func (s *SqlRoleStore) classHigherScopedPermissionsQuery(roleNames []string) string { 250 sqlTmpl := ` 251 SELECT 252 RoleSchemes.DefaultClassUserRole AS UserRoleName, 253 RoleSchemes.DefaultClassAdminRole AS AdminRoleName, 254 UserRoles.Permissions AS HigherScopedUserPermissions, 255 AdminRoles.Permissions AS HigherScopedAdminPermissions 256 FROM 257 Schemes AS RoleSchemes 258 JOIN Classes ON Classes.SchemeId = RoleSchemes.Id 259 JOIN Branches ON Branches.Id = Classes.BranchId 260 JOIN Schemes ON Schemes.Id = Branches.SchemeId 261 JOIN Roles AS UserRoles ON UserRoles.Name = Schemes.DefaultClassUserRole 262 JOIN Roles AS AdminRoles ON AdminRoles.Name = Schemes.DefaultClassAdminRole 263 WHERE 264 RoleSchemes.DefaultClassUserRole IN ('%[1]s') 265 OR RoleSchemes.DefaultClassAdminRole IN ('%[1]s') 266 UNION 267 SELECT 268 Schemes.DefaultClassUserRole AS UserRoleName, 269 Schemes.DefaultClassAdminRole AS AdminRoleName, 270 UserRoles.Permissions AS HigherScopedUserPermissions, 271 AdminRoles.Permissions AS HigherScopedAdminPermissions 272 FROM 273 Schemes 274 JOIN Classes ON Classes.SchemeId = Schemes.Id 275 JOIN Branches ON Branches.Id = Classes.BranchId 276 JOIN Roles AS UserRoles ON UserRoles.Name = '%[3]s' 277 JOIN Roles AS AdminRoles ON AdminRoles.Name = '%[4]s' 278 WHERE 279 (Schemes.DefaultClassUserRole IN ('%[1]s') 280 OR Schemes.DefaultClassAdminRole IN ('%[1]s')) 281 AND (Branches.SchemeId = '' 282 OR Branches.SchemeId IS NULL) 283 ` 284 285 // The below three class role names are referenced by their name value because there is no system scheme 286 // record that ships with Mattermost, otherwise the system scheme would be referenced by name and the class 287 // roles would be referenced by their column names. 288 return fmt.Sprintf( 289 sqlTmpl, 290 strings.Join(roleNames, "', '"), 291 model.CLASS_USER_ROLE_ID, 292 model.CLASS_ADMIN_ROLE_ID, 293 ) 294 } 295 296 func (s *SqlRoleStore) ClassHigherScopedPermissions(roleNames []string) (map[string]*model.RolePermissions, *model.AppError) { 297 sql := s.classHigherScopedPermissionsQuery(roleNames) 298 299 var rolesPermissions []*classRolesPermissions 300 if _, err := s.GetReplica().Select(&rolesPermissions, sql); err != nil { 301 return nil, model.NewAppError("SqlRoleStore.HigherScopedPermissions", "store.sql_role.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError) 302 } 303 304 roleNameHigherScopedPermissions := map[string]*model.RolePermissions{} 305 306 for _, rp := range rolesPermissions { 307 roleNameHigherScopedPermissions[rp.UserRoleName] = &model.RolePermissions{RoleID: model.CLASS_USER_ROLE_ID, Permissions: strings.Split(rp.HigherScopedUserPermissions, " ")} 308 roleNameHigherScopedPermissions[rp.AdminRoleName] = &model.RolePermissions{RoleID: model.CLASS_ADMIN_ROLE_ID, Permissions: strings.Split(rp.HigherScopedAdminPermissions, " ")} 309 } 310 311 return roleNameHigherScopedPermissions, nil 312 } 313 314 func (s *SqlRoleStore) AllClassSchemeRoles() ([]*model.Role, *model.AppError) { 315 query := s.getQueryBuilder(). 316 Select("Roles.*"). 317 From("Schemes"). 318 Join("Roles ON Schemes.DefaultClassUserRole = Roles.Name OR Schemes.DefaultClassAdminRole = Roles.Name"). 319 Where(sq.Eq{"Schemes.Scope": model.SCHEME_SCOPE_CLASS}). 320 Where(sq.Eq{"Roles.DeleteAt": 0}). 321 Where(sq.Eq{"Schemes.DeleteAt": 0}) 322 323 queryString, args, err := query.ToSql() 324 if err != nil { 325 return nil, model.NewAppError("SqlRoleStore.AllClassSchemeManagedRoles", "store.sql.build_query.app_error", nil, err.Error(), http.StatusInternalServerError) 326 } 327 328 var dbRoles []*Role 329 if _, err = s.GetReplica().Select(&dbRoles, queryString, args...); err != nil { 330 return nil, model.NewAppError("SqlRoleStore.AllClassSchemeManagedRoles", "store.sql_role.get.app_error", nil, err.Error(), http.StatusInternalServerError) 331 } 332 333 var roles []*model.Role 334 for _, dbRole := range dbRoles { 335 roles = append(roles, dbRole.ToModel()) 336 } 337 338 return roles, nil 339 } 340 341 // ClassRolesUnderBranchRole finds all of the class-scheme roles under the branch of the given branch-scheme role. 342 func (s *SqlRoleStore) ClassRolesUnderBranchRole(roleName string) ([]*model.Role, *model.AppError) { 343 query := s.getQueryBuilder(). 344 Select("ClassSchemeRoles.*"). 345 From("Roles AS HigherScopedRoles"). 346 Join("Schemes AS HigherScopedSchemes ON (HigherScopedRoles.Name = HigherScopedSchemes.DefaultClassUserRole OR HigherScopedRoles.Name = HigherScopedSchemes.DefaultClassAdminRole)"). 347 Join("Branches ON Branches.SchemeId = HigherScopedSchemes.Id"). 348 Join("Classes ON Classes.BranchId = Branches.Id"). 349 Join("Schemes AS ClassSchemes ON Classes.SchemeId = ClassSchemes.Id"). 350 Join("Roles AS ClassSchemeRoles ON (ClassSchemeRoles.Name = ClassSchemes.DefaultClassUserRole OR ClassSchemeRoles.Name = ClassSchemes.DefaultClassAdminRole)"). 351 Where(sq.Eq{"HigherScopedSchemes.Scope": model.SCHEME_SCOPE_BRANCH}). 352 Where(sq.Eq{"HigherScopedRoles.Name": roleName}). 353 Where(sq.Eq{"HigherScopedRoles.DeleteAt": 0}). 354 Where(sq.Eq{"HigherScopedSchemes.DeleteAt": 0}). 355 Where(sq.Eq{"Branches.DeleteAt": 0}). 356 Where(sq.Eq{"Classes.DeleteAt": 0}). 357 Where(sq.Eq{"ClassSchemes.DeleteAt": 0}). 358 Where(sq.Eq{"ClassSchemeRoles.DeleteAt": 0}) 359 360 queryString, args, err := query.ToSql() 361 if err != nil { 362 return nil, model.NewAppError("SqlRoleStore.ClassRolesUnderBranchRole", "store.sql.build_query.app_error", nil, err.Error(), http.StatusInternalServerError) 363 } 364 365 var dbRoles []*Role 366 if _, err = s.GetReplica().Select(&dbRoles, queryString, args...); err != nil { 367 return nil, model.NewAppError("SqlRoleStore.ClassRolesUnderBranchRole", "store.sql_role.get.app_error", nil, err.Error(), http.StatusInternalServerError) 368 } 369 370 var roles []*model.Role 371 for _, dbRole := range dbRoles { 372 roles = append(roles, dbRole.ToModel()) 373 } 374 375 return roles, nil 376 }