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