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