api_auth_test.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package api
  7. import (
  8. "testing"
  9. "time"
  10. "github.com/syncthing/syncthing/lib/config"
  11. "github.com/syncthing/syncthing/lib/db"
  12. "github.com/syncthing/syncthing/lib/db/backend"
  13. "github.com/syncthing/syncthing/lib/events"
  14. )
  15. var guiCfg config.GUIConfiguration
  16. func init() {
  17. guiCfg.User = "user"
  18. guiCfg.SetPassword("pass")
  19. }
  20. func TestStaticAuthOK(t *testing.T) {
  21. t.Parallel()
  22. ok := authStatic("user", "pass", guiCfg)
  23. if !ok {
  24. t.Fatalf("should pass auth")
  25. }
  26. }
  27. func TestSimpleAuthUsernameFail(t *testing.T) {
  28. t.Parallel()
  29. ok := authStatic("userWRONG", "pass", guiCfg)
  30. if ok {
  31. t.Fatalf("should fail auth")
  32. }
  33. }
  34. func TestStaticAuthPasswordFail(t *testing.T) {
  35. t.Parallel()
  36. ok := authStatic("user", "passWRONG", guiCfg)
  37. if ok {
  38. t.Fatalf("should fail auth")
  39. }
  40. }
  41. func TestFormatOptionalPercentS(t *testing.T) {
  42. t.Parallel()
  43. cases := []struct {
  44. template string
  45. username string
  46. expected string
  47. }{
  48. {"cn=%s,dc=some,dc=example,dc=com", "username", "cn=username,dc=some,dc=example,dc=com"},
  49. {"cn=fixedusername,dc=some,dc=example,dc=com", "username", "cn=fixedusername,dc=some,dc=example,dc=com"},
  50. {"cn=%%s,dc=%s,dc=example,dc=com", "username", "cn=%s,dc=username,dc=example,dc=com"},
  51. {"cn=%%s,dc=%%s,dc=example,dc=com", "username", "cn=%s,dc=%s,dc=example,dc=com"},
  52. {"cn=%s,dc=%s,dc=example,dc=com", "username", "cn=username,dc=username,dc=example,dc=com"},
  53. }
  54. for _, c := range cases {
  55. templatedDn := formatOptionalPercentS(c.template, c.username)
  56. if c.expected != templatedDn {
  57. t.Fatalf("result should be %s != %s", c.expected, templatedDn)
  58. }
  59. }
  60. }
  61. func TestEscapeForLDAPFilter(t *testing.T) {
  62. t.Parallel()
  63. cases := []struct {
  64. in string
  65. out string
  66. }{
  67. {"username", `username`},
  68. {"user(name", `user\28name`},
  69. {"user)name", `user\29name`},
  70. {"user\\name", `user\5Cname`},
  71. {"user*name", `user\2Aname`},
  72. {"*,CN=asdf", `\2A,CN=asdf`},
  73. }
  74. for _, c := range cases {
  75. res := escapeForLDAPFilter(c.in)
  76. if c.out != res {
  77. t.Fatalf("result should be %s != %s", c.out, res)
  78. }
  79. }
  80. }
  81. func TestEscapeForLDAPDN(t *testing.T) {
  82. t.Parallel()
  83. cases := []struct {
  84. in string
  85. out string
  86. }{
  87. {"username", `username`},
  88. {"* ,CN=asdf", `*\20\2CCN\3Dasdf`},
  89. }
  90. for _, c := range cases {
  91. res := escapeForLDAPDN(c.in)
  92. if c.out != res {
  93. t.Fatalf("result should be %s != %s", c.out, res)
  94. }
  95. }
  96. }
  97. type mockClock struct {
  98. now time.Time
  99. }
  100. func (c *mockClock) Now() time.Time {
  101. c.now = c.now.Add(1) // time always ticks by at least 1 ns
  102. return c.now
  103. }
  104. func (c *mockClock) wind(t time.Duration) {
  105. c.now = c.now.Add(t)
  106. }
  107. func TestTokenManager(t *testing.T) {
  108. t.Parallel()
  109. mdb, _ := db.NewLowlevel(backend.OpenMemory(), events.NoopLogger)
  110. kdb := db.NewNamespacedKV(mdb, "test")
  111. clock := &mockClock{now: time.Now()}
  112. // Token manager keeps up to three tokens with a validity time of 24 hours.
  113. tm := newTokenManager("testTokens", kdb, 24*time.Hour, 3)
  114. tm.timeNow = clock.Now
  115. // Create three tokens
  116. t0 := tm.New()
  117. t1 := tm.New()
  118. t2 := tm.New()
  119. // Check that the tokens are valid
  120. if !tm.Check(t0) {
  121. t.Errorf("token %q should be valid", t0)
  122. }
  123. if !tm.Check(t1) {
  124. t.Errorf("token %q should be valid", t1)
  125. }
  126. if !tm.Check(t2) {
  127. t.Errorf("token %q should be valid", t2)
  128. }
  129. // Create a fourth token
  130. t3 := tm.New()
  131. // It should be valid
  132. if !tm.Check(t3) {
  133. t.Errorf("token %q should be valid", t3)
  134. }
  135. // But the first token should have been removed
  136. if tm.Check(t0) {
  137. t.Errorf("token %q should be invalid", t0)
  138. }
  139. // Wind the clock by 12 hours
  140. clock.wind(12 * time.Hour)
  141. // The second token should still be valid (and checking it will give it more life)
  142. if !tm.Check(t1) {
  143. t.Errorf("token %q should be valid", t1)
  144. }
  145. // Wind the clock by 12 hours
  146. clock.wind(12 * time.Hour)
  147. // The second token should still be valid
  148. if !tm.Check(t1) {
  149. t.Errorf("token %q should be valid", t1)
  150. }
  151. // But the third and fourth tokens should have expired
  152. if tm.Check(t2) {
  153. t.Errorf("token %q should be invalid", t2)
  154. }
  155. if tm.Check(t3) {
  156. t.Errorf("token %q should be invalid", t3)
  157. }
  158. }