ldap_debug.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package api
  2. import (
  3. "fmt"
  4. "net/http"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/models"
  7. "github.com/grafana/grafana/pkg/services/ldap"
  8. "github.com/grafana/grafana/pkg/services/multildap"
  9. "github.com/grafana/grafana/pkg/util"
  10. )
  11. var (
  12. getLDAPConfig = multildap.GetConfig
  13. newLDAP = multildap.New
  14. errOrganizationNotFound = func(orgId int64) error {
  15. return fmt.Errorf("Unable to find organization with ID '%d'", orgId)
  16. }
  17. )
  18. // LDAPAttribute is a serializer for user attributes mapped from LDAP. Is meant to display both the serialized value and the LDAP key we received it from.
  19. type LDAPAttribute struct {
  20. ConfigAttributeValue string `json:"cfgAttrValue"`
  21. LDAPAttributeValue string `json:"ldapValue"`
  22. }
  23. // RoleDTO is a serializer for mapped roles from LDAP
  24. type RoleDTO struct {
  25. OrgId int64 `json:"orgId"`
  26. OrgName string `json:"orgName"`
  27. OrgRole models.RoleType `json:"orgRole"`
  28. GroupDN string `json:"groupDN"`
  29. }
  30. // TeamDTO is a serializer for mapped Teams from LDAP
  31. type TeamDTO struct {
  32. GroupDN string `json:"groupDN"`
  33. TeamId int64 `json:"teamId"`
  34. TeamName string `json:"teamName"`
  35. }
  36. // LDAPUserDTO is a serializer for users mapped from LDAP
  37. type LDAPUserDTO struct {
  38. Name *LDAPAttribute `json:"name"`
  39. Surname *LDAPAttribute `json:"surname"`
  40. Email *LDAPAttribute `json:"email"`
  41. Username *LDAPAttribute `json:"login"`
  42. IsGrafanaAdmin *bool `json:"isGrafanaAdmin"`
  43. IsDisabled bool `json:"isDisabled"`
  44. OrgRoles []RoleDTO `json:"roles"`
  45. Teams []TeamDTO `json:"teams"`
  46. }
  47. // FetchOrgs fetches the organization(s) information by executing a single query to the database. Then, populating the DTO with the information retrieved.
  48. func (user *LDAPUserDTO) FetchOrgs() error {
  49. orgIds := []int64{}
  50. for _, or := range user.OrgRoles {
  51. orgIds = append(orgIds, or.OrgId)
  52. }
  53. q := &models.SearchOrgsQuery{}
  54. q.Ids = orgIds
  55. if err := bus.Dispatch(q); err != nil {
  56. return err
  57. }
  58. orgNamesById := map[int64]string{}
  59. for _, org := range q.Result {
  60. orgNamesById[org.Id] = org.Name
  61. }
  62. for i, orgDTO := range user.OrgRoles {
  63. orgName := orgNamesById[orgDTO.OrgId]
  64. if orgName != "" {
  65. user.OrgRoles[i].OrgName = orgName
  66. } else {
  67. return errOrganizationNotFound(orgDTO.OrgId)
  68. }
  69. }
  70. return nil
  71. }
  72. // ReloadLDAPCfg reloads the LDAP configuration
  73. func (server *HTTPServer) ReloadLDAPCfg() Response {
  74. if !ldap.IsEnabled() {
  75. return Error(400, "LDAP is not enabled", nil)
  76. }
  77. err := ldap.ReloadConfig()
  78. if err != nil {
  79. return Error(500, "Failed to reload ldap config.", err)
  80. }
  81. return Success("LDAP config reloaded")
  82. }
  83. // GetUserFromLDAP finds an user based on a username in LDAP. This helps illustrate how would the particular user be mapped in Grafana when synced.
  84. func (server *HTTPServer) GetUserFromLDAP(c *models.ReqContext) Response {
  85. ldapConfig, err := getLDAPConfig()
  86. if err != nil {
  87. return Error(400, "Failed to obtain the LDAP configuration. Please ", err)
  88. }
  89. ldap := newLDAP(ldapConfig.Servers)
  90. username := c.Params(":username")
  91. if len(username) == 0 {
  92. return Error(http.StatusBadRequest, "Validation error. You must specify an username", nil)
  93. }
  94. user, serverConfig, err := ldap.User(username)
  95. if user == nil {
  96. return Error(http.StatusNotFound, "No user was found on the LDAP server(s)", err)
  97. }
  98. name, surname := splitName(user.Name)
  99. u := &LDAPUserDTO{
  100. Name: &LDAPAttribute{serverConfig.Attr.Name, name},
  101. Surname: &LDAPAttribute{serverConfig.Attr.Surname, surname},
  102. Email: &LDAPAttribute{serverConfig.Attr.Email, user.Email},
  103. Username: &LDAPAttribute{serverConfig.Attr.Username, user.Login},
  104. IsGrafanaAdmin: user.IsGrafanaAdmin,
  105. IsDisabled: user.IsDisabled,
  106. }
  107. orgRoles := []RoleDTO{}
  108. for _, g := range serverConfig.Groups {
  109. role := &RoleDTO{}
  110. if isMatchToLDAPGroup(user, g) {
  111. role.OrgId = g.OrgID
  112. role.OrgRole = user.OrgRoles[g.OrgID]
  113. role.GroupDN = g.GroupDN
  114. orgRoles = append(orgRoles, *role)
  115. } else {
  116. role.OrgId = g.OrgID
  117. role.GroupDN = g.GroupDN
  118. orgRoles = append(orgRoles, *role)
  119. }
  120. }
  121. u.OrgRoles = orgRoles
  122. err = u.FetchOrgs()
  123. if err != nil {
  124. return Error(http.StatusBadRequest, "Organization not found - Please verify your LDAP configuration", err)
  125. }
  126. return JSON(200, u)
  127. }
  128. // isMatchToLDAPGroup determines if we were able to match an LDAP group to an organization+role.
  129. // Since we allow one role per organization. If it's set, we were able to match it.
  130. func isMatchToLDAPGroup(user *models.ExternalUserInfo, groupConfig *ldap.GroupToOrgRole) bool {
  131. return user.OrgRoles[groupConfig.OrgID] == groupConfig.OrgRole
  132. }
  133. // splitName receives the full name of a user and splits it into two parts: A name and a surname.
  134. func splitName(name string) (string, string) {
  135. names := util.SplitString(name)
  136. switch len(names) {
  137. case 0:
  138. return "", ""
  139. case 1:
  140. return names[0], ""
  141. default:
  142. return names[0], names[1]
  143. }
  144. }