github.com/polarismesh/polaris@v1.17.8/store/mysql/user.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package sqldb
    19  
    20  import (
    21  	"database/sql"
    22  	"fmt"
    23  	"strings"
    24  	"time"
    25  
    26  	apisecurity "github.com/polarismesh/specification/source/go/api/v1/security"
    27  	"go.uber.org/zap"
    28  
    29  	"github.com/polarismesh/polaris/common/model"
    30  	"github.com/polarismesh/polaris/common/utils"
    31  	"github.com/polarismesh/polaris/store"
    32  )
    33  
    34  var (
    35  	// 用户查询相关属性对应关系
    36  	userAttributeMapping = map[string]string{
    37  		"owner":    "u.owner",
    38  		"name":     "u.name",
    39  		"group_id": "group_id",
    40  	}
    41  
    42  	// 用户-用户组关系查询属性对应关系
    43  	userLinkGroupAttributeMapping map[string]string = map[string]string{
    44  		"user_id":    "ul.user_id",
    45  		"group_name": "ug.name",
    46  		"group_id":   "ug.group_id",
    47  		"owner":      "ug.owner",
    48  	}
    49  )
    50  
    51  type userStore struct {
    52  	master *BaseDB
    53  	slave  *BaseDB
    54  }
    55  
    56  // AddUser 添加用户
    57  func (u *userStore) AddUser(user *model.User) error {
    58  	if user.ID == "" || user.Name == "" || user.Token == "" || user.Password == "" {
    59  		return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
    60  			"add user missing some params, id is %s, name is %s", user.ID, user.Name))
    61  	}
    62  
    63  	// 先清理无效数据
    64  	if err := u.cleanInValidUser(user.Name, user.Owner); err != nil {
    65  		return err
    66  	}
    67  
    68  	err := RetryTransaction("addUser", func() error {
    69  		return u.addUser(user)
    70  	})
    71  
    72  	return store.Error(err)
    73  }
    74  
    75  func (u *userStore) addUser(user *model.User) error {
    76  
    77  	tx, err := u.master.Begin()
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	defer func() { _ = tx.Rollback() }()
    83  
    84  	addSql := "INSERT INTO user(`id`, `name`, `password`, `owner`, `source`, `token`, " +
    85  		" `comment`, `flag`, `user_type`, " +
    86  		" `ctime`, `mtime`, `mobile`, `email`) VALUES (?,?,?,?,?,?,?,?,?,sysdate(),sysdate(),?,?)"
    87  
    88  	_, err = tx.Exec(addSql, []interface{}{
    89  		user.ID,
    90  		user.Name,
    91  		user.Password,
    92  		user.Owner,
    93  		user.Source,
    94  		user.Token,
    95  		user.Comment,
    96  		0,
    97  		user.Type,
    98  		user.Mobile,
    99  		user.Email,
   100  	}...)
   101  
   102  	if err != nil {
   103  		return store.Error(err)
   104  	}
   105  
   106  	owner := user.Owner
   107  	if owner == "" {
   108  		owner = user.ID
   109  	}
   110  
   111  	if err := createDefaultStrategy(tx, model.PrincipalUser, user.ID, user.Name, user.Owner); err != nil {
   112  		log.Error("[Auth][User] create default strategy", zap.Error(err))
   113  		return store.Error(err)
   114  	}
   115  
   116  	if err := tx.Commit(); err != nil {
   117  		log.Errorf("[Store][User] add user tx commit err: %s", err.Error())
   118  		return store.Error(err)
   119  	}
   120  	return nil
   121  }
   122  
   123  // UpdateUser 更新用户信息
   124  func (u *userStore) UpdateUser(user *model.User) error {
   125  	if user.ID == "" || user.Name == "" || user.Token == "" || user.Password == "" {
   126  		return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
   127  			"update user missing some params, id is %s, name is %s", user.ID, user.Name))
   128  	}
   129  
   130  	err := RetryTransaction("updateUser", func() error {
   131  		return u.updateUser(user)
   132  	})
   133  
   134  	return store.Error(err)
   135  }
   136  
   137  func (u *userStore) updateUser(user *model.User) error {
   138  
   139  	tx, err := u.master.Begin()
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	defer func() { _ = tx.Rollback() }()
   145  
   146  	tokenEnable := 1
   147  	if !user.TokenEnable {
   148  		tokenEnable = 0
   149  	}
   150  
   151  	modifySql := "UPDATE user SET password = ?, token = ?, comment = ?, token_enable = ?, mobile = ?, email = ?, " +
   152  		" mtime = sysdate() WHERE id = ? AND flag = 0"
   153  
   154  	_, err = tx.Exec(modifySql, []interface{}{
   155  		user.Password,
   156  		user.Token,
   157  		user.Comment,
   158  		tokenEnable,
   159  		user.Mobile,
   160  		user.Email,
   161  		user.ID,
   162  	}...)
   163  
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	if err := tx.Commit(); err != nil {
   169  		log.Errorf("[Store][User] update user tx commit err: %s", err.Error())
   170  		return err
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  // DeleteUser delete user by user id
   177  func (u *userStore) DeleteUser(user *model.User) error {
   178  	if user.ID == "" || user.Name == "" {
   179  		return store.NewStatusError(store.EmptyParamsErr, "delete user id parameter missing")
   180  	}
   181  
   182  	err := RetryTransaction("deleteUser", func() error {
   183  		return u.deleteUser(user)
   184  	})
   185  
   186  	return store.Error(err)
   187  }
   188  
   189  // deleteUser Specific deletion user steps
   190  // step 1. Delete the user-associated policy information
   191  //
   192  //	a. Delete the user's default policy
   193  //	b. Update the latest update time of related policies, make the Cache mechanism
   194  //	c. Delete the association relationship of the user and policy
   195  //
   196  // step 2. Delete the user group associated with this user
   197  func (u *userStore) deleteUser(user *model.User) error {
   198  	tx, err := u.master.Begin()
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	defer func() { _ = tx.Rollback() }()
   204  
   205  	if err := cleanLinkStrategy(tx, model.PrincipalUser, user.ID, user.Owner); err != nil {
   206  		return err
   207  	}
   208  
   209  	if _, err = tx.Exec("UPDATE user SET flag = 1 WHERE id = ?", user.ID); err != nil {
   210  		log.Error("[Store][User] update set user flag", zap.Error(err))
   211  		return err
   212  	}
   213  
   214  	if _, err = tx.Exec("UPDATE user_group SET mtime = sysdate() WHERE id IN (SELECT DISTINCT group_id FROM "+
   215  		" user_group_relation WHERE user_id = ?)", user.ID); err != nil {
   216  		log.Error("[Store][User] update usergroup mtime", zap.Error(err))
   217  		return err
   218  	}
   219  
   220  	if _, err = tx.Exec("DELETE FROM user_group_relation WHERE user_id = ?", user.ID); err != nil {
   221  		log.Error("[Store][User] delete usergroup relation", zap.Error(err))
   222  		return err
   223  	}
   224  
   225  	if err := tx.Commit(); err != nil {
   226  		log.Error("[Store][User] delete user tx commit", zap.Error(err))
   227  		return err
   228  	}
   229  	return nil
   230  }
   231  
   232  // GetSubCount get user's sub count
   233  func (u *userStore) GetSubCount(user *model.User) (uint32, error) {
   234  	var (
   235  		countSql   = "SELECT COUNT(*) FROM user WHERE owner = ? AND flag = 0"
   236  		count, err = queryEntryCount(u.master, countSql, []interface{}{user.ID})
   237  	)
   238  
   239  	if err != nil {
   240  		log.Error("[Store][User] count sub-account", zap.String("owner", user.Owner), zap.Error(err))
   241  	}
   242  
   243  	return count, err
   244  }
   245  
   246  // GetUser get user by user id
   247  func (u *userStore) GetUser(id string) (*model.User, error) {
   248  	var tokenEnable, userType int
   249  	getSql := `
   250  		 SELECT u.id, u.name, u.password, u.owner, u.comment, u.source, u.token, u.token_enable, 
   251  		 	u.user_type, u.mobile, u.email
   252  		 FROM user u
   253  		 WHERE u.flag = 0 AND u.id = ? 
   254  	  `
   255  	var (
   256  		row  = u.master.QueryRow(getSql, id)
   257  		user = new(model.User)
   258  	)
   259  
   260  	if err := row.Scan(&user.ID, &user.Name, &user.Password, &user.Owner, &user.Comment, &user.Source,
   261  		&user.Token, &tokenEnable, &userType, &user.Mobile, &user.Email); err != nil {
   262  		switch err {
   263  		case sql.ErrNoRows:
   264  			return nil, nil
   265  		default:
   266  			return nil, store.Error(err)
   267  		}
   268  	}
   269  
   270  	user.TokenEnable = tokenEnable == 1
   271  	user.Type = model.UserRoleType(userType)
   272  	// 北极星后续不在保存用户的 mobile 以及 email 信息,这里针对原来保存的数据也不进行对外展示,强制屏蔽数据
   273  	user.Mobile = ""
   274  	user.Email = ""
   275  	return user, nil
   276  }
   277  
   278  // GetUserByName 根据用户名、owner 获取用户
   279  func (u *userStore) GetUserByName(name, ownerId string) (*model.User, error) {
   280  	getSql := `
   281  		 SELECT u.id, u.name, u.password, u.owner, u.comment, u.source, u.token, u.token_enable, 
   282  		 	u.user_type, u.mobile, u.email
   283  		 FROM user u
   284  		 WHERE u.flag = 0
   285  			  AND u.name = ?
   286  			  AND u.owner = ? 
   287  	  `
   288  
   289  	var (
   290  		row                   = u.master.QueryRow(getSql, name, ownerId)
   291  		user                  = new(model.User)
   292  		tokenEnable, userType int
   293  	)
   294  
   295  	if err := row.Scan(&user.ID, &user.Name, &user.Password, &user.Owner, &user.Comment, &user.Source,
   296  		&user.Token, &tokenEnable, &userType, &user.Mobile, &user.Email); err != nil {
   297  		switch err {
   298  		case sql.ErrNoRows:
   299  			return nil, nil
   300  		default:
   301  			return nil, store.Error(err)
   302  		}
   303  	}
   304  
   305  	user.TokenEnable = tokenEnable == 1
   306  	user.Type = model.UserRoleType(userType)
   307  	// 北极星后续不在保存用户的 mobile 以及 email 信息,这里针对原来保存的数据也不进行对外展示,强制屏蔽数据
   308  	user.Mobile = ""
   309  	user.Email = ""
   310  	return user, nil
   311  }
   312  
   313  // GetUserByIds Get user list data according to user ID
   314  func (u *userStore) GetUserByIds(ids []string) ([]*model.User, error) {
   315  	if len(ids) == 0 {
   316  		return nil, nil
   317  	}
   318  
   319  	getSql := `
   320  	  SELECT u.id, u.name, u.password, u.owner, u.comment, u.source
   321  		  , u.token, u.token_enable, u.user_type, UNIX_TIMESTAMP(u.ctime)
   322  		  , UNIX_TIMESTAMP(u.mtime), u.flag, u.mobile, u.email
   323  	  FROM user u
   324  	  WHERE u.flag = 0 
   325  		  AND u.id IN ( 
   326  	  `
   327  
   328  	for i := range ids {
   329  		getSql += " ? "
   330  		if i != len(ids)-1 {
   331  			getSql += ","
   332  		}
   333  	}
   334  	getSql += ")"
   335  
   336  	args := make([]interface{}, 0, 8)
   337  	for index := range ids {
   338  		args = append(args, ids[index])
   339  	}
   340  
   341  	rows, err := u.master.Query(getSql, args...)
   342  	if err != nil {
   343  		return nil, store.Error(err)
   344  	}
   345  	defer func() {
   346  		_ = rows.Close()
   347  	}()
   348  
   349  	users := make([]*model.User, 0)
   350  	for rows.Next() {
   351  		user, err := fetchRown2User(rows)
   352  		if err != nil {
   353  			log.Errorf("[Store][User] fetch user rows scan err: %s", err.Error())
   354  			return nil, store.Error(err)
   355  		}
   356  		users = append(users, user)
   357  	}
   358  
   359  	return users, nil
   360  }
   361  
   362  // GetUsers Query user list information
   363  // Case 1. From the user's perspective, normal query conditions
   364  // Case 2. From the perspective of the user group, query is the list of users involved under a user group.
   365  func (u *userStore) GetUsers(filters map[string]string, offset uint32, limit uint32) (uint32,
   366  	[]*model.User, error) {
   367  	if _, ok := filters["group_id"]; ok {
   368  		return u.listGroupUsers(filters, offset, limit)
   369  	}
   370  	return u.listUsers(filters, offset, limit)
   371  }
   372  
   373  // listUsers Query user list information
   374  func (u *userStore) listUsers(filters map[string]string, offset uint32, limit uint32) (uint32,
   375  	[]*model.User, error) {
   376  	countSql := "SELECT COUNT(*) FROM user WHERE flag = 0 "
   377  	getSql := `
   378  	  SELECT id, name, password, owner, comment, source
   379  		  , token, token_enable, user_type, UNIX_TIMESTAMP(ctime)
   380  		  , UNIX_TIMESTAMP(mtime), flag, mobile, email
   381  	  FROM user
   382  	  WHERE flag = 0 
   383  	  `
   384  
   385  	if val, ok := filters["hide_admin"]; ok && val == "true" {
   386  		delete(filters, "hide_admin")
   387  		countSql += "  AND user_type != 0 "
   388  		getSql += "  AND user_type != 0 "
   389  	}
   390  
   391  	args := make([]interface{}, 0)
   392  
   393  	if len(filters) != 0 {
   394  		for k, v := range filters {
   395  			getSql += " AND "
   396  			countSql += " AND "
   397  			if k == NameAttribute {
   398  				if utils.IsPrefixWildName(v) {
   399  					getSql += " " + k + " like ? "
   400  					countSql += " " + k + " like ? "
   401  					args = append(args, "%"+v[:len(v)-1]+"%")
   402  				} else {
   403  					getSql += " " + k + " = ? "
   404  					countSql += " " + k + " = ? "
   405  					args = append(args, v)
   406  				}
   407  			} else if k == OwnerAttribute {
   408  				getSql += " (id = ? OR owner = ?) "
   409  				countSql += " (id = ? OR owner = ?) "
   410  				args = append(args, v, v)
   411  				continue
   412  			} else {
   413  				getSql += " " + k + " = ? "
   414  				countSql += " " + k + " = ? "
   415  				args = append(args, v)
   416  			}
   417  		}
   418  	}
   419  
   420  	count, err := queryEntryCount(u.master, countSql, args)
   421  	if err != nil {
   422  		return 0, nil, store.Error(err)
   423  	}
   424  
   425  	getSql += " ORDER BY mtime LIMIT ? , ?"
   426  	getArgs := append(args, offset, limit)
   427  
   428  	users, err := u.collectUsers(u.master.Query, getSql, getArgs)
   429  	if err != nil {
   430  		return 0, nil, err
   431  	}
   432  	return count, users, nil
   433  }
   434  
   435  // listGroupUsers Check the user information under a user group
   436  func (u *userStore) listGroupUsers(filters map[string]string, offset uint32, limit uint32) (uint32,
   437  	[]*model.User, error) {
   438  	if _, ok := filters[GroupIDAttribute]; !ok {
   439  		return 0, nil, store.NewStatusError(store.EmptyParamsErr, "group_id is missing")
   440  	}
   441  
   442  	args := make([]interface{}, 0, len(filters))
   443  	querySql := `
   444  		  SELECT u.id, name, password, owner, u.comment, source
   445  			  , token, token_enable, user_type, UNIX_TIMESTAMP(u.ctime)
   446  			  , UNIX_TIMESTAMP(u.mtime), u.flag, u.mobile, u.email
   447  		  FROM user_group_relation ug
   448  			  LEFT JOIN user u ON ug.user_id = u.id AND u.flag = 0
   449  		  WHERE 1=1 
   450  	  `
   451  	countSql := `
   452  		  SELECT COUNT(*)
   453  		  FROM user_group_relation ug
   454  			  LEFT JOIN user u ON ug.user_id = u.id AND u.flag = 0 
   455  		  WHERE 1=1 
   456  	  `
   457  
   458  	if val, ok := filters["hide_admin"]; ok && val == "true" {
   459  		delete(filters, "hide_admin")
   460  		countSql += " AND u.user_type != 0 "
   461  		querySql += " AND u.user_type != 0 "
   462  	}
   463  
   464  	for k, v := range filters {
   465  		if newK, ok := userLinkGroupAttributeMapping[k]; ok {
   466  			k = newK
   467  		}
   468  
   469  		if k == "ug.owner" {
   470  			k = "u.owner"
   471  		}
   472  
   473  		if utils.IsPrefixWildName(v) {
   474  			querySql += " AND " + k + " like ?"
   475  			countSql += " AND " + k + " like ?"
   476  			args = append(args, v[:len(v)-1]+"%")
   477  		} else {
   478  			querySql += " AND " + k + " = ?"
   479  			countSql += " AND " + k + " = ?"
   480  			args = append(args, v)
   481  		}
   482  	}
   483  
   484  	count, err := queryEntryCount(u.slave, countSql, args)
   485  	if err != nil {
   486  		return 0, nil, err
   487  	}
   488  
   489  	querySql += " ORDER BY u.mtime LIMIT ? , ?"
   490  	args = append(args, offset, limit)
   491  
   492  	users, err := u.collectUsers(u.master.Query, querySql, args)
   493  	if err != nil {
   494  		return 0, nil, err
   495  	}
   496  
   497  	return count, users, nil
   498  }
   499  
   500  // GetUsersForCache Get user information, mainly for cache
   501  func (u *userStore) GetUsersForCache(mtime time.Time, firstUpdate bool) ([]*model.User, error) {
   502  	args := make([]interface{}, 0)
   503  	querySql := `
   504  	  SELECT u.id, u.name, u.password, u.owner, u.comment, u.source
   505  		  , u.token, u.token_enable, user_type, UNIX_TIMESTAMP(u.ctime)
   506  		  , UNIX_TIMESTAMP(u.mtime), u.flag, u.mobile, u.email
   507  	  FROM user u 
   508  	  `
   509  
   510  	if !firstUpdate {
   511  		querySql += " WHERE u.mtime >= FROM_UNIXTIME(?) "
   512  		args = append(args, timeToTimestamp(mtime))
   513  	}
   514  
   515  	users, err := u.collectUsers(u.master.Query, querySql, args)
   516  	if err != nil {
   517  		return nil, err
   518  	}
   519  
   520  	return users, nil
   521  }
   522  
   523  // collectUsers General query user list
   524  func (u *userStore) collectUsers(handler QueryHandler, querySql string, args []interface{}) ([]*model.User, error) {
   525  	rows, err := u.master.Query(querySql, args...)
   526  	if err != nil {
   527  		log.Error("[Store][User] list user ", zap.String("query sql", querySql), zap.Any("args", args), zap.Error(err))
   528  		return nil, store.Error(err)
   529  	}
   530  	defer func() {
   531  		_ = rows.Close()
   532  	}()
   533  	users := make([]*model.User, 0)
   534  	for rows.Next() {
   535  		user, err := fetchRown2User(rows)
   536  		if err != nil {
   537  			log.Errorf("[Store][User] fetch user rows scan err: %s", err.Error())
   538  			return nil, store.Error(err)
   539  		}
   540  		users = append(users, user)
   541  	}
   542  
   543  	return users, nil
   544  }
   545  
   546  func createDefaultStrategy(tx *BaseTx, role model.PrincipalType, id, name, owner string) error {
   547  	if strings.Compare(owner, "") == 0 {
   548  		owner = id
   549  	}
   550  
   551  	// Create the user's default weight policy
   552  	strategy := &model.StrategyDetail{
   553  		ID:        utils.NewUUID(),
   554  		Name:      model.BuildDefaultStrategyName(role, name),
   555  		Action:    apisecurity.AuthAction_READ_WRITE.String(),
   556  		Default:   true,
   557  		Owner:     owner,
   558  		Revision:  utils.NewUUID(),
   559  		Resources: []model.StrategyResource{},
   560  		Valid:     true,
   561  		Comment:   "Default Strategy",
   562  	}
   563  
   564  	// 需要清理过期的 auth_strategy
   565  	cleanInvalidRule := "DELETE FROM auth_strategy WHERE name = ? AND owner = ? AND flag = 1 AND `default` = ?"
   566  	if _, err := tx.Exec(cleanInvalidRule, []interface{}{strategy.Name, strategy.Owner,
   567  		strategy.Default}...); err != nil {
   568  		return err
   569  	}
   570  
   571  	// Save policy master information
   572  	saveMainSql := "INSERT INTO auth_strategy(`id`, `name`, `action`, `owner`, `comment`, `flag`, " +
   573  		" `default`, `revision`) VALUES (?,?,?,?,?,?,?,?)"
   574  	if _, err := tx.Exec(saveMainSql, []interface{}{strategy.ID, strategy.Name, strategy.Action,
   575  		strategy.Owner, strategy.Comment,
   576  		0, strategy.Default, strategy.Revision}...); err != nil {
   577  		return err
   578  	}
   579  
   580  	// Insert User / Group and Policy Association
   581  	savePrincipalSql := "INSERT INTO auth_principal(`strategy_id`, `principal_id`, `principal_role`) VALUES (?,?,?)"
   582  	_, err := tx.Exec(savePrincipalSql, []interface{}{strategy.ID, id, role}...)
   583  	return err
   584  }
   585  
   586  func fetchRown2User(rows *sql.Rows) (*model.User, error) {
   587  	var (
   588  		ctime, mtime                int64
   589  		flag, tokenEnable, userType int
   590  		user                        = new(model.User)
   591  		err                         = rows.Scan(&user.ID, &user.Name, &user.Password, &user.Owner,
   592  			&user.Comment, &user.Source, &user.Token, &tokenEnable, &userType, &ctime, &mtime,
   593  			&flag, &user.Mobile, &user.Email)
   594  	)
   595  
   596  	if err != nil {
   597  		return nil, err
   598  	}
   599  
   600  	user.Valid = flag == 0
   601  	user.TokenEnable = tokenEnable == 1
   602  	user.CreateTime = time.Unix(ctime, 0)
   603  	user.ModifyTime = time.Unix(mtime, 0)
   604  	user.Type = model.UserRoleType(userType)
   605  
   606  	// 北极星后续不在保存用户的 mobile 以及 email 信息,这里针对原来保存的数据也不进行对外展示,强制屏蔽数据
   607  	user.Mobile = ""
   608  	user.Email = ""
   609  
   610  	return user, nil
   611  }
   612  
   613  func (u *userStore) cleanInValidUser(name, owner string) error {
   614  	log.Infof("[Store][User] clean user, name=(%s), owner=(%s)", name, owner)
   615  	str := "delete from user where name = ? and owner = ? and flag = 1"
   616  	if _, err := u.master.Exec(str, name, owner); err != nil {
   617  		log.Errorf("[Store][User] clean user(%s) err: %s", name, err.Error())
   618  		return err
   619  	}
   620  
   621  	return nil
   622  }