client_auth_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  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. "crypto/tls"
  17. "crypto/x509"
  18. "encoding/json"
  19. "encoding/pem"
  20. "errors"
  21. "fmt"
  22. "io/ioutil"
  23. "net/http"
  24. "net/http/httptest"
  25. "net/url"
  26. "path"
  27. "sort"
  28. "strings"
  29. "testing"
  30. "go.etcd.io/etcd/etcdserver/api"
  31. "go.etcd.io/etcd/etcdserver/api/v2auth"
  32. "go.uber.org/zap"
  33. )
  34. const goodPassword = "good"
  35. func mustJSONRequest(t *testing.T, method string, p string, body string) *http.Request {
  36. req, err := http.NewRequest(method, path.Join(authPrefix, p), strings.NewReader(body))
  37. if err != nil {
  38. t.Fatalf("Error making JSON request: %s %s %s\n", method, p, body)
  39. }
  40. req.Header.Set("Content-Type", "application/json")
  41. return req
  42. }
  43. type mockAuthStore struct {
  44. users map[string]*v2auth.User
  45. roles map[string]*v2auth.Role
  46. err error
  47. enabled bool
  48. }
  49. func (s *mockAuthStore) AllUsers() ([]string, error) {
  50. var us []string
  51. for u := range s.users {
  52. us = append(us, u)
  53. }
  54. sort.Strings(us)
  55. return us, s.err
  56. }
  57. func (s *mockAuthStore) GetUser(name string) (v2auth.User, error) {
  58. u, ok := s.users[name]
  59. if !ok {
  60. return v2auth.User{}, s.err
  61. }
  62. return *u, s.err
  63. }
  64. func (s *mockAuthStore) CreateOrUpdateUser(user v2auth.User) (out v2auth.User, created bool, err error) {
  65. if s.users == nil {
  66. out, err = s.CreateUser(user)
  67. return out, true, err
  68. }
  69. out, err = s.UpdateUser(user)
  70. return out, false, err
  71. }
  72. func (s *mockAuthStore) CreateUser(user v2auth.User) (v2auth.User, error) { return user, s.err }
  73. func (s *mockAuthStore) DeleteUser(name string) error { return s.err }
  74. func (s *mockAuthStore) UpdateUser(user v2auth.User) (v2auth.User, error) {
  75. return *s.users[user.User], s.err
  76. }
  77. func (s *mockAuthStore) AllRoles() ([]string, error) {
  78. return []string{"awesome", "guest", "root"}, s.err
  79. }
  80. func (s *mockAuthStore) GetRole(name string) (v2auth.Role, error) {
  81. r, ok := s.roles[name]
  82. if ok {
  83. return *r, s.err
  84. }
  85. return v2auth.Role{}, fmt.Errorf("%q does not exist (%v)", name, s.err)
  86. }
  87. func (s *mockAuthStore) CreateRole(role v2auth.Role) error { return s.err }
  88. func (s *mockAuthStore) DeleteRole(name string) error { return s.err }
  89. func (s *mockAuthStore) UpdateRole(role v2auth.Role) (v2auth.Role, error) {
  90. return *s.roles[role.Role], s.err
  91. }
  92. func (s *mockAuthStore) AuthEnabled() bool { return s.enabled }
  93. func (s *mockAuthStore) EnableAuth() error { return s.err }
  94. func (s *mockAuthStore) DisableAuth() error { return s.err }
  95. func (s *mockAuthStore) CheckPassword(user v2auth.User, password string) bool {
  96. return user.Password == password
  97. }
  98. func (s *mockAuthStore) HashPassword(password string) (string, error) {
  99. return password, nil
  100. }
  101. func TestAuthFlow(t *testing.T) {
  102. api.EnableCapability(api.AuthCapability)
  103. var testCases = []struct {
  104. req *http.Request
  105. store mockAuthStore
  106. wcode int
  107. wbody string
  108. }{
  109. {
  110. req: mustJSONRequest(t, "PUT", "users/alice", `{{{{{{{`),
  111. store: mockAuthStore{},
  112. wcode: http.StatusBadRequest,
  113. wbody: `{"message":"Invalid JSON in request body."}`,
  114. },
  115. {
  116. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "password": "goodpassword"}`),
  117. store: mockAuthStore{enabled: true},
  118. wcode: http.StatusUnauthorized,
  119. wbody: `{"message":"Insufficient credentials"}`,
  120. },
  121. // Users
  122. {
  123. req: mustJSONRequest(t, "GET", "users", ""),
  124. store: mockAuthStore{
  125. users: map[string]*v2auth.User{
  126. "alice": {
  127. User: "alice",
  128. Roles: []string{"alicerole", "guest"},
  129. Password: "wheeee",
  130. },
  131. "bob": {
  132. User: "bob",
  133. Roles: []string{"guest"},
  134. Password: "wheeee",
  135. },
  136. "root": {
  137. User: "root",
  138. Roles: []string{"root"},
  139. Password: "wheeee",
  140. },
  141. },
  142. roles: map[string]*v2auth.Role{
  143. "alicerole": {
  144. Role: "alicerole",
  145. },
  146. "guest": {
  147. Role: "guest",
  148. },
  149. "root": {
  150. Role: "root",
  151. },
  152. },
  153. },
  154. wcode: http.StatusOK,
  155. wbody: `{"users":[` +
  156. `{"user":"alice","roles":[` +
  157. `{"role":"alicerole","permissions":{"kv":{"read":null,"write":null}}},` +
  158. `{"role":"guest","permissions":{"kv":{"read":null,"write":null}}}` +
  159. `]},` +
  160. `{"user":"bob","roles":[{"role":"guest","permissions":{"kv":{"read":null,"write":null}}}]},` +
  161. `{"user":"root","roles":[{"role":"root","permissions":{"kv":{"read":null,"write":null}}}]}]}`,
  162. },
  163. {
  164. req: mustJSONRequest(t, "GET", "users/alice", ""),
  165. store: mockAuthStore{
  166. users: map[string]*v2auth.User{
  167. "alice": {
  168. User: "alice",
  169. Roles: []string{"alicerole"},
  170. Password: "wheeee",
  171. },
  172. },
  173. roles: map[string]*v2auth.Role{
  174. "alicerole": {
  175. Role: "alicerole",
  176. },
  177. },
  178. },
  179. wcode: http.StatusOK,
  180. wbody: `{"user":"alice","roles":[{"role":"alicerole","permissions":{"kv":{"read":null,"write":null}}}]}`,
  181. },
  182. {
  183. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "password": "goodpassword"}`),
  184. store: mockAuthStore{},
  185. wcode: http.StatusCreated,
  186. wbody: `{"user":"alice","roles":null}`,
  187. },
  188. {
  189. req: mustJSONRequest(t, "DELETE", "users/alice", ``),
  190. store: mockAuthStore{},
  191. wcode: http.StatusOK,
  192. wbody: ``,
  193. },
  194. {
  195. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "password": "goodpassword"}`),
  196. store: mockAuthStore{
  197. users: map[string]*v2auth.User{
  198. "alice": {
  199. User: "alice",
  200. Roles: []string{"alicerole", "guest"},
  201. Password: "wheeee",
  202. },
  203. },
  204. },
  205. wcode: http.StatusOK,
  206. wbody: `{"user":"alice","roles":["alicerole","guest"]}`,
  207. },
  208. {
  209. req: mustJSONRequest(t, "PUT", "users/alice", `{"user": "alice", "grant": ["alicerole"]}`),
  210. store: mockAuthStore{
  211. users: map[string]*v2auth.User{
  212. "alice": {
  213. User: "alice",
  214. Roles: []string{"alicerole", "guest"},
  215. Password: "wheeee",
  216. },
  217. },
  218. },
  219. wcode: http.StatusOK,
  220. wbody: `{"user":"alice","roles":["alicerole","guest"]}`,
  221. },
  222. {
  223. req: mustJSONRequest(t, "GET", "users/alice", ``),
  224. store: mockAuthStore{
  225. users: map[string]*v2auth.User{},
  226. err: v2auth.Error{Status: http.StatusNotFound, Errmsg: "auth: User alice doesn't exist."},
  227. },
  228. wcode: http.StatusNotFound,
  229. wbody: `{"message":"auth: User alice doesn't exist."}`,
  230. },
  231. {
  232. req: mustJSONRequest(t, "GET", "roles/manager", ""),
  233. store: mockAuthStore{
  234. roles: map[string]*v2auth.Role{
  235. "manager": {
  236. Role: "manager",
  237. },
  238. },
  239. },
  240. wcode: http.StatusOK,
  241. wbody: `{"role":"manager","permissions":{"kv":{"read":null,"write":null}}}`,
  242. },
  243. {
  244. req: mustJSONRequest(t, "DELETE", "roles/manager", ``),
  245. store: mockAuthStore{},
  246. wcode: http.StatusOK,
  247. wbody: ``,
  248. },
  249. {
  250. req: mustJSONRequest(t, "PUT", "roles/manager", `{"role":"manager","permissions":{"kv":{"read":[],"write":[]}}}`),
  251. store: mockAuthStore{},
  252. wcode: http.StatusCreated,
  253. wbody: `{"role":"manager","permissions":{"kv":{"read":[],"write":[]}}}`,
  254. },
  255. {
  256. req: mustJSONRequest(t, "PUT", "roles/manager", `{"role":"manager","revoke":{"kv":{"read":["foo"],"write":[]}}}`),
  257. store: mockAuthStore{
  258. roles: map[string]*v2auth.Role{
  259. "manager": {
  260. Role: "manager",
  261. },
  262. },
  263. },
  264. wcode: http.StatusOK,
  265. wbody: `{"role":"manager","permissions":{"kv":{"read":null,"write":null}}}`,
  266. },
  267. {
  268. req: mustJSONRequest(t, "GET", "roles", ""),
  269. store: mockAuthStore{
  270. roles: map[string]*v2auth.Role{
  271. "awesome": {
  272. Role: "awesome",
  273. },
  274. "guest": {
  275. Role: "guest",
  276. },
  277. "root": {
  278. Role: "root",
  279. },
  280. },
  281. },
  282. wcode: http.StatusOK,
  283. wbody: `{"roles":[{"role":"awesome","permissions":{"kv":{"read":null,"write":null}}},` +
  284. `{"role":"guest","permissions":{"kv":{"read":null,"write":null}}},` +
  285. `{"role":"root","permissions":{"kv":{"read":null,"write":null}}}]}`,
  286. },
  287. {
  288. req: mustJSONRequest(t, "GET", "enable", ""),
  289. store: mockAuthStore{
  290. enabled: true,
  291. },
  292. wcode: http.StatusOK,
  293. wbody: `{"enabled":true}`,
  294. },
  295. {
  296. req: mustJSONRequest(t, "PUT", "enable", ""),
  297. store: mockAuthStore{
  298. enabled: false,
  299. },
  300. wcode: http.StatusOK,
  301. wbody: ``,
  302. },
  303. {
  304. req: (func() *http.Request {
  305. req := mustJSONRequest(t, "DELETE", "enable", "")
  306. req.SetBasicAuth("root", "good")
  307. return req
  308. })(),
  309. store: mockAuthStore{
  310. enabled: true,
  311. users: map[string]*v2auth.User{
  312. "root": {
  313. User: "root",
  314. Password: goodPassword,
  315. Roles: []string{"root"},
  316. },
  317. },
  318. roles: map[string]*v2auth.Role{
  319. "root": {
  320. Role: "root",
  321. },
  322. },
  323. },
  324. wcode: http.StatusOK,
  325. wbody: ``,
  326. },
  327. {
  328. req: (func() *http.Request {
  329. req := mustJSONRequest(t, "DELETE", "enable", "")
  330. req.SetBasicAuth("root", "bad")
  331. return req
  332. })(),
  333. store: mockAuthStore{
  334. enabled: true,
  335. users: map[string]*v2auth.User{
  336. "root": {
  337. User: "root",
  338. Password: goodPassword,
  339. Roles: []string{"root"},
  340. },
  341. },
  342. roles: map[string]*v2auth.Role{
  343. "root": {
  344. Role: "guest",
  345. },
  346. },
  347. },
  348. wcode: http.StatusUnauthorized,
  349. wbody: `{"message":"Insufficient credentials"}`,
  350. },
  351. }
  352. for i, tt := range testCases {
  353. mux := http.NewServeMux()
  354. h := &authHandler{
  355. lg: zap.NewExample(),
  356. sec: &tt.store,
  357. cluster: &fakeCluster{id: 1},
  358. }
  359. handleAuth(mux, h)
  360. rw := httptest.NewRecorder()
  361. mux.ServeHTTP(rw, tt.req)
  362. if rw.Code != tt.wcode {
  363. t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
  364. }
  365. g := rw.Body.String()
  366. g = strings.TrimSpace(g)
  367. if g != tt.wbody {
  368. t.Errorf("#%d: got body=%s, want %s", i, g, tt.wbody)
  369. }
  370. }
  371. }
  372. func TestGetUserGrantedWithNonexistingRole(t *testing.T) {
  373. sh := &authHandler{
  374. sec: &mockAuthStore{
  375. users: map[string]*v2auth.User{
  376. "root": {
  377. User: "root",
  378. Roles: []string{"root", "foo"},
  379. },
  380. },
  381. roles: map[string]*v2auth.Role{
  382. "root": {
  383. Role: "root",
  384. },
  385. },
  386. },
  387. cluster: &fakeCluster{id: 1},
  388. }
  389. srv := httptest.NewServer(http.HandlerFunc(sh.baseUsers))
  390. defer srv.Close()
  391. req, err := http.NewRequest("GET", "", nil)
  392. if err != nil {
  393. t.Fatal(err)
  394. }
  395. req.URL, err = url.Parse(srv.URL)
  396. if err != nil {
  397. t.Fatal(err)
  398. }
  399. req.Header.Set("Content-Type", "application/json")
  400. cli := http.DefaultClient
  401. resp, err := cli.Do(req)
  402. if err != nil {
  403. t.Fatal(err)
  404. }
  405. defer resp.Body.Close()
  406. var uc usersCollections
  407. if err := json.NewDecoder(resp.Body).Decode(&uc); err != nil {
  408. t.Fatal(err)
  409. }
  410. if len(uc.Users) != 1 {
  411. t.Fatalf("expected 1 user, got %+v", uc.Users)
  412. }
  413. if uc.Users[0].User != "root" {
  414. t.Fatalf("expected 'root', got %q", uc.Users[0].User)
  415. }
  416. if len(uc.Users[0].Roles) != 1 {
  417. t.Fatalf("expected 1 role, got %+v", uc.Users[0].Roles)
  418. }
  419. if uc.Users[0].Roles[0].Role != "root" {
  420. t.Fatalf("expected 'root', got %q", uc.Users[0].Roles[0].Role)
  421. }
  422. }
  423. func mustAuthRequest(username, password string) *http.Request {
  424. req, err := http.NewRequest(http.MethodGet, "path", strings.NewReader(""))
  425. if err != nil {
  426. panic("Cannot make auth request: " + err.Error())
  427. }
  428. req.SetBasicAuth(username, password)
  429. return req
  430. }
  431. func unauthedRequest() *http.Request {
  432. req, err := http.NewRequest(http.MethodGet, "path", strings.NewReader(""))
  433. if err != nil {
  434. panic("Cannot make request: " + err.Error())
  435. }
  436. return req
  437. }
  438. func tlsAuthedRequest(req *http.Request, certname string) *http.Request {
  439. bytes, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.pem", certname))
  440. if err != nil {
  441. panic(err)
  442. }
  443. block, _ := pem.Decode(bytes)
  444. cert, err := x509.ParseCertificate(block.Bytes)
  445. if err != nil {
  446. panic(err)
  447. }
  448. req.TLS = &tls.ConnectionState{
  449. VerifiedChains: [][]*x509.Certificate{{cert}},
  450. }
  451. return req
  452. }
  453. func TestPrefixAccess(t *testing.T) {
  454. var table = []struct {
  455. key string
  456. req *http.Request
  457. store *mockAuthStore
  458. hasRoot bool
  459. hasKeyPrefixAccess bool
  460. hasRecursiveAccess bool
  461. }{
  462. {
  463. key: "/foo",
  464. req: mustAuthRequest("root", "good"),
  465. store: &mockAuthStore{
  466. users: map[string]*v2auth.User{
  467. "root": {
  468. User: "root",
  469. Password: goodPassword,
  470. Roles: []string{"root"},
  471. },
  472. },
  473. roles: map[string]*v2auth.Role{
  474. "root": {
  475. Role: "root",
  476. },
  477. },
  478. enabled: true,
  479. },
  480. hasRoot: true,
  481. hasKeyPrefixAccess: true,
  482. hasRecursiveAccess: true,
  483. },
  484. {
  485. key: "/foo",
  486. req: mustAuthRequest("user", "good"),
  487. store: &mockAuthStore{
  488. users: map[string]*v2auth.User{
  489. "user": {
  490. User: "user",
  491. Password: goodPassword,
  492. Roles: []string{"foorole"},
  493. },
  494. },
  495. roles: map[string]*v2auth.Role{
  496. "foorole": {
  497. Role: "foorole",
  498. Permissions: v2auth.Permissions{
  499. KV: v2auth.RWPermission{
  500. Read: []string{"/foo"},
  501. Write: []string{"/foo"},
  502. },
  503. },
  504. },
  505. },
  506. enabled: true,
  507. },
  508. hasRoot: false,
  509. hasKeyPrefixAccess: true,
  510. hasRecursiveAccess: false,
  511. },
  512. {
  513. key: "/foo",
  514. req: mustAuthRequest("user", "good"),
  515. store: &mockAuthStore{
  516. users: map[string]*v2auth.User{
  517. "user": {
  518. User: "user",
  519. Password: goodPassword,
  520. Roles: []string{"foorole"},
  521. },
  522. },
  523. roles: map[string]*v2auth.Role{
  524. "foorole": {
  525. Role: "foorole",
  526. Permissions: v2auth.Permissions{
  527. KV: v2auth.RWPermission{
  528. Read: []string{"/foo*"},
  529. Write: []string{"/foo*"},
  530. },
  531. },
  532. },
  533. },
  534. enabled: true,
  535. },
  536. hasRoot: false,
  537. hasKeyPrefixAccess: true,
  538. hasRecursiveAccess: true,
  539. },
  540. {
  541. key: "/foo",
  542. req: mustAuthRequest("user", "bad"),
  543. store: &mockAuthStore{
  544. users: map[string]*v2auth.User{
  545. "user": {
  546. User: "user",
  547. Password: goodPassword,
  548. Roles: []string{"foorole"},
  549. },
  550. },
  551. roles: map[string]*v2auth.Role{
  552. "foorole": {
  553. Role: "foorole",
  554. Permissions: v2auth.Permissions{
  555. KV: v2auth.RWPermission{
  556. Read: []string{"/foo*"},
  557. Write: []string{"/foo*"},
  558. },
  559. },
  560. },
  561. },
  562. enabled: true,
  563. },
  564. hasRoot: false,
  565. hasKeyPrefixAccess: false,
  566. hasRecursiveAccess: false,
  567. },
  568. {
  569. key: "/foo",
  570. req: mustAuthRequest("user", "good"),
  571. store: &mockAuthStore{
  572. users: map[string]*v2auth.User{},
  573. err: errors.New("Not the user"),
  574. enabled: true,
  575. },
  576. hasRoot: false,
  577. hasKeyPrefixAccess: false,
  578. hasRecursiveAccess: false,
  579. },
  580. {
  581. key: "/foo",
  582. req: mustJSONRequest(t, "GET", "somepath", ""),
  583. store: &mockAuthStore{
  584. users: map[string]*v2auth.User{
  585. "user": {
  586. User: "user",
  587. Password: goodPassword,
  588. Roles: []string{"foorole"},
  589. },
  590. },
  591. roles: map[string]*v2auth.Role{
  592. "guest": {
  593. Role: "guest",
  594. Permissions: v2auth.Permissions{
  595. KV: v2auth.RWPermission{
  596. Read: []string{"/foo*"},
  597. Write: []string{"/foo*"},
  598. },
  599. },
  600. },
  601. },
  602. enabled: true,
  603. },
  604. hasRoot: false,
  605. hasKeyPrefixAccess: true,
  606. hasRecursiveAccess: true,
  607. },
  608. {
  609. key: "/bar",
  610. req: mustJSONRequest(t, "GET", "somepath", ""),
  611. store: &mockAuthStore{
  612. users: map[string]*v2auth.User{
  613. "user": {
  614. User: "user",
  615. Password: goodPassword,
  616. Roles: []string{"foorole"},
  617. },
  618. },
  619. roles: map[string]*v2auth.Role{
  620. "guest": {
  621. Role: "guest",
  622. Permissions: v2auth.Permissions{
  623. KV: v2auth.RWPermission{
  624. Read: []string{"/foo*"},
  625. Write: []string{"/foo*"},
  626. },
  627. },
  628. },
  629. },
  630. enabled: true,
  631. },
  632. hasRoot: false,
  633. hasKeyPrefixAccess: false,
  634. hasRecursiveAccess: false,
  635. },
  636. // check access for multiple roles
  637. {
  638. key: "/foo",
  639. req: mustAuthRequest("user", "good"),
  640. store: &mockAuthStore{
  641. users: map[string]*v2auth.User{
  642. "user": {
  643. User: "user",
  644. Password: goodPassword,
  645. Roles: []string{"role1", "role2"},
  646. },
  647. },
  648. roles: map[string]*v2auth.Role{
  649. "role1": {
  650. Role: "role1",
  651. },
  652. "role2": {
  653. Role: "role2",
  654. Permissions: v2auth.Permissions{
  655. KV: v2auth.RWPermission{
  656. Read: []string{"/foo"},
  657. Write: []string{"/foo"},
  658. },
  659. },
  660. },
  661. },
  662. enabled: true,
  663. },
  664. hasRoot: false,
  665. hasKeyPrefixAccess: true,
  666. hasRecursiveAccess: false,
  667. },
  668. {
  669. key: "/foo",
  670. req: (func() *http.Request {
  671. req := mustJSONRequest(t, "GET", "somepath", "")
  672. req.Header.Set("Authorization", "malformedencoding")
  673. return req
  674. })(),
  675. store: &mockAuthStore{
  676. enabled: true,
  677. users: map[string]*v2auth.User{
  678. "root": {
  679. User: "root",
  680. Password: goodPassword,
  681. Roles: []string{"root"},
  682. },
  683. },
  684. roles: map[string]*v2auth.Role{
  685. "guest": {
  686. Role: "guest",
  687. Permissions: v2auth.Permissions{
  688. KV: v2auth.RWPermission{
  689. Read: []string{"/foo*"},
  690. Write: []string{"/foo*"},
  691. },
  692. },
  693. },
  694. },
  695. },
  696. hasRoot: false,
  697. hasKeyPrefixAccess: false,
  698. hasRecursiveAccess: false,
  699. },
  700. { // guest access in non-TLS mode
  701. key: "/foo",
  702. req: (func() *http.Request {
  703. return mustJSONRequest(t, "GET", "somepath", "")
  704. })(),
  705. store: &mockAuthStore{
  706. enabled: true,
  707. users: map[string]*v2auth.User{
  708. "root": {
  709. User: "root",
  710. Password: goodPassword,
  711. Roles: []string{"root"},
  712. },
  713. },
  714. roles: map[string]*v2auth.Role{
  715. "guest": {
  716. Role: "guest",
  717. Permissions: v2auth.Permissions{
  718. KV: v2auth.RWPermission{
  719. Read: []string{"/foo*"},
  720. Write: []string{"/foo*"},
  721. },
  722. },
  723. },
  724. },
  725. },
  726. hasRoot: false,
  727. hasKeyPrefixAccess: true,
  728. hasRecursiveAccess: true,
  729. },
  730. }
  731. for i, tt := range table {
  732. if tt.hasRoot != hasRootAccess(zap.NewExample(), tt.store, tt.req, true) {
  733. t.Errorf("#%d: hasRoot doesn't match (expected %v)", i, tt.hasRoot)
  734. }
  735. if tt.hasKeyPrefixAccess != hasKeyPrefixAccess(zap.NewExample(), tt.store, tt.req, tt.key, false, true) {
  736. t.Errorf("#%d: hasKeyPrefixAccess doesn't match (expected %v)", i, tt.hasRoot)
  737. }
  738. if tt.hasRecursiveAccess != hasKeyPrefixAccess(zap.NewExample(), tt.store, tt.req, tt.key, true, true) {
  739. t.Errorf("#%d: hasRecursiveAccess doesn't match (expected %v)", i, tt.hasRoot)
  740. }
  741. }
  742. }
  743. func TestUserFromClientCertificate(t *testing.T) {
  744. witherror := &mockAuthStore{
  745. users: map[string]*v2auth.User{
  746. "user": {
  747. User: "user",
  748. Roles: []string{"root"},
  749. Password: "password",
  750. },
  751. "basicauth": {
  752. User: "basicauth",
  753. Roles: []string{"root"},
  754. Password: "password",
  755. },
  756. },
  757. roles: map[string]*v2auth.Role{
  758. "root": {
  759. Role: "root",
  760. },
  761. },
  762. err: errors.New(""),
  763. }
  764. noerror := &mockAuthStore{
  765. users: map[string]*v2auth.User{
  766. "user": {
  767. User: "user",
  768. Roles: []string{"root"},
  769. Password: "password",
  770. },
  771. "basicauth": {
  772. User: "basicauth",
  773. Roles: []string{"root"},
  774. Password: "password",
  775. },
  776. },
  777. roles: map[string]*v2auth.Role{
  778. "root": {
  779. Role: "root",
  780. },
  781. },
  782. }
  783. var table = []struct {
  784. req *http.Request
  785. userExists bool
  786. store v2auth.Store
  787. username string
  788. }{
  789. {
  790. // non tls request
  791. req: unauthedRequest(),
  792. userExists: false,
  793. store: witherror,
  794. },
  795. {
  796. // cert with cn of existing user
  797. req: tlsAuthedRequest(unauthedRequest(), "user"),
  798. userExists: true,
  799. username: "user",
  800. store: noerror,
  801. },
  802. {
  803. // cert with cn of non-existing user
  804. req: tlsAuthedRequest(unauthedRequest(), "otheruser"),
  805. userExists: false,
  806. store: witherror,
  807. },
  808. }
  809. for i, tt := range table {
  810. user := userFromClientCertificate(zap.NewExample(), tt.store, tt.req)
  811. userExists := user != nil
  812. if tt.userExists != userExists {
  813. t.Errorf("#%d: userFromClientCertificate doesn't match (expected %v)", i, tt.userExists)
  814. }
  815. if user != nil && (tt.username != user.User) {
  816. t.Errorf("#%d: userFromClientCertificate username doesn't match (expected %s, got %s)", i, tt.username, user.User)
  817. }
  818. }
  819. }
  820. func TestUserFromBasicAuth(t *testing.T) {
  821. sec := &mockAuthStore{
  822. users: map[string]*v2auth.User{
  823. "user": {
  824. User: "user",
  825. Roles: []string{"root"},
  826. Password: "password",
  827. },
  828. },
  829. roles: map[string]*v2auth.Role{
  830. "root": {
  831. Role: "root",
  832. },
  833. },
  834. }
  835. var table = []struct {
  836. username string
  837. req *http.Request
  838. userExists bool
  839. }{
  840. {
  841. // valid user, valid pass
  842. username: "user",
  843. req: mustAuthRequest("user", "password"),
  844. userExists: true,
  845. },
  846. {
  847. // valid user, bad pass
  848. username: "user",
  849. req: mustAuthRequest("user", "badpass"),
  850. userExists: false,
  851. },
  852. {
  853. // valid user, no pass
  854. username: "user",
  855. req: mustAuthRequest("user", ""),
  856. userExists: false,
  857. },
  858. {
  859. // missing user
  860. username: "missing",
  861. req: mustAuthRequest("missing", "badpass"),
  862. userExists: false,
  863. },
  864. {
  865. // no basic auth
  866. req: unauthedRequest(),
  867. userExists: false,
  868. },
  869. }
  870. for i, tt := range table {
  871. user := userFromBasicAuth(zap.NewExample(), sec, tt.req)
  872. userExists := user != nil
  873. if tt.userExists != userExists {
  874. t.Errorf("#%d: userFromBasicAuth doesn't match (expected %v)", i, tt.userExists)
  875. }
  876. if user != nil && (tt.username != user.User) {
  877. t.Errorf("#%d: userFromBasicAuth username doesn't match (expected %s, got %s)", i, tt.username, user.User)
  878. }
  879. }
  880. }