Coverage for heritrace/routes/auth.py: 100%
61 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-08-01 22:12 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-08-01 22:12 +0000
1import os
2from datetime import timedelta
4from flask import (Blueprint, current_app, flash, redirect, request, session,
5 url_for)
6from flask_babel import gettext
7from flask_login import current_user, login_user, logout_user
8from heritrace.apis.orcid import extract_orcid_id, is_orcid_url
9from heritrace.models import User
10from requests_oauthlib import OAuth2Session
12auth_bp = Blueprint("auth", __name__)
15@auth_bp.route("/login")
16def login():
17 if current_user.is_authenticated:
18 return redirect(url_for("main.catalogue"))
20 if os.environ.get("FLASK_ENV") == "demo":
21 user_id_from_env = os.environ.get("USER_ID", "demo_user")
22 demo_uri = f"http://example.org/demo/{user_id_from_env}"
23 user_name = f"Demo User ({user_id_from_env})"
25 user = User(id=demo_uri, name=user_name, orcid=demo_uri)
26 session["user_name"] = user_name
27 session.permanent = True
28 current_app.permanent_session_lifetime = timedelta(days=30)
29 login_user(user)
31 flash(gettext("Welcome! You've been automatically logged in to the demo"), "info")
32 return redirect(url_for("main.catalogue"))
34 callback_url = url_for("auth.callback", _external=True, _scheme="https")
35 orcid = OAuth2Session(
36 current_app.config["ORCID_CLIENT_ID"],
37 redirect_uri=callback_url,
38 scope=[current_app.config["ORCID_SCOPE"], "openid"],
39 )
40 authorization_url, state = orcid.authorization_url(
41 current_app.config["ORCID_AUTHORIZE_URL"],
42 prompt="login", # Forza il re-login
43 nonce=os.urandom(16).hex(), # Aggiungiamo un nonce per sicurezza
44 )
45 session["oauth_state"] = state
46 return redirect(authorization_url)
49@auth_bp.route("/callback")
50def callback():
51 if request.url.startswith("http://"):
52 secure_url = request.url.replace("http://", "https://", 1)
53 else:
54 secure_url = request.url
56 orcid = OAuth2Session(
57 current_app.config["ORCID_CLIENT_ID"], state=session["oauth_state"]
58 )
59 try:
60 token = orcid.fetch_token(
61 current_app.config["ORCID_TOKEN_URL"],
62 client_secret=current_app.config["ORCID_CLIENT_SECRET"],
63 authorization_response=secure_url,
64 )
65 except Exception as e:
66 flash(
67 gettext("An error occurred during authentication. Please try again"),
68 "danger",
69 )
70 return redirect(url_for("auth.login"))
71 orcid_id = token["orcid"]
73 whitelist = current_app.config["ORCID_WHITELIST"]
74 if whitelist:
75 normalized_whitelist = {
76 extract_orcid_id(item) if is_orcid_url(item) else item for item in whitelist
77 }
78 if orcid_id not in normalized_whitelist:
79 flash(
80 gettext("Your ORCID is not authorized to access this application"),
81 "danger",
82 )
83 return redirect(url_for("auth.login"))
85 session["user_name"] = token["name"]
86 user = User(id=orcid_id, name=token["name"], orcid=orcid_id)
87 session.permanent = True
88 current_app.permanent_session_lifetime = timedelta(days=30)
89 login_user(user)
90 flash(gettext("Welcome back %(name)s!", name=current_user.name), "success")
91 return redirect(url_for("main.catalogue"))
94@auth_bp.route("/logout")
95def logout():
96 if not current_user.is_authenticated:
97 return "", 401
98 logout_user()
99 flash(gettext("You have been logged out"), "info")
100 return redirect(url_for("main.index"))