ldap_debug_test.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. package api
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "net/http"
  6. "net/http/httptest"
  7. "testing"
  8. "github.com/grafana/grafana/pkg/bus"
  9. "github.com/grafana/grafana/pkg/models"
  10. "github.com/grafana/grafana/pkg/services/ldap"
  11. "github.com/grafana/grafana/pkg/services/multildap"
  12. "github.com/grafana/grafana/pkg/setting"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. type LDAPMock struct {
  17. Results []*models.ExternalUserInfo
  18. }
  19. var userSearchResult *models.ExternalUserInfo
  20. var userSearchConfig ldap.ServerConfig
  21. var pingResult []*multildap.ServerStatus
  22. var pingError error
  23. func (m *LDAPMock) Ping() ([]*multildap.ServerStatus, error) {
  24. return pingResult, pingError
  25. }
  26. func (m *LDAPMock) Login(query *models.LoginUserQuery) (*models.ExternalUserInfo, error) {
  27. return &models.ExternalUserInfo{}, nil
  28. }
  29. func (m *LDAPMock) Users(logins []string) ([]*models.ExternalUserInfo, error) {
  30. s := []*models.ExternalUserInfo{}
  31. return s, nil
  32. }
  33. func (m *LDAPMock) User(login string) (*models.ExternalUserInfo, ldap.ServerConfig, error) {
  34. return userSearchResult, userSearchConfig, nil
  35. }
  36. //***
  37. // GetUserFromLDAP tests
  38. //***
  39. func getUserFromLDAPContext(t *testing.T, requestURL string) *scenarioContext {
  40. t.Helper()
  41. sc := setupScenarioContext(requestURL)
  42. ldap := setting.LDAPEnabled
  43. setting.LDAPEnabled = true
  44. defer func() { setting.LDAPEnabled = ldap }()
  45. hs := &HTTPServer{Cfg: setting.NewCfg()}
  46. sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
  47. sc.context = c
  48. return hs.GetUserFromLDAP(c)
  49. })
  50. sc.m.Get("/api/admin/ldap/:username", sc.defaultHandler)
  51. sc.resp = httptest.NewRecorder()
  52. req, _ := http.NewRequest(http.MethodGet, requestURL, nil)
  53. sc.req = req
  54. sc.exec()
  55. return sc
  56. }
  57. func TestGetUserFromLDAPApiEndpoint_UserNotFound(t *testing.T) {
  58. getLDAPConfig = func() (*ldap.Config, error) {
  59. return &ldap.Config{}, nil
  60. }
  61. newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
  62. return &LDAPMock{}
  63. }
  64. userSearchResult = nil
  65. sc := getUserFromLDAPContext(t, "/api/admin/ldap/user-that-does-not-exist")
  66. require.Equal(t, sc.resp.Code, http.StatusNotFound)
  67. responseString, err := getBody(sc.resp)
  68. assert.Nil(t, err)
  69. assert.Equal(t, "{\"message\":\"No user was found on the LDAP server(s)\"}", responseString)
  70. }
  71. func TestGetUserFromLDAPApiEndpoint_OrgNotfound(t *testing.T) {
  72. isAdmin := true
  73. userSearchResult = &models.ExternalUserInfo{
  74. Name: "John Doe",
  75. Email: "john.doe@example.com",
  76. Login: "johndoe",
  77. OrgRoles: map[int64]models.RoleType{1: models.ROLE_ADMIN, 2: models.ROLE_VIEWER},
  78. IsGrafanaAdmin: &isAdmin,
  79. }
  80. userSearchConfig = ldap.ServerConfig{
  81. Attr: ldap.AttributeMap{
  82. Name: "ldap-name",
  83. Surname: "ldap-surname",
  84. Email: "ldap-email",
  85. Username: "ldap-username",
  86. },
  87. Groups: []*ldap.GroupToOrgRole{
  88. {
  89. GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
  90. OrgID: 1,
  91. OrgRole: models.ROLE_ADMIN,
  92. },
  93. {
  94. GroupDN: "cn=admins,ou=groups,dc=grafana2,dc=org",
  95. OrgID: 2,
  96. OrgRole: models.ROLE_VIEWER,
  97. },
  98. },
  99. }
  100. mockOrgSearchResult := []*models.OrgDTO{
  101. {Id: 1, Name: "Main Org."},
  102. }
  103. bus.AddHandler("test", func(query *models.SearchOrgsQuery) error {
  104. query.Result = mockOrgSearchResult
  105. return nil
  106. })
  107. getLDAPConfig = func() (*ldap.Config, error) {
  108. return &ldap.Config{}, nil
  109. }
  110. newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
  111. return &LDAPMock{}
  112. }
  113. sc := getUserFromLDAPContext(t, "/api/admin/ldap/johndoe")
  114. require.Equal(t, sc.resp.Code, http.StatusBadRequest)
  115. jsonResponse, err := getJSONbody(sc.resp)
  116. assert.Nil(t, err)
  117. expected := `
  118. {
  119. "error": "Unable to find organization with ID '2'",
  120. "message": "An oganization was not found - Please verify your LDAP configuration"
  121. }
  122. `
  123. var expectedJSON interface{}
  124. _ = json.Unmarshal([]byte(expected), &expectedJSON)
  125. assert.Equal(t, expectedJSON, jsonResponse)
  126. }
  127. func TestGetUserFromLDAPApiEndpoint(t *testing.T) {
  128. isAdmin := true
  129. userSearchResult = &models.ExternalUserInfo{
  130. Name: "John Doe",
  131. Email: "john.doe@example.com",
  132. Login: "johndoe",
  133. OrgRoles: map[int64]models.RoleType{1: models.ROLE_ADMIN},
  134. IsGrafanaAdmin: &isAdmin,
  135. }
  136. userSearchConfig = ldap.ServerConfig{
  137. Attr: ldap.AttributeMap{
  138. Name: "ldap-name",
  139. Surname: "ldap-surname",
  140. Email: "ldap-email",
  141. Username: "ldap-username",
  142. },
  143. Groups: []*ldap.GroupToOrgRole{
  144. {
  145. GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
  146. OrgID: 1,
  147. OrgRole: models.ROLE_ADMIN,
  148. },
  149. },
  150. }
  151. mockOrgSearchResult := []*models.OrgDTO{
  152. {Id: 1, Name: "Main Org."},
  153. }
  154. bus.AddHandler("test", func(query *models.SearchOrgsQuery) error {
  155. query.Result = mockOrgSearchResult
  156. return nil
  157. })
  158. getLDAPConfig = func() (*ldap.Config, error) {
  159. return &ldap.Config{}, nil
  160. }
  161. newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
  162. return &LDAPMock{}
  163. }
  164. sc := getUserFromLDAPContext(t, "/api/admin/ldap/johndoe")
  165. require.Equal(t, sc.resp.Code, http.StatusOK)
  166. jsonResponse, err := getJSONbody(sc.resp)
  167. assert.Nil(t, err)
  168. expected := `
  169. {
  170. "name": {
  171. "cfgAttrValue": "ldap-name", "ldapValue": "John"
  172. },
  173. "surname": {
  174. "cfgAttrValue": "ldap-surname", "ldapValue": "Doe"
  175. },
  176. "email": {
  177. "cfgAttrValue": "ldap-email", "ldapValue": "john.doe@example.com"
  178. },
  179. "login": {
  180. "cfgAttrValue": "ldap-username", "ldapValue": "johndoe"
  181. },
  182. "isGrafanaAdmin": true,
  183. "isDisabled": false,
  184. "roles": [
  185. { "orgId": 1, "orgRole": "Admin", "orgName": "Main Org.", "groupDN": "cn=admins,ou=groups,dc=grafana,dc=org" }
  186. ],
  187. "teams": null
  188. }
  189. `
  190. var expectedJSON interface{}
  191. _ = json.Unmarshal([]byte(expected), &expectedJSON)
  192. assert.Equal(t, expectedJSON, jsonResponse)
  193. }
  194. func TestGetUserFromLDAPApiEndpoint_WithTeamHandler(t *testing.T) {
  195. isAdmin := true
  196. userSearchResult = &models.ExternalUserInfo{
  197. Name: "John Doe",
  198. Email: "john.doe@example.com",
  199. Login: "johndoe",
  200. OrgRoles: map[int64]models.RoleType{1: models.ROLE_ADMIN},
  201. IsGrafanaAdmin: &isAdmin,
  202. }
  203. userSearchConfig = ldap.ServerConfig{
  204. Attr: ldap.AttributeMap{
  205. Name: "ldap-name",
  206. Surname: "ldap-surname",
  207. Email: "ldap-email",
  208. Username: "ldap-username",
  209. },
  210. Groups: []*ldap.GroupToOrgRole{
  211. {
  212. GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
  213. OrgID: 1,
  214. OrgRole: models.ROLE_ADMIN,
  215. },
  216. },
  217. }
  218. mockOrgSearchResult := []*models.OrgDTO{
  219. {Id: 1, Name: "Main Org."},
  220. }
  221. bus.AddHandler("test", func(query *models.SearchOrgsQuery) error {
  222. query.Result = mockOrgSearchResult
  223. return nil
  224. })
  225. bus.AddHandler("test", func(cmd *models.GetTeamsForLDAPGroupCommand) error {
  226. cmd.Result = []models.TeamOrgGroupDTO{}
  227. return nil
  228. })
  229. getLDAPConfig = func() (*ldap.Config, error) {
  230. return &ldap.Config{}, nil
  231. }
  232. newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
  233. return &LDAPMock{}
  234. }
  235. sc := getUserFromLDAPContext(t, "/api/admin/ldap/johndoe")
  236. require.Equal(t, sc.resp.Code, http.StatusOK)
  237. jsonResponse, err := getJSONbody(sc.resp)
  238. assert.Nil(t, err)
  239. expected := `
  240. {
  241. "name": {
  242. "cfgAttrValue": "ldap-name", "ldapValue": "John"
  243. },
  244. "surname": {
  245. "cfgAttrValue": "ldap-surname", "ldapValue": "Doe"
  246. },
  247. "email": {
  248. "cfgAttrValue": "ldap-email", "ldapValue": "john.doe@example.com"
  249. },
  250. "login": {
  251. "cfgAttrValue": "ldap-username", "ldapValue": "johndoe"
  252. },
  253. "isGrafanaAdmin": true,
  254. "isDisabled": false,
  255. "roles": [
  256. { "orgId": 1, "orgRole": "Admin", "orgName": "Main Org.", "groupDN": "cn=admins,ou=groups,dc=grafana,dc=org" }
  257. ],
  258. "teams": []
  259. }
  260. `
  261. var expectedJSON interface{}
  262. _ = json.Unmarshal([]byte(expected), &expectedJSON)
  263. assert.Equal(t, expectedJSON, jsonResponse)
  264. }
  265. //***
  266. // GetLDAPStatus tests
  267. //***
  268. func getLDAPStatusContext(t *testing.T) *scenarioContext {
  269. t.Helper()
  270. requestURL := "/api/admin/ldap/status"
  271. sc := setupScenarioContext(requestURL)
  272. ldap := setting.LDAPEnabled
  273. setting.LDAPEnabled = true
  274. defer func() { setting.LDAPEnabled = ldap }()
  275. hs := &HTTPServer{Cfg: setting.NewCfg()}
  276. sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
  277. sc.context = c
  278. return hs.GetLDAPStatus(c)
  279. })
  280. sc.m.Get("/api/admin/ldap/status", sc.defaultHandler)
  281. sc.resp = httptest.NewRecorder()
  282. req, _ := http.NewRequest(http.MethodGet, requestURL, nil)
  283. sc.req = req
  284. sc.exec()
  285. return sc
  286. }
  287. func TestGetLDAPStatusApiEndpoint(t *testing.T) {
  288. pingResult = []*multildap.ServerStatus{
  289. {Host: "10.0.0.3", Port: 361, Available: true, Error: nil},
  290. {Host: "10.0.0.3", Port: 362, Available: true, Error: nil},
  291. {Host: "10.0.0.5", Port: 361, Available: false, Error: errors.New("something is awfully wrong")},
  292. }
  293. getLDAPConfig = func() (*ldap.Config, error) {
  294. return &ldap.Config{}, nil
  295. }
  296. newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
  297. return &LDAPMock{}
  298. }
  299. sc := getLDAPStatusContext(t)
  300. require.Equal(t, http.StatusOK, sc.resp.Code)
  301. jsonResponse, err := getJSONbody(sc.resp)
  302. assert.Nil(t, err)
  303. expected := `
  304. [
  305. { "host": "10.0.0.3", "port": 361, "available": true, "error": "" },
  306. { "host": "10.0.0.3", "port": 362, "available": true, "error": "" },
  307. { "host": "10.0.0.5", "port": 361, "available": false, "error": "something is awfully wrong" }
  308. ]
  309. `
  310. var expectedJSON interface{}
  311. _ = json.Unmarshal([]byte(expected), &expectedJSON)
  312. assert.Equal(t, expectedJSON, jsonResponse)
  313. }