auth_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package xs
  2. import (
  3. "errors"
  4. "fmt"
  5. "os/user"
  6. "strings"
  7. "testing"
  8. )
  9. type userVerifs struct {
  10. user string
  11. passwd string
  12. good bool
  13. }
  14. var (
  15. dummyShadowA = `johndoe:$6$EeQlTtn/KXdSh6CW$UHbFuEw3UA0Jg9/GoPHxgWk6Ws31x3IjqsP22a9pVMOte0yQwX1.K34oI4FACu8GRg9DArJ5RyWUE9m98qwzZ1:18310:0:99999:7:::
  16. joebloggs:$6$F.0IXOrb0w0VJHG1$3O4PYyng7F3hlh42mbroEdQZvslybY5etPPiLMQJ1xosjABY.Q4xqAfyIfe03Du61ZjGQIt3nL0j12P9k1fsK/:18310:0:99999:7:::
  17. disableduser:!:18310::::::`
  18. dummyAuthTokenFile = "hostA:johndoe:abcdefg\nhostB:imposter:wxyz\n"
  19. dummyXsPasswdFile = `#username:salt:authCookie
  20. bobdobbs:$2a$12$9vqGkFqikspe/2dTARqu1O:$2a$12$9vqGkFqikspe/2dTARqu1OuDKCQ/RYWsnaFjmi.HtmECRkxcZ.kBK
  21. notbob:$2a$12$cZpiYaq5U998cOkXzRKdyu:$2a$12$cZpiYaq5U998cOkXzRKdyuJ2FoEQyVLa3QkYdPQk74VXMoAzhvuP6
  22. `
  23. testGoodUsers = []userVerifs{
  24. {"johndoe", "testpass", true},
  25. {"joebloggs", "testpass2", true},
  26. {"johndoe", "badpass", false},
  27. }
  28. testXsPasswdUsers = []userVerifs{
  29. {"bobdobbs", "praisebob", true},
  30. {"notbob", "imposter", false},
  31. }
  32. userlookup_arg_u string
  33. readfile_arg_f string
  34. )
  35. func newMockAuthCtx(reader func(string) ([]byte, error), userlookup func(string) (*user.User, error)) (ret *AuthCtx) {
  36. ret = &AuthCtx{reader, userlookup}
  37. return
  38. }
  39. func _mock_user_Lookup(username string) (*user.User, error) {
  40. username = userlookup_arg_u
  41. if username == "baduser" {
  42. return &user.User{}, errors.New("bad user")
  43. }
  44. urec := &user.User{Uid: "1000", Gid: "1000", Username: username, Name: "Full Name", HomeDir: "/home/user"}
  45. fmt.Printf(" [mock user rec:%v]\n", urec)
  46. return urec, nil
  47. }
  48. func _mock_ioutil_ReadFile(f string) ([]byte, error) {
  49. f = readfile_arg_f
  50. if f == "/etc/shadow" {
  51. fmt.Println(" [mocking ReadFile(\"/etc/shadow\")]")
  52. return []byte(dummyShadowA), nil
  53. }
  54. if f == "/etc/xs.passwd" {
  55. fmt.Println(" [mocking ReadFile(\"/etc/xs.passwd\")]")
  56. return []byte(dummyXsPasswdFile), nil
  57. }
  58. if strings.Contains(f, "/.xs_id") {
  59. fmt.Println(" [mocking ReadFile(\".xs_id\")]")
  60. return []byte(dummyAuthTokenFile), nil
  61. }
  62. return []byte{}, errors.New("no readfile_arg_f supplied")
  63. }
  64. func _mock_ioutil_ReadFileEmpty(f string) ([]byte, error) {
  65. return []byte{}, nil
  66. }
  67. func _mock_ioutil_ReadFileHasError(f string) ([]byte, error) {
  68. return []byte{}, errors.New("IO Error")
  69. }
  70. func TestVerifyPass(t *testing.T) {
  71. readfile_arg_f = "/etc/shadow"
  72. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, nil)
  73. for idx, rec := range testGoodUsers {
  74. stat, e := VerifyPass(ctx, rec.user, rec.passwd)
  75. if rec.good && (!stat || e != nil) {
  76. t.Fatalf("failed %d\n", idx)
  77. }
  78. }
  79. }
  80. func TestVerifyPassFailsOnEmptyFile(t *testing.T) {
  81. ctx := newMockAuthCtx(_mock_ioutil_ReadFileEmpty, nil)
  82. stat, e := VerifyPass(ctx, "johndoe", "somepass")
  83. if stat || (e == nil) {
  84. t.Fatal("failed to fail w/empty file")
  85. }
  86. }
  87. func TestVerifyPassFailsOnFileError(t *testing.T) {
  88. ctx := newMockAuthCtx(_mock_ioutil_ReadFileEmpty, nil)
  89. stat, e := VerifyPass(ctx, "johndoe", "somepass")
  90. if stat || (e == nil) {
  91. t.Fatal("failed to fail on ioutil.ReadFile error")
  92. }
  93. }
  94. func TestVerifyPassFailsOnDisabledEntry(t *testing.T) {
  95. ctx := newMockAuthCtx(_mock_ioutil_ReadFileEmpty, nil)
  96. stat, e := VerifyPass(ctx, "disableduser", "!")
  97. if stat || (e == nil) {
  98. t.Fatal("failed to fail on disabled user entry")
  99. }
  100. }
  101. ////
  102. func TestAuthUserByTokenFailsOnMissingEntryForHost(t *testing.T) {
  103. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  104. stat := AuthUserByToken(ctx, "johndoe", "hostZ", "abcdefg")
  105. if stat {
  106. t.Fatal("failed to fail on missing/mismatched host entry")
  107. }
  108. }
  109. func TestAuthUserByTokenFailsOnMissingEntryForUser(t *testing.T) {
  110. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  111. stat := AuthUserByToken(ctx, "unkuser", "hostA", "abcdefg")
  112. if stat {
  113. t.Fatal("failed to fail on wrong user")
  114. }
  115. }
  116. func TestAuthUserByTokenFailsOnUserLookupFailure(t *testing.T) {
  117. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  118. userlookup_arg_u = "baduser"
  119. stat := AuthUserByToken(ctx, "johndoe", "hostA", "abcdefg")
  120. if stat {
  121. t.Fatal("failed to fail with bad return from user.Lookup()")
  122. }
  123. }
  124. func TestAuthUserByTokenFailsOnMismatchedTokenForUser(t *testing.T) {
  125. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  126. stat := AuthUserByToken(ctx, "johndoe", "hostA", "badtoken")
  127. if stat {
  128. t.Fatal("failed to fail with valid user, bad token")
  129. }
  130. }
  131. func TestAuthUserByTokenSucceedsWithMatchedUserAndToken(t *testing.T) {
  132. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  133. userlookup_arg_u = "johndoe"
  134. readfile_arg_f = "/.xs_id"
  135. stat := AuthUserByToken(ctx, userlookup_arg_u, "hostA", "hostA:johndoe:abcdefg")
  136. if !stat {
  137. t.Fatal("failed with valid user and token")
  138. }
  139. }
  140. func TestAuthUserByPasswdFailsOnEmptyFile(t *testing.T) {
  141. ctx := newMockAuthCtx(_mock_ioutil_ReadFileEmpty, _mock_user_Lookup)
  142. userlookup_arg_u = "bobdobbs"
  143. readfile_arg_f = "/etc/xs.passwd"
  144. stat, _ := AuthUserByPasswd(ctx, userlookup_arg_u, "praisebob", readfile_arg_f)
  145. if stat {
  146. t.Fatal("failed to fail with missing xs.passwd file")
  147. }
  148. }
  149. func TestAuthUserByPasswdFailsOnBadAuth(t *testing.T) {
  150. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  151. userlookup_arg_u = "bobdobbs"
  152. readfile_arg_f = "/etc/xs.passwd"
  153. stat, _ := AuthUserByPasswd(ctx, userlookup_arg_u, "wrongpass", readfile_arg_f)
  154. if stat {
  155. t.Fatal("failed to fail with valid user, incorrect passwd in xs.passwd file")
  156. }
  157. }
  158. func TestAuthUserByPasswdFailsOnBadUser(t *testing.T) {
  159. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  160. userlookup_arg_u = "bobdobbs"
  161. readfile_arg_f = "/etc/xs.passwd"
  162. stat, _ := AuthUserByPasswd(ctx, userlookup_arg_u, "theotherbob", readfile_arg_f)
  163. if stat {
  164. t.Fatal("failed to fail on invalid user vs. xs.passwd file")
  165. }
  166. }
  167. func TestAuthUserByPasswdPassesOnGoodAuth(t *testing.T) {
  168. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  169. userlookup_arg_u = "bobdobbs"
  170. readfile_arg_f = "/etc/xs.passwd"
  171. stat, _ := AuthUserByPasswd(ctx, userlookup_arg_u, "praisebob", readfile_arg_f)
  172. if !stat {
  173. t.Fatal("failed on valid user w/correct passwd in xs.passwd file")
  174. }
  175. }
  176. func TestAuthUserByPasswdPassesOnOtherGoodAuth(t *testing.T) {
  177. ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
  178. userlookup_arg_u = "notbob"
  179. readfile_arg_f = "/etc/xs.passwd"
  180. stat, _ := AuthUserByPasswd(ctx, userlookup_arg_u, "imposter", readfile_arg_f)
  181. if !stat {
  182. t.Fatal("failed on valid user 2nd entry w/correct passwd in xs.passwd file")
  183. }
  184. }