package ldap import ( "errors" "fmt" "github.com/astaxie/beego/logs" "github.com/astaxie/beego/orm" "github.com/go-ldap/ldap/v3" "nginx-ui/server/config" "nginx-ui/server/models" ) type UserService struct { } // Add Update 保存或者修改 func (c *UserService) Add(body *models.LdapUser) (*models.LdapUser, error) { server := models.LdapServer{ Key: body.ServerKey, } o := orm.NewOrm() err := o.Read(&server, "Key") if err != nil { return nil, err } body.Uid = server.Uid exist := models.LdapUser{ Account: body.Account, } isNew := false err = o.Read(&exist, "Account") if err != nil && errors.Is(err, orm.ErrNoRows) { _, err = o.Insert(body) isNew = true } else if err != nil { return nil, err } else { body.Id = exist.Id _, err = o.Update(body) } if err != nil { return nil, err } client, err := GetActiveClient(&server) if err != nil { return nil, err } err = client.Add(body) if err != nil { return nil, err } if body.Password != config.ReplacePassword { err := client.ModifyPasswordByAdmin(body.DN, body.Password) if err != nil { return nil, errors.New("新增成功,但密码修改失败!") } if isNew { SendUserAddEmail(body, body.Password) } } entry, err := client.SearchByAccount(body.Account) if err != nil { return nil, err } modifyLDAPUser(body, entry) _, _ = o.Update(body) return body, nil } // get /ldap/users func (c *UserService) GetDetail(id int) (*models.LdapUser, error) { o := orm.NewOrm() user := models.LdapUser{Id: id} err := o.Read(&user, "Id") if err != nil { return nil, err } user.Password = config.ReplacePassword return &user, nil } func (c *UserService) GetByAccount(account string) (*models.LdapUser, error) { o := orm.NewOrm() user := models.LdapUser{Account: account} err := o.Read(&user, "Account") if err != nil { return nil, err } user.Password = config.ReplacePassword return &user, nil } func (c *UserService) Search(server *models.LdapServer, filter string) ([]*models.LdapUser, []*models.LdapOrganize, error) { client, err := GetActiveClient(server) if err != nil { return nil, nil, err } entries, err := client.Search(filter) if err != nil { return nil, nil, err } var users []*models.LdapUser var organizeList []*models.LdapOrganize for _, entry := range entries { var isOrganize = false objectClass := entry.GetAttributeValues("objectClass") for _, oc := range objectClass { if oc == server.OrganizeClass || oc == "organization" { isOrganize = true break } } if isOrganize { organize := models.LdapOrganize{ Name: entry.GetAttributeValue("ou"), DN: entry.DN, ServerKey: server.Key, ObjectClass: entry.GetAttributeValue("objectClass"), } organizeList = append(organizeList, &organize) } else { user := createUser(entry) user.ServerKey = server.Key users = append(users, &user) } } return users, organizeList, nil } // SyncUser SyncUsers 同步用户信息 // post /ldap/user/sync func (c *UserService) SyncUser(server *models.LdapServer, current *models.LdapUser) error { o := orm.NewOrm() if server == nil { server := &models.LdapServer{Key: current.ServerKey} err := o.Read(server, "Key") if err != nil { return err } } filter := fmt.Sprintf("(&(objectClass=*)(uid=%s))", current.Account) users, _, err := c.Search(server, filter) if len(users) != 1 { return errors.New("账号不存在或者账号重复!") } user := users[0] user.Id = current.Id user.ServerKey = current.ServerKey user.Uid = current.Uid user.Remark = current.Remark _, err = o.Update(user) if err != nil { return err } return nil } // SyncUsers 同步用户信息 // post /ldap/user/sync func (c *UserService) SyncUsers(current *models.User, req *LDAPUserSyncReq) (int, error) { server := &models.LdapServer{Key: req.ServerKey} o := orm.NewOrm() err := o.Read(server, "Key") if err != nil { return 0, err } users, organizeList, err := c.Search(server, req.Filter) if err != nil { return 0, err } for _, user := range users { user.Uid = string(rune(current.Id)) _, err := models.InsertOrUpdate[models.LdapUser](o, user, "DN") if err != nil { logs.Error("save user fail: %v", err) } } for _, organize := range organizeList { _, err = models.InsertOrUpdate[models.LdapOrganize](o, organize, "DN") if err != nil { logs.Error("save organize fail: %v", err) } } return len(users), nil } func (c *UserService) Authentication(server *models.LdapServer, account string, password string) (*models.User, error) { o := orm.NewOrm() ldapUser := &models.LdapUser{ Account: account, } err := o.Read(ldapUser, "Account") if err != nil && !errors.Is(err, orm.ErrNoRows) { return nil, err } else if err != nil { // The username and password we want to check filter := fmt.Sprintf("(&(objectClass=*)(uid=%s))", ldap.EscapeFilter(account)) users, _, err := c.Search(server, filter) if err != nil || len(users) != 1 { logs.Error("search fail: %v", err) return nil, errors.New("您输入的账号或者密码错误!") } ldapUser = users[0] _, err = models.InsertOrUpdate[models.LdapUser](o, ldapUser, "DN") if err != nil { return nil, err } } userDN := ldapUser.DN client, err := GetActiveClient(server) if err != nil { return nil, err } err = client.Authentication(userDN, password) if err != nil { return nil, err } user := &models.User{ Account: account, } err = o.Read(user, "Account") if err != nil && !errors.Is(err, orm.ErrNoRows) { return nil, err } else if err != nil { CreateLocalUser(user, ldapUser) _, err = o.Insert(user) if err != nil { return nil, err } } else if user.Source == "LDAP" { user.Nickname = ldapUser.UserName _, _ = o.Update(user, "Nickname") } return user, nil } // UpdateUserPassword 更新用户密码 // post /ldap/user/modifyPassword func (c *UserService) UpdateUserPassword(req *UpdatePasswordReq, byAdmin bool) error { o := orm.NewOrm() user := models.LdapUser{ Account: req.Account, } err := o.Read(&user, "Account") if err != nil { if errors.Is(err, orm.ErrNoRows) { return nil } logs.Error("read user fail: %v", err) return err } server := models.LdapServer{ Key: user.ServerKey, } err = o.Read(&server, "Key") if err != nil { return err } client, err := GetActiveClient(&server) if err != nil { return err } if byAdmin { err = client.ModifyPasswordByAdmin(user.DN, req.Password) } else { err = client.ModifyPassword(user.DN, req.OldPassword, req.Password) } if err != nil { return err } err = c.SyncUser(&server, &user) if err != nil { return errors.New("密码更新成功,但更新用户信息失败:" + err.Error()) } return nil }