109 lines
4.3 KiB
Python
109 lines
4.3 KiB
Python
import streamlit as st
|
|
import requests
|
|
import logging
|
|
import os
|
|
from utils.translations import _
|
|
from utils.persistance import get_champ_statut, maj_champ_statut
|
|
|
|
def initialiser_logger():
|
|
LOG_FILE_PATH = "/var/log/fabnum-auth.log"
|
|
if not os.path.exists(os.path.dirname(LOG_FILE_PATH)):
|
|
os.makedirs(os.path.dirname(LOG_FILE_PATH), exist_ok=True)
|
|
|
|
logger = logging.getLogger("auth_logger")
|
|
logger.setLevel(logging.INFO)
|
|
if not logger.hasHandlers():
|
|
fh = logging.FileHandler(LOG_FILE_PATH)
|
|
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
|
fh.setFormatter(formatter)
|
|
logger.addHandler(fh)
|
|
return logger
|
|
|
|
def connexion():
|
|
login = get_champ_statut("login")
|
|
if login == "":
|
|
auth_title = str(_("auth.title"))
|
|
st.html(f"""
|
|
<section role="region" aria-label="region-authentification">
|
|
<div role="region" aria-labelledby="Authentification">
|
|
<p id="Authentification" class="decorative-heading">{auth_title}</p>
|
|
""")
|
|
|
|
GITEA_URL = "https://fabnum-git.peccini.fr/api/v1"
|
|
ORGANISATION = "FabNum"
|
|
EQUIPE_CIBLE = "Administrateurs"
|
|
|
|
logger = initialiser_logger()
|
|
|
|
if get_champ_statut("login") == "":
|
|
with st.form("auth_form"):
|
|
# Ajout d'un champ identifiant fictif pour activer l'autocomplétion navigateur
|
|
# et permettre de stocker le token comme un mot de passe par le navigateur
|
|
# L'identifiant n'est donc pas utilisé par la suite ; il est caché en CSS
|
|
identifiant = st.text_input(str(_("auth.username")), value="fabnum-connexion", key="nom_utilisateur")
|
|
token = st.text_input(str(_("auth.token")), type="password")
|
|
submitted = st.form_submit_button(str(_("auth.login")), icon=":material/login:")
|
|
|
|
if submitted and token:
|
|
erreur = True
|
|
headers = {"Authorization": f"token {token}"}
|
|
ip = os.environ.get("REMOTE_ADDR", "inconnu")
|
|
username = "inconnu"
|
|
|
|
try:
|
|
user_response = requests.get(f"{GITEA_URL}/user", headers=headers, timeout=5)
|
|
user_response.raise_for_status()
|
|
utilisateur = user_response.json()
|
|
username = utilisateur.get("login", "inconnu")
|
|
logger.info(f"Tentative par {username} depuis IP {ip}")
|
|
|
|
teams_url = f"{GITEA_URL}/orgs/{ORGANISATION}/teams"
|
|
teams_response = requests.get(teams_url, headers=headers, timeout=5)
|
|
teams_response.raise_for_status()
|
|
equipes = teams_response.json()
|
|
equipe_admin = next((e for e in equipes if e["name"] == EQUIPE_CIBLE), None)
|
|
|
|
if equipe_admin:
|
|
team_id = equipe_admin["id"]
|
|
check_url = f"{GITEA_URL}/teams/{team_id}/members/{username}"
|
|
check_response = requests.get(check_url, headers=headers, timeout=5)
|
|
if check_response.status_code == 200:
|
|
erreur = False
|
|
maj_champ_statut("login", username)
|
|
logger.info(f"Connexion réussie pour {username} depuis IP {ip}")
|
|
st.rerun()
|
|
|
|
except requests.RequestException:
|
|
st.error(str(_("auth.gitea_error")))
|
|
|
|
if erreur:
|
|
logger.warning(f"Accès refusé pour tentative avec token depuis IP {ip}")
|
|
st.error(str(_("auth.error")))
|
|
|
|
st.html("""
|
|
</div>
|
|
</section>
|
|
""")
|
|
|
|
|
|
def bouton_deconnexion():
|
|
login = get_champ_statut("login")
|
|
if not login == "":
|
|
auth_title = str(_("auth.title"))
|
|
st.html(f"""
|
|
<section role="region" aria-label="region-authentification">
|
|
<div role="region" aria-labelledby="Authentification">
|
|
<p id="Authentification" class="decorative-heading">{auth_title}</p>
|
|
""")
|
|
|
|
st.sidebar.markdown(f"{str(_('auth.logged_as'))} `{login}`")
|
|
if st.sidebar.button(str(_("auth.logout")), icon=":material/logout:"):
|
|
maj_champ_statut("login", "")
|
|
st.success(str(_("auth.success")))
|
|
st.rerun()
|
|
|
|
st.html("""
|
|
</div>
|
|
</section>
|
|
""")
|