security_test.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // Copyright 2015 CoreOS, Inc.
  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 security
  15. import (
  16. "reflect"
  17. "testing"
  18. "time"
  19. "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/crypto/bcrypt"
  20. "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
  21. "github.com/coreos/etcd/etcdserver"
  22. "github.com/coreos/etcd/etcdserver/etcdserverpb"
  23. "github.com/coreos/etcd/store"
  24. )
  25. func TestMergeUser(t *testing.T) {
  26. tbl := []struct {
  27. input User
  28. merge User
  29. expect User
  30. iserr bool
  31. }{
  32. {
  33. User{User: "foo"},
  34. User{User: "bar"},
  35. User{},
  36. true,
  37. },
  38. {
  39. User{User: "foo"},
  40. User{User: "foo"},
  41. User{User: "foo", Roles: []string{}},
  42. false,
  43. },
  44. {
  45. User{User: "foo"},
  46. User{User: "foo", Grant: []string{"role1"}},
  47. User{User: "foo", Roles: []string{"role1"}},
  48. false,
  49. },
  50. {
  51. User{User: "foo", Roles: []string{"role1"}},
  52. User{User: "foo", Grant: []string{"role1"}},
  53. User{},
  54. true,
  55. },
  56. {
  57. User{User: "foo", Roles: []string{"role1"}},
  58. User{User: "foo", Revoke: []string{"role2"}},
  59. User{},
  60. true,
  61. },
  62. {
  63. User{User: "foo", Roles: []string{"role1"}},
  64. User{User: "foo", Grant: []string{"role2"}},
  65. User{User: "foo", Roles: []string{"role1", "role2"}},
  66. false,
  67. },
  68. {
  69. User{User: "foo"},
  70. User{User: "foo", Password: "bar"},
  71. User{User: "foo", Roles: []string{}, Password: "$2a$10$aUPOdbOGNawaVSusg3g2wuC3AH6XxIr9/Ms4VgDvzrAVOJPYzZILa"},
  72. false,
  73. },
  74. }
  75. for i, tt := range tbl {
  76. out, err := tt.input.Merge(tt.merge)
  77. if err != nil && !tt.iserr {
  78. t.Fatalf("Got unexpected error on item %d", i)
  79. }
  80. if !tt.iserr {
  81. err := bcrypt.CompareHashAndPassword([]byte(out.Password), []byte(tt.merge.Password))
  82. if err == nil {
  83. tt.expect.Password = out.Password
  84. }
  85. if !reflect.DeepEqual(out, tt.expect) {
  86. t.Errorf("Unequal merge expectation on item %d: got: %#v, expect: %#v", i, out, tt.expect)
  87. }
  88. }
  89. }
  90. }
  91. func TestMergeRole(t *testing.T) {
  92. tbl := []struct {
  93. input Role
  94. merge Role
  95. expect Role
  96. iserr bool
  97. }{
  98. {
  99. Role{Role: "foo"},
  100. Role{Role: "bar"},
  101. Role{},
  102. true,
  103. },
  104. {
  105. Role{Role: "foo"},
  106. Role{Role: "foo", Grant: &Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
  107. Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
  108. false,
  109. },
  110. {
  111. Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
  112. Role{Role: "foo", Revoke: &Permissions{KV: rwPermission{Read: []string{"/foodir"}, Write: []string{"/foodir"}}}},
  113. Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{}, Write: []string{}}}},
  114. false,
  115. },
  116. {
  117. Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/bardir"}}}},
  118. Role{Role: "foo", Revoke: &Permissions{KV: rwPermission{Read: []string{"/foodir"}}}},
  119. Role{},
  120. true,
  121. },
  122. }
  123. for i, tt := range tbl {
  124. out, err := tt.input.Merge(tt.merge)
  125. if err != nil && !tt.iserr {
  126. t.Fatalf("Got unexpected error on item %d", i)
  127. }
  128. if !tt.iserr {
  129. if !reflect.DeepEqual(out, tt.expect) {
  130. t.Errorf("Unequal merge expectation on item %d: got: %#v, expect: %#v", i, out, tt.expect)
  131. }
  132. }
  133. }
  134. }
  135. type testDoer struct {
  136. get []etcdserver.Response
  137. index int
  138. }
  139. func (td *testDoer) Do(_ context.Context, req etcdserverpb.Request) (etcdserver.Response, error) {
  140. if req.Method == "GET" {
  141. res := td.get[td.index]
  142. td.index++
  143. return res, nil
  144. }
  145. return etcdserver.Response{}, nil
  146. }
  147. func TestAllUsers(t *testing.T) {
  148. d := &testDoer{
  149. get: []etcdserver.Response{
  150. {
  151. Event: &store.Event{
  152. Action: store.Get,
  153. Node: &store.NodeExtern{
  154. Nodes: store.NodeExterns{
  155. &store.NodeExtern{
  156. Key: StorePermsPrefix + "/users/cat",
  157. },
  158. &store.NodeExtern{
  159. Key: StorePermsPrefix + "/users/dog",
  160. },
  161. },
  162. },
  163. },
  164. },
  165. },
  166. }
  167. expected := []string{"cat", "dog"}
  168. s := Store{d, time.Second, false}
  169. users, err := s.AllUsers()
  170. if err != nil {
  171. t.Error("Unexpected error", err)
  172. }
  173. if !reflect.DeepEqual(users, expected) {
  174. t.Error("AllUsers doesn't match given store. Got", users, "expected", expected)
  175. }
  176. }
  177. func TestGetAndDeleteUser(t *testing.T) {
  178. data := `{"user": "cat", "roles" : ["animal"]}`
  179. d := &testDoer{
  180. get: []etcdserver.Response{
  181. {
  182. Event: &store.Event{
  183. Action: store.Get,
  184. Node: &store.NodeExtern{
  185. Key: StorePermsPrefix + "/users/cat",
  186. Value: &data,
  187. },
  188. },
  189. },
  190. },
  191. }
  192. expected := User{User: "cat", Roles: []string{"animal"}}
  193. s := Store{d, time.Second, false}
  194. out, err := s.GetUser("cat")
  195. if err != nil {
  196. t.Error("Unexpected error", err)
  197. }
  198. if !reflect.DeepEqual(out, expected) {
  199. t.Error("GetUser doesn't match given store. Got", out, "expected", expected)
  200. }
  201. err = s.DeleteUser("cat")
  202. if err != nil {
  203. t.Error("Unexpected error", err)
  204. }
  205. }
  206. func TestAllRoles(t *testing.T) {
  207. d := &testDoer{
  208. get: []etcdserver.Response{
  209. {
  210. Event: &store.Event{
  211. Action: store.Get,
  212. Node: &store.NodeExtern{
  213. Nodes: store.NodeExterns{
  214. &store.NodeExtern{
  215. Key: StorePermsPrefix + "/roles/animal",
  216. },
  217. &store.NodeExtern{
  218. Key: StorePermsPrefix + "/roles/human",
  219. },
  220. },
  221. },
  222. },
  223. },
  224. },
  225. }
  226. expected := []string{"animal", "human", "root"}
  227. s := Store{d, time.Second, false}
  228. out, err := s.AllRoles()
  229. if err != nil {
  230. t.Error("Unexpected error", err)
  231. }
  232. if !reflect.DeepEqual(out, expected) {
  233. t.Error("AllRoles doesn't match given store. Got", out, "expected", expected)
  234. }
  235. }
  236. func TestGetAndDeleteRole(t *testing.T) {
  237. data := `{"role": "animal"}`
  238. d := &testDoer{
  239. get: []etcdserver.Response{
  240. {
  241. Event: &store.Event{
  242. Action: store.Get,
  243. Node: &store.NodeExtern{
  244. Key: StorePermsPrefix + "/roles/animal",
  245. Value: &data,
  246. },
  247. },
  248. },
  249. },
  250. }
  251. expected := Role{Role: "animal"}
  252. s := Store{d, time.Second, false}
  253. out, err := s.GetRole("animal")
  254. if err != nil {
  255. t.Error("Unexpected error", err)
  256. }
  257. if !reflect.DeepEqual(out, expected) {
  258. t.Error("GetRole doesn't match given store. Got", out, "expected", expected)
  259. }
  260. err = s.DeleteRole("animal")
  261. if err != nil {
  262. t.Error("Unexpected error", err)
  263. }
  264. }
  265. func TestEnsure(t *testing.T) {
  266. d := &testDoer{
  267. get: []etcdserver.Response{
  268. {
  269. Event: &store.Event{
  270. Action: store.Set,
  271. Node: &store.NodeExtern{
  272. Key: StorePermsPrefix,
  273. Dir: true,
  274. },
  275. },
  276. },
  277. {
  278. Event: &store.Event{
  279. Action: store.Set,
  280. Node: &store.NodeExtern{
  281. Key: StorePermsPrefix + "/users/",
  282. Dir: true,
  283. },
  284. },
  285. },
  286. {
  287. Event: &store.Event{
  288. Action: store.Set,
  289. Node: &store.NodeExtern{
  290. Key: StorePermsPrefix + "/roles/",
  291. Dir: true,
  292. },
  293. },
  294. },
  295. },
  296. }
  297. s := Store{d, time.Second, false}
  298. err := s.ensureSecurityDirectories()
  299. if err != nil {
  300. t.Error("Unexpected error", err)
  301. }
  302. }
  303. func TestSimpleMatch(t *testing.T) {
  304. role := Role{Role: "foo", Permissions: Permissions{KV: rwPermission{Read: []string{"/foodir/*", "/fookey"}, Write: []string{"/bardir/*", "/barkey"}}}}
  305. if !role.HasKeyAccess("/foodir/foo/bar", false) {
  306. t.Fatal("role lacks expected access")
  307. }
  308. if !role.HasKeyAccess("/fookey", false) {
  309. t.Fatal("role lacks expected access")
  310. }
  311. if role.HasKeyAccess("/bardir/bar/foo", false) {
  312. t.Fatal("role has unexpected access")
  313. }
  314. if role.HasKeyAccess("/barkey", false) {
  315. t.Fatal("role has unexpected access")
  316. }
  317. if role.HasKeyAccess("/foodir/foo/bar", true) {
  318. t.Fatal("role has unexpected access")
  319. }
  320. if role.HasKeyAccess("/fookey", true) {
  321. t.Fatal("role has unexpected access")
  322. }
  323. if !role.HasKeyAccess("/bardir/bar/foo", true) {
  324. t.Fatal("role lacks expected access")
  325. }
  326. if !role.HasKeyAccess("/barkey", true) {
  327. t.Fatal("role lacks expected access")
  328. }
  329. }