emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 0ecc10a 2/2: Let Tramp save passwords


From: Michael Albinus
Subject: [Emacs-diffs] master 0ecc10a 2/2: Let Tramp save passwords
Date: Mon, 23 Apr 2018 04:16:52 -0400 (EDT)

branch: master
commit 0ecc10a7771bf1f62d15b2e6c747bee9f7a557ff
Author: Michael Albinus <address@hidden>
Commit: Michael Albinus <address@hidden>

    Let Tramp save passwords
    
    * lisp/auth-source.el (auth-source-secrets-saver): New defun.
    (auth-source-secrets-create): Use it.
    
    * lisp/net/secrets.el (secrets-struct-secret-content-type):
    (secrets-create-item): Do not hard-code :xdg:schema.
    
    * lisp/net/tramp.el (tramp-password-save-function): New defvar.
    (tramp-read-passwd): Set it properly.
    (tramp-process-actions):
    * lisp/net/tramp-gvfs.el (tramp-gvfs-maybe-open-connection):
    Save password.
    
    * lisp/net/tramp-cmds.el (tramp-bug): Don't report
    `tramp-password-save-function'.
    
    * test/lisp/net/secrets-tests.el (secrets-test03-items):
    Extend test with another :xdg:schema.
---
 lisp/auth-source.el            | 37 ++++++++++++++++++++++++++++++-
 lisp/net/secrets.el            | 21 +++++++++++++-----
 lisp/net/tramp-cmds.el         |  4 +++-
 lisp/net/tramp-gvfs.el         |  3 +++
 lisp/net/tramp.el              | 50 ++++++++++++++++++++++++++++--------------
 test/lisp/net/secrets-tests.el | 15 ++++++++++---
 6 files changed, 102 insertions(+), 28 deletions(-)

diff --git a/lisp/auth-source.el b/lisp/auth-source.el
index a2ed47a..df3622a 100644
--- a/lisp/auth-source.el
+++ b/lisp/auth-source.el
@@ -1732,10 +1732,45 @@ authentication tokens:
             (item (plist-get artificial :label))
             (secret (plist-get artificial :secret))
             (secret (if (functionp secret) (funcall secret) secret)))
-       (lambda () (apply 'secrets-create-item collection item secret args))))
+       (lambda ()
+        (apply 'auth-source-secrets-saver collection item secret args))))
 
     (list artificial)))
 
+(defun auth-source-secrets-saver (collection item secret args)
+  "Wrapper around `secrets-create-item', prompting along the way.
+Respects `auth-source-save-behavior'."
+  (let ((prompt (format "Save auth info to secrets collection %s? " 
collection))
+        (done (not (eq auth-source-save-behavior 'ask)))
+        (bufname "*auth-source Help*")
+        doit k)
+    (while (not done)
+      (setq k (auth-source-read-char-choice prompt '(?y ?n ?N ??)))
+      (cl-case k
+        (?y (setq done t doit t))
+        (?? (save-excursion
+              (with-output-to-temp-buffer bufname
+                (princ
+                 (concat "(y)es, save\n"
+                         "(n)o but use the info\n"
+                         "(N)o and don't ask to save again\n"
+                         "(?) for help as you can see.\n"))
+                ;; Why?  Doesn't with-output-to-temp-buffer already do
+                ;; the exact same thing anyway?  --Stef
+                (set-buffer standard-output)
+                (help-mode))))
+        (?n (setq done t doit nil))
+        (?N (setq done t doit nil)
+            (customize-save-variable 'auth-source-save-behavior nil))
+        (t nil)))
+
+    (when doit
+      (progn
+        (auth-source-do-debug
+         "secrets-create-item: wrote 1 new item to %s" collection)
+        (message "Saved new authentication information to %s" collection)
+       (apply 'secrets-create-item collection item secret args)))))
+
 ;;; Backend specific parsing: Mac OS Keychain (using /usr/bin/security) backend
 
 (cl-defun auth-source-macos-keychain-search (&rest spec
diff --git a/lisp/net/secrets.el b/lisp/net/secrets.el
index 8070ccf..f7cc011 100644
--- a/lisp/net/secrets.el
+++ b/lisp/net/secrets.el
@@ -331,9 +331,7 @@ It returns t if not."
             ;; Properties.
             `(:array
               (:dict-entry ,(concat secrets-interface-item ".Label")
-                           (:variant "dummy"))
-              (:dict-entry ,(concat secrets-interface-item ".Type")
-                           (:variant ,secrets-interface-item-type-generic)))
+                           (:variant " ")))
             ;; Secret.
             `(:struct :object-path ,path
                       (:array :signature "y")
@@ -649,11 +647,24 @@ keys are keyword symbols, starting with a colon.  Example:
   (secrets-create-item \"Tramp collection\" \"item\" \"geheim\"
    :method \"sudo\" :user \"joe\" :host \"remote-host\")
 
+The key `:xdg:schema' determines the scope of the item to be
+generated, i.e. for which applications the item is intended for.
+This is just a string like \"org.freedesktop.NetworkManager.Mobile\"
+or \"org.gnome.OnlineAccounts\", the other required keys are
+determined by this.  If no `:xdg:schema' is given,
+\"org.freedesktop.Secret.Generic\" is used by default.
+
 The object path of the created item is returned."
   (unless (member item (secrets-list-items collection))
     (let ((collection-path (secrets-unlock-collection collection))
          result props)
       (unless (secrets-empty-path collection-path)
+        ;; Set default type if needed.
+        (unless (member :xdg:schema attributes)
+          (setq attributes
+                (append
+                 attributes
+                 `(:xdg:schema ,secrets-interface-item-type-generic))))
        ;; Create attributes list.
        (while (consp (cdr attributes))
          (unless (keywordp (car attributes))
@@ -675,9 +686,7 @@ The object path of the created item is returned."
               (append
                `(:array
                  (:dict-entry ,(concat secrets-interface-item ".Label")
-                              (:variant ,item))
-                 (:dict-entry ,(concat secrets-interface-item ".Type")
-                              (:variant ,secrets-interface-item-type-generic)))
+                              (:variant ,item)))
                (when props
                  `((:dict-entry ,(concat secrets-interface-item ".Attributes")
                                 (:variant ,(append '(:array) props))))))
diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el
index cbb9cd3..b05f475 100644
--- a/lisp/net/tramp-cmds.el
+++ b/lisp/net/tramp-cmds.el
@@ -181,7 +181,9 @@ This includes password cache, file cache, connection cache, 
buffers."
   "Submit a bug report to the Tramp developers."
   (interactive)
   (catch 'dont-send
-    (let ((reporter-prompt-for-summary-p t))
+    (let ((reporter-prompt-for-summary-p t)
+         ;; In rare cases, it could contain the password.  So we make it nil.
+         tramp-password-save-function)
       (reporter-submit-bug-report
        tramp-bug-report-address                ; to-address
        (format "tramp (%s)" tramp-version) ; package name and version
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index b3d5339..199ac4f 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -2041,6 +2041,9 @@ connection if a previous connection has died for some 
reason."
               (tramp-get-file-property vec "/" "fuse-mountpoint" "") "/")
          (tramp-error vec 'file-error "FUSE mount denied"))
 
+       ;; Save the password.
+       (ignore-errors (funcall tramp-password-save-function))
+
        ;; Set connection-local variables.
        (tramp-set-connection-local-variables vec)
 
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 5c785b1..c394f28 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -1192,6 +1192,11 @@ means to use always cached values for the directory 
contents."
 (defvar tramp-current-connection nil
   "Last connection timestamp.")
 
+(defvar tramp-password-save-function nil
+  "Password save function.
+Will be called once the password has been verified by successful
+authentication.")
+
 (defconst tramp-completion-file-name-handler-alist
   '((file-name-all-completions
      . tramp-completion-handle-file-name-all-completions)
@@ -3852,7 +3857,9 @@ connection buffer."
        (with-current-buffer (tramp-get-connection-buffer vec)
          (widen)
          (tramp-message vec 6 "\n%s" (buffer-string)))
-       (unless (eq exit 'ok)
+       (if (eq exit 'ok)
+           (ignore-errors (funcall tramp-password-save-function))
+         ;; Not successful.
          (tramp-clear-passwd vec)
          (delete-process proc)
          (tramp-error-with-buffer
@@ -4458,12 +4465,14 @@ Invokes `password-read' if available, `read-passwd' 
else."
              (with-current-buffer (process-buffer proc)
                (tramp-check-for-regexp proc tramp-password-prompt-regexp)
                (format "%s for %s " (capitalize (match-string 1)) key))))
+        (auth-source-creation-prompts `((secret . ,pw-prompt)))
         ;; We suspend the timers while reading the password.
          (stimers (with-timeout-suspend))
         auth-info auth-passwd)
 
     (unwind-protect
        (with-parsed-tramp-file-name key nil
+         (setq tramp-password-save-function nil)
          (setq user
                (or user (tramp-get-connection-property key "login-as" nil)))
          (prog1
@@ -4474,31 +4483,38 @@ Invokes `password-read' if available, `read-passwd' 
else."
                       v "first-password-request" nil)
                      ;; Try with Tramp's current method.
                      (setq auth-info
-                           (auth-source-search
-                            :max 1
-                            (and user :user)
-                            (if domain
-                                (concat user tramp-prefix-domain-format domain)
-                              user)
-                            :host
-                            (if port
-                                (concat host tramp-prefix-port-format port)
-                              host)
-                            :port method
-                            :require (cons :secret (and user '(:user))))
-                           auth-passwd (plist-get
-                                        (nth 0 auth-info) :secret)
+                           (car
+                            (auth-source-search
+                             :max 1
+                             (and user :user)
+                             (if domain
+                                 (concat
+                                  user tramp-prefix-domain-format domain)
+                               user)
+                             :host
+                             (if port
+                                 (concat
+                                  host tramp-prefix-port-format port)
+                               host)
+                             :port method
+                             :require (cons :secret (and user '(:user)))
+                             :create t))
+                           tramp-password-save-function
+                           (plist-get auth-info :save-function)
+                           auth-passwd (plist-get auth-info :secret)
                            auth-passwd (if (functionp auth-passwd)
                                            (funcall auth-passwd)
                                          auth-passwd))))
+
               ;; Try the password cache.
               (let ((password (password-read pw-prompt key)))
-                ;; FIXME test password works before caching it.
-                (password-cache-add key password)
+                (setq tramp-password-save-function
+                      (lambda () (password-cache-add key password)))
                 password)
               ;; Else, get the password interactively.
               (read-passwd pw-prompt))
            (tramp-set-connection-property v "first-password-request" nil)))
+
       ;; Reenable the timers.
       (with-timeout-unsuspend stimers))))
 
diff --git a/test/lisp/net/secrets-tests.el b/test/lisp/net/secrets-tests.el
index dc9c7f1..23512d4 100644
--- a/test/lisp/net/secrets-tests.el
+++ b/test/lisp/net/secrets-tests.el
@@ -169,9 +169,16 @@
        (should
         (equal
          (secrets-get-attributes "session" "bar")
-         '((:host . "remote-host") (:user . "joe")
-           (:method . "sudo")
-           (:xdg:schema . "org.freedesktop.Secret.Generic"))))
+         '((:xdg:schema . "org.freedesktop.Secret.Generic")
+            (:host . "remote-host") (:user . "joe") (:method . "sudo"))))
+
+       ;; Create an item with another schema.
+       (secrets-create-item
+         "session" "baz" "secret" :xdg:schema "org.gnu.Emacs.foo")
+       (should
+        (equal
+         (secrets-get-attributes "session" "baz")
+         '((:xdg:schema . "org.gnu.Emacs.foo"))))
 
        ;; Delete them.
        (dolist (item (secrets-list-items "session"))
@@ -206,6 +213,8 @@
 
        ;; Search the items.
        (should-not (secrets-search-items "session" :user "john"))
+       (should-not
+         (secrets-search-items "session" :xdg:schema "org.gnu.Emacs.foo"))
        (should
         (equal
          (sort (secrets-search-items "session" :user "joe") 'string-lessp)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]