From 37082850de0eb9e8aa030e0b2d58cdbb529c62eb Mon Sep 17 00:00:00 2001 From: Jean-Pierre Sevigny <41591249+sevignyj@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:59:56 -0500 Subject: [PATCH] apply changes from code review --- requirements.txt | 1 + tokendito/__init__.py | 2 +- tokendito/http_client.py | 4 +- tokendito/okta.py | 92 +++++++++------------------------------- 4 files changed, 25 insertions(+), 74 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7a106b8f..3ea3a668 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ beautifulsoup4>=4.6.0 botocore>=1.12.36 +certifi>=2022.12.07 # This can be removed when requests updates its requirements from 2017.4.17 to >=2022.12.07 platformdirs>=2.5.4 requests>=2.19.0 diff --git a/tokendito/__init__.py b/tokendito/__init__.py index e8082c01..90577d0d 100644 --- a/tokendito/__init__.py +++ b/tokendito/__init__.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """Tokendito module initialization.""" -__version__ = "2.2.0.rc4" +__version__ = "2.3.0" __title__ = "tokendito" __description__ = "Get AWS STS tokens from Okta SSO" __long_description_content_type__ = "text/markdown" diff --git a/tokendito/http_client.py b/tokendito/http_client.py index 80819980..48923eae 100644 --- a/tokendito/http_client.py +++ b/tokendito/http_client.py @@ -29,7 +29,7 @@ def get(self, url, params=None, headers=None, allow_redirects=True): """Perform a GET request.""" response = None try: - logger.debug(f"get to {url}") + logger.debug(f"GET to {url}") logger.debug(f"Sending cookies: {self.session.cookies}") logger.debug(f"Sending headers: {self.session.headers}") response = self.session.get( @@ -53,7 +53,7 @@ def get(self, url, params=None, headers=None, allow_redirects=True): def post(self, url, data=None, json=None, headers=None, return_json=False): """Perform a POST request.""" - logger.debug(f"post to {url}") + logger.debug(f"POST to {url}") try: response = self.session.post(url, data=data, json=json, headers=headers) response.raise_for_status() diff --git a/tokendito/okta.py b/tokendito/okta.py index 63f92a1b..95f5f26e 100644 --- a/tokendito/okta.py +++ b/tokendito/okta.py @@ -44,7 +44,6 @@ def api_error_code_parser(status=None): param status: Response status return message: status message """ - logger.debug(f"api_error_code_parser({status})") if status and status in _status_dict.keys(): message = f"Okta auth failed: {_status_dict[status]}" else: @@ -57,7 +56,6 @@ def get_auth_pipeline(url=None): """Get auth pipeline version.""" logger.debug(f"get_auth_pipeline({url})") headers = {"accept": "application/json"} - # https://developer.okta.com/docs/api/openapi/okta-management/management/tag/OrgSetting/ url = f"{url}/.well-known/okta-organization" response = HTTP_client.get(url, headers=headers) @@ -89,9 +87,7 @@ def get_auth_properties(userid=None, url=None): :param url: Okta organization URL where we are looking up the user. :returns: Dictionary containing authentication properties. """ - logger.debug(f"get_auth_properies({userid}, {url})") payload = {"resource": f"okta:acct:{userid}", "rel": "okta:idp"} - # payload = {"resource": f"okta:acct:{userid}"} headers = {"accept": "application/jrd+json"} url = f"{url}/.well-known/webfinger" logger.debug(f"Looking up auth endpoint for {userid} in {url}") @@ -152,7 +148,7 @@ def get_saml_request(auth_properties): return saml_request -def send_saml_request(saml_request, cookies): +def send_saml_request(saml_request): """ Submit SAML request to IdP, and get the response back. @@ -162,11 +158,10 @@ def send_saml_request(saml_request, cookies): """ logger.debug( f""" - send_saml_request - HTTP_client cookies is {HTTP_client.session.cookies}") - we'll set them to {cookies} - """ + HTTP_client cookies is {HTTP_client.session.cookies}") + + """ ) # Define the payload and headers for the request payload = { @@ -198,13 +193,10 @@ def send_saml_request(saml_request, cookies): # Mask sensitive values for logging purposes user.add_sensitive_value_to_be_masked(saml_response["response"]) - # Log the formed SAML response - # logger.debug(f"SAML response is {saml_response}") logger.debug( f""" - After SAML Request call, - we have HTTP_client.session cookies at {HTTP_client.session.cookies} - """ + we have HTTP_client.session cookies: {HTTP_client.session.cookies} + """ ) # Return the formed SAML response @@ -254,11 +246,11 @@ def send_saml_response(config, saml_response): # Log the SAML response details. logger.debug( - f""" send_saml_response + f""" + Sending SAML response back to {url} - Sending SAML response back to {url} - and HTTP_client session cookies is {HTTP_client.session.cookies} - """ + HTTP_client session cookies is {HTTP_client.session.cookies} + """ ) # Use the HTTP client to make a POST request. @@ -266,10 +258,8 @@ def send_saml_response(config, saml_response): # Extract cookies from the response. session_cookies = response.cookies - # session_cookies.set("session_token", session_token, path="/") # Get the 'sid' value from the cookies. - sid = session_cookies.get("sid") logger.debug(f" new sid is {sid}") @@ -277,7 +267,7 @@ def send_saml_response(config, saml_response): if sid is not None: user.add_sensitive_value_to_be_masked(sid) else: - logger.debug("we dont have a sid cookies.") + logger.debug("We did not find a 'sid' entry in the cookies.") # Log the session cookies. logger.debug( f""" @@ -299,7 +289,7 @@ def send_saml_response(config, saml_response): ) session_cookies = myresponse.cookies - logger.debug(f"in send SAML response, we return {session_cookies}") + logger.debug(f"We return session_cookies: {session_cookies}") # Return the session cookies. return session_cookies @@ -398,11 +388,6 @@ def get_authorize_scope(): So we're only returning "openid", which is ok for what we do. """ - # return""" - # openid profile email okta.users.read.self okta.users.manage.self - # okta.internal.enduser.read okta.internal.enduser.manage okta.enduser.dashboard.read - # okta.enduser.dashboard.manage - # """ return "openid" @@ -482,7 +467,6 @@ def get_authorize_code(response, payload): ) sys.exit(1) authorize_code = re.search(r"(?<=code=)[^&]+", callback_url) - # authorize_state = re.search(r"(?<=state=)[^&]+", callback_url).group() if authorize_code: return authorize_code.group() @@ -498,13 +482,11 @@ def authorization_code_request(config, authz_code_flow_data): """ logger.debug(f"oauth_code_request({config}, {authz_code_flow_data})") headers = {"accept": "application/json", "content-type": "application/json"} - session_token = HTTP_client.session.cookies.get("session_token") payload = { "client_id": authz_code_flow_data["client_id"], "redirect_uri": authz_code_flow_data["redirect_uri"], "response_type": authz_code_flow_data["response_type"], - "sessionToken": session_token, "scope": authz_code_flow_data["scope"], "state": authz_code_flow_data["state"], "code_challenge": authz_code_flow_data["code_challenge"], @@ -674,36 +656,6 @@ def create_sid_cookies(authn_org_url, session_token): return cookies -def create_idx_cookies(authn_org_url, session_cookies): - """ - Create session cookie. - - :param authn_org_url: org url - :param session_token: session token, str - :returns: cookies jar with session_id value we got using the token - """ - # Construct the URL from the base URL provided. - url = f"{authn_org_url}/api/v1/sessions" - - # Define the payload and headers for the request. - data = {"sessionToken": session_cookies} - headers = {"Content-Type": "application/json", "accept": "application/json"} - - # Log the request details. - logger.debug(f"Requesting session cookies from {url}") - - # Use the HTTP client to make a POST request. - response_json = HTTP_client.post(url, json=data, headers=headers, return_json=True) - if "id" not in response_json: - logger.error(f"'id' not found in response. Full response: {response_json}") - sys.exit(1) - - session_id = response_json["id"] - cookies = requests.cookies.RequestsCookieJar() - cookies.set("sid", session_id, domain=urlparse(url).netloc, path="/") - return cookies - - def idp_auth(config): """Authenticate and authorize with the IDP. @@ -729,7 +681,6 @@ def idp_auth(config): ======= """ ) - if is_saml2_authentication(auth_properties): # We may loop thru the saml2 servers until # we find the authentication server. @@ -740,15 +691,15 @@ def idp_auth(config): cookies are {HTTP_client.session.cookies} """ ) - elif user_authentication_enabled(auth_properties): - session_token = user_authenticate(config) + elif local_authentication_enabled(auth_properties): + session_token = local_authenticate(config) # authentication sends us a token # which we then put in our session cookies HTTP_client.session.cookies = create_sid_cookies(config.okta["org"], session_token) logger.debug( f""" - authenticated via user_authenticate + authenticated via local_authenticate http session cookies are {HTTP_client.session.cookies} """ @@ -760,9 +711,9 @@ def idp_auth(config): # Once we get there, the user is authenticated. if config.okta["client_id"] is not None: - # If the user passed a client-id value - # we will run the oauth2 authorize flow on OIE enabled okta. - # we will then get and idx cookies + # If the user passed a client-id value, + # we will run the oauth2 authorize flow on OIE enabled okta + # and we will then get an idx cookies logger.debug("client_id = {client_id}") if oie_enabled(config.okta["org"]): logger.debug( @@ -800,7 +751,7 @@ def saml2_authenticate(config, auth_properties): # Once we are authenticated, send the SAML request to the IdP. # This call requires session cookies. - saml_response = send_saml_request(saml_request, session_cookies) + saml_response = send_saml_request(saml_request) # Send SAML response from the IdP back to the SP, which will generate new # session cookies. @@ -821,13 +772,12 @@ def oie_enabled(url): return False -def user_authenticate(config): +def local_authenticate(config): """Authenticate user on local okta instance. :param config: Config object :return: auth session ID cookie. """ - logger.debug(f"user_authenticate({config}") session_token = None headers = {"content-type": "application/json", "accept": "application/json"} payload = {"username": config.okta["username"], "password": config.okta["password"]} @@ -852,7 +802,7 @@ def user_authenticate(config): return session_token -def user_authentication_enabled(auth_properties): +def local_authentication_enabled(auth_properties): """Check whether authentication happens on the current instance. :param auth_properties: auth_properties dict