Created
September 7, 2021 10:07
-
-
Save ties/b5f5572f2578b6b5b6c304fee019ad0a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import logging | |
import os | |
import requests | |
import sys | |
import urllib.parse | |
from typing import Optional | |
import pyotp | |
from lxml import etree | |
logging.basicConfig() | |
LOG = logging.getLogger(__name__) | |
def get_token(url: str, | |
username: str, | |
password: str, | |
otp_secret: Optional[str] = None): | |
# Get the initial form for SSO token | |
s = requests.Session() | |
res = s.get(url) | |
root = etree.HTML(res.text) | |
csrf = root.xpath('//input[@name="org.scalatra.CsrfTokenSupport.key"]')[0].get('value') | |
LOG.debug("cfrf token: %s", csrf) | |
auth_resp = s.post( | |
url, | |
headers={ | |
"referer": url | |
}, | |
data={ | |
"org.scalatra.CsrfTokenSupport.key": csrf, | |
"username": username, | |
"password": password, | |
"originalUrl": url | |
}, | |
allow_redirects=False) | |
if "Two-step verification" in auth_resp.text: | |
if not otp_secret: | |
raise ValueError("Two-factor verification was enabled for account but secret was not provided.") | |
root = etree.HTML(auth_resp.text) | |
csrf = root.xpath('//input[@name="org.scalatra.CsrfTokenSupport.key"]')[0].get('value') | |
# Try to create totp instance | |
totp = pyotp.TOTP(otp_secret) | |
totp_code = totp.now() | |
LOG.debug("sending totp code: %s", totp_code) | |
auth_resp = s.post( | |
urllib.parse.urljoin(url, "two-factor-authentication"), | |
headers={ | |
"referer": auth_resp.url | |
}, | |
data={ | |
"org.scalatra.CsrfTokenSupport.key": csrf, | |
"securityCode": totp_code | |
}, | |
allow_redirects=False) | |
# The HTTP 200 for 2fa is handled above. Both paths that arrive here have | |
# a HTTP 302 for success. | |
if auth_resp.status_code != 302: | |
raise ValueError("Authentication failed.") | |
print(f"crowd.token_key={auth_resp.cookies['crowd.token_key']}") | |
def main(): | |
parser = argparse.ArgumentParser( | |
description="""Get a ripe.token cookie value. | |
Username is taken from RIPE_PORTAL_USERNAME env far. | |
Password is taken from RIPE_PORTAL_PASSWORD env var.""") | |
parser.add_argument('--url', | |
help='Login form URL (e.g. https://access.ripe.net/', | |
default='https://access.ripe.net/') | |
parser.add_argument('--username', | |
help='Username (default: from environment)', | |
default=os.environ.get('RIPE_PORTAL_USERNAME', '')) | |
parser.add_argument('--password', | |
help='Password (default: from environment)', | |
default=os.environ.get('RIPE_PORTAL_PASSWORD', '')) | |
parser.add_argument('--2fa-secret', | |
dest="otp_secret", | |
help='2FA secreet (default: from environment)', | |
default=os.environ.get('RIPE_PORTAL_2FA_SECRET', '')) | |
parser.add_argument('-v', | |
dest="verbose", | |
action="store_true") | |
args = parser.parse_args() | |
if args.verbose: | |
logging.getLogger().setLevel(logging.DEBUG) | |
if not args.username or not args.password: | |
parser.print_help() | |
sys.exit(2) | |
else: | |
get_token(args.url, args.username, args.password, args.otp_secret) | |
if __name__ == "__main__": | |
main() | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
requests | |
beautifulsoup4 | |
pyotp | |
lxml |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment