-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
1943: Fix permission checks and reuse user checks #1944
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,74 +4,54 @@ | |||||||||||||||||||||
import app.ehrenamtskarte.backend.auth.webservice.schema.types.Role | ||||||||||||||||||||||
import app.ehrenamtskarte.backend.common.webservice.EAK_BAYERN_PROJECT | ||||||||||||||||||||||
import app.ehrenamtskarte.backend.common.webservice.KOBLENZ_PASS_PROJECT | ||||||||||||||||||||||
import app.ehrenamtskarte.backend.projects.database.ProjectEntity | ||||||||||||||||||||||
import app.ehrenamtskarte.backend.projects.database.Projects | ||||||||||||||||||||||
import app.ehrenamtskarte.backend.regions.database.RegionEntity | ||||||||||||||||||||||
import org.jetbrains.exposed.sql.transactions.transaction | ||||||||||||||||||||||
|
||||||||||||||||||||||
object Authorizer { | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayCreateCardInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role in setOf( | ||||||||||||||||||||||
Role.REGION_MANAGER.db_value, | ||||||||||||||||||||||
Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_MANAGER, Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayDeleteCardInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role in setOf( | ||||||||||||||||||||||
Role.REGION_MANAGER.db_value, | ||||||||||||||||||||||
Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_MANAGER, Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewApplicationsInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role in setOf( | ||||||||||||||||||||||
Role.REGION_MANAGER.db_value, | ||||||||||||||||||||||
Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_MANAGER, Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayUpdateApplicationsInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role in setOf( | ||||||||||||||||||||||
Role.REGION_MANAGER.db_value, | ||||||||||||||||||||||
Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_MANAGER, Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayDeleteApplicationsInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role in setOf( | ||||||||||||||||||||||
Role.REGION_MANAGER.db_value, | ||||||||||||||||||||||
Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_MANAGER, Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayUpdateSettingsInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role == Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewUsersInProject(user: AdministratorEntity?, projectId: Int): Boolean { | ||||||||||||||||||||||
return user?.projectId?.value == projectId && user.role == Role.PROJECT_ADMIN.db_value | ||||||||||||||||||||||
fun mayViewUsersInProject(user: AdministratorEntity, projectId: Int): Boolean { | ||||||||||||||||||||||
return user.isProject(projectId) && user.isRole(Role.PROJECT_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewUsersInRegion(user: AdministratorEntity?, region: RegionEntity): Boolean { | ||||||||||||||||||||||
return (user?.role == Role.REGION_ADMIN.db_value && user.regionId == region.id) || | ||||||||||||||||||||||
mayViewUsersInProject(user, region.projectId.value) | ||||||||||||||||||||||
fun mayViewUsersInRegion(user: AdministratorEntity, region: RegionEntity): Boolean { | ||||||||||||||||||||||
return mayViewUsersInProject(user, region.projectId.value) || | ||||||||||||||||||||||
(user.isRole(Role.REGION_ADMIN) && user.isRegion(region.id.value)) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun maySendMailsInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.regionId?.value == regionId && user.role in setOf( | ||||||||||||||||||||||
Role.REGION_MANAGER.db_value, | ||||||||||||||||||||||
Role.REGION_ADMIN.db_value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
return user.isRegion(regionId) && user.isRole(Role.REGION_MANAGER, Role.REGION_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewCardStatisticsInProject(user: AdministratorEntity?, projectId: Int): Boolean { | ||||||||||||||||||||||
return user?.projectId?.value == projectId && user.role == Role.PROJECT_ADMIN.db_value | ||||||||||||||||||||||
fun mayViewCardStatisticsInProject(user: AdministratorEntity, projectId: Int): Boolean { | ||||||||||||||||||||||
return user.isProject(projectId) && user.isRole(Role.PROJECT_ADMIN) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewCardStatisticsInRegion(user: AdministratorEntity?, region: RegionEntity): Boolean { | ||||||||||||||||||||||
return user?.role == Role.REGION_ADMIN.db_value && user.regionId == region.id | ||||||||||||||||||||||
fun mayViewCardStatisticsInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.isRole(Role.REGION_ADMIN) && user.isRegion(regionId) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayCreateUser( | ||||||||||||||||||||||
|
@@ -80,30 +60,19 @@ | |||||||||||||||||||||
newAdminRole: Role, | ||||||||||||||||||||||
newAdminRegion: RegionEntity? | ||||||||||||||||||||||
): Boolean { | ||||||||||||||||||||||
if (actingAdmin.projectId.value != newAdminProjectId) { | ||||||||||||||||||||||
return false | ||||||||||||||||||||||
} else if (newAdminRole == Role.NO_RIGHTS) { | ||||||||||||||||||||||
if (actingAdmin.projectId.value != newAdminProjectId || newAdminRole == Role.NO_RIGHTS) { | ||||||||||||||||||||||
return false | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (actingAdmin.role == Role.PROJECT_ADMIN.db_value && newAdminRole == Role.EXTERNAL_VERIFIED_API_USER) { | ||||||||||||||||||||||
return transaction { | ||||||||||||||||||||||
ProjectEntity.find { Projects.project eq EAK_BAYERN_PROJECT } | ||||||||||||||||||||||
.single().id.value == actingAdmin.projectId.value | ||||||||||||||||||||||
if (actingAdmin.isRole(Role.PROJECT_ADMIN)) { | ||||||||||||||||||||||
return newAdminRole != Role.EXTERNAL_VERIFIED_API_USER || transaction { | ||||||||||||||||||||||
actingAdmin.isProject( | ||||||||||||||||||||||
EAK_BAYERN_PROJECT | ||||||||||||||||||||||
) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+67
to
71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like negating statements, using disjunctions, and packing everything into a return statement makes it harder to read (at least for me).
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, negating should be avoided if possible. Will adjust accordingly. |
||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (actingAdmin.role == Role.PROJECT_ADMIN.db_value) { | ||||||||||||||||||||||
return true | ||||||||||||||||||||||
} else if ( | ||||||||||||||||||||||
actingAdmin.role == Role.REGION_ADMIN.db_value && | ||||||||||||||||||||||
return actingAdmin.isRole(Role.REGION_ADMIN) && | ||||||||||||||||||||||
newAdminRegion != null && actingAdmin.regionId == newAdminRegion.id && | ||||||||||||||||||||||
newAdminRole in setOf(Role.REGION_ADMIN, Role.REGION_MANAGER) | ||||||||||||||||||||||
Check warning on line 75 in backend/src/main/kotlin/app/ehrenamtskarte/backend/auth/service/Authorizer.kt
|
||||||||||||||||||||||
) { | ||||||||||||||||||||||
return true | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
return false | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayEditUser( | ||||||||||||||||||||||
|
@@ -113,74 +82,54 @@ | |||||||||||||||||||||
newAdminRole: Role, | ||||||||||||||||||||||
newAdminRegion: RegionEntity? | ||||||||||||||||||||||
): Boolean { | ||||||||||||||||||||||
if (actingAdmin.projectId.value != newAdminProjectId || existingAdmin.projectId.value != newAdminProjectId) { | ||||||||||||||||||||||
return false | ||||||||||||||||||||||
} else if (newAdminRole == Role.NO_RIGHTS) { | ||||||||||||||||||||||
if (!actingAdmin.isProject(newAdminProjectId) || !existingAdmin.isProject(newAdminProjectId) || newAdminRole == Role.NO_RIGHTS) { | ||||||||||||||||||||||
Check warning on line 85 in backend/src/main/kotlin/app/ehrenamtskarte/backend/auth/service/Authorizer.kt
|
||||||||||||||||||||||
return false | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (actingAdmin.role == Role.PROJECT_ADMIN.db_value) { | ||||||||||||||||||||||
return true | ||||||||||||||||||||||
} else if ( | ||||||||||||||||||||||
actingAdmin.role == Role.REGION_ADMIN.db_value && | ||||||||||||||||||||||
if (actingAdmin.isRole(Role.PROJECT_ADMIN)) { | ||||||||||||||||||||||
return newAdminRole != Role.EXTERNAL_VERIFIED_API_USER || transaction { | ||||||||||||||||||||||
actingAdmin.isProject( | ||||||||||||||||||||||
EAK_BAYERN_PROJECT | ||||||||||||||||||||||
) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+89
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is new, aligns behavior with create user |
||||||||||||||||||||||
} | ||||||||||||||||||||||
return actingAdmin.isRole(Role.REGION_ADMIN) && | ||||||||||||||||||||||
existingAdmin.regionId == actingAdmin.regionId && | ||||||||||||||||||||||
newAdminRegion != null && actingAdmin.regionId == newAdminRegion.id && | ||||||||||||||||||||||
newAdminRole in setOf(Role.REGION_ADMIN, Role.REGION_MANAGER) | ||||||||||||||||||||||
) { | ||||||||||||||||||||||
return true | ||||||||||||||||||||||
} | ||||||||||||||||||||||
return false | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayDeleteUser( | ||||||||||||||||||||||
actingAdmin: AdministratorEntity, | ||||||||||||||||||||||
existingAdmin: AdministratorEntity | ||||||||||||||||||||||
): Boolean { | ||||||||||||||||||||||
if (actingAdmin.projectId.value != existingAdmin.projectId.value && existingAdmin.role != Role.NO_RIGHTS.db_value) { | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why should we not delete a user if it has no rights? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I know, a user has the NO_RIGHTS if and only if the user is deleted. (This might have changed though). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for clarifying 👍 |
||||||||||||||||||||||
fun mayDeleteUser(actingAdmin: AdministratorEntity, existingAdmin: AdministratorEntity): Boolean { | ||||||||||||||||||||||
if (actingAdmin.projectId != existingAdmin.projectId) { | ||||||||||||||||||||||
return false | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
if (actingAdmin.role == Role.PROJECT_ADMIN.db_value) { | ||||||||||||||||||||||
return true | ||||||||||||||||||||||
} else if (actingAdmin.role == Role.REGION_ADMIN.db_value && existingAdmin.regionId == actingAdmin.regionId) { | ||||||||||||||||||||||
if (actingAdmin.isRole(Role.PROJECT_ADMIN)) { | ||||||||||||||||||||||
return true | ||||||||||||||||||||||
} | ||||||||||||||||||||||
return false | ||||||||||||||||||||||
return actingAdmin.isRole(Role.REGION_ADMIN) && existingAdmin.regionId == actingAdmin.regionId | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayUpdateStoresInProject(user: AdministratorEntity, projectId: Int): Boolean { | ||||||||||||||||||||||
return user.projectId.value == projectId && user.role == Role.PROJECT_STORE_MANAGER.db_value | ||||||||||||||||||||||
return user.projectId.value == projectId && user.isRole(Role.PROJECT_STORE_MANAGER) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewFreinetAgencyInformationInRegion(user: AdministratorEntity, regionId: Int): Boolean { | ||||||||||||||||||||||
return user.role == Role.REGION_ADMIN.db_value && ProjectEntity.find { Projects.project eq EAK_BAYERN_PROJECT } | ||||||||||||||||||||||
.single().id.value == user.projectId.value && user.regionId?.value == regionId | ||||||||||||||||||||||
return user.isRole(Role.REGION_ADMIN) && user.isProject(EAK_BAYERN_PROJECT) && user.isRegion(regionId) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayAddApiTokensInProject(user: AdministratorEntity): Boolean { | ||||||||||||||||||||||
return transaction { | ||||||||||||||||||||||
( | ||||||||||||||||||||||
user.role == Role.PROJECT_ADMIN.db_value && ProjectEntity.find { Projects.project eq KOBLENZ_PASS_PROJECT } | ||||||||||||||||||||||
.single().id.value == user.projectId.value | ||||||||||||||||||||||
) || | ||||||||||||||||||||||
( | ||||||||||||||||||||||
user.role == Role.EXTERNAL_VERIFIED_API_USER.db_value && ProjectEntity.find { Projects.project eq EAK_BAYERN_PROJECT } | ||||||||||||||||||||||
.single().id.value == user.projectId.value | ||||||||||||||||||||||
) | ||||||||||||||||||||||
(user.isRole(Role.PROJECT_ADMIN) && user.isProject(KOBLENZ_PASS_PROJECT)) || | ||||||||||||||||||||||
(user.isRole(Role.EXTERNAL_VERIFIED_API_USER) && user.isProject(EAK_BAYERN_PROJECT)) | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
119
to
124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wild :D (not your changes, but the fact that we actually make such distinctions between projects for the roles. I feel like this is going to get confusing very quickly, when we have more than 3 projects) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. @f1sh1918 do you have any more insights whether we actually have to distinguish between projects here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes i'm also not super happy with this implementation. I think the main aspect was not to create a separate role for that because it would be more effort. Which we in the end did for verein360 since we had to ensure that they don't get project admin rights as a third party provider, but that wasn't planned so far when we implemented that for koblenz.. I think it would be easier and cleaner to also use this separate role for koblenz (like for eak) My suggestion would be to add the ability for koblenz to create As a third step it would probably make sense to add RBAC and also be able to have different roles as a user so someone could be |
||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayViewApiMetadataInProject(user: AdministratorEntity): Boolean = | ||||||||||||||||||||||
user.role == Role.PROJECT_ADMIN.db_value || user.role == Role.EXTERNAL_VERIFIED_API_USER.db_value | ||||||||||||||||||||||
user.isRole(Role.PROJECT_ADMIN) || user.isRole(Role.EXTERNAL_VERIFIED_API_USER) | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun mayDeleteApiTokensInProject(user: AdministratorEntity): Boolean = | ||||||||||||||||||||||
user.role == Role.PROJECT_ADMIN.db_value || user.role == Role.EXTERNAL_VERIFIED_API_USER.db_value | ||||||||||||||||||||||
user.isRole(Role.PROJECT_ADMIN) || user.isRole(Role.EXTERNAL_VERIFIED_API_USER) | ||||||||||||||||||||||
|
||||||||||||||||||||||
fun maySeeHashingPepper(user: AdministratorEntity): Boolean { | ||||||||||||||||||||||
return transaction { | ||||||||||||||||||||||
ProjectEntity.find { Projects.project eq KOBLENZ_PASS_PROJECT } | ||||||||||||||||||||||
.single().id.value == user.projectId.value && | ||||||||||||||||||||||
user.role == Role.PROJECT_ADMIN.db_value | ||||||||||||||||||||||
} | ||||||||||||||||||||||
fun mayViewHashingPepper(user: AdministratorEntity): Boolean { | ||||||||||||||||||||||
return transaction { user.isProject(KOBLENZ_PASS_PROJECT) && user.isRole(Role.PROJECT_ADMIN) } | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't
hasRole
make more sense?Similarly, I'd prefer
isInProject
andisInRegion
?Or maybe
roleIs
,projectIs
andregionIs
?