forked from ScoDoc/ScoDoc
API users: password, plus de tests unitaires, correctifs.
This commit is contained in:
parent
64f9de95a5
commit
c6a99dc7d2
@ -14,9 +14,9 @@ from flask_login import current_user, login_required
|
|||||||
|
|
||||||
from app import db, log
|
from app import db, log
|
||||||
from app.api import api_bp as bp, api_web_bp
|
from app.api import api_bp as bp, api_web_bp
|
||||||
from app.models.etudiants import Identite
|
|
||||||
from app.scodoc.sco_utils import json_error
|
from app.scodoc.sco_utils import json_error
|
||||||
from app.auth.models import User, Role, UserRole
|
from app.auth.models import User, Role, UserRole
|
||||||
|
from app.auth.models import is_valid_password
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
@ -38,7 +38,7 @@ def user_info(uid: int):
|
|||||||
return json_error(404, "user not found")
|
return json_error(404, "user not found")
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersView)
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersView)
|
||||||
if user.dept not in allowed_depts:
|
if (None not in allowed_depts) and (user.dept not in allowed_depts):
|
||||||
return json_error(404, "user not found")
|
return json_error(404, "user not found")
|
||||||
|
|
||||||
return jsonify(user.to_dict())
|
return jsonify(user.to_dict())
|
||||||
@ -109,7 +109,7 @@ def user_create():
|
|||||||
if dept == "@all":
|
if dept == "@all":
|
||||||
dept = None
|
dept = None
|
||||||
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
||||||
if dept not in allowed_depts:
|
if (None not in allowed_depts) and (dept not in allowed_depts):
|
||||||
return json_error(403, "user_create: departement non autorise")
|
return json_error(403, "user_create: departement non autorise")
|
||||||
if (dept is not None) and (
|
if (dept is not None) and (
|
||||||
Departement.query.filter_by(acronym=dept).first() is None
|
Departement.query.filter_by(acronym=dept).first() is None
|
||||||
@ -168,6 +168,35 @@ def user_edit(uid: int):
|
|||||||
return jsonify(user.to_dict())
|
return jsonify(user.to_dict())
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/user/<int:uid>/password", methods=["POST"])
|
||||||
|
@api_web_bp.route("/user/<int:uid>/password", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoUsersAdmin)
|
||||||
|
def user_password(uid: int):
|
||||||
|
"""Modification du mot de passe d'un utilisateur
|
||||||
|
Champs modifiables:
|
||||||
|
{
|
||||||
|
"password": str
|
||||||
|
}
|
||||||
|
Si le mot de passe ne convient pas, erreur 400.
|
||||||
|
"""
|
||||||
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
|
user: User = User.query.get_or_404(uid)
|
||||||
|
password = data.get("password")
|
||||||
|
if not password:
|
||||||
|
return json_error(404, "user_password: missing password")
|
||||||
|
if not is_valid_password(password):
|
||||||
|
return json_error(400, "user_password: invalid password")
|
||||||
|
allowed_depts = current_user.get_depts_with_permission(Permission.ScoUsersAdmin)
|
||||||
|
if (None not in allowed_depts) and ((user.dept not in allowed_depts)):
|
||||||
|
return json_error(403, "user_password: departement non autorise")
|
||||||
|
user.set_password(password)
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
return jsonify(user.to_dict())
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/user/<int:uid>/role/<string:role_name>/add", methods=["POST"])
|
@bp.route("/user/<int:uid>/role/<string:role_name>/add", methods=["POST"])
|
||||||
@api_web_bp.route("/user/<int:uid>/role/<string:role_name>/add", methods=["POST"])
|
@api_web_bp.route("/user/<int:uid>/role/<string:role_name>/add", methods=["POST"])
|
||||||
@bp.route(
|
@bp.route(
|
||||||
|
@ -51,6 +51,7 @@ print(f"API URL={API_URL}")
|
|||||||
|
|
||||||
|
|
||||||
HEADERS = get_auth_headers(API_USER, API_PASSWORD)
|
HEADERS = get_auth_headers(API_USER, API_PASSWORD)
|
||||||
|
admin_h = get_auth_headers("admin_api", "admin_api")
|
||||||
|
|
||||||
departements = GET("/departements", headers=HEADERS)
|
departements = GET("/departements", headers=HEADERS)
|
||||||
pp(departements)
|
pp(departements)
|
||||||
|
@ -76,10 +76,14 @@ def GET(path: str, headers: dict = None, errmsg=None, dept=None):
|
|||||||
return r.json() # decode la reponse JSON
|
return r.json() # decode la reponse JSON
|
||||||
|
|
||||||
|
|
||||||
def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None):
|
def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None, dept=None):
|
||||||
"""Post"""
|
"""Post"""
|
||||||
|
if dept:
|
||||||
|
url = SCODOC_URL + f"/ScoDoc/{dept}/api" + path
|
||||||
|
else:
|
||||||
|
url = API_URL + path
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
API_URL + path,
|
url,
|
||||||
json=data,
|
json=data,
|
||||||
headers=headers or {},
|
headers=headers or {},
|
||||||
verify=CHECK_CERTIFICATE,
|
verify=CHECK_CERTIFICATE,
|
||||||
|
@ -8,6 +8,7 @@ Utilisation :
|
|||||||
|
|
||||||
from tests.api.setup_test_api import (
|
from tests.api.setup_test_api import (
|
||||||
API_URL,
|
API_URL,
|
||||||
|
APIError,
|
||||||
CHECK_CERTIFICATE,
|
CHECK_CERTIFICATE,
|
||||||
GET,
|
GET,
|
||||||
POST_JSON,
|
POST_JSON,
|
||||||
@ -83,7 +84,7 @@ def test_edit_users(api_admin_headers):
|
|||||||
assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
|
assert (nb_users + 1) == len(GET("/users/query", headers=admin_h))
|
||||||
# Change le dept et rend inactif
|
# Change le dept et rend inactif
|
||||||
user = POST_JSON(
|
user = POST_JSON(
|
||||||
f"/user/edit/{user['id']}",
|
f"/user/{user['id']}/edit",
|
||||||
{"active": False, "dept": "TAPI"},
|
{"active": False, "dept": "TAPI"},
|
||||||
headers=admin_h,
|
headers=admin_h,
|
||||||
)
|
)
|
||||||
@ -129,3 +130,102 @@ def test_roles(api_admin_headers):
|
|||||||
assert set(role["permissions"]) == {"ScoView", "ScoAbsAddBillet"}
|
assert set(role["permissions"]) == {"ScoView", "ScoAbsAddBillet"}
|
||||||
ans = POST_JSON("/role/Test_Y/delete", headers=admin_h)
|
ans = POST_JSON("/role/Test_Y/delete", headers=admin_h)
|
||||||
assert ans["OK"] is True
|
assert ans["OK"] is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_modif_users_depts(api_admin_headers):
|
||||||
|
"""
|
||||||
|
Ce test vise à vérifier qu'un admin déclaré sur deux départements peut
|
||||||
|
bien modifier les utilisateurs de ses départements mais pas ceux des autres.
|
||||||
|
"""
|
||||||
|
admin_h = api_admin_headers
|
||||||
|
depts = GET("/departements", headers=admin_h)
|
||||||
|
assert len(depts) > 2
|
||||||
|
dept1, dept2, dept3 = depts[:3]
|
||||||
|
# On va utiliser les 3 1er dept (TAPI, AA, BB)
|
||||||
|
# On crée un nouvel utilisateur "chef2", admin dans les 2 premiers dept
|
||||||
|
# puis un utilisateur lambda, dans le dept 2 (AA)
|
||||||
|
chef2 = POST_JSON(
|
||||||
|
"/user/create",
|
||||||
|
{
|
||||||
|
"user_name": "chef2",
|
||||||
|
"nom": "Chef",
|
||||||
|
"prenom": "Test",
|
||||||
|
"dept": dept1["acronym"], # rattaché à dept1
|
||||||
|
},
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
role_chef = POST_JSON(
|
||||||
|
"/role/create/chef",
|
||||||
|
{"permissions": ["ScoView", "ScoUsersAdmin", "ScoUsersView"]},
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
_ = POST_JSON(
|
||||||
|
f"/user/{chef2['id']}/role/chef/add/departement/{dept1['acronym']}",
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
_ = POST_JSON(
|
||||||
|
f"/user/{chef2['id']}/role/chef/add/departement/{dept2['acronym']}",
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
# Un mot de passe trop simple:
|
||||||
|
ok = False
|
||||||
|
try:
|
||||||
|
_ = POST_JSON(
|
||||||
|
f"/user/{chef2['id']}/password",
|
||||||
|
{"password": "123456"},
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
except APIError as exc:
|
||||||
|
if exc.args[1]["status"] == 400:
|
||||||
|
ok = True
|
||||||
|
assert ok
|
||||||
|
# Un "vrai" mot de passe:
|
||||||
|
chef2_password = "17HIOPpYhabb8qw'E:/jd7FFddjd"
|
||||||
|
_ = POST_JSON(
|
||||||
|
f"/user/{chef2['id']}/password",
|
||||||
|
{"password": chef2_password},
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
# Création user lambda:
|
||||||
|
u_lambda = POST_JSON(
|
||||||
|
"/user/create",
|
||||||
|
{
|
||||||
|
"user_name": "lambda",
|
||||||
|
"nom": "Lambda",
|
||||||
|
"prenom": "Test",
|
||||||
|
"dept": dept2["acronym"],
|
||||||
|
},
|
||||||
|
headers=admin_h,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Le chef va modifier u_lambda:
|
||||||
|
chef_h = get_auth_headers(chef2["user_name"], chef2_password)
|
||||||
|
# on utilise une URL avec département car on n'a pas le droit sur tous:
|
||||||
|
u = POST_JSON(
|
||||||
|
f"/user/{u_lambda['id']}/edit",
|
||||||
|
{"nom": "toto"},
|
||||||
|
headers=chef_h,
|
||||||
|
dept=dept1["acronym"],
|
||||||
|
)
|
||||||
|
assert u["nom"] == "toto"
|
||||||
|
# Dans l'autre ?
|
||||||
|
u = POST_JSON(
|
||||||
|
f"/user/{u_lambda['id']}/edit",
|
||||||
|
{"nom": "toto"},
|
||||||
|
headers=chef_h,
|
||||||
|
dept=dept2["acronym"],
|
||||||
|
)
|
||||||
|
# mais pas dans le troisième:
|
||||||
|
ok = False
|
||||||
|
try:
|
||||||
|
u = POST_JSON(
|
||||||
|
f"/user/{u_lambda['id']}/edit",
|
||||||
|
{"nom": "toto"},
|
||||||
|
headers=chef_h,
|
||||||
|
dept=dept3["acronym"],
|
||||||
|
)
|
||||||
|
except APIError as exc:
|
||||||
|
if exc.args[1]["status"] == 401:
|
||||||
|
ok = True
|
||||||
|
assert ok
|
||||||
|
# Nettoyage:
|
||||||
|
Loading…
Reference in New Issue
Block a user