Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
6 changed files with 54 additions and 23 deletions
Showing only changes of commit 5d7d967cf2 - Show all commits

View File

@ -39,6 +39,15 @@ def after_cas_login():
"scodoc_cas_login_date"
] = datetime.datetime.now().isoformat()
user.cas_last_login = datetime.datetime.utcnow()
if flask.session.get("CAS_EDT_ID"):
# essaie de récupérer l'edt_id s'il est présent
# cet ID peut être renvoyé par le CAS et extrait par ScoDoc
# via l'expression `cas_edt_id_from_xml_regexp`
# voir flask_cas.routing
edt_id = flask.session.get("CAS_EDT_ID")
current_app.logger.info(f"""after_cas_login: storing edt_id for {
user.user_name}: '{edt_id}'""")
user.edt_id = edt_id
db.session.add(user)
db.session.commit()
return flask.redirect(url_for("scodoc.index"))

View File

@ -185,18 +185,7 @@ class User(UserMixin, db.Model):
return self._migrate_scodoc7_password(password)
return False
password_ok = check_password_hash(self.password_hash, password)
if password_ok and cas_enabled and flask.session.get("CAS_EDT_ID"):
# essaie de récupérer l'edt_id s'il est présent
# cet ID peut être renvoyé par le CAS et extrait par ScoDoc
# via l'expression `cas_edt_id_from_xml_regexp`
# voir flask_cas.routing
edt_id = flask.session.get("CAS_EDT_ID")
log(f"Storing edt_id for {self.user_name}: '{edt_id}'")
self.edt_id = edt_id
db.session.add(self)
db.session.commit()
return password_ok
return check_password_hash(self.password_hash, password)
def _migrate_scodoc7_password(self, password) -> bool:
"""After migration, rehash password."""

View File

@ -38,10 +38,14 @@ from app.models import ScoDocSiteConfig
def check_cas_uid_from_mail_regexp(form, field):
"Vérifie la regexp fournie pur l'extraction du CAS id"
"Vérifie la regexp fournie pour l'extraction du CAS id"
if not ScoDocSiteConfig.cas_uid_from_mail_regexp_is_valid(field.data):
raise ValidationError("expression régulière invalide")
def check_cas_edt_id_from_xml_regexp(form, field):
"Vérifie la regexp fournie pour l'extraction du CAS id"
if not ScoDocSiteConfig.cas_edt_id_from_xml_regexp_is_valid(field.data):
raise ValidationError("expression régulière pour edt_id invalide")
class ConfigCASForm(FlaskForm):
"Formulaire paramétrage CAS"
@ -58,18 +62,18 @@ class ConfigCASForm(FlaskForm):
description="""url complète. Commence en général par <tt>https://</tt>.""",
)
cas_login_route = StringField(
label="Route du login CAS",
label="Optionnel: route du login CAS",
description="""ajouté à l'URL du serveur: exemple <tt>/cas</tt>
(si commence par <tt>/</tt>, part de la racine)""",
default="/cas",
)
cas_logout_route = StringField(
label="Route du logout CAS",
label="Optionnel: route du logout CAS",
description="""ajouté à l'URL du serveur: exemple <tt>/cas/logout</tt>""",
default="/cas/logout",
)
cas_validate_route = StringField(
label="Route de validation CAS",
label="Optionnel: route de validation CAS",
description="""ajouté à l'URL du serveur: exemple <tt>/cas/serviceValidate</tt>""",
default="/cas/serviceValidate",
)
@ -81,7 +85,7 @@ class ConfigCASForm(FlaskForm):
)
cas_uid_from_mail_regexp = StringField(
label="Expression pour extraire l'identifiant utilisateur",
label="Optionnel: expression pour extraire l'identifiant utilisateur",
description="""regexp python appliquée au mail institutionnel de l'utilisateur,
dont le premier groupe doit donner l'identifiant CAS.
Si non fournie, le super-admin devra saisir cet identifiant pour chaque compte.
@ -92,6 +96,17 @@ class ConfigCASForm(FlaskForm):
validators=[Optional(), check_cas_uid_from_mail_regexp],
)
cas_edt_id_from_xml_regexp = StringField(
label="Optionnel: expression pour extraire l'identifiant edt",
description="""regexp python appliquée à la réponse XML du serveur CAS pour
retrouver l'id de l'utilisateur sur le SI de l'institution, et notamment sur les
calendrier d'emploi du temps. Par exemple, si cet id est renvoyé dans le champ
<b>supannEmpId</b>, utiliser:
<tt>&lt;cas:supannEmpId&gt;(.*?)&lt;/cas:supannEmpId&gt;</tt>
""",
validators=[Optional(), check_cas_edt_id_from_xml_regexp],
)
cas_ssl_verify = BooleanField("Vérification du certificat SSL")
cas_ssl_certificate_file = FileField(
label="Certificat (PEM)",

View File

@ -286,7 +286,7 @@ class ScoDocSiteConfig(db.Model):
@classmethod
def set(cls, name: str, value: str) -> bool:
"Set parameter, returns True if change. Commit session."
value_str = str(value or "")
value_str = str(value or "").strip()
if (cls.get(name) or "") != value_str:
cfg = ScoDocSiteConfig.query.filter_by(name=name).first()
if cfg is None:
@ -429,7 +429,17 @@ class ScoDocSiteConfig(db.Model):
return False
# and returns at least one group on a simple cannonical address
match = pattern.search("emmanuel@exemple.fr")
return len(match.groups()) > 0
return match is not None and len(match.groups()) > 0
@classmethod
def cas_edt_id_from_xml_regexp_is_valid(cls, exp: str) -> bool:
"True si l'expression régulière semble valide"
# check that it compiles
try:
_ = re.compile(exp)
except re.error:
return False
return True
@classmethod
def assi_get_rounded_time(cls, label: str, default: str) -> float:

View File

@ -24,6 +24,7 @@
{{ wtf.form_field(form.cas_validate_route) }}
{{ wtf.form_field(form.cas_attribute_id) }}
{{ wtf.form_field(form.cas_uid_from_mail_regexp) }}
{{ wtf.form_field(form.cas_edt_id_from_xml_regexp) }}
<div class="cas_settings">
{{ wtf.form_field(form.cas_ssl_verify) }}
{{ wtf.form_field(form.cas_ssl_certificate_file) }}
@ -40,8 +41,8 @@
{{ wtf.form_field(form.cancel) }}
</div>
<div class="form-group" style="margin-top:16px;">
<em>Note: si le CAS est forcé, le super-admin et les utilisateurs autorisés
à "se connecter via ScoDoc" pourront toujours se
<em>Note: si le CAS est forcé, le super-admin et les utilisateurs autorisés
à "se connecter via ScoDoc" pourront toujours se
connecter via l'adresse spéciale</em>
<tt style="color: blue;">{{url_for("auth.login_scodoc", _external=True)}}</tt>
</div>
@ -50,6 +51,6 @@
</div>
{% endblock %}
{% endblock %}

View File

@ -273,6 +273,10 @@ def config_cas():
"cas_uid_from_mail_regexp", form.data["cas_uid_from_mail_regexp"]
):
flash("Expression extraction identifiant CAS enregistrée")
if ScoDocSiteConfig.set(
"cas_edt_id_from_xml_regexp", form.data["cas_edt_id_from_xml_regexp"]
):
flash("Expression extraction identifiant edt enregistrée")
if ScoDocSiteConfig.set("cas_ssl_verify", form.data["cas_ssl_verify"]):
flash("Vérification SSL modifiée")
if form.cas_ssl_certificate_file.data:
@ -300,6 +304,9 @@ def config_cas():
form.cas_uid_from_mail_regexp.data = ScoDocSiteConfig.get(
"cas_uid_from_mail_regexp"
)
form.cas_edt_id_from_xml_regexp.data = ScoDocSiteConfig.get(
"cas_edt_id_from_xml_regexp"
)
form.cas_ssl_verify.data = ScoDocSiteConfig.get("cas_ssl_verify")
return render_template(
"config_cas.j2",