acl_test.go 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271
  1. package access
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "testing"
  8. "time"
  9. "devt.de/krotik/common/fileutil"
  10. )
  11. func TestPersistedACLTable(t *testing.T) {
  12. testACLFile := "persist_tester.acl"
  13. defer func() {
  14. os.Remove(testACLFile)
  15. }()
  16. // Test the most basic start and stop
  17. pt, err := NewPersistedACLTable(testACLFile, time.Millisecond)
  18. if err != nil {
  19. t.Error(err)
  20. return
  21. }
  22. if _, _, err := pt.IsPermitted("", "", &Rights{}); err == nil || err.Error() != "Unknown user: " {
  23. t.Error("Unexpected result:", err)
  24. return
  25. }
  26. if err := pt.Close(); err != nil {
  27. t.Error(err)
  28. return
  29. }
  30. // Check that we get an error back when trying to close a thing twice or we try any other operation
  31. if _, _, err := pt.IsPermitted("", "", &Rights{}); err == nil || err.Error() != "ACL table was closed" {
  32. t.Error("Unexpected result:", err)
  33. return
  34. }
  35. if err := pt.Close(); err == nil || err.Error() != "ACL table was closed" {
  36. t.Error("Unexpected result:", err)
  37. return
  38. }
  39. // Create communication channel which can be used to trigger the watch thread
  40. watchToggle := make(chan bool)
  41. watchSleep = func(t time.Duration) {
  42. <-watchToggle
  43. }
  44. // Now test again but with some data
  45. pt, err = NewPersistedACLTable(testACLFile, time.Millisecond)
  46. if err != nil {
  47. t.Error(err)
  48. return
  49. }
  50. time.Sleep(50 * time.Millisecond)
  51. if pt.String() != `
  52. ACLTable
  53. ========
  54. Users:
  55. `[1:] {
  56. t.Error("Unexpected result:", pt.String())
  57. return
  58. }
  59. // Add the fi
  60. if err := pt.AddGroup("foo"); err != nil {
  61. t.Error(err)
  62. return
  63. }
  64. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `
  65. {
  66. "groups": {
  67. "foo": {}
  68. },
  69. "users": {}
  70. }`[1:] {
  71. t.Error("Unexpected result:", string(res))
  72. return
  73. }
  74. if err := ioutil.WriteFile(testACLFile, []byte(`
  75. {
  76. "groups": {
  77. "bar": {
  78. "/bla": "CRUD",
  79. "/blatest*": "-R-D"
  80. },
  81. "public": {
  82. "/special": "-R-D",
  83. "/test*": "-R-D"
  84. }
  85. },
  86. "users": {
  87. "hans": [
  88. "public"
  89. ]
  90. }
  91. }`), 0666); err != nil {
  92. t.Error(err)
  93. return
  94. }
  95. watchToggle <- true
  96. time.Sleep(50 * time.Millisecond)
  97. // Check the new configuration has been loaded from disk
  98. if pt.String() != `
  99. ACLTable
  100. ========
  101. Users:
  102. hans : public
  103. Group: bar
  104. ====
  105. /bla : CRUD
  106. /blatest : -R-D
  107. Group: public
  108. ====
  109. /special : -R-D
  110. /test : -R-D
  111. `[1:] {
  112. t.Error("Unexpected result:", pt.String())
  113. return
  114. }
  115. // Produce some faulty disk configuration and see that it is rewritten
  116. // after PersistedACLTableErrRetries
  117. PersistedACLTableErrRetries = 2
  118. if err := ioutil.WriteFile(testACLFile, []byte(`
  119. {
  120. "groups": {
  121. "bar": {
  122. `), 0666); err != nil {
  123. t.Error(err)
  124. return
  125. }
  126. watchToggle <- true
  127. time.Sleep(time.Millisecond)
  128. watchToggle <- true
  129. time.Sleep(time.Millisecond)
  130. if err := pt.(*PersistedACLTable).SyncError; err == nil ||
  131. err.Error() != "Could not sync ACL table config from disk: unexpected end of JSON input" {
  132. t.Error("Unexpected result:", err)
  133. return
  134. }
  135. watchToggle <- true
  136. time.Sleep(50 * time.Millisecond)
  137. if err := pt.(*PersistedACLTable).SyncError; err != nil {
  138. t.Error("Unexpected result:", err)
  139. return
  140. }
  141. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  142. "groups": {
  143. "bar": {
  144. "/bla": "CRUD",
  145. "/blatest*": "-R-D"
  146. },
  147. "public": {
  148. "/special": "-R-D",
  149. "/test*": "-R-D"
  150. }
  151. },
  152. "users": {
  153. "hans": [
  154. "public"
  155. ]
  156. }
  157. }` {
  158. t.Error("Unexpected result:", string(res))
  159. return
  160. }
  161. if pt.String() != `
  162. ACLTable
  163. ========
  164. Users:
  165. hans : public
  166. Group: bar
  167. ====
  168. /bla : CRUD
  169. /blatest : -R-D
  170. Group: public
  171. ====
  172. /special : -R-D
  173. /test : -R-D
  174. `[1:] {
  175. t.Error("Unexpected result:", pt.String())
  176. return
  177. }
  178. // Test the various access functions
  179. if res, err := pt.GroupNames(); fmt.Sprint(res) != "[bar public]" {
  180. t.Error("Unexpected result:", res, err)
  181. return
  182. }
  183. if res, err := pt.UserNames(); fmt.Sprint(res) != "[hans]" {
  184. t.Error("Unexpected result:", res, err)
  185. return
  186. }
  187. if res, err := pt.GroupsOfUser("hans"); fmt.Sprint(res) != "[public]" {
  188. t.Error("Unexpected result:", res, err)
  189. return
  190. }
  191. if err := pt.AddPermission("public", "woo", &Rights{}); err != nil {
  192. t.Error("Unexpected result:", err)
  193. return
  194. }
  195. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  196. "groups": {
  197. "bar": {
  198. "/bla": "CRUD",
  199. "/blatest*": "-R-D"
  200. },
  201. "public": {
  202. "/special": "-R-D",
  203. "/test*": "-R-D",
  204. "woo": "----"
  205. }
  206. },
  207. "users": {
  208. "hans": [
  209. "public"
  210. ]
  211. }
  212. }` {
  213. t.Error("Unexpected result:", string(res))
  214. return
  215. }
  216. if err := pt.AddUserToGroup("hans", "bar"); err != nil {
  217. t.Error("Unexpected result:", err)
  218. return
  219. }
  220. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  221. "groups": {
  222. "bar": {
  223. "/bla": "CRUD",
  224. "/blatest*": "-R-D"
  225. },
  226. "public": {
  227. "/special": "-R-D",
  228. "/test*": "-R-D",
  229. "woo": "----"
  230. }
  231. },
  232. "users": {
  233. "hans": [
  234. "bar",
  235. "public"
  236. ]
  237. }
  238. }` {
  239. t.Error("Unexpected result:", string(res))
  240. return
  241. }
  242. conf, err := pt.GetConfig()
  243. if err != nil {
  244. t.Error(err)
  245. return
  246. }
  247. res, err := json.MarshalIndent(conf, "", " ")
  248. if err != nil || string(res) != `
  249. {
  250. "groups": {
  251. "bar": {
  252. "/bla": "CRUD",
  253. "/blatest*": "-R-D"
  254. },
  255. "public": {
  256. "/special": "-R-D",
  257. "/test*": "-R-D",
  258. "woo": "----"
  259. }
  260. },
  261. "users": {
  262. "hans": [
  263. "bar",
  264. "public"
  265. ]
  266. }
  267. }`[1:] {
  268. t.Error("Unexpected result:", string(res), err)
  269. return
  270. }
  271. if err := pt.RemoveUserFromGroup("hans", "bar"); err != nil {
  272. t.Error("Unexpected result:", err)
  273. return
  274. }
  275. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  276. "groups": {
  277. "bar": {
  278. "/bla": "CRUD",
  279. "/blatest*": "-R-D"
  280. },
  281. "public": {
  282. "/special": "-R-D",
  283. "/test*": "-R-D",
  284. "woo": "----"
  285. }
  286. },
  287. "users": {
  288. "hans": [
  289. "public"
  290. ]
  291. }
  292. }` {
  293. t.Error("Unexpected result:", string(res))
  294. return
  295. }
  296. if err := pt.RemoveGroup("public"); err != nil {
  297. t.Error("Unexpected result:", err)
  298. return
  299. }
  300. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  301. "groups": {
  302. "bar": {
  303. "/bla": "CRUD",
  304. "/blatest*": "-R-D"
  305. }
  306. },
  307. "users": {}
  308. }` {
  309. t.Error("Unexpected result:", string(res))
  310. return
  311. }
  312. if err := pt.ClearPermissions("bar"); err != nil {
  313. t.Error("Unexpected result:", err)
  314. return
  315. }
  316. if res, err := pt.Permissions("bar"); fmt.Sprint(res) != "map[]" || err != nil {
  317. t.Error("Unexpected result:", res, err)
  318. return
  319. }
  320. // Test that a sync failure blocks the whole object
  321. testerror := fmt.Errorf("Testerror")
  322. pt.(*PersistedACLTable).SyncError = testerror
  323. if _, err := pt.GroupNames(); err != testerror {
  324. t.Error("Unexpected result:", err)
  325. return
  326. }
  327. if _, err := pt.UserNames(); err != testerror {
  328. t.Error("Unexpected result:", err)
  329. return
  330. }
  331. if _, err := pt.GroupsOfUser(""); err != testerror {
  332. t.Error("Unexpected result:", err)
  333. return
  334. }
  335. if err := pt.AddPermission("", "", nil); err != testerror {
  336. t.Error("Unexpected result:", err)
  337. return
  338. }
  339. if _, err := pt.Permissions(""); err != testerror {
  340. t.Error("Unexpected result:", err)
  341. return
  342. }
  343. if err := pt.ClearPermissions(""); err != testerror {
  344. t.Error("Unexpected result:", err)
  345. return
  346. }
  347. if err := pt.AddGroup(""); err != testerror {
  348. t.Error("Unexpected result:", err)
  349. return
  350. }
  351. if err := pt.RemoveGroup(""); err != testerror {
  352. t.Error("Unexpected result:", err)
  353. return
  354. }
  355. if err := pt.AddUserToGroup("", ""); err != testerror {
  356. t.Error("Unexpected result:", err)
  357. return
  358. }
  359. if err := pt.RemoveUserFromGroup("", ""); err != testerror {
  360. t.Error("Unexpected result:", err)
  361. return
  362. }
  363. if _, err := pt.GetConfig(); err != testerror {
  364. t.Error("Unexpected result:", err)
  365. return
  366. }
  367. // Toggle the watch routine and close
  368. pt.(*PersistedACLTable).SyncError = ErrClosed
  369. watchToggle <- true
  370. err = pt.Close()
  371. // Error is preserved by by Close since it was set before it was called
  372. if err != ErrClosed {
  373. t.Error(err)
  374. }
  375. }
  376. func TestPersistedACLTableSync(t *testing.T) {
  377. testACLFile := "sycn_tester.acl"
  378. defer func() {
  379. os.Remove(testACLFile)
  380. }()
  381. pt := &PersistedACLTable{}
  382. pt.filename = testACLFile
  383. // We start with no file and no table
  384. if ok, _ := fileutil.PathExists(testACLFile); ok {
  385. t.Error("Unexpected result:", ok)
  386. return
  387. }
  388. // This should create an empty table in memory and on disk
  389. if err := pt.sync(true); err != nil {
  390. t.Error(err)
  391. return
  392. }
  393. if ok, _ := fileutil.PathExists(testACLFile); !ok {
  394. t.Error("Unexpected result:", ok)
  395. return
  396. }
  397. if pt.table.String() != `
  398. ACLTable
  399. ========
  400. Users:
  401. `[1:] {
  402. t.Error("Unexpected result:", pt.table.String())
  403. return
  404. }
  405. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  406. "groups": {},
  407. "users": {}
  408. }` {
  409. t.Error("Unexpected result:", string(res))
  410. return
  411. }
  412. os.Remove(testACLFile)
  413. if ok, _ := fileutil.PathExists(testACLFile); ok {
  414. t.Error("Unexpected result:", ok)
  415. return
  416. }
  417. pt.table = nil
  418. // Now do the same exercise again but with syncing from memory
  419. if err := pt.sync(false); err != nil {
  420. t.Error(err)
  421. return
  422. }
  423. if ok, _ := fileutil.PathExists(testACLFile); !ok {
  424. t.Error("Unexpected result:", ok)
  425. return
  426. }
  427. if pt.table.String() != `
  428. ACLTable
  429. ========
  430. Users:
  431. `[1:] {
  432. t.Error("Unexpected result:", pt.table.String())
  433. return
  434. }
  435. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `{
  436. "groups": {},
  437. "users": {}
  438. }` {
  439. t.Error("Unexpected result:", string(res))
  440. return
  441. }
  442. // Fill up the memory but sync from disk
  443. pt.table.AddGroup("foo")
  444. if pt.table.String() != `
  445. ACLTable
  446. ========
  447. Users:
  448. Group: foo
  449. ====
  450. `[1:] {
  451. t.Error("Unexpected result:", pt.table.String())
  452. return
  453. }
  454. if res, err := pt.table.GetConfig(); fmt.Sprint(res["groups"]) != `map[foo:map[]]` || err != nil {
  455. t.Error("Unexpected result:", res["groups"], err)
  456. return
  457. }
  458. if err := pt.sync(true); err != nil {
  459. t.Error(err)
  460. return
  461. }
  462. if pt.table.String() != `
  463. ACLTable
  464. ========
  465. Users:
  466. `[1:] {
  467. t.Error("Unexpected result:", pt.table.String())
  468. return
  469. }
  470. // Fill up the memory and sync to disk
  471. pt.table.AddGroup("foo")
  472. if pt.table.String() != `
  473. ACLTable
  474. ========
  475. Users:
  476. Group: foo
  477. ====
  478. `[1:] {
  479. t.Error("Unexpected result:", pt.table.String())
  480. return
  481. }
  482. if err := pt.sync(false); err != nil {
  483. t.Error(err)
  484. return
  485. }
  486. if pt.table.String() != `
  487. ACLTable
  488. ========
  489. Users:
  490. Group: foo
  491. ====
  492. `[1:] {
  493. t.Error("Unexpected result:", pt.table.String())
  494. return
  495. }
  496. if res, _ := ioutil.ReadFile(testACLFile); string(res) != `
  497. {
  498. "groups": {
  499. "foo": {}
  500. },
  501. "users": {}
  502. }`[1:] {
  503. t.Error("Unexpected result:", string(res))
  504. return
  505. }
  506. // Write some rules to disk and load them into memory
  507. if err := ioutil.WriteFile(testACLFile, []byte(`
  508. {
  509. "groups": {
  510. "bar": {
  511. "/bla": "CRUD",
  512. "/blatest*": "-R-D"
  513. },
  514. "public": {
  515. "/special": "-R-D",
  516. "/test*": "-R-D"
  517. }
  518. },
  519. "users": {
  520. "hans": [
  521. "public"
  522. ]
  523. }
  524. }`), 0666); err != nil {
  525. t.Error(err)
  526. return
  527. }
  528. if err := pt.sync(true); err != nil {
  529. t.Error(err)
  530. return
  531. }
  532. if pt.table.String() != `
  533. ACLTable
  534. ========
  535. Users:
  536. hans : public
  537. Group: bar
  538. ====
  539. /bla : CRUD
  540. /blatest : -R-D
  541. Group: public
  542. ====
  543. /special : -R-D
  544. /test : -R-D
  545. `[1:] {
  546. t.Error("Unexpected result:", pt.table.String())
  547. return
  548. }
  549. }
  550. func TestRigths(t *testing.T) {
  551. r1 := &Rights{}
  552. r1.Create = true
  553. r1.Delete = true
  554. r2 := &Rights{
  555. Create: true,
  556. Delete: true,
  557. Update: true,
  558. }
  559. if res := r2.String(); res != "C-UD" {
  560. t.Error("Unexpected result:", res)
  561. return
  562. }
  563. if res := r2.IsAllowed(r1); !res {
  564. t.Error("Unexpected result:", res)
  565. return
  566. }
  567. if res := r1.IsAllowed(r2); res {
  568. t.Error("Unexpected result:", res)
  569. return
  570. }
  571. r1 = &Rights{}
  572. if res := r1.IsAllowed(&Rights{Read: true}); res {
  573. t.Error("Unexpected result:", res)
  574. return
  575. }
  576. if res := r1.IsAllowed(&Rights{Create: true}); res {
  577. t.Error("Unexpected result:", res)
  578. return
  579. }
  580. if res := r1.IsAllowed(&Rights{Update: true}); res {
  581. t.Error("Unexpected result:", res)
  582. return
  583. }
  584. if res := r1.IsAllowed(&Rights{Delete: true}); res {
  585. t.Error("Unexpected result:", res)
  586. return
  587. }
  588. if res, err := RightsFromString("C-U"); res != nil || err == nil || err.Error() != "Rigths string must be 4 characters" {
  589. t.Error("Unexpected result:", res, err)
  590. return
  591. }
  592. if res, err := RightsFromString("C0UD"); res != nil || err == nil || err.Error() != "Read permission in rights string must be either 'r' or '-'" {
  593. t.Error("Unexpected result:", res, err)
  594. return
  595. }
  596. }
  597. func TestMemoryACLTable(t *testing.T) {
  598. tab := NewMemoryACLTable()
  599. tab.Close() // Test NOP
  600. tableconfig, _ := tab.GetConfig()
  601. if res, err := json.MarshalIndent(tableconfig, "", " "); err != nil || string(res) != `
  602. {
  603. "groups": {},
  604. "users": {}
  605. }`[1:] {
  606. t.Error("Unexpected result:", string(res), err)
  607. return
  608. }
  609. // Test empty table operations
  610. if res, _ := tab.GroupNames(); fmt.Sprint(res) != "[]" {
  611. t.Error("Unexpected result:", res)
  612. return
  613. }
  614. if res, _ := tab.UserNames(); fmt.Sprint(res) != "[]" {
  615. t.Error("Unexpected result:", res)
  616. return
  617. }
  618. if res, err := tab.GroupsOfUser("hans"); err == nil || err.Error() != "Unknown user: hans" {
  619. t.Error("Unexpected result:", res, err)
  620. return
  621. }
  622. if err := tab.AddPermission("public", "", nil); err == nil || err.Error() != "Group public does not exist" {
  623. t.Error("Unexpected result:", err)
  624. return
  625. }
  626. if err := tab.RemoveGroup("foo"); err == nil || err.Error() != "Group foo does not exist" {
  627. t.Error("Unexpected result:", err)
  628. return
  629. }
  630. if err := tab.RemoveUserFromGroup("hans", "foo"); err == nil || err.Error() != "User hans does not exist" {
  631. t.Error("Unexpected result:", err)
  632. return
  633. }
  634. if _, _, err := tab.IsPermitted("hans", "", &Rights{}); err == nil || err.Error() != "Unknown user: hans" {
  635. t.Error("Unexpected result:", err)
  636. return
  637. }
  638. // Manually fill up the table
  639. if err := tab.AddGroup("public"); err != nil {
  640. t.Error("Unexpected result:", err)
  641. return
  642. }
  643. if res, err := tab.Permissions("public"); fmt.Sprint(res) != "map[]" || err != nil {
  644. t.Error("Unexpected result: ", res, err)
  645. return
  646. }
  647. if res, err := tab.Permissions("public2"); err == nil || err.Error() != "Group public2 does not exist" {
  648. t.Error("Unexpected result: ", res, err)
  649. return
  650. }
  651. if err := tab.ClearPermissions("public2"); err == nil || err.Error() != "Group public2 does not exist" {
  652. t.Error("Unexpected result: ", err)
  653. return
  654. }
  655. if err := tab.AddGroup("public"); err == nil || err.Error() != "Group public added twice" {
  656. t.Error("Unexpected result:", err)
  657. return
  658. }
  659. if res, _ := tab.GroupNames(); fmt.Sprint(res) != "[public]" {
  660. t.Error("Unexpected result:", res)
  661. return
  662. }
  663. if err := tab.AddGroup("bar"); err != nil {
  664. t.Error("Unexpected result:", err)
  665. return
  666. }
  667. if err := tab.AddUserToGroup("hans", "foo"); err == nil || err.Error() != "Group foo does not exist" {
  668. t.Error("Unexpected result:", err)
  669. return
  670. }
  671. if res, _ := tab.UserNames(); fmt.Sprint(res) != "[]" {
  672. t.Error("Unexpected result:", res)
  673. return
  674. }
  675. if err := tab.AddUserToGroup("hans", "public"); err != nil {
  676. t.Error("Unexpected result:", err)
  677. return
  678. }
  679. if err := tab.RemoveUserFromGroup("hans", "foo"); err == nil || err.Error() != "User hans is not in group foo" {
  680. t.Error("Unexpected result:", err)
  681. return
  682. }
  683. if err := tab.AddUserToGroup("hans", "bar"); err != nil {
  684. t.Error("Unexpected result:", err)
  685. return
  686. }
  687. if res, _ := tab.UserNames(); fmt.Sprint(res) != "[hans]" {
  688. t.Error("Unexpected result:", res)
  689. return
  690. }
  691. if res, _, err := tab.IsPermitted("hans", "/test", &Rights{}); err != nil || res {
  692. t.Error("Unexpected result:", res, err)
  693. return
  694. }
  695. if res, err := tab.GroupsOfUser("hans"); err != nil || fmt.Sprint(res) != "[bar public]" {
  696. t.Error("Unexpected result:", res, err)
  697. return
  698. }
  699. if err := tab.RemoveUserFromGroup("hans", "bar"); err != nil {
  700. t.Error("Unexpected result:", err)
  701. return
  702. }
  703. if res, err := tab.GroupsOfUser("hans"); err != nil || fmt.Sprint(res) != "[public]" {
  704. t.Error("Unexpected result:", res, err)
  705. return
  706. }
  707. // Finally add some permissions
  708. if err := tab.AddPermission("public", "/special", &Rights{
  709. Read: true,
  710. Delete: true,
  711. }); err != nil {
  712. t.Error("Unexpected result:", err)
  713. return
  714. }
  715. if res, err := tab.Permissions("public"); fmt.Sprint(res) != "map[/special:-R-D]" || err != nil {
  716. t.Error("Unexpected result: ", res, err)
  717. return
  718. }
  719. if err := tab.ClearPermissions("public"); err != nil {
  720. t.Error("Unexpected result: ", err)
  721. return
  722. }
  723. if res, err := tab.Permissions("public"); fmt.Sprint(res) != "map[]" || err != nil {
  724. t.Error("Unexpected result: ", res, err)
  725. return
  726. }
  727. if err := tab.AddPermission("public", "/special", &Rights{
  728. Read: true,
  729. Delete: true,
  730. }); err != nil {
  731. t.Error("Unexpected result:", err)
  732. return
  733. }
  734. if res, err := tab.Permissions("public"); fmt.Sprint(res) != "map[/special:-R-D]" || err != nil {
  735. t.Error("Unexpected result: ", res, err)
  736. return
  737. }
  738. if err := tab.AddPermission("public", "/special", &Rights{}); err == nil || err.Error() != "Resource access for /special registered twice" {
  739. t.Error("Unexpected result:", err)
  740. return
  741. }
  742. if err := tab.AddPermission("public", "/test*", &Rights{
  743. Read: true,
  744. Delete: true,
  745. }); err != nil {
  746. t.Error("Unexpected result:", err)
  747. return
  748. }
  749. if err := tab.AddPermission("public", "/test*", &Rights{}); err == nil || err.Error() != "Resource access wildcard for /test* registered twice" {
  750. t.Error("Unexpected result:", err)
  751. return
  752. }
  753. // Check permissions
  754. if res, _, err := tab.IsPermitted("hans", "/test", &Rights{}); err != nil || !res {
  755. t.Error("Unexpected result:", res, err)
  756. return
  757. }
  758. if res, _, err := tab.IsPermitted("hans", "/special", &Rights{}); err != nil || !res {
  759. t.Error("Unexpected result:", res, err)
  760. return
  761. }
  762. if res, _, err := tab.IsPermitted("hans", "/special1", &Rights{}); err != nil || res {
  763. t.Error("Unexpected result:", res, err)
  764. return
  765. }
  766. // Test no access in sub category
  767. if res, _, err := tab.IsPermitted("hans", "/test1", &Rights{}); err != nil || !res {
  768. t.Error("Unexpected result:", res, err)
  769. return
  770. }
  771. // Test read access in sub category
  772. if res, _, err := tab.IsPermitted("hans", "/test1", &Rights{Read: true}); err != nil || !res {
  773. t.Error("Unexpected result:", res, err)
  774. return
  775. }
  776. if res, _, err := tab.IsPermitted("hans", "/special", &Rights{Read: true}); err != nil || !res {
  777. t.Error("Unexpected result:", res, err)
  778. return
  779. }
  780. // Test no update access
  781. if res, _, err := tab.IsPermitted("hans", "/test1", &Rights{Read: true, Update: true}); err != nil || res {
  782. t.Error("Unexpected result:", res, err)
  783. return
  784. }
  785. if res, _, err := tab.IsPermitted("hans", "/special", &Rights{Read: true, Update: true}); err != nil || res {
  786. t.Error("Unexpected result:", res, err)
  787. return
  788. }
  789. // This should now be cached
  790. if res, _, err := tab.IsPermitted("hans", "/test1", &Rights{Read: true}); err != nil || !res {
  791. t.Error("Unexpected result:", res, err)
  792. return
  793. }
  794. if res, _, err := tab.IsPermitted("hans", "/test1", &Rights{Read: true, Update: true}); err != nil || res {
  795. t.Error("Unexpected result:", res, err)
  796. return
  797. }
  798. // Check a non-permitted access request
  799. if res, _, err := tab.IsPermitted("hans", "/tes", &Rights{}); err != nil || res {
  800. t.Error("Unexpected result:", res, err)
  801. return
  802. }
  803. // Check cache contents
  804. if res := tab.(*MemoryACLTable).PermissionCache.String(); res != `
  805. [hans /special ----]:true
  806. [hans /special -R--]:true
  807. [hans /special -RU-]:false
  808. [hans /special1 ----]:false
  809. [hans /tes ----]:false
  810. [hans /test ----]:true
  811. [hans /test1 ----]:true
  812. [hans /test1 -R--]:true
  813. [hans /test1 -RU-]:false
  814. `[1:] {
  815. t.Error("Unexpected result:", res)
  816. return
  817. }
  818. // Print current table
  819. if res := tab.String(); res != `
  820. ACLTable
  821. ========
  822. Users:
  823. hans : public
  824. Group: bar
  825. ====
  826. Group: public
  827. ====
  828. /special : -R-D
  829. /test : -R-D
  830. `[1:] {
  831. t.Error("Unexpected result:", res)
  832. return
  833. }
  834. if err := tab.AddPermission("bar", "/blatest*", &Rights{
  835. Read: true,
  836. Delete: true,
  837. }); err != nil {
  838. t.Error("Unexpected result:", err)
  839. return
  840. }
  841. if err := tab.AddPermission("bar", "/bla", &Rights{
  842. Read: true,
  843. Create: true,
  844. Update: true,
  845. Delete: true,
  846. }); err != nil {
  847. t.Error("Unexpected result:", err)
  848. return
  849. }
  850. if res := tab.String(); res != `
  851. ACLTable
  852. ========
  853. Users:
  854. hans : public
  855. Group: bar
  856. ====
  857. /bla : CRUD
  858. /blatest : -R-D
  859. Group: public
  860. ====
  861. /special : -R-D
  862. /test : -R-D
  863. `[1:] {
  864. t.Error("Unexpected result:", res)
  865. return
  866. }
  867. conf, err := tab.GetConfig()
  868. if err != nil {
  869. t.Error(err)
  870. return
  871. }
  872. res, err := json.MarshalIndent(conf, "", " ")
  873. if err != nil || string(res) != `
  874. {
  875. "groups": {
  876. "bar": {
  877. "/bla": "CRUD",
  878. "/blatest*": "-R-D"
  879. },
  880. "public": {
  881. "/special": "-R-D",
  882. "/test*": "-R-D"
  883. }
  884. },
  885. "users": {
  886. "hans": [
  887. "public"
  888. ]
  889. }
  890. }`[1:] {
  891. t.Error("Unexpected result:", string(res), err)
  892. return
  893. }
  894. // Duplicate the table
  895. tab2, err := NewMemoryACLTableFromConfig(conf)
  896. if err != nil {
  897. t.Error(err)
  898. return
  899. }
  900. if res := tab2.String(); res != `
  901. ACLTable
  902. ========
  903. Users:
  904. hans : public
  905. Group: bar
  906. ====
  907. /bla : CRUD
  908. /blatest : -R-D
  909. Group: public
  910. ====
  911. /special : -R-D
  912. /test : -R-D
  913. `[1:] {
  914. t.Error("Unexpected result:", res)
  915. return
  916. }
  917. // Destroy group public
  918. if err := tab.RemoveGroup("public"); err != nil {
  919. t.Error("Unexpected result:", err)
  920. return
  921. }
  922. if res, err := tab.GroupsOfUser("hans"); err == nil || err.Error() != "Unknown user: hans" {
  923. t.Error("Unexpected result:", res, err)
  924. return
  925. }
  926. // All permissions should be gone now
  927. if res, _, err := tab.IsPermitted("hans", "/test1", &Rights{Read: true}); err == nil || err.Error() != "Unknown user: hans" {
  928. t.Error("Unexpected result:", res, err)
  929. return
  930. }
  931. if res, _ := tab.GroupNames(); fmt.Sprint(res) != "[bar]" {
  932. t.Error("Unexpected result:", res)
  933. return
  934. }
  935. if res, _ := tab.UserNames(); fmt.Sprint(res) != "[]" {
  936. t.Error("Unexpected result:", res)
  937. return
  938. }
  939. if res, err := tab.GroupsOfUser("hans"); err == nil || err.Error() != "Unknown user: hans" {
  940. t.Error("Unexpected result:", res, err)
  941. return
  942. }
  943. if res, _, err := tab.IsPermitted("hans", "/test", &Rights{}); err == nil || err.Error() != "Unknown user: hans" {
  944. t.Error("Unexpected result:", res, err)
  945. return
  946. }
  947. if res, _, err := tab.IsPermitted("hans", "/tes", &Rights{}); err == nil || err.Error() != "Unknown user: hans" {
  948. t.Error("Unexpected result:", res, err)
  949. return
  950. }
  951. // Test error cases
  952. tab2 = nil
  953. var nullTable *MemoryACLTable
  954. if res := nullTable.String(); res != `
  955. ACLTable
  956. ========
  957. Users:
  958. `[1:] {
  959. t.Error("Unexpected result:", res)
  960. return
  961. }
  962. tab2 = NewMemoryACLTable()
  963. if res := tab2.String(); res != `
  964. ACLTable
  965. ========
  966. Users:
  967. `[1:] {
  968. t.Error("Unexpected result:", res)
  969. return
  970. }
  971. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{})
  972. if tab != nil || err == nil || err.Error() != "Entry 'users' is missing from ACL table config" {
  973. t.Error("Unexpected results:", tab, err)
  974. return
  975. }
  976. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  977. "users": "foo",
  978. })
  979. if tab != nil || err == nil || err.Error() != "Entry 'users' is not of the expected format" {
  980. t.Error("Unexpected results:", tab, err)
  981. return
  982. }
  983. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  984. "users": map[string][]string{},
  985. })
  986. if tab != nil || err == nil || err.Error() != "Entry 'groups' is missing from ACL table config" {
  987. t.Error("Unexpected results:", tab, err)
  988. return
  989. }
  990. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  991. "users": map[string][]string{},
  992. "groups": "foo",
  993. })
  994. if tab != nil || err == nil || err.Error() != "Entry 'groups' is not of the expected format" {
  995. t.Error("Unexpected results:", tab, err)
  996. return
  997. }
  998. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  999. "users": map[string][]string{},
  1000. "groups": map[string]string{
  1001. "foo": "bar",
  1002. },
  1003. })
  1004. if tab != nil || err == nil || err.Error() != "Entries in 'groups' are not of the expected format" {
  1005. t.Error("Unexpected results:", tab, err)
  1006. return
  1007. }
  1008. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  1009. "users": map[string]string{
  1010. "foo": "bar",
  1011. },
  1012. "groups": map[string]string{},
  1013. })
  1014. if tab != nil || err == nil || err.Error() != "Entries in 'users' are not of the expected format" {
  1015. t.Error("Unexpected results:", tab, err)
  1016. return
  1017. }
  1018. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  1019. "users": map[string][]string{},
  1020. "groups": map[string]map[string]string{
  1021. "foogroup": {
  1022. "/fooresource": "a---",
  1023. },
  1024. },
  1025. })
  1026. if tab != nil || err == nil ||
  1027. err.Error() != "Error adding resource /fooresource of group foogroup: Create permission in rights string must be either 'c' or '-'" {
  1028. t.Error("Unexpected results:", tab, err)
  1029. return
  1030. }
  1031. tab, err = NewMemoryACLTableFromConfig(map[string]interface{}{
  1032. "users": map[string][]string{
  1033. "hans": {"bargroup"},
  1034. },
  1035. "groups": map[string]map[string]string{
  1036. "foogroup": {
  1037. "/fooresource": "C---",
  1038. },
  1039. },
  1040. })
  1041. if tab != nil || err == nil ||
  1042. err.Error() != "Error adding user hans to group bargroup: Group bargroup does not exist" {
  1043. t.Error("Unexpected results:", tab, err)
  1044. return
  1045. }
  1046. }