diff options
| author | Jarno Malmari | 2017-04-01 09:19:46 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2017-04-01 09:19:46 +0300 |
| commit | 5b264d88792fec2a31a48c0de5ffe396c3c14604 (patch) | |
| tree | ec7ddb582bdcca9e795cc803046c35207b6e254e | |
| parent | 226cafd24df9c233f6359c93273d4da22db7f62d (diff) | |
| download | emacs-5b264d88792fec2a31a48c0de5ffe396c3c14604.tar.gz emacs-5b264d88792fec2a31a48c0de5ffe396c3c14604.zip | |
Initial implementation of HTTP Digest qop for url
This also refactors digest authentication functions in url-auth.el.
* lisp/url/url-auth.el (url-digest-auth, url-digest-auth-create-key):
(url-digest-auth-build-response, url-digest-auth-directory-id-assoc):
(url-digest-auth-name-value-string, url-digest-auth-source-creds):
(url-digest-cached-key, url-digest-cache-key, url-digest-find-creds):
(url-digest-find-new-key, url-digest-prompt-creds): Add new functions
to simplify code and aid in unit testing.
(url-digest-auth-build-response): Hook up new functionality, or fall
back to previous.
(url-digest-auth-make-request-digest-qop):
(url-digest-auth-make-cnonce, url-digest-auth-nonce-count):
(url-digest-auth-name-value-string): Add new helper functions.
* test/lisp/url/url-auth-tests.el (url-auth-test-colonjoin):
(url-auth-test-digest-ha1, url-auth-test-digest-ha2):
(url-auth-test-digest-request-digest): Add a few tests as now more
features are testable via intermediate functions.
(url-auth-test-challenges, url-auth-test-digest-request-digest): Test
the new implementation. Parts of these were accidentally already
merged in the past.
| -rw-r--r-- | lisp/url/url-auth.el | 403 | ||||
| -rw-r--r-- | test/lisp/url/url-auth-tests.el | 51 |
2 files changed, 347 insertions, 107 deletions
diff --git a/lisp/url/url-auth.el b/lisp/url/url-auth.el index 7b6cdd53790..2885d4e12e2 100644 --- a/lisp/url/url-auth.el +++ b/lisp/url/url-auth.el | |||
| @@ -131,8 +131,8 @@ instead of the filename inheritance method." | |||
| 131 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 131 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 132 | ;;; Digest authorization code | 132 | ;;; Digest authorization code |
| 133 | ;;; ------------------------ | 133 | ;;; ------------------------ |
| 134 | ;;; This implements the DIGEST authorization type. See the internet draft | 134 | ;;; This implements the DIGEST authorization type. See RFC 2617 |
| 135 | ;;; ftp://ds.internic.net/internet-drafts/draft-ietf-http-digest-aa-01.txt | 135 | ;;; https://www.ietf.org/rfc/rfc2617.txt |
| 136 | ;;; for the complete documentation on this type. | 136 | ;;; for the complete documentation on this type. |
| 137 | ;;; | 137 | ;;; |
| 138 | ;;; This is very secure | 138 | ;;; This is very secure |
| @@ -143,107 +143,306 @@ Its value is an assoc list of assoc lists. The first assoc list is | |||
| 143 | keyed by the server name. The cdr of this is an assoc list based | 143 | keyed by the server name. The cdr of this is an assoc list based |
| 144 | on the \"directory\" specified by the url we are looking up.") | 144 | on the \"directory\" specified by the url we are looking up.") |
| 145 | 145 | ||
| 146 | (defsubst url-digest-auth-colonjoin (&rest args) | ||
| 147 | "Concatenate ARGS as strings with colon as a separator." | ||
| 148 | (mapconcat 'identity args ":")) | ||
| 149 | |||
| 150 | (defsubst url-digest-auth-kd (data secret) | ||
| 151 | "Apply digest algorithm to DATA using SECRET and return the result." | ||
| 152 | (md5 (url-digest-auth-colonjoin secret data))) | ||
| 153 | |||
| 154 | (defsubst url-digest-auth-make-ha1 (user realm password) | ||
| 155 | "Compute checksum out of strings USER, REALM, and PASSWORD." | ||
| 156 | (md5 (url-digest-auth-colonjoin user realm password))) | ||
| 157 | |||
| 158 | (defsubst url-digest-auth-make-ha2 (method digest-uri) | ||
| 159 | "Compute checksum out of strings METHOD and DIGEST-URI." | ||
| 160 | (md5 (url-digest-auth-colonjoin method digest-uri))) | ||
| 161 | |||
| 162 | (defsubst url-digest-auth-make-request-digest (ha1 ha2 nonce) | ||
| 163 | "Construct the request-digest from hash strings HA1, HA2, and NONCE. | ||
| 164 | This is the value that server receives as a proof that user knows | ||
| 165 | a password." | ||
| 166 | (url-digest-auth-kd (url-digest-auth-colonjoin nonce ha2) ha1)) | ||
| 167 | |||
| 168 | (defsubst url-digest-auth-make-request-digest-qop (qop ha1 ha2 nonce nc cnonce) | ||
| 169 | "Construct the request-digest with qop. | ||
| 170 | QOP describes the \"quality of protection\" and algorithm to use. | ||
| 171 | All of the strings QOP, HA1, HA2, NONCE, NC, and CNONCE are | ||
| 172 | combined into a single hash value that proves to a server the | ||
| 173 | user knows a password. It's worth noting that HA2 already | ||
| 174 | depends on value of QOP." | ||
| 175 | (url-digest-auth-kd (url-digest-auth-colonjoin | ||
| 176 | nonce nc cnonce qop ha2) ha1)) | ||
| 177 | |||
| 178 | (defsubst url-digest-auth-directory-id (url realm) | ||
| 179 | "Make an identifier for selecting a key in key cache. | ||
| 180 | The identifier is made either from URL or REALM. It represents a | ||
| 181 | protection space within a server so that one server can have | ||
| 182 | multiple authorizations." | ||
| 183 | (or realm (or (url-file-directory (url-filename url)) "/"))) | ||
| 184 | |||
| 185 | (defsubst url-digest-auth-server-id (url) | ||
| 186 | "Make an identifier for selecting a server in key cache. | ||
| 187 | The identifier is made from URL's host and port. Together with | ||
| 188 | `url-digest-auth-directory-id' these identify a single key in the | ||
| 189 | key cache `url-digest-auth-storage'." | ||
| 190 | (format "%s:%d" (url-host url) (url-port url))) | ||
| 191 | |||
| 192 | (defun url-digest-auth-make-cnonce () | ||
| 193 | "Compute a new unique client nonce value." | ||
| 194 | (base64-encode-string | ||
| 195 | (apply 'format "%016x%04x%04x%05x%05x" (random) (current-time)) t)) | ||
| 196 | |||
| 197 | (defun url-digest-auth-nonce-count (nonce) | ||
| 198 | "The number requests sent to server with the given NONCE. | ||
| 199 | This count includes the request we're preparing here. | ||
| 200 | |||
| 201 | Currently, this is not implemented and will always return 1. | ||
| 202 | |||
| 203 | Value returned is in string format with leading zeroes, such as | ||
| 204 | \"00000001\"." | ||
| 205 | (format "%08x" 1)) | ||
| 206 | |||
| 207 | (defun url-digest-auth-name-value-string (pairs) | ||
| 208 | "Concatenate name-value pairs in association list PAIRS. | ||
| 209 | |||
| 210 | Output is formatted as \"name1=\\\"value1\\\", name2=\\\"value2\\\", ...\"" | ||
| 211 | (mapconcat (lambda (pair) | ||
| 212 | (format "%s=\"%s\"" | ||
| 213 | (symbol-name (car pair)) | ||
| 214 | (cdr pair))) | ||
| 215 | pairs ", ")) | ||
| 216 | |||
| 217 | (defun url-digest-auth-source-creds (url) | ||
| 218 | "Find credentials for URL object from the Emacs auth-source. | ||
| 219 | Return value is a plist that has `:user' and `:secret' properties | ||
| 220 | if credentials were found. Otherwise nil." | ||
| 221 | (let ((server (url-digest-auth-server-id url)) | ||
| 222 | (type (url-type url))) | ||
| 223 | (list :user (url-do-auth-source-search server type :user) | ||
| 224 | :secret (url-do-auth-source-search server type :secret)))) | ||
| 225 | |||
| 226 | (defun url-digest-prompt-creds (url realm &optional creds) | ||
| 227 | "Prompt credentials for URL and REALM, defaulting to CREDS. | ||
| 228 | CREDS is a plist that may have properties `:user' and `:secret'." | ||
| 229 | ;; Set explicitly in case creds were nil. This makes the second | ||
| 230 | ;; plist-put modify the same plist. | ||
| 231 | (setq creds | ||
| 232 | (plist-put creds :user | ||
| 233 | (read-string (url-auth-user-prompt url realm) | ||
| 234 | (or (plist-get creds :user) | ||
| 235 | (user-real-login-name))))) | ||
| 236 | (plist-put creds :secret | ||
| 237 | (read-passwd "Password: " nil (plist-get creds :secret)))) | ||
| 238 | |||
| 239 | (defun url-digest-auth-directory-id-assoc (dirkey keylist) | ||
| 240 | "Find the best match for DIRKEY in key alist KEYLIST. | ||
| 241 | |||
| 242 | The string DIRKEY should be obtained using | ||
| 243 | `url-digest-auth-directory-id'. The key list to search through | ||
| 244 | is the alist KEYLIST where car of each element may match DIRKEY. | ||
| 245 | If DIRKEY represents a realm, the list is searched only for an | ||
| 246 | exact match. For directory names, an ancestor is sufficient for | ||
| 247 | a match." | ||
| 248 | (or | ||
| 249 | ;; Check exact match first. | ||
| 250 | (assoc dirkey keylist) | ||
| 251 | ;; No exact match found. Continue to look for partial match if | ||
| 252 | ;; dirkey is not a realm. | ||
| 253 | (and (string-match "/" dirkey) | ||
| 254 | (let (match) | ||
| 255 | (while (and (null match) keylist) | ||
| 256 | (if (or | ||
| 257 | ;; Any realm candidate matches. Why? | ||
| 258 | (not (string-match "/" (caar keylist))) | ||
| 259 | ;; Parent directory matches. | ||
| 260 | (string-prefix-p (caar keylist) dirkey)) | ||
| 261 | (setq match (car keylist)) | ||
| 262 | (setq keylist (cdr keylist)))) | ||
| 263 | match)))) | ||
| 264 | |||
| 265 | (defun url-digest-cached-key (url realm) | ||
| 266 | "Find best match for URL and REALM from `url-digest-auth-storage'. | ||
| 267 | The return value is a list consisting of a realm (or a directory) | ||
| 268 | a user name, and hashed authentication tokens HA1 and HA2. | ||
| 269 | Modifying the contents of the returned list will modify the cache | ||
| 270 | variable `url-digest-auth-storage' itself." | ||
| 271 | (url-digest-auth-directory-id-assoc | ||
| 272 | (url-digest-auth-directory-id url realm) | ||
| 273 | (cdr (assoc (url-digest-auth-server-id url) url-digest-auth-storage)))) | ||
| 274 | |||
| 275 | (defun url-digest-cache-key (key url) | ||
| 276 | "Add key to `url-digest-auth-storage'. | ||
| 277 | KEY has the same format as returned by `url-digest-cached-key'. | ||
| 278 | The key is added to cache hierarchy under server id, deduced from | ||
| 279 | URL." | ||
| 280 | (let ((serverid (url-digest-auth-server-id url))) | ||
| 281 | (push (list serverid key) url-digest-auth-storage))) | ||
| 282 | |||
| 146 | (defun url-digest-auth-create-key (username password realm method uri) | 283 | (defun url-digest-auth-create-key (username password realm method uri) |
| 147 | "Create a key for digest authentication method" | 284 | "Create a key for digest authentication method. |
| 148 | (let* ((info (if (stringp uri) | 285 | The USERNAME and PASSWORD are the credentials for REALM and are |
| 149 | (url-generic-parse-url uri) | 286 | used in making a hashed value named HA1. The HTTP METHOD and URI |
| 150 | uri)) | 287 | makes a second hashed value HA2. These hashes are used in making |
| 151 | (a1 (md5 (concat username ":" realm ":" password))) | 288 | the authentication key that can be stored without saving the |
| 152 | (a2 (md5 (concat method ":" (url-filename info))))) | 289 | password in plain text. The return value is a list (HA1 HA2). |
| 153 | (list a1 a2))) | 290 | |
| 154 | 291 | For backward compatibility, URI is allowed to be a URL cl-struct | |
| 155 | (defun url-digest-auth (url &optional prompt overwrite realm args) | 292 | object." |
| 156 | "Get the username/password for the specified URL. | 293 | (and username password realm |
| 157 | If optional argument PROMPT is non-nil, ask for the username/password | 294 | (list (url-digest-auth-make-ha1 username realm password) |
| 158 | to use for the URL and its descendants. If optional third argument | 295 | (url-digest-auth-make-ha2 method (cond ((stringp uri) uri) |
| 159 | OVERWRITE is non-nil, overwrite the old username/password pair if it | 296 | (t (url-filename uri))))))) |
| 160 | is found in the assoc list. If REALM is specified, use that as the realm | 297 | |
| 161 | instead of hostname:portnum." | 298 | (defun url-digest-auth-build-response (key url realm attrs) |
| 162 | (if args | 299 | "Compute authorization string for the given challenge using KEY. |
| 163 | (let* ((href (if (stringp url) | 300 | |
| 164 | (url-generic-parse-url url) | 301 | The string looks like 'Digest username=\"John\", realm=\"The |
| 165 | url)) | 302 | Realm\", ...' |
| 166 | (server (url-host href)) | 303 | |
| 167 | (type (url-type href)) | 304 | Part of the challenge is already solved in a pre-computed KEY |
| 168 | (port (url-port href)) | 305 | which is list of a realm (or a directory), user name, and hash |
| 169 | (file (url-filename href)) | 306 | tokens HA1 and HA2. |
| 170 | (enable-recursive-minibuffers t) | 307 | |
| 171 | user pass byserv retval data) | 308 | Some fields are filled as is from the given URL, REALM, and |
| 172 | (setq file (cond | 309 | using the contents of alist ATTRS. |
| 173 | (realm realm) | 310 | |
| 174 | ((string-match "/$" file) file) | 311 | ATTRS is expected to contain at least the server's \"nonce\" |
| 175 | (t (url-file-directory file))) | 312 | value. It also might contain the optional \"opaque\" value. |
| 176 | server (format "%s:%d" server port) | 313 | Newer implementations conforming to RFC 2617 should also contain |
| 177 | byserv (cdr-safe (assoc server url-digest-auth-storage))) | 314 | qop (Quality Of Protection) and related attributes. |
| 178 | (cond | 315 | |
| 179 | ((and prompt (not byserv)) | 316 | Restrictions on Quality of Protection scheme: The qop value |
| 180 | (setq user (or | 317 | \"auth-int\" or algorithm any other than \"MD5\" are not |
| 181 | (url-do-auth-source-search server type :user) | 318 | implemented." |
| 182 | (read-string (url-auth-user-prompt url realm) | 319 | |
| 183 | (user-real-login-name))) | 320 | (when key |
| 184 | pass (or | 321 | (let ((user (nth 1 key)) |
| 185 | (url-do-auth-source-search server type :secret) | 322 | (ha1 (nth 2 key)) |
| 186 | (read-passwd "Password: ")) | 323 | (ha2 (nth 3 key)) |
| 187 | url-digest-auth-storage | 324 | (digest-uri (url-filename url)) |
| 188 | (cons (list server | 325 | (qop (cdr-safe (assoc "qop" attrs))) |
| 189 | (cons file | 326 | (nonce (cdr-safe (assoc "nonce" attrs))) |
| 190 | (setq retval | 327 | (opaque (cdr-safe (assoc "opaque" attrs)))) |
| 191 | (cons user | 328 | |
| 192 | (url-digest-auth-create-key | 329 | (concat |
| 193 | user pass realm | 330 | "Digest " |
| 194 | (or url-request-method "GET") | 331 | (url-digest-auth-name-value-string |
| 195 | url))))) | 332 | (append (list (cons 'username user) |
| 196 | url-digest-auth-storage))) | 333 | (cons 'realm realm) |
| 197 | (byserv | 334 | (cons 'nonce nonce) |
| 198 | (setq retval (cdr-safe (assoc file byserv))) | 335 | (cons 'uri digest-uri)) |
| 199 | (if (and (not retval) ; no exact match, check directories | 336 | |
| 200 | (string-match "/" file)) ; not looking for a realm | 337 | (cond |
| 201 | (while (and byserv (not retval)) | 338 | ((null qop) |
| 202 | (setq data (car (car byserv))) | 339 | (list (cons 'response (url-digest-auth-make-request-digest |
| 203 | (if (or (not (string-match "/" data)) | 340 | ha1 ha2 nonce)))) |
| 204 | (and | 341 | ((string= qop "auth") |
| 205 | (>= (length file) (length data)) | 342 | (let ((nc (url-digest-auth-nonce-count nonce)) |
| 206 | (string= data (substring file 0 (length data))))) | 343 | (cnonce (url-digest-auth-make-cnonce))) |
| 207 | (setq retval (cdr (car byserv)))) | 344 | (list (cons 'qop qop) |
| 208 | (setq byserv (cdr byserv)))) | 345 | (cons 'nc nc) |
| 209 | (if overwrite | 346 | (cons 'cnonce cnonce) |
| 210 | (if (and (not retval) prompt) | 347 | (cons 'response |
| 211 | (setq user (or | 348 | (url-digest-auth-make-request-digest-qop |
| 212 | (url-do-auth-source-search server type :user) | 349 | qop ha1 ha2 nonce nc cnonce))))) |
| 213 | (read-string (url-auth-user-prompt url realm) | 350 | (t (message "Quality of protection \"%s\" is not implemented." qop) |
| 214 | (user-real-login-name))) | 351 | nil)) |
| 215 | pass (or | 352 | |
| 216 | (url-do-auth-source-search server type :secret) | 353 | |
| 217 | (read-passwd "Password: ")) | 354 | (if opaque (list (cons 'opaque opaque))))))))) |
| 218 | retval (setq retval | 355 | |
| 219 | (cons user | 356 | (defun url-digest-find-creds (url prompt &optional realm) |
| 220 | (url-digest-auth-create-key | 357 | "Find or ask credentials for URL. |
| 221 | user pass realm | 358 | |
| 222 | (or url-request-method "GET") | 359 | Primary method for finding credentials is from Emacs auth-source. |
| 223 | url))) | 360 | If password isn't found, and PROMPT is non-nil, query credentials |
| 224 | byserv (assoc server url-digest-auth-storage)) | 361 | via minibuffer. Optional REALM may be used when prompting as a |
| 225 | (setcdr byserv | 362 | hint to the user. |
| 226 | (cons (cons file retval) (cdr byserv)))))) | 363 | |
| 227 | (t (setq retval nil))) | 364 | Return value is nil in case either user name or password wasn't |
| 228 | (if retval | 365 | found. Otherwise, it's a plist containing `:user' and `:secret'. |
| 229 | (if (cdr-safe (assoc "opaque" args)) | 366 | Additional `:source' property denotes the origin of the |
| 230 | (let ((nonce (or (cdr-safe (assoc "nonce" args)) "nonegiven")) | 367 | credentials and its value can be either symbol `authsource' or |
| 231 | (opaque (cdr-safe (assoc "opaque" args)))) | 368 | `interactive'." |
| 232 | (format | 369 | (let ((creds (url-digest-auth-source-creds url))) |
| 233 | (concat "Digest username=\"%s\", realm=\"%s\"," | 370 | |
| 234 | "nonce=\"%s\", uri=\"%s\"," | 371 | ;; If credentials weren't found and prompting is allowed, prompt |
| 235 | "response=\"%s\", opaque=\"%s\"") | 372 | ;; the user. |
| 236 | (nth 0 retval) realm nonce (url-filename href) | 373 | (if (and prompt |
| 237 | (md5 (concat (nth 1 retval) ":" nonce ":" | 374 | (or (null creds) |
| 238 | (nth 2 retval))) opaque)) | 375 | (null (plist-get creds :secret)))) |
| 239 | (let ((nonce (or (cdr-safe (assoc "nonce" args)) "nonegiven"))) | 376 | (progn |
| 240 | (format | 377 | (setq creds (url-digest-prompt-creds url realm creds)) |
| 241 | (concat "Digest username=\"%s\", realm=\"%s\"," | 378 | (plist-put creds :source 'interactive)) |
| 242 | "nonce=\"%s\", uri=\"%s\"," | 379 | (plist-put creds :source 'authsource)) |
| 243 | "response=\"%s\"") | 380 | |
| 244 | (nth 0 retval) realm nonce (url-filename href) | 381 | (and (plist-get creds :user) |
| 245 | (md5 (concat (nth 1 retval) ":" nonce ":" | 382 | (plist-get creds :secret) |
| 246 | (nth 2 retval)))))))))) | 383 | creds))) |
| 384 | |||
| 385 | (defun url-digest-find-new-key (url realm prompt) | ||
| 386 | "Find credentials and create a new authorization key for given URL and REALM. | ||
| 387 | |||
| 388 | Return value is the new key, or nil if credentials weren't found. | ||
| 389 | \"New\" in this context means a key that's not yet found in cache | ||
| 390 | variable `url-digest-auth-storage'. You may use `url-digest-cache-key' | ||
| 391 | to put it there. | ||
| 392 | |||
| 393 | This function uses `url-digest-find-creds' to find the | ||
| 394 | credentials. It first looks in auth-source. If not found, and | ||
| 395 | PROMPT is non-nil, user is asked for credentials interactively | ||
| 396 | via minibuffer." | ||
| 397 | (let (creds) | ||
| 398 | (unwind-protect | ||
| 399 | (if (setq creds (url-digest-find-creds url prompt realm)) | ||
| 400 | (cons (url-digest-auth-directory-id url realm) | ||
| 401 | (cons (plist-get creds :user) | ||
| 402 | (url-digest-auth-create-key | ||
| 403 | (plist-get creds :user) | ||
| 404 | (plist-get creds :secret) | ||
| 405 | realm | ||
| 406 | (or url-request-method "GET") | ||
| 407 | (url-filename url))))) | ||
| 408 | (if (and creds | ||
| 409 | ;; Don't clear secret for `authsource' since it will | ||
| 410 | ;; corrupt any future fetches for it. | ||
| 411 | (not (eq (plist-get creds :source) 'authsource))) | ||
| 412 | (clear-string (plist-get creds :secret)))))) | ||
| 413 | |||
| 414 | (defun url-digest-auth (url &optional prompt overwrite realm attrs) | ||
| 415 | "Get the HTTP Digest response string for the specified URL. | ||
| 416 | |||
| 417 | If optional argument PROMPT is non-nil, ask for the username and | ||
| 418 | password to use for the URL and its descendants but only if one | ||
| 419 | cannot be found from cache. Look also in Emacs auth-source. | ||
| 420 | |||
| 421 | If optional third argument OVERWRITE is non-nil, overwrite the | ||
| 422 | old credentials, if they're found in cache, with new ones from | ||
| 423 | user prompt or from Emacs auth-source. | ||
| 424 | |||
| 425 | If REALM is specified, use that instead of the URL descendant | ||
| 426 | method to match cached credentials. | ||
| 427 | |||
| 428 | Alist ATTRS contains additional attributes for the authentication | ||
| 429 | challenge such as nonce and opaque." | ||
| 430 | (if attrs | ||
| 431 | (let* ((href (if (stringp url) (url-generic-parse-url url) url)) | ||
| 432 | (enable-recursive-minibuffers t) | ||
| 433 | (key (url-digest-cached-key href realm))) | ||
| 434 | |||
| 435 | (if (or (null key) overwrite) | ||
| 436 | (let ((newkey (url-digest-find-new-key href realm (cond | ||
| 437 | (key nil) | ||
| 438 | (t prompt))))) | ||
| 439 | (if (and newkey key overwrite) | ||
| 440 | (setcdr key (cdr newkey)) | ||
| 441 | (if (and newkey (null key)) | ||
| 442 | (url-digest-cache-key (setq key newkey) href))))) | ||
| 443 | |||
| 444 | (if key | ||
| 445 | (url-digest-auth-build-response key href realm attrs))))) | ||
| 247 | 446 | ||
| 248 | (defvar url-registered-auth-schemes nil | 447 | (defvar url-registered-auth-schemes nil |
| 249 | "A list of the registered authorization schemes and various and sundry | 448 | "A list of the registered authorization schemes and various and sundry |
diff --git a/test/lisp/url/url-auth-tests.el b/test/lisp/url/url-auth-tests.el index 11e5a479720..30636db083c 100644 --- a/test/lisp/url/url-auth-tests.el +++ b/test/lisp/url/url-auth-tests.el | |||
| @@ -77,6 +77,49 @@ server's WWW-Authenticate header field.") | |||
| 77 | :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863" | 77 | :expected-ha2 "b44272ea65ee4af7fb26c5dba58f6863" |
| 78 | :expected-response "0d84884d967e04440efc77e9e2b5b561"))) | 78 | :expected-response "0d84884d967e04440efc77e9e2b5b561"))) |
| 79 | 79 | ||
| 80 | (ert-deftest url-auth-test-colonjoin () | ||
| 81 | "Check joining strings with `:'." | ||
| 82 | (should (string= (url-digest-auth-colonjoin) "")) | ||
| 83 | (should (string= (url-digest-auth-colonjoin nil) "")) | ||
| 84 | (should (string= (url-digest-auth-colonjoin nil nil nil) "::")) | ||
| 85 | (should (string= (url-digest-auth-colonjoin "") "")) | ||
| 86 | (should (string= (url-digest-auth-colonjoin "" "") ":")) | ||
| 87 | (should (string= (url-digest-auth-colonjoin "one") "one")) | ||
| 88 | (should (string= (url-digest-auth-colonjoin "one" "two" "three") "one:two:three"))) | ||
| 89 | |||
| 90 | (ert-deftest url-auth-test-digest-ha1 () | ||
| 91 | "Check HA1 computation." | ||
| 92 | (dolist (row url-auth-test-challenges) | ||
| 93 | (should (string= (url-digest-auth-make-ha1 (plist-get row :username) | ||
| 94 | (plist-get row :realm) | ||
| 95 | (plist-get row :password)) | ||
| 96 | (plist-get row :expected-ha1) | ||
| 97 | )))) | ||
| 98 | |||
| 99 | (ert-deftest url-auth-test-digest-ha2 () | ||
| 100 | "Check HA2 computation." | ||
| 101 | (dolist (row url-auth-test-challenges) | ||
| 102 | (should (string= (url-digest-auth-make-ha2 (plist-get row :method) | ||
| 103 | (plist-get row :uri)) | ||
| 104 | (plist-get row :expected-ha2))))) | ||
| 105 | |||
| 106 | (ert-deftest url-auth-test-digest-request-digest () | ||
| 107 | "Check digest response value." | ||
| 108 | (dolist (row url-auth-test-challenges) | ||
| 109 | (should (string= (plist-get row :expected-response) | ||
| 110 | (if (plist-member row :qop) | ||
| 111 | (url-digest-auth-make-request-digest-qop | ||
| 112 | (plist-get row :qop) | ||
| 113 | (plist-get row :expected-ha1) | ||
| 114 | (plist-get row :expected-ha2) | ||
| 115 | (plist-get row :nonce) | ||
| 116 | (plist-get row :nc) | ||
| 117 | (plist-get row :cnonce)) | ||
| 118 | (url-digest-auth-make-request-digest | ||
| 119 | (plist-get row :expected-ha1) | ||
| 120 | (plist-get row :expected-ha2) | ||
| 121 | (plist-get row :nonce))))))) | ||
| 122 | |||
| 80 | (ert-deftest url-auth-test-digest-create-key () | 123 | (ert-deftest url-auth-test-digest-create-key () |
| 81 | "Check user credentials in their hashed form." | 124 | "Check user credentials in their hashed form." |
| 82 | (dolist (challenge url-auth-test-challenges) | 125 | (dolist (challenge url-auth-test-challenges) |
| @@ -223,14 +266,12 @@ test and cannot be passed by arguments to `url-digest-auth'." | |||
| 223 | (progn | 266 | (progn |
| 224 | ;; We don't know these, just check that they exists. | 267 | ;; We don't know these, just check that they exists. |
| 225 | (should (string-match-p ".*response=\".*?\".*" auth)) | 268 | (should (string-match-p ".*response=\".*?\".*" auth)) |
| 226 | ;; url-digest-auth doesn't return these AFAICS. | 269 | (should (string-match-p ".*nc=\".*?\".*" auth)) |
| 227 | ;;; (should (string-match-p ".*nc=\".*?\".*" auth)) | 270 | (should (string-match-p ".*cnonce=\".*?\".*" auth))) |
| 228 | ;;; (should (string-match-p ".*cnonce=\".*?\".*" auth)) | ||
| 229 | ) | ||
| 230 | (should (string-match ".*response=\"\\(.*?\\)\".*" auth)) | 271 | (should (string-match ".*response=\"\\(.*?\\)\".*" auth)) |
| 231 | (should (string= (match-string 1 auth) | 272 | (should (string= (match-string 1 auth) |
| 232 | (plist-get challenge :expected-response)))) | 273 | (plist-get challenge :expected-response)))) |
| 233 | ))) | 274 | ))) |
| 234 | 275 | ||
| 235 | (ert-deftest url-auth-test-digest-auth-opaque () | 276 | (ert-deftest url-auth-test-digest-auth-opaque () |
| 236 | "Check that `opaque' value is added to result when presented by | 277 | "Check that `opaque' value is added to result when presented by |