forked from ScoDoc/ScoDoc
CAS:
- enregistre date derniere connection. - nouvelle permission: ScoUsersChangeCASId - améliore affichage infos utilisateur.
This commit is contained in:
parent
5ca85a9da9
commit
0c0d43d075
@ -8,6 +8,7 @@ import flask
|
|||||||
from flask import current_app, flash, url_for
|
from flask import current_app, flash, url_for
|
||||||
from flask_login import login_user
|
from flask_login import login_user
|
||||||
|
|
||||||
|
from app import db
|
||||||
from app.auth import bp
|
from app.auth import bp
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.models.config import ScoDocSiteConfig
|
from app.models.config import ScoDocSiteConfig
|
||||||
@ -27,7 +28,7 @@ def after_cas_login():
|
|||||||
flask.session.get("CAS_USERNAME"),
|
flask.session.get("CAS_USERNAME"),
|
||||||
)
|
)
|
||||||
if cas_id is not None:
|
if cas_id is not None:
|
||||||
user = User.query.filter_by(cas_id=cas_id).first()
|
user: User = User.query.filter_by(cas_id=cas_id).first()
|
||||||
if user and user.active:
|
if user and user.active:
|
||||||
if user.cas_allow_login:
|
if user.cas_allow_login:
|
||||||
current_app.logger.info(f"CAS: login {user.user_name}")
|
current_app.logger.info(f"CAS: login {user.user_name}")
|
||||||
@ -35,6 +36,9 @@ def after_cas_login():
|
|||||||
flask.session[
|
flask.session[
|
||||||
"scodoc_cas_login_date"
|
"scodoc_cas_login_date"
|
||||||
] = datetime.datetime.now().isoformat()
|
] = datetime.datetime.now().isoformat()
|
||||||
|
user.cas_last_login = datetime.datetime.utcnow()
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
return flask.redirect(url_for("scodoc.index"))
|
return flask.redirect(url_for("scodoc.index"))
|
||||||
else:
|
else:
|
||||||
current_app.logger.info(
|
current_app.logger.info(
|
||||||
@ -77,7 +81,7 @@ def set_cas_configuration(app: flask.app.Flask = None):
|
|||||||
"""
|
"""
|
||||||
app = app or current_app
|
app = app or current_app
|
||||||
if ScoDocSiteConfig.is_cas_enabled():
|
if ScoDocSiteConfig.is_cas_enabled():
|
||||||
current_app.logger.info("CAS: set_cas_configuration")
|
current_app.logger.debug("CAS: set_cas_configuration")
|
||||||
app.config["CAS_SERVER"] = ScoDocSiteConfig.get("cas_server")
|
app.config["CAS_SERVER"] = ScoDocSiteConfig.get("cas_server")
|
||||||
app.config["CAS_AFTER_LOGIN"] = "auth.after_cas_login"
|
app.config["CAS_AFTER_LOGIN"] = "auth.after_cas_login"
|
||||||
app.config["CAS_AFTER_LOGOUT"] = "auth.after_cas_logout"
|
app.config["CAS_AFTER_LOGOUT"] = "auth.after_cas_logout"
|
||||||
|
@ -75,6 +75,8 @@ class User(UserMixin, db.Model):
|
|||||||
"""Si CAS forcé (cas_force), peut-on se logguer sur ScoDoc directement ?
|
"""Si CAS forcé (cas_force), peut-on se logguer sur ScoDoc directement ?
|
||||||
(le rôle ScoSuperAdmin peut toujours, mettre à True pour les utilisateur API)
|
(le rôle ScoSuperAdmin peut toujours, mettre à True pour les utilisateur API)
|
||||||
"""
|
"""
|
||||||
|
cas_last_login = db.Column(db.DateTime, nullable=True)
|
||||||
|
"""date du dernier login via CAS"""
|
||||||
|
|
||||||
password_hash = db.Column(db.String(128))
|
password_hash = db.Column(db.String(128))
|
||||||
password_scodoc7 = db.Column(db.String(42))
|
password_scodoc7 = db.Column(db.String(42))
|
||||||
@ -212,6 +214,9 @@ class User(UserMixin, db.Model):
|
|||||||
"cas_id": self.cas_id,
|
"cas_id": self.cas_id,
|
||||||
"cas_allow_login": self.cas_allow_login,
|
"cas_allow_login": self.cas_allow_login,
|
||||||
"cas_allow_scodoc_login": self.cas_allow_scodoc_login,
|
"cas_allow_scodoc_login": self.cas_allow_scodoc_login,
|
||||||
|
"cas_last_login": self.cas_last_login.isoformat() + "Z"
|
||||||
|
if self.cas_last_login
|
||||||
|
else None,
|
||||||
"status_txt": "actif" if self.active else "fermé",
|
"status_txt": "actif" if self.active else "fermé",
|
||||||
"last_seen": self.last_seen.isoformat() + "Z" if self.last_seen else None,
|
"last_seen": self.last_seen.isoformat() + "Z" if self.last_seen else None,
|
||||||
"nom": (self.nom or ""), # sco8
|
"nom": (self.nom or ""), # sco8
|
||||||
@ -250,7 +255,7 @@ class User(UserMixin, db.Model):
|
|||||||
"cas_allow_login",
|
"cas_allow_login",
|
||||||
"cas_allow_scodoc_login",
|
"cas_allow_scodoc_login",
|
||||||
]:
|
]:
|
||||||
setattr(self, field, data.get(field, False))
|
setattr(self, field, scu.to_bool(data.get(field, False)))
|
||||||
|
|
||||||
if new_user:
|
if new_user:
|
||||||
if "user_name" in data:
|
if "user_name" in data:
|
||||||
@ -552,7 +557,7 @@ class UserRole(db.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<UserRole u={} r={} dept={}>".format(self.user, self.role, self.dept)
|
return f"<UserRole u={self.user} r={self.role} dept={self.dept}>"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def role_dept_from_string(role_dept: str):
|
def role_dept_from_string(role_dept: str):
|
||||||
|
@ -225,7 +225,6 @@ _identiteEditor = ndb.EditableTable(
|
|||||||
"nom",
|
"nom",
|
||||||
"nom_usuel",
|
"nom_usuel",
|
||||||
"prenom",
|
"prenom",
|
||||||
"cas_id",
|
|
||||||
"civilite", # 'M", "F", or "X"
|
"civilite", # 'M", "F", or "X"
|
||||||
"date_naissance",
|
"date_naissance",
|
||||||
"lieu_naissance",
|
"lieu_naissance",
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
used by auth
|
used by auth
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Définition des permissions: ne pas changer les numéros ou l'ordre des lignes !
|
# Définition des permissions: NE PAS CHANGER les numéros ou l'ordre des lignes !
|
||||||
|
# Les permissions sont sur un BigInt en base SQL, donc 64 bits.
|
||||||
_SCO_PERMISSIONS = (
|
_SCO_PERMISSIONS = (
|
||||||
# permission bit, symbol, description
|
# permission bit, symbol, description
|
||||||
# ScoSuperAdmin est utilisé pour:
|
# ScoSuperAdmin est utilisé pour:
|
||||||
@ -53,8 +54,10 @@ _SCO_PERMISSIONS = (
|
|||||||
"RelationsEntreprisesExport",
|
"RelationsEntreprisesExport",
|
||||||
"Exporter les données de l'application relations entreprises",
|
"Exporter les données de l'application relations entreprises",
|
||||||
),
|
),
|
||||||
# 27 à 39 ... réservé pour "entreprises"
|
(1 << 29, "ScoUsersChangeCASId", "Paramétrer l'id CAS"),
|
||||||
|
#
|
||||||
(1 << 40, "ScoEtudChangePhoto", "Modifier la photo d'un étudiant"),
|
(1 << 40, "ScoEtudChangePhoto", "Modifier la photo d'un étudiant"),
|
||||||
|
# Attention: les permissions sont codées sur 64 bits.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,7 +162,12 @@ def list_users(
|
|||||||
if current_user.is_administrator():
|
if current_user.is_administrator():
|
||||||
columns_ids.append("last_seen")
|
columns_ids.append("last_seen")
|
||||||
if ScoDocSiteConfig.is_cas_enabled():
|
if ScoDocSiteConfig.is_cas_enabled():
|
||||||
columns_ids += ["cas_id", "cas_allow_login", "cas_allow_scodoc_login"]
|
columns_ids += [
|
||||||
|
"cas_id",
|
||||||
|
"cas_allow_login",
|
||||||
|
"cas_allow_scodoc_login",
|
||||||
|
"cas_last_login",
|
||||||
|
]
|
||||||
|
|
||||||
title = "Utilisateurs définis dans ScoDoc"
|
title = "Utilisateurs définis dans ScoDoc"
|
||||||
tab = GenTable(
|
tab = GenTable(
|
||||||
@ -183,6 +188,7 @@ def list_users(
|
|||||||
"cas_id": "Id CAS",
|
"cas_id": "Id CAS",
|
||||||
"cas_allow_login": "CAS autorisé",
|
"cas_allow_login": "CAS autorisé",
|
||||||
"cas_allow_scodoc_login": "Cnx sans CAS",
|
"cas_allow_scodoc_login": "Cnx sans CAS",
|
||||||
|
"cas_last_login": "Dernier login CAS",
|
||||||
},
|
},
|
||||||
caption=title,
|
caption=title,
|
||||||
page_title="title",
|
page_title="title",
|
||||||
@ -276,6 +282,7 @@ def check_modif_user(
|
|||||||
):
|
):
|
||||||
"""Vérifie que cet utilisateur peut être créé (edit=0) ou modifié (edit=1)
|
"""Vérifie que cet utilisateur peut être créé (edit=0) ou modifié (edit=1)
|
||||||
Cherche homonymes.
|
Cherche homonymes.
|
||||||
|
Ne vérifie PAS que l'on a la permission de faire la modif.
|
||||||
returns (ok, msg)
|
returns (ok, msg)
|
||||||
- ok : si vrai, peut continuer avec ces parametres
|
- ok : si vrai, peut continuer avec ces parametres
|
||||||
(si ok est faux, l'utilisateur peut quand même forcer la creation)
|
(si ok est faux, l'utilisateur peut quand même forcer la creation)
|
||||||
|
@ -134,6 +134,31 @@ tr.bandeaugtr {
|
|||||||
color: rgb(255, 0, 0);
|
color: rgb(255, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.user_info div {
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.user_info ul li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.user_basics {
|
||||||
|
border: 1px solid blue;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.user_info_admin {
|
||||||
|
border: 1px solid red;
|
||||||
|
background-color: #fdcaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.user_info div.permissions {
|
||||||
|
border: 1px solid rgb(0, 0, 255);
|
||||||
|
background-color: #dedefd;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----- page content ------ */
|
/* ----- page content ------ */
|
||||||
|
|
||||||
div.about-logo {
|
div.about-logo {
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
|
|
||||||
|
<div class="user_info">
|
||||||
<h2>Utilisateur: {{user.user_name}} ({{'actif' if user.active else 'fermé'}})</h2>
|
<h2>Utilisateur: {{user.user_name}} ({{'actif' if user.active else 'fermé'}})</h2>
|
||||||
<p>
|
<div class="user_basics">
|
||||||
<b>Login :</b> {{user.user_name}}<br>
|
<b>Login :</b> {{user.user_name}}<br>
|
||||||
<b>CAS id:</b> {{user.cas_id or "(aucun)"}}
|
<b>CAS id:</b> {{user.cas_id or "(aucun)"}}
|
||||||
(CAS {{'autorisé' if user.cas_allow_login else 'interdit'}} pour cet utilisateur)
|
(CAS {{'autorisé' if user.cas_allow_login else 'interdit'}} pour cet utilisateur)
|
||||||
@ -17,12 +18,22 @@
|
|||||||
<b>Prénom :</b> {{user.prenom or ""}}<br>
|
<b>Prénom :</b> {{user.prenom or ""}}<br>
|
||||||
<b>Mail :</b> {{user.email}}<br>
|
<b>Mail :</b> {{user.email}}<br>
|
||||||
<b>Roles :</b> {{user.get_roles_string()}}<br>
|
<b>Roles :</b> {{user.get_roles_string()}}<br>
|
||||||
<b>Dept :</b> {{user.dept or ""}}<br>
|
<b>Dept :</b> {{user.dept or ""}}
|
||||||
|
</div>
|
||||||
|
{% if current_user.is_administrator() %}
|
||||||
|
<div class="user_info_admin">
|
||||||
|
<b>Dernière vue :</b> {{user.last_seen or "-"}}<br>
|
||||||
|
<b>Dernière connexion CAS :</b> {{user.cas_last_login or "-"}}<br>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="user_basics">
|
||||||
<b>Dernière modif mot de passe:</b>
|
<b>Dernière modif mot de passe:</b>
|
||||||
{{user.date_modif_passwd.isoformat() if user.date_modif_passwd else ""}}<br>
|
{{user.date_modif_passwd.isoformat() if user.date_modif_passwd else ""}}<br>
|
||||||
<b>Date d'expiration:</b>
|
<b>Date d'expiration:</b>
|
||||||
{{user.date_expiration.isoformat() if user.date_expiration else "(sans limite)"}}
|
{{user.date_expiration.isoformat() if user.date_expiration else "(sans limite)"}}
|
||||||
<p>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
{% if (
|
{% if (
|
||||||
current_user.is_administrator()
|
current_user.is_administrator()
|
||||||
@ -52,6 +63,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if current_user.id == user.id %}
|
{% if current_user.id == user.id %}
|
||||||
<div class="user_info_session">
|
<div class="user_info_session">
|
||||||
@ -71,9 +83,9 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{% for p in Permission.description %}
|
{% for p in Permission.description %}
|
||||||
<li>{{Permission.description[p]}} :
|
<li>{{Permission.description[p]}} :
|
||||||
{{
|
<b>{{
|
||||||
"oui" if user.has_permission(Permission.get_by_name(p), dept) else "non"
|
"oui" if user.has_permission(Permission.get_by_name(p), dept) else "non"
|
||||||
}}
|
}}</b>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
@ -84,6 +96,7 @@
|
|||||||
{{url_for('users.index_html', scodoc_dept=g.scodoc_dept)}}
|
{{url_for('users.index_html', scodoc_dept=g.scodoc_dept)}}
|
||||||
">Liste de tous les utilisateurs</a></p>
|
">Liste de tous les utilisateurs</a></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -395,7 +395,8 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
|
|||||||
else "(service CAS non activé)",
|
else "(service CAS non activé)",
|
||||||
"size": 36,
|
"size": 36,
|
||||||
"allow_null": True,
|
"allow_null": True,
|
||||||
"readonly": not cas_enabled,
|
"readonly": not cas_enabled
|
||||||
|
or not current_user.has_permission(Permission.ScoUsersChangeCASId),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -403,8 +404,9 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
|
|||||||
{
|
{
|
||||||
"title": "Autorise connexion via CAS",
|
"title": "Autorise connexion via CAS",
|
||||||
"input_type": "boolcheckbox",
|
"input_type": "boolcheckbox",
|
||||||
"explanation": " seul le super-administrateur peut changer ce réglage",
|
"explanation": """ si CAS est activé.
|
||||||
"readonly": not current_user.is_administrator(),
|
Seul le super-administrateur peut changer ce réglage.""",
|
||||||
|
"enabled": current_user.is_administrator(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -412,8 +414,9 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
|
|||||||
{
|
{
|
||||||
"title": "Autorise connexion via ScoDoc",
|
"title": "Autorise connexion via ScoDoc",
|
||||||
"input_type": "boolcheckbox",
|
"input_type": "boolcheckbox",
|
||||||
"explanation": " seul le super-administrateur peut changer ce réglage",
|
"explanation": """ même si "Forcer l'utilisation de CAS" est activé.
|
||||||
"readonly": not current_user.is_administrator(),
|
Seul le super-administrateur peut changer ce réglage""",
|
||||||
|
"enabled": current_user.is_administrator(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
@ -552,6 +555,12 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
|
|||||||
else:
|
else:
|
||||||
vals = tf[2]
|
vals = tf[2]
|
||||||
roles = set(vals["roles"]).intersection(editable_roles_strings)
|
roles = set(vals["roles"]).intersection(editable_roles_strings)
|
||||||
|
if not current_user.is_administrator():
|
||||||
|
# empeche modification des paramètres CAS
|
||||||
|
vals.pop("cas_allow_login", None)
|
||||||
|
vals.pop("cas_allow_scodoc_login", None)
|
||||||
|
if not current_user.has_permission(Permission.ScoUsersChangeCASId):
|
||||||
|
vals.pop("cas_id", None)
|
||||||
if "edit" in vals:
|
if "edit" in vals:
|
||||||
edit = int(vals["edit"])
|
edit = int(vals["edit"])
|
||||||
else:
|
else:
|
||||||
|
28
migrations/versions/5731e904baac_cas_last_login.py
Normal file
28
migrations/versions/5731e904baac_cas_last_login.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""CAS last login
|
||||||
|
|
||||||
|
Revision ID: 5731e904baac
|
||||||
|
Revises: 4c19fcb42636
|
||||||
|
Create Date: 2023-03-02 11:36:58.465579
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "5731e904baac"
|
||||||
|
down_revision = "4c19fcb42636"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column("user", sa.Column("cas_last_login", sa.DateTime(), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column("user", "cas_last_login")
|
||||||
|
# ### end Alembic commands ###
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.4.58"
|
SCOVERSION = "9.4.59"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user