schubergphilis / awsapilib

A python library exposing services that are not covered by the official boto3 library but are driven by undocumented APIs.
MIT License
60 stars 8 forks source link

Authentication: AWS Console login apparently broken #28

Closed s0enke closed 2 years ago

s0enke commented 2 years ago

It seems like AWS changed the way the redirects (from console. to signin.) work, which broke the login flow in awsapilib. I could fix this by adapting to the new login flow:

diff --git a/awsapilib/console/console.py b/awsapilib/console/console.py
index 6ef9b9e..aab4a19 100755
--- a/awsapilib/console/console.py
+++ b/awsapilib/console/console.py
@@ -464,7 +464,7 @@ class BaseConsoleInterface(LoggerMixin):
         return success

     def _resolve_account_type(self, email):
-        response = self._resolve_account_type_response(email, {'hashArgs': '#a'})
+        response = self._resolve_account_type_response(email)
         success = self._validate_response(response)
         if not success:
             raise UnableToResolveAccount(f'Failed to resolve account type with response: {response.text} '
@@ -472,14 +472,15 @@ class BaseConsoleInterface(LoggerMixin):
         self.logger.debug(f'Resolved account type successfully with response :{response.text}')
         return success

-    def _resolve_account_type_response(self, email, extra_parameters=None, session=None):
+    def _resolve_account_type_response(self, email, session=None):
         session_ = session if session else self.session
+
+        urls = Urls('us-east-1')
+        _ = session_.get(urls.regional_console_home, params={'hashArgs': '#a', 'skipRegion': 'true', 'region': 'us-east-1'})
+
         parameters = {'action': 'resolveAccountType',
-                      'email': email}
-        if extra_parameters:
-            parameters.update(extra_parameters)
-        _ = session_.get(self._console_home_url, params=parameters)
-        parameters.update({'csrf': session_.cookies.get('aws-signin-csrf', path='/signin')})
+                      'email': email,
+                      'csrf': session_.cookies.get('aws-signin-csrf', path='/signin')}
         response = session_.post(self._signin_url, data=parameters)
         self.logger.debug('Getting the resolve account type captcha.')
         parameters = self._update_parameters_with_captcha(parameters, response)
@@ -512,10 +513,12 @@ class BaseConsoleInterface(LoggerMixin):
         return None if mfa_type == 'NONE' else mfa_type

     def _get_root_console_redirect(self, email, password, session, mfa_serial=None):
-        url = Urls.console_home
+        urls = Urls('us-east-1')
+        url = urls.regional_console_home
         parameters = {'hashArgs': '#a'}
+
         self.logger.debug(f'Trying to get url: {url} with parameters :{parameters}')
-        response = session.get(url, params=parameters)
+        response = session.get(url, params={'hashArgs': '#a', 'skipRegion': 'true', 'region': 'us-east-1'})
         if not response.ok:
             raise ServerError(f'Unsuccessful response received: {response.text} '
                               f'with status code: {response.status_code}')

But now it's still not working. The follow-up error I get is:

DEBUG:authentication.RootAuthenticator: aws-creds-code-verifier (domain:us-east-1.console.aws.amazon.com/console) : 04153c0bbaf5db0ba1d655f46eb8c79d54fa0c473c3ca6e61e8cb64e049cbcd62643e53c56187824832e0253876cec892d2d902bd8beb3937d745e2c5bc95407
DEBUG:authentication.RootAuthenticator: aws-signin-account-info (domain:.signin.aws.amazon.com/) : %7B%22accountType%22%3A%221%22%2C%22email%22%3A%22root%2B07e5c%40769683309166.a4662202-595c-46a8-87be-22c29f9d33ad.net%22%7D
DEBUG:authentication.RootAuthenticator: aws-signin-csrf (domain:.signin.aws.amazon.com/signin) : zdC0I9wpXE4QLrMkBNHCSjQS7ickbFU8oBGhes7v2MtJ3BlIRF175sv9TSehi6XMLbuiul4PEUpQXG4smLdQ5yi4GRqDqTn42mJzhzqEKKDcLccADn8U5qyGVUG2NteBCDUyVXaFDUeaBJ7mYmMITH5JaMWraqLmBUCl1a8qIJS73ShJ8zjmb1OWFnhJmNfgct0rBcH2sQ2VOVcmKrto8R3miLvs0K8rOORrwpnR9jaXg2lNEntSjJns6PyAzH2G
DEBUG:authentication.RootAuthenticator: aws-ubid-main (domain:.amazon.com/) : 336-3004465-8505226
DEBUG:authentication.RootAuthenticator: aws-userInfo (domain:.amazon.com/) : %7B%22arn%22%3A%22arn%3Aaws%3Aiam%3A%3A316565747939%3Aroot%22%2C%22alias%22%3A%22%22%2C%22username%22%3A%22Log%2520Archive%22%2C%22keybase%22%3A%22%22%2C%22issuer%22%3A%22http%3A%2F%2Fsignin.aws.amazon.com%2Fsignin%22%2C%22signinType%22%3A%22PUBLIC%22%7D
DEBUG:authentication.RootAuthenticator: aws-userInfo-signed (domain:.amazon.com/) : eyJ0eXAiOiJKV1MiLCJrZXlSZWdpb24iOiJ1cy1lYXN0LTEiLCJhbGciOiJFUzM4NCIsImtpZCI6ImFhNDFkZjRjLTMxMzgtNGVkOC04YmU5LWYyMzUzYzNkOTEzYiJ9.eyJzdWIiOiIiLCJzaWduaW5UeXBlIjoiUFVCTElDIiwiaXNzIjoiaHR0cDpcL1wvc2lnbmluLmF3cy5hbWF6b24uY29tXC9zaWduaW4iLCJrZXliYXNlIjoiV2dPSVR2QyszM2YydTVFb2tSQUFBSGppeExubVhHdU9mVjlYdm5cL0JHWDQ9IiwiYXJuIjoiYXJuOmF3czppYW06OjMxNjU2NTc0NzkzOTpyb290IiwidXNlcm5hbWUiOiJMb2clMjBBcmNoaXZlIn0.5TBnwyIvCHI-rtNHF6FEyK0MzSB_RyKqPlz9Pn2fu-dPzW59EnYL06_3xdS-_oHRwiqJvgJbTQF6HYPfcUAE5w43h8u-R0S5Aw2NJ5Dvo61HXWu13MFl6Gj6TDS1WCe3
DEBUG:authentication.RootAuthenticator: JSESSIONID (domain:signin.aws.amazon.com/) : 62312673586DD0955C3FA38309F52438
DEBUG:authentication.RootAuthenticator: regStatus (domain:.amazon.com/) : registered
DEBUG:authentication.RootAuthenticator:Getting url :None with arguments : {'url': None, 'headers': {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'en-US,en;q=0.5', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:73.0) Gecko/20100101 Firefox/73.0', 'Cookie': 'aws-account-data=%7B%22marketplaceGroup%22%3A%22AWS%22%7D; aws-ubid-main=336-3004465-8505226; aws-userInfo=%7B%22arn%22%3A%22arn%3Aaws%3Aiam%3A%3A316565747939%3Aroot%22%2C%22alias%22%3A%22%22%2C%22username%22%3A%22Log%2520Archive%22%2C%22keybase%22%3A%22%22%2C%22issuer%22%3A%22http%3A%2F%2Fsignin.aws.amazon.com%2Fsignin%22%2C%22signinType%22%3A%22PUBLIC%22%7D; JSESSIONID=0E7A3AA5DC29544FE2F236834BDBC29E'}, 'cookies': {'aws-account-data': '%7B%22marketplaceGroup%22%3A%22AWS%22%7D', 'aws-ubid-main': '336-3004465-8505226', 'aws-userInfo': '%7B%22arn%22%3A%22arn%3Aaws%3Aiam%3A%3A316565747939%3Aroot%22%2C%22alias%22%3A%22%22%2C%22username%22%3A%22Log%2520Archive%22%2C%22keybase%22%3A%22%22%2C%22issuer%22%3A%22http%3A%2F%2Fsignin.aws.amazon.com%2Fsignin%22%2C%22signinType%22%3A%22PUBLIC%22%7D', 'JSESSIONID': '0E7A3AA5DC29544FE2F236834BDBC29E'}, 'allow_redirects': False}
Traceback (most recent call last):
  File "/Users/soenke.ruempler/Projects/superwerker/superwerker/tests/close-active-subaccounts/close-active-subaccounts.py", line 38, in <module>
    close_account(account)
  File "/Users/soenke.ruempler/Projects/superwerker/superwerker/tests/close-active-subaccounts/close-active-subaccounts.py", line 29, in close_account
    account_manager.terminate_account()
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 664, in terminate_account
    session = self._get_billing_session(self.email,
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 564, in _get_billing_session
    return authenticator.get_billing_root_session(redirect_url, unfiltered_session=unfiltered_session)
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 204, in get_billing_root_session
    if not self._get_console_root_session(redirect_url):
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 185, in _get_console_root_session
    dashboard = self._get_response(oauth_challenge.headers.get('Location'),
  File "lib/python3.9/site-packages/awsapilib/authentication/authentication.py", line 252, in _get_response
    response = requests.get(**arguments)
  File "lib/python3.9/site-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "lib/python3.9/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "lib/python3.9/site-packages/requests/sessions.py", line 528, in request
    prep = self.prepare_request(req)
  File "lib/python3.9/site-packages/requests/sessions.py", line 456, in prepare_request
    p.prepare(
  File "lib/python3.9/site-packages/requests/models.py", line 316, in prepare
    self.prepare_url(url, params)
  File "lib/python3.9/site-packages/requests/models.py", line 390, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL 'None': No schema supplied. Perhaps you meant http://None?
DEBUG:authentication.RootAuthenticator: aws-creds-code-verifier (domain:us-east-1.console.aws.amazon.com/console) : 04153c0bbaf5db0ba1d655f46eb8c79d54fa0c473c3ca6e61e8cb64e049cbcd62643e53c56187824832e0253876cec892d2d902bd8beb3937d745e2c5bc95407
DEBUG:authentication.RootAuthenticator: aws-signin-account-info (domain:.signin.aws.amazon.com/) : %7B%22accountType%22%3A%221%22%2C%22email%22%3A%22root%2B07e5c%40769683309166.a4662202-595c-46a8-87be-22c29f9d33ad.net%22%7D
DEBUG:authentication.RootAuthenticator: aws-signin-csrf (domain:.signin.aws.amazon.com/signin) : zdC0I9wpXE4QLrMkBNHCSjQS7ickbFU8oBGhes7v2MtJ3BlIRF175sv9TSehi6XMLbuiul4PEUpQXG4smLdQ5yi4GRqDqTn42mJzhzqEKKDcLccADn8U5qyGVUG2NteBCDUyVXaFDUeaBJ7mYmMITH5JaMWraqLmBUCl1a8qIJS73ShJ8zjmb1OWFnhJmNfgct0rBcH2sQ2VOVcmKrto8R3miLvs0K8rOORrwpnR9jaXg2lNEntSjJns6PyAzH2G
DEBUG:authentication.RootAuthenticator: aws-ubid-main (domain:.amazon.com/) : 336-3004465-8505226
DEBUG:authentication.RootAuthenticator: aws-userInfo (domain:.amazon.com/) : %7B%22arn%22%3A%22arn%3Aaws%3Aiam%3A%3A316565747939%3Aroot%22%2C%22alias%22%3A%22%22%2C%22username%22%3A%22Log%2520Archive%22%2C%22keybase%22%3A%22%22%2C%22issuer%22%3A%22http%3A%2F%2Fsignin.aws.amazon.com%2Fsignin%22%2C%22signinType%22%3A%22PUBLIC%22%7D
DEBUG:authentication.RootAuthenticator: aws-userInfo-signed (domain:.amazon.com/) : eyJ0eXAiOiJKV1MiLCJrZXlSZWdpb24iOiJ1cy1lYXN0LTEiLCJhbGciOiJFUzM4NCIsImtpZCI6ImFhNDFkZjRjLTMxMzgtNGVkOC04YmU5LWYyMzUzYzNkOTEzYiJ9.eyJzdWIiOiIiLCJzaWduaW5UeXBlIjoiUFVCTElDIiwiaXNzIjoiaHR0cDpcL1wvc2lnbmluLmF3cy5hbWF6b24uY29tXC9zaWduaW4iLCJrZXliYXNlIjoiV2dPSVR2QyszM2YydTVFb2tSQUFBSGppeExubVhHdU9mVjlYdm5cL0JHWDQ9IiwiYXJuIjoiYXJuOmF3czppYW06OjMxNjU2NTc0NzkzOTpyb290IiwidXNlcm5hbWUiOiJMb2clMjBBcmNoaXZlIn0.5TBnwyIvCHI-rtNHF6FEyK0MzSB_RyKqPlz9Pn2fu-dPzW59EnYL06_3xdS-_oHRwiqJvgJbTQF6HYPfcUAE5w43h8u-R0S5Aw2NJ5Dvo61HXWu13MFl6Gj6TDS1WCe3
DEBUG:authentication.RootAuthenticator: JSESSIONID (domain:signin.aws.amazon.com/) : 62312673586DD0955C3FA38309F52438
DEBUG:authentication.RootAuthenticator: regStatus (domain:.amazon.com/) : registered
DEBUG:authentication.RootAuthenticator:Getting url :None with arguments : {'url': None, 'headers': {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'en-US,en;q=0.5', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:73.0) Gecko/20100101 Firefox/73.0', 'Cookie': 'aws-account-data=%7B%22marketplaceGroup%22%3A%22AWS%22%7D; aws-ubid-main=336-3004465-8505226; aws-userInfo=%7B%22arn%22%3A%22arn%3Aaws%3Aiam%3A%3A316565747939%3Aroot%22%2C%22alias%22%3A%22%22%2C%22username%22%3A%22Log%2520Archive%22%2C%22keybase%22%3A%22%22%2C%22issuer%22%3A%22http%3A%2F%2Fsignin.aws.amazon.com%2Fsignin%22%2C%22signinType%22%3A%22PUBLIC%22%7D; JSESSIONID=0E7A3AA5DC29544FE2F236834BDBC29E'}, 'cookies': {'aws-account-data': '%7B%22marketplaceGroup%22%3A%22AWS%22%7D', 'aws-ubid-main': '336-3004465-8505226', 'aws-userInfo': '%7B%22arn%22%3A%22arn%3Aaws%3Aiam%3A%3A316565747939%3Aroot%22%2C%22alias%22%3A%22%22%2C%22username%22%3A%22Log%2520Archive%22%2C%22keybase%22%3A%22%22%2C%22issuer%22%3A%22http%3A%2F%2Fsignin.aws.amazon.com%2Fsignin%22%2C%22signinType%22%3A%22PUBLIC%22%7D', 'JSESSIONID': '0E7A3AA5DC29544FE2F236834BDBC29E'}, 'allow_redirects': False}
Traceback (most recent call last):
  File "/Users/soenke.ruempler/Projects/superwerker/superwerker/tests/close-active-subaccounts/close-active-subaccounts.py", line 38, in <module>
    close_account(account)
  File "/Users/soenke.ruempler/Projects/superwerker/superwerker/tests/close-active-subaccounts/close-active-subaccounts.py", line 29, in close_account
    account_manager.terminate_account()
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 664, in terminate_account
    session = self._get_billing_session(self.email,
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 564, in _get_billing_session
    return authenticator.get_billing_root_session(redirect_url, unfiltered_session=unfiltered_session)
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 204, in get_billing_root_session
    if not self._get_console_root_session(redirect_url):
  File "lib/python3.9/site-packages/awsapilib/console/console.py", line 185, in _get_console_root_session
    dashboard = self._get_response(oauth_challenge.headers.get('Location'),
  File "lib/python3.9/site-packages/awsapilib/authentication/authentication.py", line 252, in _get_response
    response = requests.get(**arguments)
  File "lib/python3.9/site-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "lib/python3.9/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "lib/python3.9/site-packages/requests/sessions.py", line 528, in request
    prep = self.prepare_request(req)
  File "lib/python3.9/site-packages/requests/sessions.py", line 456, in prepare_request
    p.prepare(
  File "lib/python3.9/site-packages/requests/models.py", line 316, in prepare
    self.prepare_url(url, params)
  File "lib/python3.9/site-packages/requests/models.py", line 390, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL 'None': No schema supplied. Perhaps you meant http://None?

Any hints or help appreciated.

costastf commented 2 years ago

I will get on it right now. What happened is that the cookie exchange also changed so we need to identify the new cookies being passed in and filter for the in the code.