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 }