Source code for security

from datetime import datetime

from flask import Blueprint
from flask import current_app as app
from flask import flash, redirect, request, session, url_for
from flask_babel import gettext
from flask_login import login_user, logout_user
from requests.exceptions import HTTPError

import backend.cookies as cookies
import backend.models as md

security = Blueprint("security", __name__, static_folder="../static")


[docs]@security.route("/login") def login(): # The UCLouvain login API only works on one specific hostname: # ade-scheduler.info.ucl.ac.be on port 443 # # To have it working locally, you need to: # - Set `FLASK_RUN_HOST` and `FLASK_RUN_PORT` environ variables accordingly # - Edit `/etc/hosts` (Linux) and write: # 127.0.0.1 ade-scheduler.info.ucl.ac.be # - Run flask with # `sudo venv/bin/flask run --cert=adhoc # # If you use another hostname, you will be logged under `Super Dev` name. # WARNING: this won't work the day where we want to add features requiring # a OAuth token... (currently, we do not use it at all.) if ( app.env == "development" and request.base_url != "https://ade-scheduler.info.ucl.ac.be/login" ): user = md.User.query.filter_by(fgs="dev").first() # If dev user doesn't exist, create it if user is None: now = datetime.now() user = md.User( fgs="dev", email="dev@ade-scheduler", first_name="Super", last_name="Dev", created_at=now, last_seen_at=now, ) md.db.session.add(user) md.db.session.commit() # Automatically login the dev-user login_user(user) return redirect(url_for("calendar.index")) # Proceed with the normal login procedure uclouvain = app.config["UCLOUVAIN_MANAGER"] # Request code if request.args.get("code") is None: redirect_uri = url_for("security.login", _external=True) return uclouvain.authorize_redirect(redirect_uri) # Code received else: # Fetch token token = uclouvain.authorize_access_token() # Fetch user role & ID my_fgs = None role = None resp = uclouvain.get("my/v0/digit/roles", token=token) try: resp.raise_for_status() except HTTPError: flash( gettext( "Hum... it looks like the authentification server is having some issues - please try again. If the problem persists, do contact us directly so we can look into it." ), "error", ) return redirect(url_for("calendar.index")) data = resp.json() roles = list() for business_role in data["businessRoles"]["businessRole"]: roles.append(business_role["businessRoleCode"]) my_fgs = business_role["identityId"] # Determine which role, priority on employee, then student. if 1 in roles: role = "employee" elif 2 in roles: role = "student" else: flash( gettext( "Hum... it looks like there is an issue with your UCLouvain account. Please contact directly so we can look into it and fix it for you !" ) + "<br><br><b>Code: role list</b>", "error", ) return redirect(url_for("calendar.index")) # Create user if does not exist user = md.User.query.filter_by(fgs=my_fgs).first() if user is None: resp = uclouvain.get(f"my/v0/{role}", token=token) try: resp.raise_for_status() except HTTPError: flash( gettext( "Hum... it looks like the authentification server is having some issues - please try again. If the problem persists, do contact us directly so we can look into it." ), "error", ) return redirect(url_for("calendar.index")) data = resp.json() # Student if role == "student": data = data["lireDossierEtudiantResponse"]["return"] email = data["email"] first_name = data["prenom"] last_name = data["nom"] # Employee elif role == "employee": data = data["person"] email = data["email"] first_name = data["firstname"] last_name = data["lastname"] # Not implemented, raise error else: raise NotImplementedError(f"Role {role} is not implemented yet !") now = datetime.now() user = md.User( fgs=my_fgs, email=email, first_name=first_name, last_name=last_name, created_at=now, last_seen_at=now, ) md.db.session.add(user) md.db.session.commit() # Login user login_user(user, remember=True) # Create response, redirect if next param is found next = session.pop("next", None) if next is not None: resp = redirect(next) else: resp = redirect(url_for("calendar.index")) return cookies.set_oauth_token(token, resp)
[docs]@security.route("/logout") def logout(): # Logout user logout_user() # Clear uclouvain token cookie resp = redirect(url_for("calendar.index")) resp.delete_cookie("uclouvain-token") return resp