git.fiddlerwoaroof.com
src/domain.lisp
683ff82b
 (in-package :mfa-tool)
 
 (defvar *accounts* ())
 (defun session-name ()
   (format nil "bootstrap~d" (+ 5000 (random 5000))))
 
 (defparameter *user_management_account_id* 597974043991)
 
40c2d5d8
 (defun read-new-mfa-token ()
   (format *query-io* "~&New MFA token: ")
   (finish-output *query-io*)
   (list (read-line *query-io*)))
683ff82b
 
72718ef5
 (defun do-auth (user role token)
   (with-retry (let ((mfa-serial-number (arn-for :mfa *user_management_account_id* user))
                     (role-arn (cj-organization-role-arn role)))
                 (aws/sts:assume-role :role-arn role-arn
                                      :role-session-name (session-name)
                                      :serial-number mfa-serial-number
edb09ea2
                                      :duration-seconds (if (eql (mfa-tool.aws-utils:session-duration role)
                                                                 :max)
                                                            #.(* 12 60 60)
                                                            (mfa-tool.aws-utils:session-duration role))
72718ef5
                                      :token-code token))
     (change-mfa-token (new-token)
                       :interactive read-new-mfa-token
                       (setf token new-token))))
40c2d5d8
 
 (defun change-mfa-token (new-value)
   (when (find-restart 'change-mfa-token)
     (invoke-restart 'change-mfa-token new-value)))
683ff82b
 
 (defun get-url (params)
   (format nil "https://signin.aws.amazon.com/federation?Action=getSigninToken&Session=~a"
           (quri.encode:url-encode (with-output-to-string (s)
                                     (yason:encode params s))
                                   :space-to-plus t)))
 
5aa9ad6e
 (cells:defmodel sts-result-handler ()
   ((credentials :accessor credentials :initarg :credentials
                 :initform (cells:c-in nil))
683ff82b
    (session-id :reader session-id
5aa9ad6e
                :initform (cells:c? (typecase (^credentials)
76ad2e41
                                      (aws:credentials
                                       (aws-sdk/credentials/base:credentials-access-key-id
                                        (^credentials)))
5aa9ad6e
                                      (cons (serapeum:assocadr "AccessKeyId" (^credentials)
                                                               :test 'equal)))))
76ad2e41
    (session-key :reader session-key
5aa9ad6e
                 :initform (cells:c? (typecase (^credentials)
76ad2e41
                                       (aws:credentials
                                        (aws-sdk/credentials/base:credentials-secret-access-key
                                         (^credentials)))
5aa9ad6e
                                       (cons (serapeum:assocadr "SecretAccessKey" (^credentials)
                                                                :test 'equal)))))
76ad2e41
    (session-token :reader session-token
5aa9ad6e
                   :initform (cells:c? (typecase (^credentials)
76ad2e41
                                         (aws:credentials
                                          (aws-sdk/credentials/base:credentials-session-token
                                           (^credentials)))
5aa9ad6e
                                         (cons (serapeum:assocadr "SessionToken" (^credentials)
                                                                  :test 'equal)))))
76ad2e41
    (url-params :reader url-params
683ff82b
                :initform (cells:c? (fw.lu:alist-string-hash-table
                                     `(("sessionId" . ,(^session-id))
                                       ("sessionKey" . ,(^session-key))
                                       ("sessionToken" . ,(^session-token)))) ))
    (url :reader url
         :initform (cells:c? (get-url (^url-params))))))
 
0d44e5e6
 (defgeneric session-credentials (source)
   (:method ((source sts-result-handler))
72718ef5
     (aws-sdk:make-credentials
      :access-key-id (session-id source)
      :secret-access-key (session-key source)
      :session-token (session-token source))))
0d44e5e6
 
76ad2e41
 (defun url-from-signin-token (signin-token &optional (region "us-west-2"))
   (format nil #.(concatenate 'string
                              "https://signin.aws.amazon.com/federation?"
                              "Action=login&"
                              "Destination=https%3A%2F%2F~a.console.aws.amazon.com&"
                              "SigninToken=~a")
           region
683ff82b
           signin-token))
 
32ddc779
 (defun read-new-aws-credentials ()
   (serapeum:collecting
     (fresh-line *query-io*)
     (format *query-io* "Access Key?")
     (finish-output *query-io*)
     (collect (read-line *query-io*))
     (format *query-io* "Secret Access Key?")
     (finish-output *query-io*)
     (collect (read-line *query-io*))))
 
72718ef5
 (defun run-process (user role token)
   (with-retry* ((set-aws-credentials (lambda (access-key-id secret-access-key)
                                        (setf aws:*session*
                                              (aws:make-session
                                               :credentials (aws:make-credentials
                                                             :access-key-id access-key-id
                                                             :secret-access-key secret-access-key
                                                             :session-token nil
                                                             :provider-name "restart-provider")))
                                        (continue))
                                      :interactive-function 'read-new-aws-credentials
                                      :report-function (lambda (s)
                                                         (princ "Supply new AWS credentials" s))
                                      :test-function (lambda (c)
                                                       (and (find-restart 'continue)
                                                            (typep c 'aws:no-credentials)))))
5aa9ad6e
     (let* ((api-result (do-auth user role token))
            (parser (make-instance 'sts-result-handler
                                   :credentials (serapeum:assocdr "Credentials" api-result
                                                                  :test 'equal)))
72718ef5
            (federation-url (url parser))
76ad2e41
            (signin-token (gethash "SigninToken"
72718ef5
                                   (yason:parse
                                    (dexador:get federation-url)))))
       (values signin-token
               parser))))
683ff82b
 
2b35742e
 (defun set-aws-credentials (access-key-id secret-access-key &optional condition)
72718ef5
   (safely-invoke-restart 'set-aws-credentials condition access-key-id secret-access-key))
40c2d5d8
 
 (defun sts-error-value (sts-response)
   (let ((parsed-error (dom:first-child
                        (cxml:parse sts-response
                                    (cxml-dom:make-dom-builder)))))
     (flet ((get-node (path)
              (dom:node-value
               (dom:first-child
                (xpath:first-node
                 (xpath:with-namespaces (("" "https://sts.amazonaws.com/doc/2011-06-15/"))
                   (xpath:evaluate path parsed-error)))))))
       (values (get-node "//Error/Type")
               (get-node "//Error/Code")
               (get-node "//Error/Message")))))