Skip to content

Commit

Permalink
Add support for persistent cookies and single login
Browse files Browse the repository at this point in the history
  • Loading branch information
gcochard committed Sep 8, 2023
1 parent f52d1c7 commit f3b0532
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
4 changes: 1 addition & 3 deletions alohomora/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ def main(self):
if not username:
alohomora.die("Oops, don't forget to provide a username")

password = getpass.getpass()

idp_url = self._get_config('idp-url', None)
if not idp_url:
alohomora.die("Oops, don't forget to provide an idp-url")
Expand All @@ -182,7 +180,7 @@ def main(self):
# Authenticate the user
#
provider = alohomora.req.DuoRequestsProvider(idp_url, auth_method)
(okay, response) = provider.login_one_factor(username, password)
(okay, response) = provider.login_one_factor(username, getpass.getpass)
assertion = None

if not okay:
Expand Down
25 changes: 22 additions & 3 deletions alohomora/req.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import time
import os
import base64
from http.cookiejar import LWPCookieJar

try:
import urlparse
Expand Down Expand Up @@ -285,22 +286,28 @@ def hex_encode(buf):

def login_one_factor(self, username, password):
self.session = requests.Session()
self.session.cookies = LWPCookieJar(os.path.expanduser('~/.alohomora.cookiejar'))

(response, soup) = self._do_get(self.idp_url)
payload = {}

username_set = False
password_set = False
for inputtag in soup.find_all('input'):
name = inputtag.get('name', '')
# value = inputtag.get('value', '')
if "user" in name.lower():
# Make an educated guess that this is the right field for the username
payload[name] = username
username_set = True
elif "email" in name.lower():
# Some IdPs also label the username field as 'email'
payload[name] = username
elif "pass" in name.lower():
# Make an educated guess that this is the right field for the password
payload[name] = password
LOG.debug('Detected password field, prompting for password')
payload[name] = password if not callable(password) else password()
password_set = True
else:
# Populate the parameter with the existing value (picks up hidden fields as well)
# payload[name] = value
Expand All @@ -314,9 +321,16 @@ def login_one_factor(self, username, password):
else:
payload_debugger[key] = payload[key]
LOG.debug(payload_debugger)
if username not in payload.values():
if not username_set:
assertion = ''
for inputtag in soup.find_all('input'):
if inputtag.get('name') == 'SAMLResponse':
# print(inputtag.get('value'))
assertion = inputtag.get('value')
if assertion != '':
return (True, assertion)
alohomora.die("Couldn't find right form field for username!")
elif password not in payload.values():
elif not password_set:
alohomora.die("Couldn't find right form field for password!")

# Some IdPs don't explicitly set a form action, but if one is set we should
Expand Down Expand Up @@ -687,12 +701,17 @@ def _do_post(self, url, data=None, headers=None, soup=True):
return self._make_request(url, self.session.post, data, headers, soup)

def _make_request(self, url, func, data=None, headers=None, soup=True):
try:
self.session.cookies.load(ignore_discard=True, ignore_expires=True)
except FileNotFoundError:
pass
LOG.debug("Pre cookie jar: %s", self.session.cookies)
LOG.debug("Fetching from URL: %s", url)
response = func(url, data=data, headers=headers)
LOG.debug("Post cookie jar: %s", self.session.cookies)
LOG.debug("Request headers: %s", response.request.headers)
LOG.debug("Response headers: %s", response.headers)
self.session.cookies.save(ignore_discard=True, ignore_expires=True)
if soup:
the_soup = BeautifulSoup(response.text, 'html.parser')
else:
Expand Down

0 comments on commit f3b0532

Please sign in to comment.