git.fiddlerwoaroof.com
Browse code

Rework mfa authentication to take advantage of arn utilities

Edward Langley authored on 25/10/2019 22:08:07
Showing 2 changed files
... ...
@@ -6,15 +6,6 @@
6 6
 
7 7
 (defparameter *user_management_account_id* 597974043991)
8 8
 
9
-(defun mfa-serial-number (account user)
10
-  (format nil "arn:aws:iam::~a:mfa/~a"
11
-          account
12
-          user))
13
-
14
-(defun role-arn (account role)
15
-  (format nil "arn:aws:iam::~a:role/cjorganization/~a"
16
-          account
17
-          role))
18 9
 (defclass cj-organization-role ()
19 10
   ((account :initarg :account
20 11
             :reader account
... ...
@@ -51,23 +42,17 @@
51 42
   (finish-output *query-io*)
52 43
   (list (read-line *query-io*)))
53 44
 
54
-(defun do-auth (user role token account)
55
-  (let ((mfa-serial-number
56
-          (mfa-serial-number *user_management_account_id*
57
-                             user))
58
-        (role-arn (role-arn account role)))
59
-    (loop
60
-      (restart-case
61
-          (return
62
-            (aws/sts:assume-role :role-arn role-arn
63
-                                 :role-session-name (session-name)
64
-                                 :serial-number mfa-serial-number
65
-                                 :duration-seconds #.(* 12 60 60)
66
-                                 :token-code token))
67
-        (change-mfa-token (new-token)
68
-          :interactive read-new-mfa-token
69
-          (setf token new-token))
70
-        (continue ())))))
45
+(defun do-auth (user role token)
46
+  (with-retry (let ((mfa-serial-number (arn-for :mfa *user_management_account_id* user))
47
+                    (role-arn (cj-organization-role-arn role)))
48
+                (aws/sts:assume-role :role-arn role-arn
49
+                                     :role-session-name (session-name)
50
+                                     :serial-number mfa-serial-number
51
+                                     :duration-seconds #.(* 12 60 60)
52
+                                     :token-code token))
53
+    (change-mfa-token (new-token)
54
+                      :interactive read-new-mfa-token
55
+                      (setf token new-token))))
71 56
 
72 57
 (defun change-mfa-token (new-value)
73 58
   (when (find-restart 'change-mfa-token)
... ...
@@ -104,10 +89,10 @@
104 89
 
105 90
 (defgeneric session-credentials (source)
106 91
   (:method ((source sts-result-handler))
107
-   (aws-sdk:make-credentials
108
-    :access-key-id (session-id source)
109
-    :secret-access-key (session-key source)
110
-    :session-token (session-token source))))
92
+    (aws-sdk:make-credentials
93
+     :access-key-id (session-id source)
94
+     :secret-access-key (session-key source)
95
+     :session-token (session-token source))))
111 96
 
112 97
 (defun url-from-signin-token (signin-token)
113 98
   (format nil "https://signin.aws.amazon.com/federation?Action=login&Destination=https%3A%2F%2Fconsole.aws.amazon.com&SigninToken=~a"
... ...
@@ -123,42 +108,33 @@
123 108
     (finish-output *query-io*)
124 109
     (collect (read-line *query-io*))))
125 110
 
126
-(defun run-process (account user token)
127
-  (loop
128
-    (restart-bind ((set-aws-credentials (lambda (access-key-id secret-access-key)
129
-                                          (setf aws:*session*
130
-                                                (aws:make-session
131
-                                                 :credentials (aws:make-credentials
132
-                                                               :access-key-id access-key-id
133
-                                                               :secret-access-key secret-access-key
134
-                                                               :session-token nil
135
-                                                               :provider-name "restart-provider")))
136
-                                          (continue))
137
-                                        :interactive-function 'read-new-aws-credentials
138
-                                        :report-function (lambda (s)
139
-                                                           (princ "Supply new AWS credentials" s))
140
-                                        :test-function (lambda (c)
141
-                                                         (and (find-restart 'continue)
142
-                                                              (typep c 'aws:no-credentials)))))
143
-      (let* ((api-result (cells:c-in (do-auth user "CJDeveloperAccessRole" token account)))
144
-             (parser (make-instance 'sts-result-handler :api-result api-result))
145
-             (federation-url (url parser))
146
-             (signin-token (gethash "SigninToken" 
147
-                                    (yason:parse
148
-                                     (dexador:get federation-url)))))
149
-        (return-from run-process
150
-          (values signin-token
151
-                  parser))))))
111
+(defun run-process (user role token)
112
+  (with-retry* ((set-aws-credentials (lambda (access-key-id secret-access-key)
113
+                                       (setf aws:*session*
114
+                                             (aws:make-session
115
+                                              :credentials (aws:make-credentials
116
+                                                            :access-key-id access-key-id
117
+                                                            :secret-access-key secret-access-key
118
+                                                            :session-token nil
119
+                                                            :provider-name "restart-provider")))
120
+                                       (continue))
121
+                                     :interactive-function 'read-new-aws-credentials
122
+                                     :report-function (lambda (s)
123
+                                                        (princ "Supply new AWS credentials" s))
124
+                                     :test-function (lambda (c)
125
+                                                      (and (find-restart 'continue)
126
+                                                           (typep c 'aws:no-credentials)))))
127
+    (let* ((api-result (cells:c-in (do-auth user role token)))
128
+           (parser (make-instance 'sts-result-handler :api-result api-result))
129
+           (federation-url (url parser))
130
+           (signin-token (gethash "SigninToken" 
131
+                                  (yason:parse
132
+                                   (dexador:get federation-url)))))
133
+      (values signin-token
134
+              parser))))
152 135
 
153 136
 (defun set-aws-credentials (access-key-id secret-access-key &optional condition)
154
-  (alexandria:when-let ((restart (find-restart 'set-aws-credentials condition)))
155
-    (invoke-restart restart access-key-id secret-access-key)))
156
-
157
-(defun open-url (url)
158
-  (capi:contain (make-instance 'capi:browser-pane
159
-                               :url url)
160
-                :best-width 1280
161
-                :best-height 800))
137
+  (safely-invoke-restart 'set-aws-credentials condition access-key-id secret-access-key))
162 138
 
163 139
 (defun sts-error-value (sts-response)
164 140
   (let ((parsed-error (dom:first-child
... ...
@@ -34,7 +34,7 @@
34 34
                                :secret-access-key secret-access-key
35 35
                                :session-token nil))))
36 36
 
37
-(defun authenticate (account user-name token)
37
+(defun authenticate (user-name role token)
38 38
   (handler-bind ((aws-sdk:no-credentials
39 39
                    (lambda (c)
40 40
                      (alexandria:when-let
... ...
@@ -42,7 +42,9 @@
42 42
                        (set-aws-credentials (mfa-tool.read-credentials:access-key result)
43 43
                                             (mfa-tool.read-credentials:secret-access-key result)
44 44
                                             c)))))
45
-    (run-process account user-name token)))
45
+    (run-process user-name
46
+                 role
47
+                 token)))
46 48
 
47 49
 (defun go-on (_ interface)
48 50
   (declare (ignore _))
... ...
@@ -66,7 +68,9 @@
66 68
                                                 new-code)
67 69
                                           (change-mfa-token new-code))
68 70
                                    (capi:abort-callback)))))))
69
-          (authenticate account user-name token))
71
+          (authenticate user-name
72
+                        (cj-developer-role account)
73
+                        token))
70 74
       (with-open-file (stream (make-pathname :name ""
71 75
                                              :type "cj-aws"
72 76
                                              :defaults (user-homedir-pathname))