github.com/infraboard/keyauth@v0.8.1/apps/user/impl/user.go (about) 1 package impl 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/infraboard/mcube/exception" 8 "github.com/infraboard/mcube/types/ftime" 9 "go.mongodb.org/mongo-driver/bson" 10 "go.mongodb.org/mongo-driver/mongo" 11 12 "github.com/infraboard/keyauth/apps/domain" 13 "github.com/infraboard/keyauth/apps/policy" 14 "github.com/infraboard/keyauth/apps/user" 15 "github.com/infraboard/keyauth/common/password" 16 common "github.com/infraboard/keyauth/common/types" 17 ) 18 19 func (s *service) QueryAccount(ctx context.Context, req *user.QueryAccountRequest) (*user.Set, error) { 20 r, err := newQueryUserRequest(req) 21 if err != nil { 22 return nil, err 23 } 24 return s.queryAccount(ctx, r) 25 } 26 27 func (s *service) CreateAccount(ctx context.Context, req *user.CreateAccountRequest) (*user.User, error) { 28 u, err := user.New(req) 29 if err != nil { 30 return nil, err 31 } 32 33 // 如果是管理员创建的账号需要用户自己重置密码 34 if u.CreateType.IsIn(user.CreateType_DOMAIN_CREATED) { 35 u.HashedPassword.SetNeedReset("admin created user need reset when first login") 36 } 37 38 if err := s.saveAccount(u); err != nil { 39 return nil, err 40 } 41 42 u.HashedPassword = nil 43 return u, nil 44 } 45 46 func (s *service) UpdateAccountProfile(ctx context.Context, req *user.UpdateAccountRequest) (*user.User, error) { 47 if err := req.Validate(); err != nil { 48 return nil, exception.NewBadRequest("validate update department error, %s", err) 49 } 50 51 s.log.Debugf("[%s] update %s profile", req.UpdateMode.String(), req.Account) 52 u, err := s.DescribeAccount(ctx, user.NewDescriptAccountRequestWithAccount(req.Account)) 53 if err != nil { 54 return nil, err 55 } 56 u.UpdateAt = ftime.Now().Timestamp() 57 58 // 更新profile 59 if req.Profile != nil { 60 u.IsInitialized = true 61 switch req.UpdateMode { 62 case common.UpdateMode_PUT: 63 *u.Profile = *req.Profile 64 case common.UpdateMode_PATCH: 65 u.Profile.Patch(req.Profile) 66 default: 67 return nil, exception.NewBadRequest("unknown update mode: %s", req.UpdateMode) 68 } 69 } 70 71 _, err = s.col.UpdateOne(context.TODO(), bson.M{"_id": u.Account}, bson.M{"$set": u}) 72 if err != nil { 73 return nil, exception.NewInternalServerError("update user(%s) error, %s", u.Account, err) 74 } 75 76 return u, nil 77 } 78 79 func (s *service) UpdateAccountPassword(ctx context.Context, req *user.UpdatePasswordRequest) (*user.Password, error) { 80 if err := req.Validate(); err != nil { 81 return nil, exception.NewBadRequest("check update pass request error, %s", err) 82 } 83 return s.changePass(ctx, req.Account, req.OldPass, req.NewPass, req.IsReset) 84 } 85 86 func (s *service) changePass(ctx context.Context, account, old, new string, isReset bool) (*user.Password, error) { 87 descReq := user.NewDescriptAccountRequest() 88 descReq.Account = account 89 s.log.Debugf("query user account ...") 90 u, err := s.DescribeAccount(ctx, descReq) 91 if err != nil { 92 return nil, err 93 } 94 95 s.log.Debugf("query domain security setting ...") 96 // 根据域设置的规则检测密码策略 97 descDom := domain.NewDescribeDomainRequestWithName(u.Domain) 98 dom, err := s.domain.DescribeDomain(ctx, descDom) 99 if err != nil { 100 return nil, err 101 } 102 103 s.log.Debugf("check password strength ...") 104 // 检测密码强度 105 if err := dom.SecuritySetting.PasswordSecurity.Check(new); err != nil { 106 return nil, err 107 } 108 109 s.log.Debugf("check password is history ...") 110 // 判断是不是历史密码 111 if u.HashedPassword.IsHistory(new) { 112 return nil, exception.NewBadRequest("password not last %d used", dom.SecuritySetting.PasswordSecurity.RepeateLimite) 113 } 114 115 s.log.Debugf("change password ...") 116 if err := u.ChangePassword(old, new, dom.SecuritySetting.GetPasswordRepeateLimite(), isReset); err != nil { 117 return nil, exception.NewBadRequest("change password error, %s", err) 118 } 119 120 s.log.Debugf("save password to db ...") 121 _, err = s.col.UpdateOne(context.TODO(), bson.M{"_id": u.Account}, bson.M{"$set": bson.M{ 122 "password": u.HashedPassword, 123 }}) 124 125 if err != nil { 126 return nil, exception.NewInternalServerError("update user(%s) password error, %s", u.Account, err) 127 } 128 129 u.Desensitize() 130 return u.HashedPassword, nil 131 } 132 133 func (s *service) DescribeAccount(ctx context.Context, req *user.DescribeAccountRequest) (*user.User, error) { 134 r, err := newDescribeRequest(req) 135 if err != nil { 136 return nil, err 137 } 138 139 ins := user.NewDefaultUser() 140 if err := s.col.FindOne(ctx, r.FindFilter()).Decode(ins); err != nil { 141 if err == mongo.ErrNoDocuments { 142 return nil, exception.NewNotFound("user %s not found", req) 143 } 144 145 return nil, exception.NewInternalServerError("find user %s error, %s", req, err) 146 } 147 148 dom, err := s.domain.DescribeDomain(ctx, domain.NewDescribeDomainRequestWithName(ins.Domain)) 149 if err != nil { 150 return nil, err 151 } 152 153 dom.SecuritySetting.PasswordSecurity.SetPasswordNeedReset(ins.HashedPassword) 154 return ins, nil 155 } 156 157 func (s *service) BlockAccount(ctx context.Context, req *user.BlockAccountRequest) (*user.User, error) { 158 if err := req.Validate(); err != nil { 159 return nil, err 160 } 161 162 desc := user.NewDescriptAccountRequestWithAccount(req.Account) 163 user, err := s.DescribeAccount(ctx, desc) 164 if err != nil { 165 return nil, fmt.Errorf("describe user error, %s", err) 166 } 167 168 user.Block(req.Reason) 169 _, err = s.col.UpdateOne(context.TODO(), bson.M{"_id": user.Account}, bson.M{"$set": bson.M{ 170 "status": user.Status, 171 }}) 172 if err != nil { 173 return nil, fmt.Errorf("update user status error, %s", err) 174 } 175 176 return user, nil 177 } 178 179 func (s *service) UnBlockAccount(ctx context.Context, req *user.UnBlockAccountRequest) (*user.User, error) { 180 if err := req.Validate(); err != nil { 181 return nil, err 182 } 183 184 desc := user.NewDescriptAccountRequestWithAccount(req.Account) 185 user, err := s.DescribeAccount(ctx, desc) 186 if err != nil { 187 return nil, fmt.Errorf("describe user error, %s", err) 188 } 189 190 err = user.UnBlock() 191 if err != nil { 192 return nil, err 193 } 194 195 _, err = s.col.UpdateOne(context.TODO(), bson.M{"_id": user.Account}, bson.M{"$set": bson.M{ 196 "status": user.Status, 197 }}) 198 if err != nil { 199 return nil, fmt.Errorf("update user status error, %s", err) 200 } 201 202 return user, nil 203 } 204 205 func (s *service) DeleteAccount(ctx context.Context, req *user.DeleteAccountRequest) (*user.User, error) { 206 _, err := s.col.DeleteOne(context.TODO(), bson.M{"_id": req.Account}) 207 if err != nil { 208 return nil, exception.NewInternalServerError("delete user(%s) error, %s", req.Account, err) 209 } 210 211 // 清除账号的关联的所有策略 212 if _, err := s.policy.DeletePolicy(ctx, policy.NewDeletePolicyRequestWithAccount(req.Account)); err != nil { 213 s.log.Errorf("delete account policy error, %s", err) 214 } 215 216 return user.NewDefaultUser(), nil 217 } 218 219 func (s *service) GeneratePassword(ctx context.Context, req *user.GeneratePasswordRequest) (*user.GeneratePasswordResponse, error) { 220 s.log.Debugf("query domain security setting ...") 221 // 根据域设置的规则检测密码策略 222 descDom := domain.NewDescribeDomainRequestWithName(req.Domain) 223 dom, err := s.domain.DescribeDomain(ctx, descDom) 224 if err != nil { 225 return nil, err 226 } 227 228 genConf := dom.SecuritySetting.PasswordSecurity.GenRandomPasswordConfig() 229 ranPass, err := password.New(&genConf).Generate() 230 if err != nil { 231 return nil, fmt.Errorf("generate random password error, %s", err) 232 } 233 return user.NewGeneratePasswordResponse(*ranPass), nil 234 }