From 3272d09d13fb7265157ee87a12efbb9c826f2a9c Mon Sep 17 00:00:00 2001 From: niladic Date: Wed, 19 May 2021 11:52:14 +0200 Subject: [PATCH] =?UTF-8?q?Corrige=20les=20groupes=20non=20=C3=A9ditables?= =?UTF-8?q?=20par=20les=20responsables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/GroupController.scala | 104 +++++++++++++------------- app/controllers/UserController.scala | 27 ++++--- app/models/Authorization.scala | 24 +++++- app/models/UserGroup.scala | 5 -- app/views/allUsersByGroup.scala.html | 2 +- app/views/editGroup.scala.html | 42 +++++++++-- app/views/editMyGroups.scala.html | 2 +- 7 files changed, 125 insertions(+), 81 deletions(-) diff --git a/app/controllers/GroupController.scala b/app/controllers/GroupController.scala index 34edc991b..06e4cc049 100644 --- a/app/controllers/GroupController.scala +++ b/app/controllers/GroupController.scala @@ -4,9 +4,10 @@ import java.time.{ZoneId, ZonedDateTime} import java.util.UUID import actions.{LoginAction, RequestWithUserData} +import cats.syntax.all._ import Operators._ import javax.inject.{Inject, Singleton} -import models.{Area, Organisation, UserGroup} +import models.{Area, Authorization, Organisation, UserGroup} import models.formModels.{normalizedOptionalText, normalizedText} import org.webjars.play.WebJarsUtil import play.api.Configuration @@ -78,12 +79,14 @@ case class GroupController @Inject() ( def editGroup(id: UUID): Action[AnyContent] = loginAction.async { implicit request => withGroup(id) { group: UserGroup => - if (!group.canHaveUsersAddedBy(request.currentUser)) { - eventService.log(EditGroupUnauthorized, s"Accès non autorisé à l'edition de ce groupe") - Future( - Unauthorized("Vous ne pouvez pas éditer ce groupe : êtes-vous dans la bonne zone ?") - ) - } else { + asUserWithAuthorization(Authorization.canEditGroup(group))( + () => + ( + EditGroupUnauthorized, + s"Tentative d'accès non autorisé à l'edition du groupe ${group.id}" + ), + Unauthorized("Vous ne pouvez pas éditer ce groupe : êtes-vous dans la bonne zone ?").some + ) { () => val groupUsers = userService.byGroupIds(List(id), includeDisabled = true) eventService.log(EditGroupShowed, s"Visualise la vue de modification du groupe") val isEmpty = groupService.isGroupEmpty(group.id) @@ -151,58 +154,55 @@ case class GroupController @Inject() ( def editGroupPost(groupId: UUID): Action[AnyContent] = loginAction.async { implicit request => - asAdmin(() => EditGroupUnauthorized -> s"Accès non autorisé à l'edition de ce groupe") { () => - withGroup(groupId) { currentGroup: UserGroup => - if (not(currentGroup.canHaveUsersAddedBy(request.currentUser))) { - eventService.log( - AddUserToGroupUnauthorized, - s"L'utilisateur ${request.currentUser.id} n'est pas authorisé à ajouter des utilisateurs au groupe ${currentGroup.id}." - ) - Future( - Unauthorized("Vous n'êtes pas authorisé à ajouter des utilisateurs à ce groupe.") - ) - } else { - addGroupForm(Time.timeZoneParis) - .bindFromRequest() - .fold( - formWithError => { + withGroup(groupId) { currentGroup: UserGroup => + asUserWithAuthorization(Authorization.canEditGroup(currentGroup))( + () => + ( + EditGroupUnauthorized, + s"Tentative d'édition non autorisée du groupe ${currentGroup.id}" + ), + Unauthorized("Vous ne pouvez pas éditer ce groupe : êtes-vous dans la bonne zone ?").some + ) { () => + addGroupForm(Time.timeZoneParis) + .bindFromRequest() + .fold( + formWithError => { + eventService.log( + EditUserGroupError, + s"Tentative d'edition du groupe ${currentGroup.id} avec des erreurs de validation" + ) + Future( + Redirect(routes.GroupController.editGroup(groupId)).flashing( + "error" -> s"Impossible de modifier le groupe (erreur de formulaire) : ${formWithError.errors.mkString}" + ) + ) + }, + group => { + val newGroup = group.copy(id = groupId) + if (groupService.edit(newGroup)) { eventService.log( - EditUserGroupError, - s"Tentative d'edition du groupe ${currentGroup.id} avec des erreurs de validation" + UserGroupEdited, + s"Groupe édité ${currentGroup.toDiffLogString(newGroup)}" ) Future( - Redirect(routes.GroupController.editGroup(groupId)).flashing( - "error" -> s"Impossible de modifier le groupe (erreur de formulaire) : ${formWithError.errors.mkString}" - ) + Redirect(routes.GroupController.editGroup(groupId)) + .flashing("success" -> "Groupe modifié") ) - }, - group => { - val newGroup = group.copy(id = groupId) - if (groupService.edit(newGroup)) { - eventService.log( - UserGroupEdited, - s"Groupe édité ${currentGroup.toDiffLogString(newGroup)}" + } else { + eventService + .log( + EditUserGroupError, + s"Impossible de modifier le groupe dans la BDD ${currentGroup.toDiffLogString(newGroup)}" ) - Future( - Redirect(routes.GroupController.editGroup(groupId)) - .flashing("success" -> "Groupe modifié") - ) - } else { - eventService - .log( - EditUserGroupError, - s"Impossible de modifier le groupe dans la BDD ${currentGroup.toDiffLogString(newGroup)}" + Future( + Redirect(routes.GroupController.editGroup(groupId)) + .flashing( + "error" -> "Impossible de modifier le groupe: erreur en base de donnée" ) - Future( - Redirect(routes.GroupController.editGroup(groupId)) - .flashing( - "error" -> "Impossible de modifier le groupe: erreur en base de donnée" - ) - ) - } + ) } - ) - } + } + ) } } } diff --git a/app/controllers/UserController.scala b/app/controllers/UserController.scala index 6560561a5..a5de80039 100644 --- a/app/controllers/UserController.scala +++ b/app/controllers/UserController.scala @@ -702,10 +702,14 @@ case class UserController @Inject() ( def addPost(groupId: UUID): Action[AnyContent] = loginAction.async { implicit request => withGroup(groupId) { group: UserGroup => - if (!group.canHaveUsersAddedBy(request.currentUser)) { - eventService.log(PostAddUserUnauthorized, "Accès non autorisé à l'admin des utilisateurs") - Future(Unauthorized("Vous n'avez pas le droit de faire ça")) - } else { + asUserWithAuthorization(Authorization.canEditGroup(group))( + () => + ( + PostAddUserUnauthorized, + s"Tentative non autorisée d'ajout d'utilisateurs au groupe ${group.id}" + ), + Unauthorized("Vous ne pouvez pas ajouter des utilisateurs à ce groupe.").some + ) { () => addUsersForm .bindFromRequest() .fold( @@ -942,13 +946,14 @@ case class UserController @Inject() ( def add(groupId: UUID): Action[AnyContent] = loginAction.async { implicit request => withGroup(groupId) { group: UserGroup => - if (!group.canHaveUsersAddedBy(request.currentUser)) { - eventService.log( - ShowAddUserUnauthorized, - s"Accès non autorisé à l'admin des utilisateurs du groupe $groupId" - ) - Future(Unauthorized("Vous n'avez pas le droit de faire ça")) - } else { + asUserWithAuthorization(Authorization.canEditGroup(group))( + () => + ( + ShowAddUserUnauthorized, + s"Tentative non autorisée d'accès à l'ajout d'utilisateurs dans le groupe ${group.id}" + ), + Unauthorized("Vous ne pouvez pas ajouter des utilisateurs à ce groupe.").some + ) { () => val rows = request .getQueryString(Keys.QueryParam.rows) diff --git a/app/models/Authorization.scala b/app/models/Authorization.scala index ffcec2036..f5ca4fe0a 100644 --- a/app/models/Authorization.scala +++ b/app/models/Authorization.scala @@ -61,11 +61,14 @@ object Authorization { type Check = UserRights => Boolean + def forall[A](list: List[A], fn: A => Check): Check = + rights => list.forall(fn(_)(rights)) + def atLeastOneIsAuthorized(checks: Check*): Check = rights => checks.exists(_(rights)) def allMustBeAuthorized(checks: Check*): Check = - rights => checks.forall(_(rights)) + forall[Check](checks.toList, identity) def isInGroup(groupId: UUID): Check = _.rights.exists { @@ -115,6 +118,12 @@ object Authorization { case _ => false } + def isManagerOfGroup(groupId: UUID): Check = + _.rights.exists { + case UserRight.ManagerOfGroups(managedGroups) if managedGroups.contains(groupId) => true + case _ => false + } + def isObserver: Check = _.rights.exists { case UserRight.ObserverOfOrganisations(organisations) => organisations.nonEmpty @@ -163,8 +172,15 @@ object Authorization { def canEnableOtherUser(otherUser: User): Check = atLeastOneIsAuthorized(isAdmin, atLeastOneIsAuthorized(otherUser.groupIds.map(isInGroup): _*)) - def canEditGroups: Check = - atLeastOneIsAuthorized(isAdmin, isManager) + def canEditGroup(group: UserGroup): Check = + atLeastOneIsAuthorized( + forall(group.areaIds, isAdminOfArea), + isManagerOfGroup(group.id) + ) + + /** For organisation & areas. */ + def canEditGroupAnyField(group: UserGroup): Check = + forall(group.areaIds, isAdminOfArea) def canSeeUsers: Check = atLeastOneIsAuthorized(isAdmin, isManager, isObserver) @@ -175,6 +191,8 @@ object Authorization { def canCreateSignups: Check = isAdmin + def canEditSupportMessages: Check = isAdmin + // // Authorizations concerning Applications // diff --git a/app/models/UserGroup.scala b/app/models/UserGroup.scala index 0cd1bebe3..2c58b2272 100644 --- a/app/models/UserGroup.scala +++ b/app/models/UserGroup.scala @@ -26,11 +26,6 @@ case class UserGroup( internalSupportComment: Option[String] ) { - def canHaveUsersAddedBy(user: User): Boolean = - (user.groupAdmin && user.groupIds.contains(id)) || (user.admin && areaIds.forall( - user.areas.contains - )) - lazy val organisationSetOrDeducted: Option[Organisation] = organisation .flatMap(Organisation.byId) diff --git a/app/views/allUsersByGroup.scala.html b/app/views/allUsersByGroup.scala.html index 411d146d7..0335bc16c 100644 --- a/app/views/allUsersByGroup.scala.html +++ b/app/views/allUsersByGroup.scala.html @@ -125,7 +125,7 @@ @user.name (@user.qualite) / }
} - @if(Authorization.canEditGroups(currentUserRights)) { + @if(Authorization.canEditGroup(userGroup)(currentUserRights)) { @helper.form(routes.UserController.add(userGroup.id), "method" -> "get") { @helper.CSRF.formField
diff --git a/app/views/editGroup.scala.html b/app/views/editGroup.scala.html index a81026783..9269cedca 100644 --- a/app/views/editGroup.scala.html +++ b/app/views/editGroup.scala.html @@ -1,3 +1,5 @@ +@import models.Authorization + @(currentUser: User, currentUserRights: Authorization.UserRights)(userGroup: UserGroup, groupUsers: List[User], isEmpty: Boolean)(implicit webJarsUtil: org.webjars.play.WebJarsUtil, flash: Flash, request: RequestHeader) @@ -5,6 +7,10 @@ }{ + +@defining(Authorization.canEditGroup(userGroup)(currentUserRights)) { canEdit => +@defining(Authorization.canEditGroupAnyField(userGroup)(currentUserRights)) { canEditAny => +
Territoires : @for(areaId <- userGroup.areaIds) { @{Area.fromId(areaId).get.name} @@ -12,16 +18,16 @@ @helper.form(routes.GroupController.editGroupPost(userGroup.id), "method" -> "post") { @helper.CSRF.formField
- +
- +
- +
@@ -33,27 +39,42 @@
}
- +
- @for(organisation <- Organisation.all) { } + @if(!canEditAny) { + + }
- @for(area <- currentUser.areas.flatMap(Area.fromId)) { } + @if(!canEditAny) { + + }
- @if(currentUser.admin) { + @if(Authorization.canEditSupportMessages(currentUserRights)) {
@@ -67,7 +88,7 @@ value="@userGroup.internalSupportComment"> } - @if(currentUser.admin) { + @if(canEdit) {
+ + + +} +} }{ } diff --git a/app/views/editMyGroups.scala.html b/app/views/editMyGroups.scala.html index 9c0eff4bd..2b3fb498d 100644 --- a/app/views/editMyGroups.scala.html +++ b/app/views/editMyGroups.scala.html @@ -39,7 +39,7 @@ @for(userGroup <- userGroups.sortBy(_.name)) { @defining(users.filter(_.groupIds.contains(userGroup.id))) { groupUsers => @display(groupUsers, userGroup.id) { - @if(Authorization.canEditGroups(currentUserRights)) { + @if(Authorization.canEditGroup(userGroup)(currentUserRights)) { @userGroup.name } else { @userGroup.name