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  }