git.fiddlerwoaroof.com
src/mfa-tool.lisp
683ff82b
 (in-package :mfa-tool)
 
 (defun account-selected (account)
   (setf (ubiquitous:value :default-account)
         (cdr account)))
 
106addd5
 (defun region-selected (region)
   (setf (ubiquitous:value :default-region)
         region))
4dde8453
 
683ff82b
 (defparameter *developer-p* (equal "elangley" (uiop/os:getenv "USER")))
 
0d44e5e6
 (defgeneric assumed-credentials (store))
 (defgeneric (setf assumed-credentials) (value store))
683ff82b
 
0d44e5e6
 (defun current-account (interface)
   (cdr (capi:choice-selected-item (account-selector interface))))
edb09ea2
 (defun current-role (interface)
   (capi:choice-selected-item (role-selector interface)))
0d44e5e6
 
 (defun credentials-for-account (interface account)
edb09ea2
   (gethash account
            (assumed-credentials interface)))
0d44e5e6
 (defun (setf credentials-for-account) (new-credentials interface account)
   (setf (gethash account
                  (assumed-credentials interface))
         new-credentials))
 
 (defun current-credentials (interface)
   (credentials-for-account interface
                            (current-account interface)))
683ff82b
 
2b35742e
 
 (defmethod mfa-tool.store:execute ((store (eql :mfa-tool.debugger))
                                    (action mfa-tool.read-credentials:credential-update))
   (with-accessors ((access-key mfa-tool.read-credentials:access-key)
                    (secret-access-key mfa-tool.read-credentials:secret-access-key)) action
     (mfa-tool.credential-provider:save-ubiquitous-credentials
      (aws-sdk:make-credentials :access-key-id access-key
                                :secret-access-key secret-access-key
                                :session-token nil))))
 
72718ef5
 (defun authenticate (user-name role token)
2b35742e
   (handler-bind ((aws-sdk:no-credentials
                    (lambda (c)
                      (alexandria:when-let
                          ((result (mfa-tool.read-credentials:prompt-for-aws-credentials :mfa-tool.debugger)))
                        (set-aws-credentials (mfa-tool.read-credentials:access-key result)
                                             (mfa-tool.read-credentials:secret-access-key result)
                                             c)))))
72718ef5
     (run-process user-name
                  role
                  token)))
2b35742e
 
683ff82b
 (defun go-on (_ interface)
   (declare (ignore _))
   (let ((token (capi:text-input-pane-text (mfa-input interface)))
         (user-name (capi:text-input-pane-text (user-input interface)))
0d44e5e6
         (account (current-account interface)))
683ff82b
     (clear-cookies)
40c2d5d8
     (multiple-value-bind (signin-token creds)
         (handler-bind (((or dexador:http-request-forbidden
                             dexador:http-request-bad-request)
                          (lambda (c)
                            (let ((message (nth-value 2 (sts-error-value (dex:response-body c)))))
                              (multiple-value-bind (new-code completed)
                                  (capi:prompt-for-string (format nil "~a~%Enter new MFA token:"
                                                                  message)
                                                          :ok-check (lambda (v)
                                                                      (and (every 'digit-char-p v)
                                                                           (= (length v) 6))))
                                (if completed
                                    (progn (setf (capi:text-input-pane-text (mfa-input interface))
                                                 new-code)
                                           (change-mfa-token new-code))
                                    (capi:abort-callback)))))))
72718ef5
           (authenticate user-name
edb09ea2
                         (ecase (current-role interface)
                           (:|Developer Role| (cj-developer-role account))
                           (:|Provisioner Role| (cj-provisioner-role account)))
72718ef5
                         token))
683ff82b
       (with-open-file (stream (make-pathname :name ""
                                              :type "cj-aws"
                                              :defaults (user-homedir-pathname))
                               :direction :output
                               :if-exists :rename
                               :if-does-not-exist :create)
2b35742e
         (let ((cred-stream (make-broadcast-stream stream
                                                   (capi:collector-pane-stream (output interface)))))
           (format cred-stream
                   "export AWS_ACCESS_KEY_ID='~a'~%export AWS_SECRET_ACCESS_KEY='~a'~%export AWS_SESSION_TOKEN='~a'~%"
                   (session-id creds)
                   (session-key creds)
                   (session-token creds))))
683ff82b
       (capi:set-button-panel-enabled-items (slot-value interface 'action-buttons)
                                            :set t)
106addd5
       (setf (capi:button-enabled (slot-value interface 'open-console-button))
             t)
0d44e5e6
       (setf (credentials-for-account interface account) (session-credentials creds)
             (signin-url interface) (url-from-signin-token signin-token)))))
683ff82b
 
 (defun close-active-screen ()
   (let ((active-interface
           (capi:screen-active-interface
            (capi:convert-to-screen))))
     (unless (typep active-interface 'mfa-tool)
       (capi:destroy active-interface))))
 
 
 (defun close-active-screen-enabled ()
   (let ((active-interface
           (capi:screen-active-interface
            (capi:convert-to-screen))))
     (typep active-interface '(not mfa-tool))))
 
40c2d5d8
 (defun load-accounts (&optional account-source)
683ff82b
   (yason:parse
    (alexandria:read-file-into-string
40c2d5d8
     (if account-source
         account-source
79334b59
         (json-resource "accounts")))))
683ff82b
 
 (defun reprocess-accounts (accounts)
   (let ((accounts (gethash "Accounts" accounts))
         (result ()))
     (mapc (lambda (account)
106addd5
             (push (cons (format nil "~a: ~a (~a)"
683ff82b
                                 (gethash "Name" account)
145a649d
                                 (gethash "Id" account)
683ff82b
                                 (gethash "Type" account))
                         (gethash "Id" account))
                   result))
           accounts)
106addd5
     (coerce (sort result 'string-lessp
683ff82b
                   :key 'car)
             'list)))