Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Step-Up challenge assertion is too narrow. #150

Merged
merged 1 commit into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Tokendito

<p align="center">
<img src="https://raw.githubusercontent.com/dowjones/tokendito/main/docs/tokendito.png"/>
</p>
Expand Down Expand Up @@ -26,11 +28,19 @@ tokens into your local `~/.aws/credentials` file.

See [Releases](https://github.com/dowjones/tokendito/releases) for a detailed Changelog.

### Tokendito 2.4.0

Version 2.4.0 of Tokendito introduces the following new features:

- Add support for Okta question MFA.
- Many bug fixes and contributions.

### Tokendito 2.3.0

Version 2.3.0 of Tokendito introduces the following new features:

- Basic OIE support while forcing Classic mode.
- Support for saving the Device Token ID for later reuse.
- Misc bug fixes

Note: This feature currently works with locally enabled OIE organizations, but it does not for Organizations with chained Authentication in mixed OIE/Classic environments.
Expand Down
7 changes: 4 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ tokendito --profile engineer
usage: tokendito [-h] [--version] [--configure] [--username OKTA_USERNAME] [--password OKTA_PASSWORD] [--profile USER_CONFIG_PROFILE] [--config-file USER_CONFIG_FILE]
[--loglevel {DEBUG,INFO,WARN,ERROR}] [--log-output-file USER_LOG_OUTPUT_FILE] [--aws-config-file AWS_CONFIG_FILE] [--aws-output AWS_OUTPUT]
[--aws-profile AWS_PROFILE] [--aws-region AWS_REGION] [--aws-role-arn AWS_ROLE_ARN] [--aws-shared-credentials-file AWS_SHARED_CREDENTIALS_FILE]
[--okta-org OKTA_ORG | --okta-tile OKTA_TILE] [--okta-mfa OKTA_MFA] [--okta-mfa-response OKTA_MFA_RESPONSE] [--use-device-token] [--quiet]
[--okta-org OKTA_ORG | --okta-tile OKTA_TILE] [--okta-client-id OKTA_CLIENT_ID] [--okta-mfa OKTA_MFA] [--okta-mfa-response OKTA_MFA_RESPONSE]
[--use-device-token] [--quiet]

Gets an STS token to use with the AWS CLI and SDK.

Expand Down Expand Up @@ -111,9 +112,9 @@ options:
Okta tile URL to use.
--okta-client-id OKTA_CLIENT_ID
For OIE enabled Orgs this sets the Okta client ID to replace the value found by tokendito. It is used in the authorize code flow.
--okta-mfa OKTA_MFA Sets the MFA method
--okta-mfa OKTA_MFA Sets the MFA method. You can also use the TOKENDITO_OKTA_MFA environment variable.
--okta-mfa-response OKTA_MFA_RESPONSE
Sets the MFA response to a challenge
Sets the MFA response to a challenge. You can also use the TOKENDITO_OKTA_MFA_RESPONSE environment variable.
--use-device-token Use device token across sessions
--quiet Suppress output
```
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exclude_lines = [
"break",
"except KeyboardInterrupt:",
"if __name__ == .__main__.:",
"if __package__ is None:",
"if not __package__:",
"logger.debug",
"pragma: no cover",
"print..Invalid input, try again...",
Expand Down
2 changes: 1 addition & 1 deletion tokendito/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# vim: set filetype=python ts=4 sw=4
# -*- coding: utf-8 -*-
"""Tokendito module initialization."""
__version__ = "2.3.3"
__version__ = "2.4.0"
__title__ = "tokendito"
__description__ = "Get AWS STS tokens from Okta SSO"
__long_description_content_type__ = "text/markdown"
Expand Down
2 changes: 1 addition & 1 deletion tokendito/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

def main(args=None): # needed for console script
"""Packge entry point."""
if __package__ is None:
if not __package__:
import os.path

path = os.path.dirname(os.path.dirname(__file__))
Expand Down
2 changes: 1 addition & 1 deletion tokendito/aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def authenticate_to_roles(config, urls):
saml_xml = okta.extract_saml_response(saml_response_string)
if not saml_xml:
state_token = okta.extract_state_token(saml_response_string)
if "Extra Verification" in saml_response_string and state_token:
if state_token:
logger.info(f"Step-Up authentication required for {url}.")
if okta.step_up_authenticate(config, state_token):
return authenticate_to_roles(config, urls)
Expand Down
6 changes: 6 additions & 0 deletions tokendito/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def get(self, url, params=None, headers=None, allow_redirects=True):

def post(self, url, data=None, json=None, headers=None, params=None, return_json=False):
"""Perform a POST request."""
response = None
logger.debug(f"POST to {url}")
try:
response = self.session.post(url, data=data, json=json, params=params, headers=headers)
Expand All @@ -95,6 +96,11 @@ def post(self, url, data=None, json=None, headers=None, params=None, return_json
return response
except requests.RequestException as e:
logger.error(f"Error during POST request to {url}. Error: {e}")
if response:
logger.debug(f"Response Headers: {response.headers}")
logger.debug(f"Response Text: {response.text}")
else:
logger.debug("No response received")
sys.exit(1)
except Exception as err:
logger.error(f"The post request to {url} failed with {err}")
Expand Down
14 changes: 11 additions & 3 deletions tokendito/okta.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ def get_saml_request(auth_properties):
response = HTTP_client.get(url, headers=headers)

# Extract the required parameters from the SAML request.
post_url = extract_form_post_url(response.text)
base_url = user.get_base_url(post_url)
saml_request = {
"base_url": user.get_base_url(extract_form_post_url(response.text)),
"post_url": extract_form_post_url(response.text),
"base_url": base_url,
"post_url": post_url,
"relay_state": extract_saml_relaystate(response.text),
"request": extract_saml_request(response.text, raw=True),
}
Expand Down Expand Up @@ -263,7 +265,6 @@ def send_saml_response(config, saml_response):

# Get the 'sid' value from the reponse cookies.
sid = response.cookies.get("sid", None)
logger.debug(f"New sid is {sid}")

# If 'sid' is present, mask its value for logging purposes.
if sid:
Expand Down Expand Up @@ -564,6 +565,12 @@ def authorize_request(oauth2_config, oauth2_session_data):
params=payload,
)

idx = HTTP_client.session.cookies.get("idx", None)
if idx:
user.add_sensitive_value_to_be_masked(idx)
else:
logger.debug("We did not find an 'idx' entry in the cookies.")

authorize_code = get_authorize_code(response, session_token)
return authorize_code

Expand Down Expand Up @@ -699,6 +706,7 @@ def idp_authenticate(config):
logger.error("Okta auth failed: unknown type.")
sys.exit(1)

# Possible recursion ahead. The exit condition should be the first if statement.
if local_authentication_enabled(auth_properties):
session_token = local_authenticate(config)
# authentication sends us a token
Expand Down
2 changes: 1 addition & 1 deletion tokendito/tokendito.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

def main(args=None): # needed for console script
"""Packge entry point."""
if __package__ is None:
if not __package__:
import os.path

path = os.path.dirname(os.path.dirname(__file__))
Expand Down
7 changes: 1 addition & 6 deletions tokendito/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,7 @@ def cmd_interface(args):

# get authentication and authorization cookies from okta
okta.access_control(config)
logger.debug(
f"""
about to call discover_tile
we have client cookies: {HTTP_client.session.cookies}
"""
)

if config.okta["tile"]:
tile_label = ""
config.okta["tile"] = (config.okta["tile"], tile_label)
Expand Down
Loading