sessions.scm 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. ;;; guile-gcrypt --- crypto tooling for guile
  2. ;;; Copyright © 2016 Christopher Allan Webber <cwebber@dustycloud.org>
  3. ;;;
  4. ;;; This file is part of guile-gcrypt.
  5. ;;;
  6. ;;; guile-gcrypt is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or
  9. ;;; (at your option) any later version.
  10. ;;;
  11. ;;; guile-gcrypt is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;;; General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with guile-gcrypt. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (test-web-sessions)
  19. #:use-module (ice-9 match)
  20. #:use-module (srfi srfi-19)
  21. #:use-module (srfi srfi-64)
  22. #:use-module (rnrs bytevectors)
  23. #:use-module (web request)
  24. #:use-module (web uri)
  25. #:use-module (gcrypt hmac)
  26. #:use-module (gcrypt base64)
  27. #:use-module (webutils sessions))
  28. (test-begin "test-web-sessions")
  29. (define-syntax-rule (import-from-sessions name)
  30. (define name
  31. (@@ (webutils sessions) name)))
  32. ;; Pull in some non-exported procedures
  33. (import-from-sessions session-manager-future-expires)
  34. (import-from-sessions still-fresh-by-date-string?)
  35. (import-from-sessions still-fresh-by-date?)
  36. (import-from-sessions split-session-string)
  37. ;; Fix the current time for easier testing
  38. (import-from-sessions %current-time)
  39. (define a-time
  40. (make-time 'time-utc 0 1472514613)) ; "2016-08-29T23:50:13"
  41. (define-syntax-rule (at-fixed-time body1 body2 ...)
  42. (parameterize ((%current-time (const a-time)))
  43. body1 body2 ...))
  44. ;; This time shouldn't be expired yet
  45. (at-fixed-time
  46. (test-assert (still-fresh-by-date-string?
  47. "2016-08-31T14:01:59.977681000-05:00")) ; the expires-by time
  48. ;; Neither should the time it currently believes it is
  49. (test-assert (still-fresh-by-date?
  50. (session-manager-future-expires
  51. (make-session-manager (gen-signing-key))))))
  52. ;; This should be though
  53. (at-fixed-time
  54. (test-assert (not (still-fresh-by-date-string?
  55. "2016-02-28T14:01:59Z")))) ; that was like, yesterday, man!
  56. ;; An invalid http date string will be considered not-fresh
  57. (at-fixed-time
  58. (test-assert (not (still-fresh-by-date-string? "I'm a date, honest!!!!"))))
  59. ;; A date explicitly in 2 days, 1 hour, 30 minutes
  60. (at-fixed-time
  61. (test-equal (make-date 0 13 20 01 1 9 2016 0)
  62. (session-manager-future-expires
  63. (make-session-manager (gen-signing-key)
  64. #:expire-delta '(2 1 30)))))
  65. ;;; Sessions tests
  66. ;;; ==============
  67. (define our-key
  68. #vu8(252 37 107 2 66 0 168 137 9 168 198 225 153 220 231 85 106 204 78 114 40
  69. 195 23 20 132 120 31 182 47 63 209 50 175 17 120 123 14 17 171 236 130
  70. 151 32 175 89 171 179 83 185 65 149 0 21 77 49 177 7 118 172 63 174 230
  71. 158 236 161 111 191 186 104 196 168 123 252 156 189 166 244 37 132 178
  72. 215 78 18 86 93 218 122 7 107 211 57 147 62 207 46 98 130 18 36 205 89 92
  73. 17 36 62 246 38 152 250 66 220 242 129 174 190 167 81 33 201 242 232 122
  74. 118 81 176 2 238 99))
  75. (define test-session-manager
  76. (make-session-manager our-key
  77. #:algorithm 'sha512
  78. #:expire-delta '(30 0 0)))
  79. (define (set-cookie->session-str set-cookie-header)
  80. (match set-cookie-header
  81. (('set-cookie "session" (? string? session-str) (("Expires" . (? date? _))))
  82. session-str)))
  83. (define signed-cookie-str
  84. (at-fixed-time
  85. (set-cookie->session-str (set-session test-session-manager '(its fine)))))
  86. (match (split-session-string signed-cookie-str)
  87. ((sig date-str b64-data)
  88. ;; Maybe not the most useful test but it would be strange if this changed
  89. (test-equal sig
  90. "VvcskyTMO4LWMOwhrxNKgLd8EB/F/nwosQ5XwfceYEsNra1VmWndEf9RtP7TR7yeOiGZhRJaYFB+/u1POtiwQw==")
  91. ;; These are more useful
  92. (test-equal date-str "2016-09-28T23:50:13Z")
  93. (test-equal (utf8->string (base64-decode b64-data))
  94. "(its fine)")))
  95. ;;; Now let's make a new session based on this data
  96. (at-fixed-time
  97. (let ((fake-request
  98. (build-request (string->uri "https://example.who/cares/")
  99. #:headers `((cookie ("session" . ,signed-cookie-str))))))
  100. (test-equal
  101. (session-data test-session-manager fake-request)
  102. '(its fine))))
  103. (define cookie-str-with-bad-sig
  104. "c6SD1S6It8HRYIXLYzRvLln0/yOWrIhy+XV86m42eSvKhv8U8NqZNqAny35qDd1QObZrwXhq1jjVNUiAwU1I0w==$2016-09-28T23:50:13Z$KGl0cyBmaW5lKQ==")
  105. ;;; Now let's do a cookie signature that's not legitimate
  106. (at-fixed-time
  107. (let ((fake-request
  108. (build-request (string->uri "https://example.who/cares/")
  109. #:headers `((cookie ("session" .
  110. ,cookie-str-with-bad-sig))))))
  111. (test-equal
  112. (session-data test-session-manager fake-request)
  113. #f)))
  114. (define expired-time
  115. (make-time 'time-utc 0 1443484213)) ; "2015-09-28T23:50:13Z" ... a year prior
  116. ;;; Here's one that's legitimate, but it's expired by now
  117. (define expired-cookie-str
  118. (parameterize ((%current-time (const expired-time)))
  119. (set-cookie->session-str
  120. (set-session test-session-manager '(its fine)))))
  121. ;;; This is expired, so it should be invalid.
  122. (at-fixed-time
  123. (let ((fake-request
  124. (build-request (string->uri "https://example.who/cares/")
  125. #:headers `((cookie ("session" .
  126. ,expired-cookie-str))))))
  127. (test-equal
  128. (session-data test-session-manager fake-request)
  129. #f)))
  130. ;;; And now, deleting cookies! It really ought to create a cookie
  131. ;;; with an empty value, set to Expire at the epoch.
  132. (test-equal (delete-session test-session-manager)
  133. `(set-cookie "session" ""
  134. (("Expires" . ,(@@ (webutils cookie) %the-epoch)))))
  135. (test-end "test-web-sessions")