package ldap import ( "crypto/md5" "encoding/hex" "errors" "fmt" "github.com/astaxie/beego/logs" "github.com/astaxie/beego/orm" "nginx-ui/server/config" "nginx-ui/server/models" "nginx-ui/server/vo" ) type Service struct { } // GetServer 获取一个可用的LDAP 连接, 用于登录时获取服务信息 func (c *Service) GetServer() (*models.LdapServer, error) { o := orm.NewOrm() server := models.LdapServer{ Active: true, } err := o.Read(&server, "Active") if err != nil { return nil, err } return &server, nil } func (c *Service) Login(req *LDAPLoginReq) (*models.User, error) { server := models.LdapServer{Key: req.ServerKey} o := orm.NewOrm() err := o.Read(&server, "Key") if err != nil { return nil, errors.New("未找到对应的LDAP服务!") } client, err := GetActiveClient(&server) if err != nil { return nil, err } ldapUser, err := client.Authentication(req.Account, req.Password) if err != nil { return nil, err } ldapUser.Uid = server.Uid ldapUser.ServerKey = server.Key _, err = o.InsertOrUpdate(ldapUser, "DN") if err != nil { return nil, err } var user = models.User{ Account: ldapUser.Account, } err = o.Read(&user, "Account") if err != nil { if !errors.Is(err, orm.ErrNoRows) { return nil, err } user.Password = ldapUser.Password user.Account = ldapUser.Account user.Nickname = ldapUser.UserName user.Source = "LDAP" _, err := o.Insert(&user) if err != nil { return nil, err } } else if user.Source == "LDAP" { // 更新用户 user.Password = ldapUser.Password user.Nickname = ldapUser.UserName _, err = o.Update(&user, "Password", "Nickname") if err != nil { return nil, err } } user.Password = "" return &user, nil } // GetServers 获取用户所有的LDAP连接 // get /ldap/server func (c *Service) GetServers(current *models.User, req *vo.PageReq) (*vo.PageResp, error) { o := orm.NewOrm() req.Ensure() qs := o.QueryTable(&models.LdapServer{}) if !current.IsAdmin() { qs = qs.Filter("Uid", current.Account) } total, err := qs.Count() if err != nil { return nil, err } qs.OrderBy("Id") qs.Offset(req.Offset) qs.Limit(req.PageSize) var list []*models.LdapServer _, err = qs.All(&list) for _, v := range list { v.Password = config.ReplacePassword } if err != nil { return nil, err } resp := vo.PageResp{ Current: req.Current, PageSize: req.PageSize, Total: total, List: list, } return &resp, err } // SyncUsers 同步用户信息 // post /ldap/user/sync func (c *Service) 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 } client, err := GetActiveClient(&server) if err != nil { return 0, err } users, err := client.Search(req.Filter) if err != nil { return 0, err } for _, user := range users { user.ServerKey = server.Key user.Uid = string(rune(current.Id)) _, err := o.InsertOrUpdate(&user, "DN") if err != nil { logs.Error("save user fail: %v", err) } } return len(users), nil } // SyncUser SyncUsers 同步用户信息 // post /ldap/user/sync func (c *Service) 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 } } client, err := GetActiveClient(server) if err != nil { return err } users, err := client.Search(fmt.Sprintf("(&(objectClass=*)(uid=%s))", current.Account)) if err != nil { return err } 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 } // Update 保存或者修改 // post /ldap/server func (c *Service) Update(current *models.User, body *models.LdapServer) (*models.LdapServer, error) { if body.Url == "" { return nil, errors.New("请完成服务配置,缺少Url!") } if body.Key == "" { key := md5.Sum([]byte(body.Url)) body.Key = hex.EncodeToString(key[:]) } o := orm.NewOrm() if body.Id == 0 { exist := models.LdapServer{Key: body.Key} err := o.Read(&exist, "Key") if err != nil && !errors.Is(err, orm.ErrNoRows) { return nil, err } if exist.Id > 0 { return nil, errors.New("该服务Url已存在!") } } if body.Id > 0 { exist := models.LdapServer{Id: body.Id} err := o.Read(&exist, "Id") if err != nil { return nil, err } if config.ReplacePassword == body.Password { body.Password = exist.Password } _, err = o.Update(body) if err != nil { return nil, err } } else { id, err := o.Insert(body) if err != nil { return nil, err } body.Id = int(id) } return body, nil } // VerifyServer 验证服务 func (c *Service) VerifyServer(req *VerifyReq) ([]models.LdapUser, error) { var server = &models.LdapServer{ Id: req.Id, } o := orm.NewOrm() err := o.Read(server, "Id") if err != nil { return nil, err } client, err := GetActiveClient(server) if err != nil { return nil, err } if req.Filter == "" && req.Username != "" { req.Filter = fmt.Sprintf("(&(objectClass=*)(uid=%s))", req.Username) } if req.Filter != "" { users, err := client.Search(req.Filter) if err != nil { return nil, err } return users, nil } return make([]models.LdapUser, 0), nil } // UpdateUserPassword 更新用户密码 // post /ldap/user/modifyPassword func (c *Service) 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 } // GetUsers 获取全部用户 // get /ldap/users func (c *Service) GetUsers(current *models.User, req *UserListReq) (*vo.PageResp, error) { req.Ensure() o := orm.NewOrm() qs := o.QueryTable(&models.LdapUser{}) if !current.IsAdmin() { qs = qs.Filter("Uid", current.Account) } qs.Filter("ServerKey", req.ServerKey) total, err := qs.Count() if err != nil { return nil, err } qs.OrderBy("Id") qs.Offset(req.Offset) qs.Limit(req.PageSize) var list []*models.LdapUser _, err = qs.All(&list) if err != nil { return nil, err } resp := vo.PageResp{ Current: req.Current, PageSize: req.PageSize, Total: total, List: list, } return &resp, nil }