multildap.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package multildap
  2. import (
  3. "errors"
  4. "github.com/grafana/grafana/pkg/models"
  5. "github.com/grafana/grafana/pkg/services/ldap"
  6. )
  7. // GetConfig gets LDAP config
  8. var GetConfig = ldap.GetConfig
  9. // IsEnabled checks if LDAP is enabled
  10. var IsEnabled = ldap.IsEnabled
  11. // newLDAP return instance of the single LDAP server
  12. var newLDAP = ldap.New
  13. // ErrInvalidCredentials is returned if username and password do not match
  14. var ErrInvalidCredentials = ldap.ErrInvalidCredentials
  15. // ErrCouldNotFindUser is returned when username hasn't been found (not username+password)
  16. var ErrCouldNotFindUser = ldap.ErrCouldNotFindUser
  17. // ErrNoLDAPServers is returned when there is no LDAP servers specified
  18. var ErrNoLDAPServers = errors.New("No LDAP servers are configured")
  19. // ErrDidNotFindUser if request for user is unsuccessful
  20. var ErrDidNotFindUser = errors.New("Did not find a user")
  21. // ServerStatus holds the LDAP server status
  22. type ServerStatus struct {
  23. Host string
  24. Port int
  25. Available bool
  26. Error error
  27. }
  28. // IMultiLDAP is interface for MultiLDAP
  29. type IMultiLDAP interface {
  30. Ping() ([]*ServerStatus, error)
  31. Login(query *models.LoginUserQuery) (
  32. *models.ExternalUserInfo, error,
  33. )
  34. Users(logins []string) (
  35. []*models.ExternalUserInfo, error,
  36. )
  37. User(login string) (
  38. *models.ExternalUserInfo, ldap.ServerConfig, error,
  39. )
  40. }
  41. // MultiLDAP is basic struct of LDAP authorization
  42. type MultiLDAP struct {
  43. configs []*ldap.ServerConfig
  44. }
  45. // New creates the new LDAP auth
  46. func New(configs []*ldap.ServerConfig) IMultiLDAP {
  47. return &MultiLDAP{
  48. configs: configs,
  49. }
  50. }
  51. // Ping dials each of the LDAP servers and returns their status. If the server is unavailable, it also returns the error.
  52. func (multiples *MultiLDAP) Ping() ([]*ServerStatus, error) {
  53. if len(multiples.configs) == 0 {
  54. return nil, ErrNoLDAPServers
  55. }
  56. serverStatuses := []*ServerStatus{}
  57. for _, config := range multiples.configs {
  58. status := &ServerStatus{}
  59. status.Host = config.Host
  60. status.Port = config.Port
  61. server := newLDAP(config)
  62. err := server.Dial()
  63. if err == nil {
  64. status.Available = true
  65. serverStatuses = append(serverStatuses, status)
  66. } else {
  67. status.Available = false
  68. status.Error = err
  69. serverStatuses = append(serverStatuses, status)
  70. }
  71. defer server.Close()
  72. }
  73. return serverStatuses, nil
  74. }
  75. // Login tries to log in the user in multiples LDAP
  76. func (multiples *MultiLDAP) Login(query *models.LoginUserQuery) (
  77. *models.ExternalUserInfo, error,
  78. ) {
  79. if len(multiples.configs) == 0 {
  80. return nil, ErrNoLDAPServers
  81. }
  82. for _, config := range multiples.configs {
  83. server := newLDAP(config)
  84. if err := server.Dial(); err != nil {
  85. return nil, err
  86. }
  87. defer server.Close()
  88. user, err := server.Login(query)
  89. if user != nil {
  90. return user, nil
  91. }
  92. // Continue if we couldn't find the user
  93. if err == ErrCouldNotFindUser {
  94. continue
  95. }
  96. if err != nil {
  97. return nil, err
  98. }
  99. }
  100. // Return invalid credentials if we couldn't find the user anywhere
  101. return nil, ErrInvalidCredentials
  102. }
  103. // User attempts to find an user by login/username by searching into all of the configured LDAP servers. Then, if the user is found it returns the user alongisde the server it was found.
  104. func (multiples *MultiLDAP) User(login string) (
  105. *models.ExternalUserInfo,
  106. ldap.ServerConfig,
  107. error,
  108. ) {
  109. if len(multiples.configs) == 0 {
  110. return nil, ldap.ServerConfig{}, ErrNoLDAPServers
  111. }
  112. search := []string{login}
  113. for _, config := range multiples.configs {
  114. server := newLDAP(config)
  115. if err := server.Dial(); err != nil {
  116. return nil, *config, err
  117. }
  118. defer server.Close()
  119. if err := server.Bind(); err != nil {
  120. return nil, *config, err
  121. }
  122. users, err := server.Users(search)
  123. if err != nil {
  124. return nil, *config, err
  125. }
  126. if len(users) != 0 {
  127. return users[0], *config, nil
  128. }
  129. }
  130. return nil, ldap.ServerConfig{}, ErrDidNotFindUser
  131. }
  132. // Users gets users from multiple LDAP servers
  133. func (multiples *MultiLDAP) Users(logins []string) (
  134. []*models.ExternalUserInfo,
  135. error,
  136. ) {
  137. var result []*models.ExternalUserInfo
  138. if len(multiples.configs) == 0 {
  139. return nil, ErrNoLDAPServers
  140. }
  141. for _, config := range multiples.configs {
  142. server := newLDAP(config)
  143. if err := server.Dial(); err != nil {
  144. return nil, err
  145. }
  146. defer server.Close()
  147. if err := server.Bind(); err != nil {
  148. return nil, err
  149. }
  150. users, err := server.Users(logins)
  151. if err != nil {
  152. return nil, err
  153. }
  154. result = append(result, users...)
  155. }
  156. return result, nil
  157. }