Skip to content

Commit 329f80a

Browse files
daltonconleyDalton Conley
andauthored
fix(idp, ping): utilize sessions for retrieving SAML (#29)
Co-authored-by: Dalton Conley <dconley@phdata.io>
1 parent 9cca6a7 commit 329f80a

File tree

1 file changed

+97
-95
lines changed

1 file changed

+97
-95
lines changed

redshift_connector/plugin/ping_credentials_provider.py

Lines changed: 97 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -31,102 +31,104 @@ def get_saml_assertion(self: "PingCredentialsProvider") -> str:
3131

3232
self.check_required_parameters()
3333

34-
if self.partner_sp_id is None:
35-
self.partner_sp_id = "urn%3Aamazon%3Awebservices"
36-
37-
url: str = "https://{host}:{port}/idp/startSSO.ping?PartnerSpId={sp_id}".format(
38-
host=self.idp_host, port=str(self.idpPort), sp_id=self.partner_sp_id
39-
)
40-
try:
41-
response: "requests.Response" = requests.get(url, verify=self.do_verify_ssl_cert())
42-
response.raise_for_status()
43-
except requests.exceptions.HTTPError as e:
44-
if "response" in vars():
45-
_logger.debug("get_saml_assertion https response: {}".format(response.text)) # type: ignore
46-
else:
47-
_logger.debug("get_saml_assertion could not receive https response due to an error")
48-
_logger.error("Request for SAML assertion when refreshing credentials was unsuccessful. {}".format(str(e)))
49-
raise InterfaceError(e)
50-
except requests.exceptions.Timeout as e:
51-
_logger.error("A timeout occurred when requesting SAML assertion")
52-
raise InterfaceError(e)
53-
except requests.exceptions.TooManyRedirects as e:
54-
_logger.error(
55-
"A error occurred when requesting SAML assertion to refresh credentials. "
56-
"Verify RedshiftProperties are correct"
34+
with requests.Session() as session:
35+
36+
if self.partner_sp_id is None:
37+
self.partner_sp_id = "urn%3Aamazon%3Awebservices"
38+
39+
url: str = "https://{host}:{port}/idp/startSSO.ping?PartnerSpId={sp_id}".format(
40+
host=self.idp_host, port=str(self.idpPort), sp_id=self.partner_sp_id
5741
)
58-
raise InterfaceError(e)
59-
except requests.exceptions.RequestException as e:
60-
_logger.error("A unknown error occurred when requesting SAML assertion to refresh credentials")
61-
raise InterfaceError(e)
62-
63-
try:
64-
soup = bs4.BeautifulSoup(response.text)
65-
except Exception as e:
66-
_logger.error("An error occurred while parsing response: {}".format(str(e)))
67-
raise InterfaceError(e)
68-
69-
payload: typing.Dict[str, typing.Optional[str]] = {}
70-
username: bool = False
71-
pwd: bool = False
72-
73-
for inputtag in soup.find_all(re.compile("(INPUT|input)")):
74-
name: str = inputtag.get("name", "")
75-
id: str = inputtag.get("id", "")
76-
value: str = inputtag.get("value", "")
77-
78-
if username is False and self.is_text(inputtag) and id == "username":
79-
payload[name] = self.user_name
80-
username = True
81-
elif self.is_password(inputtag) and ("pass" in name):
82-
if pwd is True:
83-
raise InterfaceError("Duplicate password fields on login page.")
84-
payload[name] = self.password
85-
pwd = True
86-
elif name != "":
87-
payload[name] = value
88-
89-
if username is False:
42+
try:
43+
response: "requests.Response" = session.get(url, verify=self.do_verify_ssl_cert())
44+
response.raise_for_status()
45+
except requests.exceptions.HTTPError as e:
46+
if "response" in vars():
47+
_logger.debug("get_saml_assertion https response: {}".format(response.text)) # type: ignore
48+
else:
49+
_logger.debug("get_saml_assertion could not receive https response due to an error")
50+
_logger.error("Request for SAML assertion when refreshing credentials was unsuccessful. {}".format(str(e)))
51+
raise InterfaceError(e)
52+
except requests.exceptions.Timeout as e:
53+
_logger.error("A timeout occurred when requesting SAML assertion")
54+
raise InterfaceError(e)
55+
except requests.exceptions.TooManyRedirects as e:
56+
_logger.error(
57+
"A error occurred when requesting SAML assertion to refresh credentials. "
58+
"Verify RedshiftProperties are correct"
59+
)
60+
raise InterfaceError(e)
61+
except requests.exceptions.RequestException as e:
62+
_logger.error("A unknown error occurred when requesting SAML assertion to refresh credentials")
63+
raise InterfaceError(e)
64+
65+
try:
66+
soup = bs4.BeautifulSoup(response.text)
67+
except Exception as e:
68+
_logger.error("An error occurred while parsing response: {}".format(str(e)))
69+
raise InterfaceError(e)
70+
71+
payload: typing.Dict[str, typing.Optional[str]] = {}
72+
username: bool = False
73+
pwd: bool = False
74+
9075
for inputtag in soup.find_all(re.compile("(INPUT|input)")):
91-
name = inputtag.get("name", "")
92-
if self.is_text(inputtag) and ("user" in name or "email" in name):
76+
name: str = inputtag.get("name", "")
77+
id: str = inputtag.get("id", "")
78+
value: str = inputtag.get("value", "")
79+
80+
if username is False and self.is_text(inputtag) and id == "username":
9381
payload[name] = self.user_name
9482
username = True
95-
96-
if (username is False) or (pwd is False):
97-
raise InterfaceError("Failed to parse login form.")
98-
99-
action: typing.Optional[str] = self.get_form_action(soup)
100-
if action and action.startswith("/"):
101-
url = "https://{host}:{port}{action}".format(host=self.idp_host, port=str(self.idpPort), action=action)
102-
try:
103-
response = requests.post(url, data=payload, verify=self.do_verify_ssl_cert())
104-
response.raise_for_status()
105-
except requests.exceptions.HTTPError as e:
106-
_logger.error("Request to refresh credentials was unsuccessful. {}".format(str(e)))
107-
raise InterfaceError(e)
108-
except requests.exceptions.Timeout as e:
109-
_logger.error("A timeout occurred when attempting to refresh credentials")
110-
raise InterfaceError(e)
111-
except requests.exceptions.TooManyRedirects as e:
112-
_logger.error("A error occurred when refreshing credentials. Verify RedshiftProperties are correct")
113-
raise InterfaceError(e)
114-
except requests.exceptions.RequestException as e:
115-
_logger.error("A unknown error occurred when refreshing credentials")
116-
raise InterfaceError(e)
117-
118-
try:
119-
soup = bs4.BeautifulSoup(response.text)
120-
except Exception as e:
121-
_logger.error("An error occurred while parsing SAML response: {}".format(str(e)))
122-
raise InterfaceError(e)
123-
124-
assertion: str = ""
125-
for inputtag in soup.find_all("input"):
126-
if inputtag.get("name") == "SAMLResponse":
127-
assertion = inputtag.get("value")
128-
129-
if assertion == "":
130-
raise InterfaceError("Failed to retrieve SAMLAssertion.")
131-
132-
return assertion
83+
elif self.is_password(inputtag) and ("pass" in name):
84+
if pwd is True:
85+
raise InterfaceError("Duplicate password fields on login page.")
86+
payload[name] = self.password
87+
pwd = True
88+
elif name != "":
89+
payload[name] = value
90+
91+
if username is False:
92+
for inputtag in soup.find_all(re.compile("(INPUT|input)")):
93+
name = inputtag.get("name", "")
94+
if self.is_text(inputtag) and ("user" in name or "email" in name):
95+
payload[name] = self.user_name
96+
username = True
97+
98+
if (username is False) or (pwd is False):
99+
raise InterfaceError("Failed to parse login form.")
100+
101+
action: typing.Optional[str] = self.get_form_action(soup)
102+
if action and action.startswith("/"):
103+
url = "https://{host}:{port}{action}".format(host=self.idp_host, port=str(self.idpPort), action=action)
104+
try:
105+
response = session.post(url, data=payload, verify=self.do_verify_ssl_cert())
106+
response.raise_for_status()
107+
except requests.exceptions.HTTPError as e:
108+
_logger.error("Request to refresh credentials was unsuccessful. {}".format(str(e)))
109+
raise InterfaceError(e)
110+
except requests.exceptions.Timeout as e:
111+
_logger.error("A timeout occurred when attempting to refresh credentials")
112+
raise InterfaceError(e)
113+
except requests.exceptions.TooManyRedirects as e:
114+
_logger.error("A error occurred when refreshing credentials. Verify RedshiftProperties are correct")
115+
raise InterfaceError(e)
116+
except requests.exceptions.RequestException as e:
117+
_logger.error("A unknown error occurred when refreshing credentials")
118+
raise InterfaceError(e)
119+
120+
try:
121+
soup = bs4.BeautifulSoup(response.text)
122+
except Exception as e:
123+
_logger.error("An error occurred while parsing SAML response: {}".format(str(e)))
124+
raise InterfaceError(e)
125+
126+
assertion: str = ""
127+
for inputtag in soup.find_all("input"):
128+
if inputtag.get("name") == "SAMLResponse":
129+
assertion = inputtag.get("value")
130+
131+
if assertion == "":
132+
raise InterfaceError("Failed to retrieve SAMLAssertion.")
133+
134+
return assertion

0 commit comments

Comments
 (0)