import logging
|
|
import random
|
|
import re
|
|
from http.cookiejar import Cookie
|
|
from urllib.parse import urljoin, urlparse, parse_qs
|
|
|
|
import requests
|
|
|
|
from .utils.webclient import WebClient
|
|
from .utils.exceptions import *
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger.setLevel(logging.INFO)
|
|
|
|
|
|
class PasteurSSO:
|
|
HEADERS = {
|
|
'User-Agent': ("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0)"
|
|
" Gecko/20100101 Firefox/104.0)")
|
|
}
|
|
SP_START = "https://connect.pasteur.fr"
|
|
IDP_ENTRY_POINT = "https://idp.pasteur.fr/idp/profile/SAML2/POST/SSO"
|
|
|
|
def __init__(self, username, password):
|
|
self.username = username
|
|
self.password = password
|
|
self.client = WebClient(headers=self.HEADERS)
|
|
|
|
def authenticate(self):
|
|
# Go to SP authentication start page and look for SAML form.
|
|
logger.info(f"SP: Starting authentication from {self.SP_START}")
|
|
self.client.get(self.SP_START)
|
|
if not self.client.find_forms(action=self.IDP_ENTRY_POINT):
|
|
logger.info("SP: SAML form not found: already logged in?")
|
|
self.verify_sp_auth()
|
|
return
|
|
|
|
# Send SAML form to the IDP entry point
|
|
logger.info(f"SP: SAML form found: submitting to IDP")
|
|
self.client.select_form(action=self.IDP_ENTRY_POINT)
|
|
self.client.submit_form()
|
|
if self.client.status_code == 400:
|
|
raise Exception("IDP: Error 400: SAML request probably expired.")
|
|
|
|
# Check if already authenticated to IDP
|
|
self.client.select_form()
|
|
if 'SAMLResponse' in self.client.form:
|
|
logger.info("IDP: Already authenticated")
|
|
else:
|
|
# Perform authentication with IDP
|
|
logger.info("IDP: Authentication required.")
|
|
self.client.select_form()
|
|
self.client.submit_form()
|
|
self.client.select_form()
|
|
self.client.form['j_username'] = self.username
|
|
self.client.form['j_password'] = self.password
|
|
self.client.form['_eventId_proceed'] = ""
|
|
# Make authentication persistent
|
|
self.client.form['donotcache'] = "0"
|
|
logger.info(f"IDP: Authenticating '{self.username}'.")
|
|
self.client.submit_form()
|
|
self.client.select_form()
|
|
if 'SAMLResponse' not in self.client.form:
|
|
raise Exception("IDP: Authentication failed.")
|
|
|
|
# Send IDP SAMLResponse back to SP
|
|
logger.info("IDP: Got SAMLResponse, sending to SP")
|
|
self.client.submit_form()
|
|
|
|
self.sp_after_saml()
|
|
|
|
def verify_sp_auth(self):
|
|
m = re.match(
|
|
r"https://connect.pasteur.fr/f5-w-[0-9a-f]+\$\$/connect/$",
|
|
sso.client.url
|
|
)
|
|
if not m:
|
|
raise Exception("SP: unlogged and not redirecting to IDP!")
|
|
|
|
def sp_after_saml(self):
|
|
pass
|
|
|
|
|
|
class PasteurEmail(PasteurSSO):
|
|
SP_START = "https://email.pasteur.fr"
|
|
|
|
def verify_sp_auth(self):
|
|
if self.client.url != 'https://email.pasteur.fr/owa/':
|
|
raise Exception("SP: unlogged and not redirecting to IDP!")
|
|
|
|
|
|
class PasteurSAP(PasteurSSO):
|
|
SP_START = "https://portailha.pasteur.fr"
|
|
|
|
def sp_after_saml(self):
|
|
self.client.select_form(action="/sap/bc/ui2/nwbc")
|
|
self.client.submit_form()
|
|
|
|
def verify_sp_auth(self):
|
|
pass
|
|
|
|
|
|
class PasteurEurofins(PasteurSAP):
|
|
def authenticate(self):
|
|
self.client.get("https://b2b.eurofinsgenomics.eu")
|
|
if self.client.url == "https://b2b.eurofinsgenomics.eu/":
|
|
return True
|
|
|
|
super().authenticate()
|
|
|
|
self.client.get(
|
|
f"https://portailha.pasteur.fr/sap/opu/odata/srmnxp"
|
|
f"/CATALOG_LAUNCH_DETAILS/PollDetails(LAUNCH_FROM='PUNCH_OUT',"
|
|
f"SERVICE_ID='PEUROFINS2',OBJECT_ID='442078',PRODUCTID='')/?="
|
|
f"&random={random.random()}&random={random.random()}",
|
|
headers={'Accept': "application/json"}
|
|
)
|
|
launch_data = self.client.res.json()['d']
|
|
self.client.post(
|
|
launch_data['SERVICE_URL'],
|
|
data=launch_data['FORM_DATA']
|
|
)
|