url-auth-tests.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. ;;; url-auth-tests.el --- Test suite for url-auth.
  2. ;; Copyright (C) 2015-2016 Free Software Foundation, Inc.
  3. ;; Author: Jarno Malmari <jarno@malmari.fi>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;; Test HTTP authentication methods.
  17. ;;; Code:
  18. (require 'ert)
  19. (require 'url-auth)
  20. (defvar url-auth-test-challenges nil
  21. "List of challenges for testing.
  22. Each challenge is a plist. Values are as presented by the
  23. server's WWW-Authenticate header field.")
  24. ;; Set explicitly for easier modification for re-runs.
  25. (setq url-auth-test-challenges
  26. (list
  27. (list :qop "auth"
  28. :nonce "uBr3+qkQBybTr/dKWkmpUqVO7SaEwWYzyTKO7g==$"
  29. :uri "/random/path"
  30. :method "GET"
  31. :realm "Some test realm"
  32. :cnonce "YWU4NDcxYWMxMDAxMjlkMjAwMDE4MjI5MDAwMGY4NGQ="
  33. :nc "00000001"
  34. :username "jytky"
  35. :password "xi5Ac2HEfKt1lKKO05DCSqsK0u7hqqtsT"
  36. :expected-ha1 "af521db3a83abd91262fead04fa31892"
  37. :expected-ha2 "e490a6a147c79404b365d1f6059ddda5"
  38. :expected-response "ecb6396e93b9e09e31f19264cfd8f854")
  39. (list :nonce "a1be8a3065e00c5bf190ad499299aea5"
  40. :opaque "d7c2a27230fc8c74bb6e06be8c9cd189"
  41. :realm "The Test Realm"
  42. :username "user"
  43. :password "passwd"
  44. :uri "/digest-auth/auth/user/passwd"
  45. :method "GET"
  46. :expected-ha1 "19c41161a8720edaeb7922ef8531137d"
  47. :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863"
  48. :expected-response "46c47a6d8e1fa95a3efcf49724af3fe7")
  49. (list :nonce "servernonce"
  50. :username "user"
  51. :password "passwd"
  52. :realm "The Test Realm 1"
  53. :uri "/digest-auth/auth/user/passwd"
  54. :method "GET"
  55. :expected-ha1 "00f848f943c9a05dd06c932a7334f120"
  56. :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863"
  57. :expected-response "b8a48cdc9aa9e514509a5a5c53d4e8cf")
  58. (list :nonce "servernonce"
  59. :username "user"
  60. :password "passwd"
  61. :realm "The Test Realm 2"
  62. :uri "/digest-auth/auth/user/passwd"
  63. :method "GET"
  64. :expected-ha1 "74d6abd3651d6b8260733d8a4c37ec1a"
  65. :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863"
  66. :expected-response "0d84884d967e04440efc77e9e2b5b561")))
  67. (ert-deftest url-auth-test-digest-create-key ()
  68. "Check user credentials in their hashed form."
  69. (dolist (challenge url-auth-test-challenges)
  70. (let ((key (url-digest-auth-create-key (plist-get challenge :username)
  71. (plist-get challenge :password)
  72. (plist-get challenge :realm)
  73. (plist-get challenge :method)
  74. (plist-get challenge :uri))))
  75. (should (= (length key) 2))
  76. (should (string= (nth 0 key) (plist-get challenge :expected-ha1)))
  77. (should (string= (nth 1 key) (plist-get challenge :expected-ha2)))
  78. )))
  79. (ert-deftest url-auth-test-digest-auth-retrieve-cache ()
  80. "Check how the entry point retrieves cached authentication.
  81. Essential is how realms and paths are matched."
  82. (let* ((url-digest-auth-storage
  83. '(("example.org:80"
  84. ("/path/auth1" "auth1user" "key")
  85. ("/path" "pathuser" "key")
  86. ("/" "rootuser" "key")
  87. ("realm1" "realm1user" "key")
  88. ("realm2" "realm2user" "key")
  89. ("/path/auth2" "auth2user" "key"))
  90. ("example.org:443"
  91. ("realm" "secure_user" "key"))
  92. ("rootless.org:80" ; no "/" entry for this on purpose
  93. ("/path" "pathuser" "key")
  94. ("realm" "realmuser" "key"))))
  95. (attrs (list (cons "nonce" "servernonce")))
  96. auth)
  97. (dolist (row (list
  98. ;; If :expected-user is `nil' it indicates
  99. ;; authentication information shouldn't be found.
  100. ;; non-existent server
  101. (list :url "http://other.com/path"
  102. :realm nil :expected-user nil)
  103. ;; unmatched port
  104. (list :url "http://example.org:444/path"
  105. :realm nil :expected-user nil)
  106. ;; root, no realm
  107. (list :url "http://example.org/"
  108. :realm nil :expected-user "rootuser")
  109. ;; root, no realm, explicit port
  110. (list :url "http://example.org:80/"
  111. :realm nil :expected-user "rootuser")
  112. (list :url "http://example.org/unknown"
  113. :realm nil :expected-user "rootuser")
  114. ;; realm specified, overrides any path
  115. (list :url "http://example.org/"
  116. :realm "realm1" :expected-user "realm1user")
  117. ;; realm specified, overrides any path
  118. (list :url "http://example.org/"
  119. :realm "realm2" :expected-user "realm2user")
  120. ;; authentication determined by path
  121. (list :url "http://example.org/path/auth1/query"
  122. :realm nil :expected-user "auth1user")
  123. ;; /path shadows /path/auth2, hence pathuser is expected
  124. (list :url "http://example.org/path/auth2/query"
  125. :realm nil :expected-user "pathuser")
  126. (list :url "https://example.org/path"
  127. :realm nil :expected-user "secure_user")
  128. ;; not really secure user but using the same port
  129. (list :url "http://example.org:443/path"
  130. :realm nil :expected-user "secure_user")
  131. ;; preferring realm user over path, even though no
  132. ;; realm specified (not sure why)
  133. (list :url "http://rootless.org/"
  134. :realm nil :expected-user "realmuser")
  135. ;; second variant for the same case
  136. (list :url "http://rootless.org/unknown/path"
  137. :realm nil :expected-user "realmuser")
  138. ;; path match
  139. (list :url "http://rootless.org/path/query?q=a"
  140. :realm nil :expected-user "pathuser")
  141. ;; path match, realm match, prefer realm
  142. (list :url "http://rootless.org/path/query?q=a"
  143. :realm "realm" :expected-user "realmuser")
  144. ))
  145. (setq auth (url-digest-auth (plist-get row :url)
  146. nil nil
  147. (plist-get row :realm) attrs))
  148. (if (plist-get row :expected-user)
  149. (progn (should auth)
  150. (should (string-match ".*username=\"\\(.*?\\)\".*" auth))
  151. (should (string= (match-string 1 auth)
  152. (plist-get row :expected-user))))
  153. (should-not auth)))))
  154. (ert-deftest url-auth-test-digest-auth ()
  155. "Check common authorization string contents.
  156. Challenges with qop are not checked for response since a unique
  157. cnonce is used for generating them which is not mocked by the
  158. test and cannot be passed by arguments to `url-digest-auth'."
  159. (dolist (challenge url-auth-test-challenges)
  160. (let* ((attrs (append
  161. (list (cons "nonce" (plist-get challenge :nonce)))
  162. (if (plist-get challenge :qop)
  163. (list (cons "qop" (plist-get challenge :qop))))))
  164. (url (concat "http://example.org" (plist-get challenge :uri)))
  165. url-digest-auth-storage
  166. auth)
  167. ;; Add authentication info to cache so `url-digest-auth' can
  168. ;; complete without prompting minibuffer input.
  169. (setq url-digest-auth-storage
  170. (list
  171. (list "example.org:80"
  172. (cons (or (plist-get challenge :realm) "/")
  173. (cons (plist-get challenge :username)
  174. (url-digest-auth-create-key
  175. (plist-get challenge :username)
  176. (plist-get challenge :password)
  177. (plist-get challenge :realm)
  178. (plist-get challenge :method)
  179. (plist-get challenge :uri)))))))
  180. (setq auth (url-digest-auth (url-generic-parse-url url) nil nil
  181. (plist-get challenge :realm) attrs))
  182. (should auth)
  183. (should (string-prefix-p "Digest " auth))
  184. (should (string-match ".*username=\"\\(.*?\\)\".*" auth))
  185. (should (string= (match-string 1 auth)
  186. (plist-get challenge :username)))
  187. (should (string-match ".*realm=\"\\(.*?\\)\".*" auth))
  188. (should (string= (match-string 1 auth)
  189. (plist-get challenge :realm)))
  190. (if (plist-member challenge :qop)
  191. (progn
  192. ;; We don't know these, just check that they exists.
  193. (should (string-match-p ".*response=\".*?\".*" auth))
  194. ;; url-digest-auth doesn't return these AFAICS.
  195. ;;; (should (string-match-p ".*nc=\".*?\".*" auth))
  196. ;;; (should (string-match-p ".*cnonce=\".*?\".*" auth))
  197. )
  198. (should (string-match ".*response=\"\\(.*?\\)\".*" auth))
  199. (should (string= (match-string 1 auth)
  200. (plist-get challenge :expected-response))))
  201. )))
  202. (ert-deftest url-auth-test-digest-auth-opaque ()
  203. "Check that `opaque' value is added to result when presented by
  204. the server."
  205. (let* ((url-digest-auth-storage
  206. '(("example.org:80" ("/" "user" "key"))))
  207. (attrs (list (cons "nonce" "anynonce")))
  208. auth)
  209. ;; Get authentication info from cache without `opaque'.
  210. (setq auth (url-digest-auth "http://example.org/path" nil nil nil attrs))
  211. (should auth)
  212. (should-not (string-match-p "opaque=" auth))
  213. ;; Add `opaque' to attributes.
  214. (push (cons "opaque" "opaque-value") attrs)
  215. (setq auth (url-digest-auth "http://example.org/path" nil nil nil attrs))
  216. (should auth)
  217. (should (string-match ".*opaque=\"\\(.*?\\)\".*" auth))
  218. (should (string= (match-string 1 auth) "opaque-value"))))
  219. (provide 'url-auth-tests)
  220. ;;; url-auth-tests.el ends here