Browse code
feature: add error handling for invalid tokens
Edward Langley authored on 30/09/2019 07:36:04
Showing 3 changed files
Showing 3 changed files
... | ... |
@@ -7,21 +7,41 @@ |
7 | 7 |
|
8 | 8 |
(defparameter *user_management_account_id* 597974043991) |
9 | 9 |
|
10 |
+(defun mfa-serial-number (account user) |
|
11 |
+ (format nil "arn:aws:iam::~a:mfa/~a" |
|
12 |
+ account |
|
13 |
+ user)) |
|
14 |
+ |
|
15 |
+(defun role-arn (account role) |
|
16 |
+ (format nil "arn:aws:iam::~a:role/cjorganization/~a" |
|
17 |
+ account |
|
18 |
+ role)) |
|
19 |
+ |
|
20 |
+(defun read-new-mfa-token () |
|
21 |
+ (format *query-io* "~&New MFA token: ") |
|
22 |
+ (finish-output *query-io*) |
|
23 |
+ (list (read-line *query-io*))) |
|
10 | 24 |
|
11 | 25 |
(defun do-auth (user role token account) |
12 | 26 |
(let ((mfa-serial-number |
13 |
- (format nil "arn:aws:iam::~a:mfa/~a" |
|
14 |
- *user_management_account_id* |
|
15 |
- user)) |
|
16 |
- (role-arn |
|
17 |
- (format nil "arn:aws:iam::~a:role/cjorganization/~a" |
|
18 |
- account |
|
19 |
- role))) |
|
20 |
- (aws/sts:assume-role :role-arn role-arn |
|
21 |
- :role-session-name (session-name) |
|
22 |
- :serial-number mfa-serial-number |
|
23 |
- :duration-seconds #.(* 12 60 60) |
|
24 |
- :token-code token))) |
|
27 |
+ (mfa-serial-number *user_management_account_id* |
|
28 |
+ user)) |
|
29 |
+ (role-arn (role-arn account role))) |
|
30 |
+ (loop |
|
31 |
+ (restart-case |
|
32 |
+ (return |
|
33 |
+ (aws/sts:assume-role :role-arn role-arn |
|
34 |
+ :role-session-name (session-name) |
|
35 |
+ :serial-number mfa-serial-number |
|
36 |
+ :duration-seconds #.(* 12 60 60) |
|
37 |
+ :token-code token)) |
|
38 |
+ (change-mfa-token (new-token) |
|
39 |
+ :interactive read-new-mfa-token |
|
40 |
+ (setf token new-token)))))) |
|
41 |
+ |
|
42 |
+(defun change-mfa-token (new-value) |
|
43 |
+ (when (find-restart 'change-mfa-token) |
|
44 |
+ (invoke-restart 'change-mfa-token new-value))) |
|
25 | 45 |
|
26 | 46 |
(defun get-url (params) |
27 | 47 |
(format nil "https://signin.aws.amazon.com/federation?Action=getSigninToken&Session=~a" |
... | ... |
@@ -71,3 +91,17 @@ |
71 | 91 |
:url url) |
72 | 92 |
:best-width 1280 |
73 | 93 |
:best-height 800)) |
94 |
+ |
|
95 |
+(defun sts-error-value (sts-response) |
|
96 |
+ (let ((parsed-error (dom:first-child |
|
97 |
+ (cxml:parse sts-response |
|
98 |
+ (cxml-dom:make-dom-builder))))) |
|
99 |
+ (flet ((get-node (path) |
|
100 |
+ (dom:node-value |
|
101 |
+ (dom:first-child |
|
102 |
+ (xpath:first-node |
|
103 |
+ (xpath:with-namespaces (("" "https://sts.amazonaws.com/doc/2011-06-15/")) |
|
104 |
+ (xpath:evaluate path parsed-error))))))) |
|
105 |
+ (values (get-node "//Error/Type") |
|
106 |
+ (get-node "//Error/Code") |
|
107 |
+ (get-node "//Error/Message"))))) |
... | ... |
@@ -27,7 +27,23 @@ |
27 | 27 |
(user-name (capi:text-input-pane-text (user-input interface))) |
28 | 28 |
(account (cdr (capi:choice-selected-item (account-selector interface))))) |
29 | 29 |
(clear-cookies) |
30 |
- (multiple-value-bind (signin-token creds) (run-process account user-name token) |
|
30 |
+ (multiple-value-bind (signin-token creds) |
|
31 |
+ (handler-bind (((or dexador:http-request-forbidden |
|
32 |
+ dexador:http-request-bad-request) |
|
33 |
+ (lambda (c) |
|
34 |
+ (let ((message (nth-value 2 (sts-error-value (dex:response-body c))))) |
|
35 |
+ (multiple-value-bind (new-code completed) |
|
36 |
+ (capi:prompt-for-string (format nil "~a~%Enter new MFA token:" |
|
37 |
+ message) |
|
38 |
+ :ok-check (lambda (v) |
|
39 |
+ (and (every 'digit-char-p v) |
|
40 |
+ (= (length v) 6)))) |
|
41 |
+ (if completed |
|
42 |
+ (progn (setf (capi:text-input-pane-text (mfa-input interface)) |
|
43 |
+ new-code) |
|
44 |
+ (change-mfa-token new-code)) |
|
45 |
+ (capi:abort-callback))))))) |
|
46 |
+ (run-process account user-name token)) |
|
31 | 47 |
(with-open-file (stream (make-pathname :name "" |
32 | 48 |
:type "cj-aws" |
33 | 49 |
:defaults (user-homedir-pathname)) |
... | ... |
@@ -59,12 +75,14 @@ |
59 | 75 |
(capi:convert-to-screen)))) |
60 | 76 |
(typep active-interface '(not mfa-tool)))) |
61 | 77 |
|
62 |
-(defun load-accounts () |
|
78 |
+(defun load-accounts (&optional account-source) |
|
63 | 79 |
(yason:parse |
64 | 80 |
(alexandria:read-file-into-string |
65 |
- (merge-pathnames (make-pathname :name "accounts" |
|
66 |
- :type "json") |
|
67 |
- (bundle-resource-root))))) |
|
81 |
+ (if account-source |
|
82 |
+ account-source |
|
83 |
+ (merge-pathnames (make-pathname :name "accounts" |
|
84 |
+ :type "json") |
|
85 |
+ (bundle-resource-root)))))) |
|
68 | 86 |
|
69 | 87 |
(defun reprocess-accounts (accounts) |
70 | 88 |
(let ((accounts (gethash "Accounts" accounts)) |