diff options
| author | F. Jason Park | 2024-08-11 21:55:32 -0700 |
|---|---|---|
| committer | F. Jason Park | 2024-09-06 16:02:12 -0700 |
| commit | 80228d1f6eded7a042dfd29c3614b3214934b5c3 (patch) | |
| tree | 9e861a33f1403b71725841d0884edf7cd4be4154 | |
| parent | 6cc87d07dd8aea1d1a1669df51a872adb7ccf9c5 (diff) | |
| download | emacs-80228d1f6eded7a042dfd29c3614b3214934b5c3.tar.gz emacs-80228d1f6eded7a042dfd29c3614b3214934b5c3.zip | |
Fix discrepancies in auth-source-pass vs netrc behavior
The option `auth-source-pass-extra-query-keywords' aims to make its
back end hew as close to the other built-in ones as possible, except
WRT features not yet implemented, such as arbitrary "attribute"
retrieval and new entry creation. This change only concerns behavior
exhibited when the option is enabled.
* lisp/auth-source-pass.el (auth-source-pass--match-parts): Account
for the case in which a query lacks a reference parameter for a
`:port' or `:user' but still requires one or both via the `:require'
keyword. Previously, such a query would fail even when an entry met
this requirement by simply specifying a field with any non-null value
corresponding to the required parameter.
(auth-source-pass--find-match-many): Account for the baseline case
where a matching entry lacks a secret and the user doesn't require
one. Although this function doesn't currently return so-called
"attributes" from the contents of a matching decrypted file, were it
to eventually, this case would no longer be academic.
* test/lisp/auth-source-pass-tests.el
(auth-source-pass-extra-query-keywords--req-noparam-miss-netrc)
(auth-source-pass-extra-query-keywords--req-noparam-miss)
(auth-source-pass-extra-query-keywords--req-param-netrc)
(auth-source-pass-extra-query-keywords--req-param): New tests.
(auth-source-pass-extra-query-keywords--netrc-baseline): New test
asserting behavior of netrc backend when passed a lone `:host' as a
query parameter.
(auth-source-pass-extra-query-keywords--baseline): Reverse expected
outcome to match that of the netrc reference implementation.
(bug#72441)
| -rw-r--r-- | lisp/auth-source-pass.el | 19 | ||||
| -rw-r--r-- | test/lisp/auth-source-pass-tests.el | 54 |
2 files changed, 60 insertions, 13 deletions
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index 03fd1f35811..dd93d414d5e 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el | |||
| @@ -271,11 +271,12 @@ HOSTS can be a string or a list of strings." | |||
| 271 | n))) | 271 | n))) |
| 272 | seen))) | 272 | seen))) |
| 273 | 273 | ||
| 274 | (defun auth-source-pass--match-parts (parts key value require) | 274 | (defun auth-source-pass--match-parts (cache key reference require) |
| 275 | (let ((mv (plist-get parts key))) | 275 | (let ((value (plist-get cache key))) |
| 276 | (if (memq key require) | 276 | (cond ((memq key require) |
| 277 | (and value (equal mv value)) | 277 | (if reference (equal value reference) value)) |
| 278 | (or (not value) (not mv) (equal mv value))))) | 278 | ((and value reference) (equal value reference)) |
| 279 | (t)))) | ||
| 279 | 280 | ||
| 280 | (defun auth-source-pass--find-match-many (hosts users ports require max) | 281 | (defun auth-source-pass--find-match-many (hosts users ports require max) |
| 281 | "Return plists for valid combinations of HOSTS, USERS, PORTS." | 282 | "Return plists for valid combinations of HOSTS, USERS, PORTS." |
| @@ -290,17 +291,17 @@ HOSTS can be a string or a list of strings." | |||
| 290 | (dolist (user (or users (list u))) | 291 | (dolist (user (or users (list u))) |
| 291 | (dolist (port (or ports (list p))) | 292 | (dolist (port (or ports (list p))) |
| 292 | (dolist (e entries) | 293 | (dolist (e entries) |
| 293 | (when-let* | 294 | (when-let |
| 294 | ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed | 295 | ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed |
| 295 | seen e (integerp port)))) | 296 | seen e (integerp port)))) |
| 296 | ((equal host (plist-get m :host))) | 297 | ((equal host (plist-get m :host))) |
| 297 | ((auth-source-pass--match-parts m :port port require)) | 298 | ((auth-source-pass--match-parts m :port port require)) |
| 298 | ((auth-source-pass--match-parts m :user user require)) | 299 | ((auth-source-pass--match-parts m :user user require)) |
| 299 | (parsed (auth-source-pass-parse-entry e)) | ||
| 300 | ;; For now, ignore body-content pairs, if any, | 300 | ;; For now, ignore body-content pairs, if any, |
| 301 | ;; from `auth-source-pass--parse-data'. | 301 | ;; from `auth-source-pass--parse-data'. |
| 302 | (secret (or (auth-source-pass--get-attr 'secret parsed) | 302 | (secret (let ((parsed (auth-source-pass-parse-entry e))) |
| 303 | (not (memq :secret require))))) | 303 | (or (auth-source-pass--get-attr 'secret parsed) |
| 304 | (not (memq :secret require)))))) | ||
| 304 | (push | 305 | (push |
| 305 | `( :host ,host ; prefer user-provided :host over h | 306 | `( :host ,host ; prefer user-provided :host over h |
| 306 | ,@(and-let* ((u (plist-get m :user))) (list :user u)) | 307 | ,@(and-let* ((u (plist-get m :user))) (list :user u)) |
diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index 6455c3393d5..c54936c3f92 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el | |||
| @@ -548,6 +548,44 @@ machine x.com port 42 password b | |||
| 548 | '((:host "x.com" :secret "a") | 548 | '((:host "x.com" :secret "a") |
| 549 | (:host "x.com" :port 42 :secret "b"))))))) | 549 | (:host "x.com" :port 42 :secret "b"))))))) |
| 550 | 550 | ||
| 551 | ;; The query requires a user and doesn't specify a user to match against. | ||
| 552 | ;; The only entry matching the host lacks a user, so the search fails. | ||
| 553 | |||
| 554 | (ert-deftest auth-source-pass-extra-query-keywords--req-noparam-miss-netrc () | ||
| 555 | (ert-with-temp-file netrc-file | ||
| 556 | :text "machine foo password a\n" | ||
| 557 | (let ((auth-sources (list netrc-file)) | ||
| 558 | (auth-source-do-cache nil)) | ||
| 559 | (should-not (auth-source-search :host "foo" :require '(:user) :max 2))))) | ||
| 560 | |||
| 561 | (ert-deftest auth-source-pass-extra-query-keywords--req-noparam-miss () | ||
| 562 | (let ((auth-source-pass-extra-query-keywords t)) | ||
| 563 | (auth-source-pass--with-store '(("foo" (secret . "a"))) | ||
| 564 | (auth-source-pass-enable) | ||
| 565 | (should-not (auth-source-search :host "foo" :require '(:user) :max 2))))) | ||
| 566 | |||
| 567 | ;; The query requires a user but does not provide a reference value to | ||
| 568 | ;; match against. An entry matching the host that specifies a user is | ||
| 569 | ;; selected because any user will do. | ||
| 570 | (ert-deftest auth-source-pass-extra-query-keywords--req-param-netrc () | ||
| 571 | (ert-with-temp-file netrc-file | ||
| 572 | :text "machine foo login bob password a\n" | ||
| 573 | (let* ((auth-sources (list netrc-file)) | ||
| 574 | (auth-source-do-cache nil) | ||
| 575 | (results (auth-source-search :host "foo" :require '(:user)))) | ||
| 576 | (dolist (result results) | ||
| 577 | (setf (plist-get result :secret) (auth-info-password result))) | ||
| 578 | (should (equal results '((:host "foo" :user "bob" :secret "a"))))))) | ||
| 579 | |||
| 580 | (ert-deftest auth-source-pass-extra-query-keywords--req-param () | ||
| 581 | (let ((auth-source-pass-extra-query-keywords t)) | ||
| 582 | (auth-source-pass--with-store '(("foo/bob" (secret . "a"))) | ||
| 583 | (auth-source-pass-enable) | ||
| 584 | (let ((results (auth-source-search :host "foo" :require '(:user)))) | ||
| 585 | (dolist (result results) | ||
| 586 | (setf (plist-get result :secret) (auth-info-password result))) | ||
| 587 | (should (equal results '((:host "foo" :user "bob" :secret "a")))))))) | ||
| 588 | |||
| 551 | ;; No entry has the requested port, but :port is required, so search fails. | 589 | ;; No entry has the requested port, but :port is required, so search fails. |
| 552 | 590 | ||
| 553 | (ert-deftest auth-source-pass-extra-query-keywords--wild-port-req-miss-netrc () | 591 | (ert-deftest auth-source-pass-extra-query-keywords--wild-port-req-miss-netrc () |
| @@ -629,14 +667,22 @@ machine Libera.Chat password b | |||
| 629 | '((:host "Libera.Chat" :secret "b"))))))) | 667 | '((:host "Libera.Chat" :secret "b"))))))) |
| 630 | 668 | ||
| 631 | 669 | ||
| 632 | ;; A retrieved store entry mustn't be nil regardless of whether its | 670 | ;; An effectively empty entry in the store returns nothing but the |
| 633 | ;; path contains port or user components. | 671 | ;; :host field matching the given host parameter. |
| 672 | |||
| 673 | (ert-deftest auth-source-pass-extra-query-keywords--netrc-baseline () | ||
| 674 | (ert-with-temp-file netrc-file | ||
| 675 | :text "machine foo\n" | ||
| 676 | (let* ((auth-sources (list netrc-file)) | ||
| 677 | (auth-source-do-cache nil) | ||
| 678 | (results (auth-source-search :host "foo"))) | ||
| 679 | (should (equal results '((:host "foo"))))))) | ||
| 634 | 680 | ||
| 635 | (ert-deftest auth-source-pass-extra-query-keywords--baseline () | 681 | (ert-deftest auth-source-pass-extra-query-keywords--baseline () |
| 636 | (let ((auth-source-pass-extra-query-keywords t)) | 682 | (let ((auth-source-pass-extra-query-keywords t)) |
| 637 | (auth-source-pass--with-store '(("x.com")) | 683 | (auth-source-pass--with-store '(("foo")) |
| 638 | (auth-source-pass-enable) | 684 | (auth-source-pass-enable) |
| 639 | (should-not (auth-source-search :host "x.com"))))) | 685 | (should (equal (auth-source-search :host "foo") '((:host "foo"))))))) |
| 640 | 686 | ||
| 641 | ;; Output port type (int or string) matches that of input parameter. | 687 | ;; Output port type (int or string) matches that of input parameter. |
| 642 | 688 | ||