client_auth_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. // Copyright 2015 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package v2http
  15. import (
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "net/http"
  20. "net/http/httptest"
  21. "net/url"
  22. "path"
  23. "sort"
  24. "strings"
  25. "testing"
  26. "github.com/coreos/etcd/etcdserver/api"
  27. "github.com/coreos/etcd/etcdserver/auth"
  28. )
  29. const goodPassword = "good"
  30. func mustJSONRequest(t *testing.T, method string, p string, body string) *http.Request {
  31. req, err := http.NewRequest(method, path.Join(authPrefix, p), strings.NewReader(body))
  32. if err != nil {
  33. t.Fatalf("Error making JSON request: %s %s %s\n", method, p, body)
  34. }
  35. req.Header.Set("Content-Type", "application/json")
  36. return req
  37. }
  38. type mockAuthStore struct {
  39. users map[string]*auth.User
  40. roles map[string]*auth.Role
  41. err error
  42. enabled bool
  43. }
  44. func (s *mockAuthStore) AllUsers() ([]string, error) {
  45. var us []string
  46. for u := range s.users {
  47. us = append(us, u)
  48. }
  49. sort.Strings(us)
  50. return us, s.err
  51. }
  52. func (s *mockAuthStore) GetUser(name string) (auth.User, error) {
  53. u, ok := s.users[name]
  54. if !ok {
  55. return auth.User{}, s.err
  56. }
  57. return *u, s.err
  58. }
  59. func (s *mockAuthStore) CreateOrUpdateUser(user auth.User) (out auth.User, created bool, err error) {
  60. if s.users == nil {
  61. out, err = s.CreateUser(user)
  62. return out, true, err
  63. }
  64. out, err = s.UpdateUser(user)
  65. return out, false, err
  66. }
  67. func (s *mockAuthStore) CreateUser(user auth.User) (auth.User, error) { return user, s.err }
  68. func (s *mockAuthStore) DeleteUser(name string) error { return s.err }
  69. func (s *mockAuthStore) UpdateUser(user auth.User) (auth.User, error) {
  70. return *s.users[user.User], s.err
  71. }
  72. func (s *mockAuthStore) AllRoles() ([]string, error) {
  73. return []string{"awesome", "guest", "root"}, s.err
  74. }
  75. func (s *mockAuthStore) GetRole(name string) (auth.Role, error) {
  76. r, ok := s.roles[name]
  77. if ok {
  78. return *r, s.err
  79. }
  80. return auth.Role{}, fmt.Errorf("%q does not exist (%v)", name, s.err)
  81. }
  82. func (s *mockAuthStore) CreateRole(role auth.Role) error { return s.err }
  83. func (s *mockAuthStore) DeleteRole(name string) error { return s.err }
  84. func (s *mockAuthStore) UpdateRole(role auth.Role) (auth.Role, error) {
  85. return *s.roles[role.Role], s.err
  86. }
  87. func (s *mockAuthStore) AuthEnabled() bool { return s.enabled }
  88. func (s *mockAuthStore) EnableAuth() error { return s.err }
  89. func (s *mockAuthStore) DisableAuth() error { return s.err }
  90. func (s *mockAuthStore) CheckPassword(user auth.User, password string) bool {
  91. return user.Password == password
  92. }
  93. func (s *mockAuthStore) HashPassword(password string) (string, error) {
  94. return password, nil
  95. }
  96. func TestAuthFlow(t *testing.T) {
  97. api.EnableCapability(api.AuthCapability)
  98. var testCases = []struct {
  99. req *http.Request
  100. store mockAuthStore
  101. wcode int
  102. wbody string
  103. }{
  104. {
  105. req: mustJSONRequest(t, "PUT", "users/alice", `{{{{{{{`),
  106. store: mockAuthStore{},
  107. wcode: http.StatusBadRequest,
  108. wbody: `{"message":"Invalid JSON in request body."}`,
  109. },
  110. {
  111. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "password": "goodpassword"}`),
  112. store: mockAuthStore{enabled: true},
  113. wcode: http.StatusUnauthorized,
  114. wbody: `{"message":"Insufficient credentials"}`,
  115. },
  116. // Users
  117. {
  118. req: mustJSONRequest(t, "GET", "users", ""),
  119. store: mockAuthStore{
  120. users: map[string]*auth.User{
  121. "alice": {
  122. User: "alice",
  123. Roles: []string{"alicerole", "guest"},
  124. Password: "wheeee",
  125. },
  126. "bob": {
  127. User: "bob",
  128. Roles: []string{"guest"},
  129. Password: "wheeee",
  130. },
  131. "root": {
  132. User: "root",
  133. Roles: []string{"root"},
  134. Password: "wheeee",
  135. },
  136. },
  137. roles: map[string]*auth.Role{
  138. "alicerole": {
  139. Role: "alicerole",
  140. },
  141. "guest": {
  142. Role: "guest",
  143. },
  144. "root": {
  145. Role: "root",
  146. },
  147. },
  148. },
  149. wcode: http.StatusOK,
  150. wbody: `{"users":[` +
  151. `{"user":"alice","roles":[` +
  152. `{"role":"alicerole","permissions":{"kv":{"read":null,"write":null}}},` +
  153. `{"role":"guest","permissions":{"kv":{"read":null,"write":null}}}` +
  154. `]},` +
  155. `{"user":"bob","roles":[{"role":"guest","permissions":{"kv":{"read":null,"write":null}}}]},` +
  156. `{"user":"root","roles":[{"role":"root","permissions":{"kv":{"read":null,"write":null}}}]}]}`,
  157. },
  158. {
  159. req: mustJSONRequest(t, "GET", "users/alice", ""),
  160. store: mockAuthStore{
  161. users: map[string]*auth.User{
  162. "alice": {
  163. User: "alice",
  164. Roles: []string{"alicerole"},
  165. Password: "wheeee",
  166. },
  167. },
  168. roles: map[string]*auth.Role{
  169. "alicerole": {
  170. Role: "alicerole",
  171. },
  172. },
  173. },
  174. wcode: http.StatusOK,
  175. wbody: `{"user":"alice","roles":[{"role":"alicerole","permissions":{"kv":{"read":null,"write":null}}}]}`,
  176. },
  177. {
  178. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "password": "goodpassword"}`),
  179. store: mockAuthStore{},
  180. wcode: http.StatusCreated,
  181. wbody: `{"user":"alice","roles":null}`,
  182. },
  183. {
  184. req: mustJSONRequest(t, "DELETE", "users/alice", ``),
  185. store: mockAuthStore{},
  186. wcode: http.StatusOK,
  187. wbody: ``,
  188. },
  189. {
  190. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "password": "goodpassword"}`),
  191. store: mockAuthStore{
  192. users: map[string]*auth.User{
  193. "alice": {
  194. User: "alice",
  195. Roles: []string{"alicerole", "guest"},
  196. Password: "wheeee",
  197. },
  198. },
  199. },
  200. wcode: http.StatusOK,
  201. wbody: `{"user":"alice","roles":["alicerole","guest"]}`,
  202. },
  203. {
  204. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "grant": ["alicerole"]}`),
  205. store: mockAuthStore{
  206. users: map[string]*auth.User{
  207. "alice": {
  208. User: "alice",
  209. Roles: []string{"alicerole", "guest"},
  210. Password: "wheeee",
  211. },
  212. },
  213. },
  214. wcode: http.StatusOK,
  215. wbody: `{"user":"alice","roles":["alicerole","guest"]}`,
  216. },
  217. {
  218. req: mustJSONRequest(t, "GET", "users/alice", ``),
  219. store: mockAuthStore{
  220. users: map[string]*auth.User{},
  221. err: auth.Error{Status: http.StatusNotFound, Errmsg: "auth: User alice doesn't exist."},
  222. },
  223. wcode: http.StatusNotFound,
  224. wbody: `{"message":"auth: User alice doesn't exist."}`,
  225. },
  226. {
  227. req: mustJSONRequest(t, "GET", "roles/manager", ""),
  228. store: mockAuthStore{
  229. roles: map[string]*auth.Role{
  230. "manager": {
  231. Role: "manager",
  232. },
  233. },
  234. },
  235. wcode: http.StatusOK,
  236. wbody: `{"role":"manager","permissions":{"kv":{"read":null,"write":null}}}`,
  237. },
  238. {
  239. req: mustJSONRequest(t, "DELETE", "roles/manager", ``),
  240. store: mockAuthStore{},
  241. wcode: http.StatusOK,
  242. wbody: ``,
  243. },
  244. {
  245. req: mustJSONRequest(t, "PUT", "roles/manager", `{"role":"manager","permissions":{"kv":{"read":[],"write":[]}}}`),
  246. store: mockAuthStore{},
  247. wcode: http.StatusCreated,
  248. wbody: `{"role":"manager","permissions":{"kv":{"read":[],"write":[]}}}`,
  249. },
  250. {
  251. req: mustJSONRequest(t, "PUT", "roles/manager", `{"role":"manager","revoke":{"kv":{"read":["foo"],"write":[]}}}`),
  252. store: mockAuthStore{
  253. roles: map[string]*auth.Role{
  254. "manager": {
  255. Role: "manager",
  256. },
  257. },
  258. },
  259. wcode: http.StatusOK,
  260. wbody: `{"role":"manager","permissions":{"kv":{"read":null,"write":null}}}`,
  261. },
  262. {
  263. req: mustJSONRequest(t, "GET", "roles", ""),
  264. store: mockAuthStore{
  265. roles: map[string]*auth.Role{
  266. "awesome": {
  267. Role: "awesome",
  268. },
  269. "guest": {
  270. Role: "guest",
  271. },
  272. "root": {
  273. Role: "root",
  274. },
  275. },
  276. },
  277. wcode: http.StatusOK,
  278. wbody: `{"roles":[{"role":"awesome","permissions":{"kv":{"read":null,"write":null}}},` +
  279. `{"role":"guest","permissions":{"kv":{"read":null,"write":null}}},` +
  280. `{"role":"root","permissions":{"kv":{"read":null,"write":null}}}]}`,
  281. },
  282. {
  283. req: mustJSONRequest(t, "GET", "enable", ""),
  284. store: mockAuthStore{
  285. enabled: true,
  286. },
  287. wcode: http.StatusOK,
  288. wbody: `{"enabled":true}`,
  289. },
  290. {
  291. req: mustJSONRequest(t, "PUT", "enable", ""),
  292. store: mockAuthStore{
  293. enabled: false,
  294. },
  295. wcode: http.StatusOK,
  296. wbody: ``,
  297. },
  298. {
  299. req: (func() *http.Request {
  300. req := mustJSONRequest(t, "DELETE", "enable", "")
  301. req.SetBasicAuth("root", "good")
  302. return req
  303. })(),
  304. store: mockAuthStore{
  305. enabled: true,
  306. users: map[string]*auth.User{
  307. "root": {
  308. User: "root",
  309. Password: goodPassword,
  310. Roles: []string{"root"},
  311. },
  312. },
  313. roles: map[string]*auth.Role{
  314. "root": {
  315. Role: "root",
  316. },
  317. },
  318. },
  319. wcode: http.StatusOK,
  320. wbody: ``,
  321. },
  322. {
  323. req: (func() *http.Request {
  324. req := mustJSONRequest(t, "DELETE", "enable", "")
  325. req.SetBasicAuth("root", "bad")
  326. return req
  327. })(),
  328. store: mockAuthStore{
  329. enabled: true,
  330. users: map[string]*auth.User{
  331. "root": {
  332. User: "root",
  333. Password: goodPassword,
  334. Roles: []string{"root"},
  335. },
  336. },
  337. roles: map[string]*auth.Role{
  338. "root": {
  339. Role: "guest",
  340. },
  341. },
  342. },
  343. wcode: http.StatusUnauthorized,
  344. wbody: `{"message":"Insufficient credentials"}`,
  345. },
  346. }
  347. for i, tt := range testCases {
  348. mux := http.NewServeMux()
  349. h := &authHandler{
  350. sec: &tt.store,
  351. cluster: &fakeCluster{id: 1},
  352. }
  353. handleAuth(mux, h)
  354. rw := httptest.NewRecorder()
  355. mux.ServeHTTP(rw, tt.req)
  356. if rw.Code != tt.wcode {
  357. t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
  358. }
  359. g := rw.Body.String()
  360. g = strings.TrimSpace(g)
  361. if g != tt.wbody {
  362. t.Errorf("#%d: got body=%s, want %s", i, g, tt.wbody)
  363. }
  364. }
  365. }
  366. func TestGetUserGrantedWithNonexistingRole(t *testing.T) {
  367. sh := &authHandler{
  368. sec: &mockAuthStore{
  369. users: map[string]*auth.User{
  370. "root": {
  371. User: "root",
  372. Roles: []string{"root", "foo"},
  373. },
  374. },
  375. roles: map[string]*auth.Role{
  376. "root": {
  377. Role: "root",
  378. },
  379. },
  380. },
  381. cluster: &fakeCluster{id: 1},
  382. }
  383. srv := httptest.NewServer(http.HandlerFunc(sh.baseUsers))
  384. defer srv.Close()
  385. req, err := http.NewRequest("GET", "", nil)
  386. if err != nil {
  387. t.Fatal(err)
  388. }
  389. req.URL, err = url.Parse(srv.URL)
  390. if err != nil {
  391. t.Fatal(err)
  392. }
  393. req.Header.Set("Content-Type", "application/json")
  394. cli := http.DefaultClient
  395. resp, err := cli.Do(req)
  396. if err != nil {
  397. t.Fatal(err)
  398. }
  399. defer resp.Body.Close()
  400. var uc usersCollections
  401. if err := json.NewDecoder(resp.Body).Decode(&uc); err != nil {
  402. t.Fatal(err)
  403. }
  404. if len(uc.Users) != 1 {
  405. t.Fatalf("expected 1 user, got %+v", uc.Users)
  406. }
  407. if uc.Users[0].User != "root" {
  408. t.Fatalf("expected 'root', got %q", uc.Users[0].User)
  409. }
  410. if len(uc.Users[0].Roles) != 1 {
  411. t.Fatalf("expected 1 role, got %+v", uc.Users[0].Roles)
  412. }
  413. if uc.Users[0].Roles[0].Role != "root" {
  414. t.Fatalf("expected 'root', got %q", uc.Users[0].Roles[0].Role)
  415. }
  416. }
  417. func mustAuthRequest(method, username, password string) *http.Request {
  418. req, err := http.NewRequest(method, "path", strings.NewReader(""))
  419. if err != nil {
  420. panic("Cannot make auth request: " + err.Error())
  421. }
  422. req.SetBasicAuth(username, password)
  423. return req
  424. }
  425. func unauthedRequest(method string) *http.Request {
  426. req, err := http.NewRequest(method, "path", strings.NewReader(""))
  427. if err != nil {
  428. panic("Cannot make request: " + err.Error())
  429. }
  430. return req
  431. }
  432. func TestPrefixAccess(t *testing.T) {
  433. var table = []struct {
  434. key string
  435. req *http.Request
  436. store *mockAuthStore
  437. hasRoot bool
  438. hasKeyPrefixAccess bool
  439. hasRecursiveAccess bool
  440. }{
  441. {
  442. key: "/foo",
  443. req: mustAuthRequest("GET", "root", "good"),
  444. store: &mockAuthStore{
  445. users: map[string]*auth.User{
  446. "root": {
  447. User: "root",
  448. Password: goodPassword,
  449. Roles: []string{"root"},
  450. },
  451. },
  452. roles: map[string]*auth.Role{
  453. "root": {
  454. Role: "root",
  455. },
  456. },
  457. enabled: true,
  458. },
  459. hasRoot: true,
  460. hasKeyPrefixAccess: true,
  461. hasRecursiveAccess: true,
  462. },
  463. {
  464. key: "/foo",
  465. req: mustAuthRequest("GET", "user", "good"),
  466. store: &mockAuthStore{
  467. users: map[string]*auth.User{
  468. "user": {
  469. User: "user",
  470. Password: goodPassword,
  471. Roles: []string{"foorole"},
  472. },
  473. },
  474. roles: map[string]*auth.Role{
  475. "foorole": {
  476. Role: "foorole",
  477. Permissions: auth.Permissions{
  478. KV: auth.RWPermission{
  479. Read: []string{"/foo"},
  480. Write: []string{"/foo"},
  481. },
  482. },
  483. },
  484. },
  485. enabled: true,
  486. },
  487. hasRoot: false,
  488. hasKeyPrefixAccess: true,
  489. hasRecursiveAccess: false,
  490. },
  491. {
  492. key: "/foo",
  493. req: mustAuthRequest("GET", "user", "good"),
  494. store: &mockAuthStore{
  495. users: map[string]*auth.User{
  496. "user": {
  497. User: "user",
  498. Password: goodPassword,
  499. Roles: []string{"foorole"},
  500. },
  501. },
  502. roles: map[string]*auth.Role{
  503. "foorole": {
  504. Role: "foorole",
  505. Permissions: auth.Permissions{
  506. KV: auth.RWPermission{
  507. Read: []string{"/foo*"},
  508. Write: []string{"/foo*"},
  509. },
  510. },
  511. },
  512. },
  513. enabled: true,
  514. },
  515. hasRoot: false,
  516. hasKeyPrefixAccess: true,
  517. hasRecursiveAccess: true,
  518. },
  519. {
  520. key: "/foo",
  521. req: mustAuthRequest("GET", "user", "bad"),
  522. store: &mockAuthStore{
  523. users: map[string]*auth.User{
  524. "user": {
  525. User: "user",
  526. Password: goodPassword,
  527. Roles: []string{"foorole"},
  528. },
  529. },
  530. roles: map[string]*auth.Role{
  531. "foorole": {
  532. Role: "foorole",
  533. Permissions: auth.Permissions{
  534. KV: auth.RWPermission{
  535. Read: []string{"/foo*"},
  536. Write: []string{"/foo*"},
  537. },
  538. },
  539. },
  540. },
  541. enabled: true,
  542. },
  543. hasRoot: false,
  544. hasKeyPrefixAccess: false,
  545. hasRecursiveAccess: false,
  546. },
  547. {
  548. key: "/foo",
  549. req: mustAuthRequest("GET", "user", "good"),
  550. store: &mockAuthStore{
  551. users: map[string]*auth.User{},
  552. err: errors.New("Not the user"),
  553. enabled: true,
  554. },
  555. hasRoot: false,
  556. hasKeyPrefixAccess: false,
  557. hasRecursiveAccess: false,
  558. },
  559. {
  560. key: "/foo",
  561. req: mustJSONRequest(t, "GET", "somepath", ""),
  562. store: &mockAuthStore{
  563. users: map[string]*auth.User{
  564. "user": {
  565. User: "user",
  566. Password: goodPassword,
  567. Roles: []string{"foorole"},
  568. },
  569. },
  570. roles: map[string]*auth.Role{
  571. "guest": {
  572. Role: "guest",
  573. Permissions: auth.Permissions{
  574. KV: auth.RWPermission{
  575. Read: []string{"/foo*"},
  576. Write: []string{"/foo*"},
  577. },
  578. },
  579. },
  580. },
  581. enabled: true,
  582. },
  583. hasRoot: false,
  584. hasKeyPrefixAccess: true,
  585. hasRecursiveAccess: true,
  586. },
  587. {
  588. key: "/bar",
  589. req: mustJSONRequest(t, "GET", "somepath", ""),
  590. store: &mockAuthStore{
  591. users: map[string]*auth.User{
  592. "user": {
  593. User: "user",
  594. Password: goodPassword,
  595. Roles: []string{"foorole"},
  596. },
  597. },
  598. roles: map[string]*auth.Role{
  599. "guest": {
  600. Role: "guest",
  601. Permissions: auth.Permissions{
  602. KV: auth.RWPermission{
  603. Read: []string{"/foo*"},
  604. Write: []string{"/foo*"},
  605. },
  606. },
  607. },
  608. },
  609. enabled: true,
  610. },
  611. hasRoot: false,
  612. hasKeyPrefixAccess: false,
  613. hasRecursiveAccess: false,
  614. },
  615. // check access for multiple roles
  616. {
  617. key: "/foo",
  618. req: mustAuthRequest("GET", "user", "good"),
  619. store: &mockAuthStore{
  620. users: map[string]*auth.User{
  621. "user": {
  622. User: "user",
  623. Password: goodPassword,
  624. Roles: []string{"role1", "role2"},
  625. },
  626. },
  627. roles: map[string]*auth.Role{
  628. "role1": {
  629. Role: "role1",
  630. },
  631. "role2": {
  632. Role: "role2",
  633. Permissions: auth.Permissions{
  634. KV: auth.RWPermission{
  635. Read: []string{"/foo"},
  636. Write: []string{"/foo"},
  637. },
  638. },
  639. },
  640. },
  641. enabled: true,
  642. },
  643. hasRoot: false,
  644. hasKeyPrefixAccess: true,
  645. hasRecursiveAccess: false,
  646. },
  647. {
  648. key: "/foo",
  649. req: (func() *http.Request {
  650. req := mustJSONRequest(t, "GET", "somepath", "")
  651. req.Header.Set("Authorization", "malformedencoding")
  652. return req
  653. })(),
  654. store: &mockAuthStore{
  655. enabled: true,
  656. users: map[string]*auth.User{
  657. "root": {
  658. User: "root",
  659. Password: goodPassword,
  660. Roles: []string{"root"},
  661. },
  662. },
  663. roles: map[string]*auth.Role{
  664. "guest": {
  665. Role: "guest",
  666. Permissions: auth.Permissions{
  667. KV: auth.RWPermission{
  668. Read: []string{"/foo*"},
  669. Write: []string{"/foo*"},
  670. },
  671. },
  672. },
  673. },
  674. },
  675. hasRoot: false,
  676. hasKeyPrefixAccess: false,
  677. hasRecursiveAccess: false,
  678. },
  679. }
  680. for i, tt := range table {
  681. if tt.hasRoot != hasRootAccess(tt.store, tt.req) {
  682. t.Errorf("#%d: hasRoot doesn't match (expected %v)", i, tt.hasRoot)
  683. }
  684. if tt.hasKeyPrefixAccess != hasKeyPrefixAccess(tt.store, tt.req, tt.key, false) {
  685. t.Errorf("#%d: hasKeyPrefixAccess doesn't match (expected %v)", i, tt.hasRoot)
  686. }
  687. if tt.hasRecursiveAccess != hasKeyPrefixAccess(tt.store, tt.req, tt.key, true) {
  688. t.Errorf("#%d: hasRecursiveAccess doesn't match (expected %v)", i, tt.hasRoot)
  689. }
  690. }
  691. }
  692. func TestUserFromBasicAuth(t *testing.T) {
  693. sec := &mockAuthStore{
  694. users: map[string]*auth.User{
  695. "user": {
  696. User: "user",
  697. Roles: []string{"root"},
  698. Password: "password",
  699. },
  700. },
  701. roles: map[string]*auth.Role{
  702. "root": {
  703. Role: "root",
  704. },
  705. },
  706. }
  707. var table = []struct {
  708. username string
  709. req *http.Request
  710. userExists bool
  711. }{
  712. {
  713. // valid user, valid pass
  714. username: "user",
  715. req: mustAuthRequest("GET", "user", "password"),
  716. userExists: true,
  717. },
  718. {
  719. // valid user, bad pass
  720. username: "user",
  721. req: mustAuthRequest("GET", "user", "badpass"),
  722. userExists: false,
  723. },
  724. {
  725. // valid user, no pass
  726. username: "user",
  727. req: mustAuthRequest("GET", "user", ""),
  728. userExists: false,
  729. },
  730. {
  731. // missing user
  732. username: "missing",
  733. req: mustAuthRequest("GET", "missing", "badpass"),
  734. userExists: false,
  735. },
  736. {
  737. // no basic auth
  738. req: unauthedRequest("GET"),
  739. userExists: false,
  740. },
  741. }
  742. for i, tt := range table {
  743. user := userFromBasicAuth(sec, tt.req)
  744. if tt.userExists == (user == nil) {
  745. t.Errorf("#%d: userFromBasicAuth doesn't match (expected %v)", i, tt.userExists)
  746. }
  747. if user != nil && (tt.username != user.User) {
  748. t.Errorf("#%d: userFromBasicAuth username doesn't match (expected %s, got %s)", i, tt.username, user.User)
  749. }
  750. }
  751. }