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  }