client.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package ldap
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/astaxie/beego/logs"
  9. "github.com/go-ldap/ldap/v3"
  10. "nginx-ui/server/models"
  11. "strings"
  12. )
  13. type Client struct {
  14. *ldap.Conn
  15. Url string
  16. Connected bool
  17. BaseDN string
  18. Admin string
  19. Password string
  20. ServerKey string
  21. }
  22. var ActiveClients = make(map[string]*Client)
  23. func Create(url string, baseDN string) *Client {
  24. var client = &Client{
  25. Url: url,
  26. BaseDN: baseDN,
  27. }
  28. conn, err := ldap.DialURL(client.Url)
  29. if err != nil {
  30. logs.Error("dialUrl fail: %v", err)
  31. client.Connected = false
  32. } else {
  33. client.Conn = conn
  34. client.Connected = true
  35. }
  36. return client
  37. }
  38. func GetActiveClient(server *models.LdapServer) (*Client, error) {
  39. client := ActiveClients[server.Key]
  40. if client == nil {
  41. client = Create(server.Url, server.BaseDN)
  42. err := client.Bind(server.UserName, server.Password, true)
  43. if err != nil {
  44. logs.Error("Bind fail: %v", err)
  45. return nil, err
  46. }
  47. ActiveClients[server.Key] = client
  48. client.ServerKey = server.Key
  49. }
  50. return client, nil
  51. }
  52. func (c *Client) Close() {
  53. if c.Connected && c.Conn != nil {
  54. c.Conn.Close()
  55. }
  56. }
  57. // Bind 验证账号密码?
  58. func (c *Client) Bind(username string, password string, isAdmin bool) error {
  59. err := c.Conn.Bind(username, password)
  60. if err != nil {
  61. logs.Error("GSSAPIBind failed, err:%v", err)
  62. return err
  63. }
  64. if isAdmin {
  65. c.Admin = username
  66. c.Password = password
  67. }
  68. return nil
  69. }
  70. func createUser(entry *ldap.Entry) models.LdapUser {
  71. user := models.LdapUser{
  72. Account: entry.GetAttributeValue("uid"),
  73. DN: entry.DN,
  74. Password: entry.GetAttributeValue("userPassword"),
  75. UserName: entry.GetAttributeValue("cn"),
  76. Mail: entry.GetAttributeValue("mail"),
  77. }
  78. jsonBytes, err := json.Marshal(entry.Attributes)
  79. if err != nil {
  80. logs.Error("marshal fail : %v", err)
  81. user.Remark = "attributes marshal fail: " + err.Error()
  82. } else {
  83. user.Attributes = string(jsonBytes)
  84. }
  85. return user
  86. }
  87. // Search 搜索用户 eg. (&(objectClass=organizationalPerson))
  88. func (c *Client) Search(filter string) ([]models.LdapUser, error) {
  89. if filter == "" {
  90. filter = "(objectClass=*)"
  91. }
  92. searchRequest := ldap.NewSearchRequest(
  93. c.BaseDN, // The base dn to search
  94. ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
  95. filter, // The filter to apply
  96. []string{"*"}, // A list attributes to retrieve,"dn", "cn", "objectClass",
  97. nil,
  98. )
  99. sr, err := c.Conn.Search(searchRequest)
  100. if err != nil {
  101. logs.Error("search fail : %v", err)
  102. return nil, err
  103. }
  104. var users []models.LdapUser
  105. for _, entry := range sr.Entries {
  106. user := createUser(entry)
  107. user.ServerKey = c.ServerKey
  108. users = append(users, user)
  109. }
  110. return users, nil
  111. }
  112. func (c *Client) ModifyAdminPassword() error {
  113. return nil
  114. }
  115. func (c *Client) ModifyPassword() error {
  116. return nil
  117. }
  118. func (c *Client) Modify() error {
  119. return nil
  120. }
  121. func (c *Client) Authentication(account string, password string) (*models.LdapUser, error) {
  122. // The username and password we want to check
  123. users, err := c.Search(fmt.Sprintf("(&(objectClass=*)(uid=%s))", ldap.EscapeFilter(account)))
  124. if err != nil {
  125. logs.Error("search fail: %v", err)
  126. return nil, err
  127. }
  128. if len(users) != 1 {
  129. logs.Error("User does not exist or too many entries returned")
  130. return nil, errors.New("未找到用户或者账号重复!")
  131. }
  132. userDN := users[0].Account
  133. userPassword := users[0].Password
  134. if strings.HasPrefix(userPassword, "{MD5}") {
  135. pass := md5.Sum([]byte(password))
  136. password = hex.EncodeToString(pass[:])
  137. if strings.TrimPrefix(userPassword, "{MD5}") != password {
  138. return nil, errors.New("登录失败,账号或者密码不正确!")
  139. }
  140. } else {
  141. client, err := ldap.DialURL(c.Url)
  142. if err != nil {
  143. logs.Error("DialURL failed, err:%v", err)
  144. return nil, errors.New("服务连接异常!")
  145. }
  146. defer client.Close()
  147. err = client.Bind(userDN, password)
  148. if err != nil {
  149. logs.Error("GSSAPIBind failed, err:%v", err)
  150. return nil, errors.New("登录失败,账号或者密码不正确!")
  151. }
  152. }
  153. return &users[0], nil
  154. }