diff --git a/README.md b/README.md index 6c1e44f..756efb0 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ Okta is a registered trademark of Okta, Inc. and this tool has no affiliation wi Python 3.7+ +#### A Note on Python 3.10+ Compatibility on Windows + +`gimme-aws-creds` depends on the [ctap-keyring-device](https://pypi.org/project/ctap-keyring-device/) library for WebAuthn support. All of the released versions of ctap-keyring-device require [winRT](https://pypi.org/project/winrt/) on Windows, which only works on Python 3.9 and lower and is no longer maintained. Until a version of ctap-keyring-device that supports `winSDK` (the replacement for winRT) is released to PyPi, or some other solution is found, WebAuthn support will not be available for people running Python 3.10+ on Windows. + ### Optional [Gimme-creds-lambda](https://github.com/Nike-Inc/gimme-aws-creds/tree/master/lambda) can be used as a proxy to the Okta APIs needed by gimme-aws-creds. This removes the requirement of an Okta API key. Gimme-aws-creds authenticates to gimme-creds-lambda using OpenID Connect and the lambda handles all interactions with the Okta APIs. Alternately, you can set the `OKTA_API_KEY` environment variable and the `gimme_creds_server` configuration value to 'internal' to call the Okta APIs directly from gimme-aws-creds. diff --git a/gimme_aws_creds/__init__.py b/gimme_aws_creds/__init__.py index cbf482b..525dabe 100644 --- a/gimme_aws_creds/__init__.py +++ b/gimme_aws_creds/__init__.py @@ -1,2 +1,2 @@ __all__ = ['config', 'aws', 'main', 'ui', 'common', 'default', 'duo', 'errors', 'okta_classic', 'okta_identity_engine', 'registered_authenticators', 'u2f', 'webauthn'] -version = '2.8.1.1' +version = '2.8.2-pre' diff --git a/gimme_aws_creds/dummy_webauthn.py b/gimme_aws_creds/dummy_webauthn.py new file mode 100644 index 0000000..55e3819 --- /dev/null +++ b/gimme_aws_creds/dummy_webauthn.py @@ -0,0 +1,60 @@ +""" +Copyright 2024-present Nike, Inc. +Licensed under the Apache License, Version 2.0 (the "License"); +You may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and* limitations under the License.* +""" + + +from . import errors + +class FakeAssertion(object): + def __init__(self): + self.signature = b'fake' + self.auth_data = b'fake' + + +class WebAuthnClient(object): + """ Dummy WebAuthnClient class - needed until ctap-keyring-device is updated to support Python 3.10+ on Windows""" + def __init__(self, ui, okta_org_url, challenge, credential_id=None, timeout_ms=30_000): + return None + + def locate_device(self): + return None + + def on_keepalive(self, status): + return None + + def verify(self): + raise errors.GimmeAWSCredsError( + "WebAuthn devices not supported on this platform", 2 + ) + + def _verify(self, client): + return None + + def make_credential(self, user): + raise errors.GimmeAWSCredsError( + "WebAuthn devices not supported on this platform", 2 + ) + + def _make_credential(self, client, user): + return None + + def _run_in_thread(self, method, *args, **kwargs): + return None + + def _get_pin_from_client(self, client): + raise errors.GimmeAWSCredsError( + "WebAuthn devices not supported on this platform", 2 + ) + @staticmethod + def _get_user_verification_requirement_from_client(client): + raise errors.GimmeAWSCredsError( + "WebAuthn devices not supported on this platform", 2 + ) diff --git a/gimme_aws_creds/main.py b/gimme_aws_creds/main.py index f28abc6..b110602 100644 --- a/gimme_aws_creds/main.py +++ b/gimme_aws_creds/main.py @@ -17,6 +17,7 @@ import os import re import sys +import platform import concurrent.futures # extras @@ -510,7 +511,7 @@ def okta_platform(self): self.okta_org_url + '/.well-known/okta-organization', headers={ 'Accept': 'application/json', - 'User-Agent': "gimme-aws-creds {}".format(version) + 'User-Agent': "gimme-aws-creds {};{};{}".format(version, sys.platform, platform.python_version()) }, timeout=30 ) diff --git a/gimme_aws_creds/okta_classic.py b/gimme_aws_creds/okta_classic.py index c17aa49..420e069 100644 --- a/gimme_aws_creds/okta_classic.py +++ b/gimme_aws_creds/okta_classic.py @@ -10,6 +10,8 @@ See the License for the specific language governing permissions and* limitations under the License.* """ import base64 +import sys +import platform import copy import re import socket @@ -30,13 +32,20 @@ from requests.adapters import HTTPAdapter, Retry from gimme_aws_creds.u2f import FactorU2F -from gimme_aws_creds.webauthn import WebAuthnClient, FakeAssertion + +# avoid importing ctap-keyring-device on Windows until it supports Python 3.10+ +if sys.platform == "win32" and sys.version_info >= (3, 10): + from gimme_aws_creds.dummy_webauthn import WebAuthnClient, FakeAssertion +else: + from gimme_aws_creds.webauthn import WebAuthnClient, FakeAssertion + from . import errors, ui, version, duo from .duo_universal import OktaDuoUniversal from .errors import GimmeAWSCredsMFAEnrollStatus from .registered_authenticators import RegisteredAuthenticators + class OktaClassicClient(object): """ The Okta Client Class performs the necessary API @@ -284,7 +293,7 @@ def auth_oauth(self, client_id, **kwargs): def _get_headers(): """sets the default headers""" headers = { - 'User-Agent': "gimme-aws-creds {}".format(version), + 'User-Agent': "gimme-aws-creds {};{};{}".format(version, sys.platform, platform.python_version()), 'Accept': 'application/json', 'Content-Type': 'application/json', } @@ -622,7 +631,11 @@ def _login_multi_factor(self, state_token, login_data): elif factor['factorType'] == 'u2f': return self._login_input_webauthn_challenge(state_token, factor) elif factor['factorType'] == 'webauthn': - return self._login_input_webauthn_challenge(state_token, factor) + # Block webauthn until ctap-kering-device is updated to support Python 3.10+ on Windows + if sys.platform == "win32" and sys.version_info >= (3, 10): + raise errors.GimmeAWSCredsError("WebAuthn devices not supported on this platform", 2) + else: + return self._login_input_webauthn_challenge(state_token, factor) elif factor['factorType'] == 'token:hardware': return self._login_input_mfa_challenge(state_token, factor['_links']['verify']['href']) elif factor['factorType'] == 'claims_provider': diff --git a/gimme_aws_creds/okta_identity_engine.py b/gimme_aws_creds/okta_identity_engine.py index 08f025d..d007e18 100644 --- a/gimme_aws_creds/okta_identity_engine.py +++ b/gimme_aws_creds/okta_identity_engine.py @@ -9,6 +9,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and* limitations under the License.* """ +import sys +import platform import time import webbrowser import jwt @@ -200,7 +202,7 @@ def get_saml_response(self, url, auth_session): def _get_headers(): """sets the default headers""" headers = { - 'User-Agent': "gimme-aws-creds {}".format(version), + 'User-Agent': "gimme-aws-creds {};{};{}".format(version, sys.platform, platform.python_version()), 'Accept': 'application/json' } return headers diff --git a/requirements.txt b/requirements.txt index 1f07ffb..df42e17 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ keyring>=21.4.0 requests>=2.25.0,<3.0.0 fido2>=0.9.1,<0.10.0 okta>=2.9.0,<3.0.0 -ctap-keyring-device==1.0.6 +ctap-keyring-device==1.0.6; (sys_platform == "win32" and python_version < "3.10") or sys_platform != "win32" pyjwt>=2.4.0,<3.0.0 urllib3>=1.26.0,<2.0.0 html5lib>=1.1,<2.0.0 diff --git a/setup.py b/setup.py index 081ae4c..6c3759e 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name='gimme_aws_creds', - version='2.8.1.1', + version='2.8.2-pre', install_requires=requirements, author='Eric Pierce', author_email='eric.pierce@nike.com',