From 49a03a57cb5868dc4b1d05fa8ef63940578c600a Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 22 Jan 2021 22:07:25 +0100 Subject: [PATCH] Rename Voter to AccessControl --- src/main/kotlin/application/Application.kt | 4 +- src/main/kotlin/application/KoinModule.kt | 38 +++++------ ...rticleVoter.kt => ArticleAccessControl.kt} | 14 ++-- .../article/routes/FindArticleVersions.kt | 8 +-- .../component/article/routes/FindArticles.kt | 8 +-- .../component/article/routes/GetOneArticle.kt | 8 +-- .../component/article/routes/UpsertArticle.kt | 8 +-- ...itizenVoter.kt => CitizenAccessControl.kt} | 14 ++-- .../citizen/routes/ChangeMyPassword.kt | 8 +-- .../component/citizen/routes/FindCitizens.kt | 8 +-- .../citizen/routes/GetCurrentCitizen.kt | 8 +-- .../component/citizen/routes/GetOneCitizen.kt | 8 +-- .../article/routes/CreateCommentArticle.kt | 8 +-- .../article/routes/GetArticleComments.kt | 8 +-- .../routes/GetCitizenArticleComments.kt | 8 +-- ...ommentVoter.kt => CommentAccessControl.kt} | 14 ++-- .../generic/routes/CreateCommentChildren.kt | 8 +-- .../comment/generic/routes/EditComment.kt | 8 +-- .../generic/routes/GetCommentChildren.kt | 8 +-- .../comment/generic/routes/GetOneComment.kt | 8 +-- ...{FollowVoter.kt => FollowAccessControl.kt} | 14 ++-- .../follow/routes/article/FollowArticle.kt | 8 +-- .../follow/routes/article/GetFollowArticle.kt | 8 +-- .../routes/article/GetMyFollowsArticle.kt | 8 +-- .../follow/routes/article/UnfollowArticle.kt | 8 +-- .../routes/constitution/FollowConstitution.kt | 8 +-- .../constitution/GetFollowConstitution.kt | 8 +-- .../constitution/GetMyFollowsConstitution.kt | 8 +-- .../constitution/UnfollowConstitution.kt | 8 +-- ...pinionVoter.kt => OpinionAccessControl.kt} | 16 ++--- ...Voter.kt => OpinionChoiceAccessControl.kt} | 10 +-- .../opinion/routes/GetCitizenOpinions.kt | 8 +-- .../opinion/routes/GetMyOpinionsArticle.kt | 8 +-- .../opinion/routes/GetOpinionChoice.kt | 8 +-- .../opinion/routes/GetOpinionChoices.kt | 8 +-- .../opinion/routes/OpinionArticle.kt | 8 +-- .../{VoteVoter.kt => VoteAccessControl.kt} | 12 ++-- .../component/vote/routes/GetCitizenVotes.kt | 8 +-- .../vote/routes/GetCitizenVotesOnArticle.kt | 8 +-- .../component/vote/routes/PutVoteOnArticle.kt | 8 +-- .../component/vote/routes/PutVoteOnComment.kt | 8 +-- .../component/vote/routes/VoteConstitution.kt | 8 +-- ...roupVoter.kt => WorkgroupAccessControl.kt} | 22 +++---- .../workgroup/routes/CreateWorkgroup.kt | 8 +-- .../workgroup/routes/DeleteWorkgroup.kt | 8 +-- .../workgroup/routes/EditWorkgroup.kt | 8 +-- .../workgroup/routes/GetWorkgroup.kt | 8 +-- .../workgroup/routes/GetWorkgroups.kt | 8 +-- .../routes/members/AddMemberToWorkgroup.kt | 8 +-- .../members/DeleteMembersOfWorkgroup.kt | 8 +-- .../routes/members/UpdateMemberOfWorkgroup.kt | 8 +-- src/main/kotlin/routes/CommentConstitution.kt | 12 ++-- src/main/kotlin/routes/Constitution.kt | 12 ++-- .../AccessControlModule.kt} | 64 +++++++++---------- .../voter/ConstitutionAccessControl.kt} | 16 ++--- .../ArticleAccessControlTest.kt} | 56 ++++++++-------- .../CitizenAccessControlTest.kt} | 40 ++++++------ .../CommentAccessControlTest.kt} | 44 ++++++------- .../FollowAccessControlTest.kt} | 44 ++++++------- .../OpinionAccessControlTest.kt} | 40 ++++++------ .../OpinionChoiceAccessControlTest.kt} | 18 +++--- .../VoteAccessControlTest.kt} | 36 +++++------ .../WorkgroupAccessControlTest.kt} | 56 ++++++++-------- 63 files changed, 462 insertions(+), 462 deletions(-) rename src/main/kotlin/component/article/{ArticleVoter.kt => ArticleAccessControl.kt} (86%) rename src/main/kotlin/component/citizen/{CitizenVoter.kt => CitizenAccessControl.kt} (75%) rename src/main/kotlin/component/comment/generic/{CommentVoter.kt => CommentAccessControl.kt} (84%) rename src/main/kotlin/component/follow/{FollowVoter.kt => FollowAccessControl.kt} (65%) rename src/main/kotlin/component/opinion/{OpinionVoter.kt => OpinionAccessControl.kt} (70%) rename src/main/kotlin/component/opinion/{OpinionChoiceVoter.kt => OpinionChoiceAccessControl.kt} (55%) rename src/main/kotlin/component/vote/{VoteVoter.kt => VoteAccessControl.kt} (74%) rename src/main/kotlin/component/workgroup/{WorkgroupVoter.kt => WorkgroupAccessControl.kt} (86%) rename src/main/kotlin/{voter/VoterModule.kt => security/AccessControlModule.kt} (51%) rename src/main/kotlin/{voter/ConstitutionVoter.kt => security/voter/ConstitutionAccessControl.kt} (78%) rename src/test/kotlin/unit/{voter/ArticleVoterTest.kt => security/ArticleAccessControlTest.kt} (76%) rename src/test/kotlin/unit/{voter/CitizenVoterTest.kt => security/CitizenAccessControlTest.kt} (76%) rename src/test/kotlin/unit/{voter/CommentVoterTest.kt => security/CommentAccessControlTest.kt} (81%) rename src/test/kotlin/unit/{voter/FollowVoterTest.kt => security/FollowAccessControlTest.kt} (81%) rename src/test/kotlin/unit/{voter/OpinionVoterTest.kt => security/OpinionAccessControlTest.kt} (79%) rename src/test/kotlin/unit/{voter/OpinionChoiceVoterTest.kt => security/OpinionChoiceAccessControlTest.kt} (83%) rename src/test/kotlin/unit/{voter/VoteVoterTest.kt => security/VoteAccessControlTest.kt} (84%) rename src/test/kotlin/unit/{voter/WorkgroupVoterTest.kt => security/WorkgroupAccessControlTest.kt} (77%) diff --git a/src/main/kotlin/application/Application.kt b/src/main/kotlin/application/Application.kt index 7e32e15..47411be 100644 --- a/src/main/kotlin/application/Application.kt +++ b/src/main/kotlin/application/Application.kt @@ -28,7 +28,7 @@ import fr.dcproject.routes.commentConstitution import fr.dcproject.routes.constitution import fr.dcproject.routes.definition import fr.dcproject.routes.notificationArticle -import fr.dcproject.voter.VoterDeniedException +import fr.dcproject.security.AccessDeniedException import fr.postgresjson.migration.Migrations import io.ktor.application.Application import io.ktor.application.call @@ -166,7 +166,7 @@ fun Application.module(env: Env = PROD) { exception { e -> call.respond(HttpStatusCode.NotFound, e.message!!) } - exception { + exception { if (call.user == null) call.respond(HttpStatusCode.Unauthorized) else call.respond(HttpStatusCode.Forbidden) } diff --git a/src/main/kotlin/application/KoinModule.kt b/src/main/kotlin/application/KoinModule.kt index 9d046a0..965a332 100644 --- a/src/main/kotlin/application/KoinModule.kt +++ b/src/main/kotlin/application/KoinModule.kt @@ -8,31 +8,31 @@ import com.fasterxml.jackson.databind.module.SimpleModule import com.fasterxml.jackson.datatype.joda.JodaModule import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.rabbitmq.client.ConnectionFactory +import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.article.ArticleViewManager -import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.auth.PasswordlessAuth import fr.dcproject.component.auth.UserRepository +import fr.dcproject.component.citizen.CitizenAccessControl import fr.dcproject.component.citizen.CitizenRepository -import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.component.comment.article.CommentArticleRepository -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.component.follow.FollowVoter +import fr.dcproject.component.comment.generic.CommentAccessControl +import fr.dcproject.component.follow.FollowAccessControl +import fr.dcproject.component.opinion.OpinionAccessControl +import fr.dcproject.component.opinion.OpinionChoiceAccessControl import fr.dcproject.component.opinion.OpinionChoiceRepository -import fr.dcproject.component.opinion.OpinionChoiceVoter -import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteArticleRepository import fr.dcproject.component.vote.VoteCommentRepository import fr.dcproject.component.vote.VoteConstitutionRepository import fr.dcproject.component.vote.VoteRepository -import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.event.publisher.Publisher import fr.dcproject.messages.Mailer import fr.dcproject.messages.NotificationEmailSender import fr.dcproject.repository.CommentConstitutionRepository -import fr.dcproject.security.voter.ConstitutionVoter +import fr.dcproject.security.voter.ConstitutionAccessControl import fr.postgresjson.connexion.Connection import fr.postgresjson.connexion.Requester import fr.postgresjson.migration.Migrations @@ -125,16 +125,16 @@ val KoinModule = module { single { OpinionArticleRepository(get()) } single { WorkgroupRepository(get()) } - // Voters - single { ArticleVoter(get()) } - single { CitizenVoter() } - single { CommentVoter() } - single { WorkgroupVoter() } - single { ConstitutionVoter() } - single { VoteVoter() } - single { FollowVoter() } - single { OpinionVoter() } - single { OpinionChoiceVoter() } + // AccessControl + single { ArticleAccessControl(get()) } + single { CitizenAccessControl() } + single { CommentAccessControl() } + single { WorkgroupAccessControl() } + single { ConstitutionAccessControl() } + single { VoteAccessControl() } + single { FollowAccessControl() } + single { OpinionAccessControl() } + single { OpinionChoiceAccessControl() } // Elasticsearch Client single { diff --git a/src/main/kotlin/component/article/ArticleVoter.kt b/src/main/kotlin/component/article/ArticleAccessControl.kt similarity index 86% rename from src/main/kotlin/component/article/ArticleVoter.kt rename to src/main/kotlin/component/article/ArticleAccessControl.kt index c43f57d..28873ce 100644 --- a/src/main/kotlin/component/article/ArticleVoter.kt +++ b/src/main/kotlin/component/article/ArticleAccessControl.kt @@ -3,20 +3,20 @@ package fr.dcproject.component.article import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.CreatedBy import fr.dcproject.entity.VersionableRef -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse -class ArticleVoter(private val articleRepo: ArticleRepository) : Voter() { - fun > canView(subjects: List, citizen: CitizenI?): VoterResponse = +class ArticleAccessControl(private val articleRepo: ArticleRepository) : AccessControl() { + fun > canView(subjects: List, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun > canView(subject: S, citizen: CitizenI?): VoterResponse { + fun > canView(subject: S, citizen: CitizenI?): AccessResponse { return if (subject.isDeleted()) denied("Article is deleted", "article.deleted") else if (subject.draft && (citizen == null || subject.createdBy.id != citizen.id)) denied("Article is draft, but it's not yours", "article.draft.not.yours") else granted() } - fun > canDelete(subject: S, citizen: CitizenI?): VoterResponse { + fun > canDelete(subject: S, citizen: CitizenI?): AccessResponse { if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected") return if (subject.createdBy.id == citizen.id) { granted() @@ -25,7 +25,7 @@ class ArticleVoter(private val articleRepo: ArticleRepository) : Voter() { } } - fun canUpsert(subject: S, citizen: CitizenI?): VoterResponse + fun canUpsert(subject: S, citizen: CitizenI?): AccessResponse where S : ArticleI, S : CreatedBy<*>, S : VersionableRef { diff --git a/src/main/kotlin/component/article/routes/FindArticleVersions.kt b/src/main/kotlin/component/article/routes/FindArticleVersions.kt index 38b883e..09fa170 100644 --- a/src/main/kotlin/component/article/routes/FindArticleVersions.kt +++ b/src/main/kotlin/component/article/routes/FindArticleVersions.kt @@ -1,10 +1,10 @@ package fr.dcproject.component.article.routes +import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRepository -import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import fr.postgresjson.repository.RepositoryI import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI @@ -31,10 +31,10 @@ object FindArticleVersions { private fun ArticleRepository.findVersions(request: ArticleVersionsRequest) = findVersionsByVersionId(request.page, request.limit, request.article.versionId) - fun Route.findArticleVersions(repo: ArticleRepository, voter: ArticleVoter) { + fun Route.findArticleVersions(repo: ArticleRepository, ac: ArticleAccessControl) { get { repo.findVersions(it) - .apply { voter.assert { canView(it.article, citizenOrNull) } } + .apply { ac.assert { canView(it.article, citizenOrNull) } } .let { call.respond(it) } } } diff --git a/src/main/kotlin/component/article/routes/FindArticles.kt b/src/main/kotlin/component/article/routes/FindArticles.kt index 9989c96..d16a4f7 100644 --- a/src/main/kotlin/component/article/routes/FindArticles.kt +++ b/src/main/kotlin/component/article/routes/FindArticles.kt @@ -1,12 +1,12 @@ package fr.dcproject.component.article.routes +import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.ArticleForListing import fr.dcproject.component.article.ArticleRepository -import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import fr.postgresjson.connexion.Paginated import fr.postgresjson.repository.RepositoryI import io.ktor.application.call @@ -40,10 +40,10 @@ object FindArticles { ) } - fun Route.findArticles(repo: ArticleRepository, voter: ArticleVoter) { + fun Route.findArticles(repo: ArticleRepository, ac: ArticleAccessControl) { get { repo.findArticles(it) - .apply { voter.assert { canView(result, citizenOrNull) } } + .apply { ac.assert { canView(result, citizenOrNull) } } .let { call.respond(it) } } } diff --git a/src/main/kotlin/component/article/routes/GetOneArticle.kt b/src/main/kotlin/component/article/routes/GetOneArticle.kt index bc5229f..2da147a 100644 --- a/src/main/kotlin/component/article/routes/GetOneArticle.kt +++ b/src/main/kotlin/component/article/routes/GetOneArticle.kt @@ -1,9 +1,9 @@ package fr.dcproject.component.article.routes +import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.article.ArticleViewManager -import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.article.routes.GetOneArticle.ArticleRequest.Output import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.opinion.dto.Opinionable @@ -11,7 +11,7 @@ import fr.dcproject.component.vote.dto.Votable import fr.dcproject.dto.CreatedAt import fr.dcproject.dto.Versionable import fr.dcproject.dto.Viewable -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.features.NotFoundException import io.ktor.locations.KtorExperimentalLocationsAPI @@ -53,9 +53,9 @@ object GetOneArticle { } } - fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) { + fun Route.getOneArticle(viewManager: ArticleViewManager, ac: ArticleAccessControl) { get { - voter.assert { canView(it.article, citizenOrNull) } + ac.assert { canView(it.article, citizenOrNull) } Output( it.article, diff --git a/src/main/kotlin/component/article/routes/UpsertArticle.kt b/src/main/kotlin/component/article/routes/UpsertArticle.kt index 67366b2..816d27e 100644 --- a/src/main/kotlin/component/article/routes/UpsertArticle.kt +++ b/src/main/kotlin/component/article/routes/UpsertArticle.kt @@ -1,9 +1,9 @@ package fr.dcproject.component.article.routes +import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.ArticleForUpdate import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRepository -import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.article.routes.UpsertArticle.UpsertArticleRequest.Input import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull @@ -11,7 +11,7 @@ import fr.dcproject.component.workgroup.WorkgroupRef import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.event.ArticleUpdate import fr.dcproject.event.raiseEvent -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.ApplicationCall import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI @@ -39,7 +39,7 @@ object UpsertArticle { ) } - fun Route.upsertArticle(repo: ArticleRepository, workgroupRepository: WorkgroupRepository, voter: ArticleVoter) { + fun Route.upsertArticle(repo: ArticleRepository, workgroupRepository: WorkgroupRepository, ac: ArticleAccessControl) { suspend fun ApplicationCall.convertRequestToEntity(): ArticleForUpdate = receive().run { ArticleForUpdate( id = id ?: UUID.randomUUID(), @@ -57,7 +57,7 @@ object UpsertArticle { post { val article = call.convertRequestToEntity() - voter.assert { canUpsert(article, citizenOrNull) } + ac.assert { canUpsert(article, citizenOrNull) } val newArticle: ArticleForView = repo.upsert(article) ?: error("Article not updated") call.respond(newArticle) raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle)) diff --git a/src/main/kotlin/component/citizen/CitizenVoter.kt b/src/main/kotlin/component/citizen/CitizenAccessControl.kt similarity index 75% rename from src/main/kotlin/component/citizen/CitizenVoter.kt rename to src/main/kotlin/component/citizen/CitizenAccessControl.kt index 71db36a..2ec336c 100644 --- a/src/main/kotlin/component/citizen/CitizenVoter.kt +++ b/src/main/kotlin/component/citizen/CitizenAccessControl.kt @@ -1,25 +1,25 @@ package fr.dcproject.component.citizen -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse import fr.postgresjson.entity.EntityDeletedAt -class CitizenVoter : Voter() { - fun canView(subjects: List, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S : EntityDeletedAt = +class CitizenAccessControl : AccessControl() { + fun canView(subjects: List, connectedCitizen: CitizenI?): AccessResponse where S : CitizenI, S : EntityDeletedAt = canAll(subjects) { canView(it, connectedCitizen) } - fun canView(subject: S, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S : EntityDeletedAt { + fun canView(subject: S, connectedCitizen: CitizenI?): AccessResponse where S : CitizenI, S : EntityDeletedAt { if (connectedCitizen == null) return denied("You must be connected to view citizen", "citizen.view.connected") return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted") else granted() } - fun canUpdate(subject: S, connectedCitizen: CitizenI?): VoterResponse { + fun canUpdate(subject: S, connectedCitizen: CitizenI?): AccessResponse { if (connectedCitizen == null) return denied("You must be connected to update Citizen", "citizen.update.notConnected") return if (subject.id == connectedCitizen.id) granted() else denied("You can only update your citizen", "citizen.update.notYours") } - fun canChangePassword(subject: S, connectedCitizen: CitizenI?): VoterResponse { + fun canChangePassword(subject: S, connectedCitizen: CitizenI?): AccessResponse { if (connectedCitizen == null) return denied("You must be connected to change your password", "citizen.changePassword.notConnected") return if (subject.id == connectedCitizen.id) granted() else denied("You can only change your password", "citizen.password.notYours") } diff --git a/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt b/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt index d4b8e14..249596a 100644 --- a/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt +++ b/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt @@ -5,8 +5,8 @@ import fr.dcproject.component.auth.UserRepository import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen -import fr.dcproject.component.citizen.CitizenVoter -import fr.dcproject.voter.assert +import fr.dcproject.component.citizen.CitizenAccessControl +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.auth.UserPasswordCredential import io.ktor.http.HttpStatusCode @@ -24,9 +24,9 @@ object ChangeMyPassword { data class Input(val oldPassword: String, val newPassword: String) } - fun Route.changeMyPassword(voter: CitizenVoter, userRepository: UserRepository) { + fun Route.changeMyPassword(ac: CitizenAccessControl, userRepository: UserRepository) { put { - voter.assert { canChangePassword(it.citizen, citizenOrNull) } + ac.assert { canChangePassword(it.citizen, citizenOrNull) } try { val content = call.receive() val currentUser = userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) diff --git a/src/main/kotlin/component/citizen/routes/FindCitizens.kt b/src/main/kotlin/component/citizen/routes/FindCitizens.kt index 5cfd454..d6b35d9 100644 --- a/src/main/kotlin/component/citizen/routes/FindCitizens.kt +++ b/src/main/kotlin/component/citizen/routes/FindCitizens.kt @@ -1,11 +1,11 @@ package fr.dcproject.component.citizen.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.citizen.CitizenAccessControl import fr.dcproject.component.citizen.CitizenRepository -import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import fr.postgresjson.repository.RepositoryI import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI @@ -25,10 +25,10 @@ object FindCitizens { val search: String? = null ) : PaginatedRequestI by PaginatedRequest(page, limit) - fun Route.findCitizen(voter: CitizenVoter, repo: CitizenRepository) { + fun Route.findCitizen(ac: CitizenAccessControl, repo: CitizenRepository) { get { val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search) - voter.assert { canView(citizens.result, citizenOrNull) } + ac.assert { canView(citizens.result, citizenOrNull) } call.respond(citizens) } } diff --git a/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt b/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt index a0b9e3c..4cdd71b 100644 --- a/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt +++ b/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt @@ -2,8 +2,8 @@ package fr.dcproject.component.citizen.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.citizen.CitizenVoter -import fr.dcproject.voter.assert +import fr.dcproject.component.citizen.CitizenAccessControl +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -17,13 +17,13 @@ object GetCurrentCitizen { @Location("/citizens/current") class CurrentCitizenRequest - fun Route.getCurrentCitizen(voter: CitizenVoter) { + fun Route.getCurrentCitizen(ac: CitizenAccessControl) { get { val currentUser = citizenOrNull if (currentUser === null) { call.respond(HttpStatusCode.Unauthorized) } else { - voter.assert { canView(currentUser, citizenOrNull) } + ac.assert { canView(currentUser, citizenOrNull) } call.respond(citizen) } } diff --git a/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt b/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt index ea52c67..3a92903 100644 --- a/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt +++ b/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt @@ -2,8 +2,8 @@ package fr.dcproject.component.citizen.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen -import fr.dcproject.component.citizen.CitizenVoter -import fr.dcproject.voter.assert +import fr.dcproject.component.citizen.CitizenAccessControl +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -16,9 +16,9 @@ object GetOneCitizen { @Location("/citizens/{citizen}") class CitizenRequest(val citizen: Citizen) - fun Route.getOneCitizen(voter: CitizenVoter) { + fun Route.getOneCitizen(ac: CitizenAccessControl) { get { - voter.assert { canView(it.citizen, citizenOrNull) } + ac.assert { canView(it.citizen, citizenOrNull) } call.respond(it.citizen) } diff --git a/src/main/kotlin/component/comment/article/routes/CreateCommentArticle.kt b/src/main/kotlin/component/comment/article/routes/CreateCommentArticle.kt index 4080cfd..32a63b8 100644 --- a/src/main/kotlin/component/comment/article/routes/CreateCommentArticle.kt +++ b/src/main/kotlin/component/comment/article/routes/CreateCommentArticle.kt @@ -4,9 +4,9 @@ import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.comment.article.CommentArticleRepository +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentForUpdate -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.ApplicationCall import io.ktor.application.call import io.ktor.http.HttpStatusCode @@ -36,10 +36,10 @@ object CreateCommentArticle { } } - fun Route.createCommentArticle(repo: CommentArticleRepository, voter: CommentVoter) { + fun Route.createCommentArticle(repo: CommentArticleRepository, ac: CommentAccessControl) { post { it.getComment(call).let { comment -> - voter.assert { canCreate(comment, citizenOrNull) } + ac.assert { canCreate(comment, citizenOrNull) } repo.comment(comment) call.respond(HttpStatusCode.Created, comment) } diff --git a/src/main/kotlin/component/comment/article/routes/GetArticleComments.kt b/src/main/kotlin/component/comment/article/routes/GetArticleComments.kt index 0b01ece..92fc428 100644 --- a/src/main/kotlin/component/comment/article/routes/GetArticleComments.kt +++ b/src/main/kotlin/component/comment/article/routes/GetArticleComments.kt @@ -3,10 +3,10 @@ package fr.dcproject.component.comment.article.routes import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.comment.article.CommentArticleRepository -import fr.dcproject.component.comment.generic.CommentVoter +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -28,11 +28,11 @@ object GetArticleComments { val sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.fromString(sort) ?: CommentArticleRepository.Sort.CREATED_AT } - fun Route.getArticleComments(repo: CommentArticleRepository, voter: CommentVoter) { + fun Route.getArticleComments(repo: CommentArticleRepository, ac: CommentAccessControl) { get { val comment = repo.findByTarget(it.article, it.page, it.limit, it.sort) if (comment.result.isNotEmpty()) { - voter.assert { canView(comment.result, citizenOrNull) } + ac.assert { canView(comment.result, citizenOrNull) } } call.respond(HttpStatusCode.OK, comment) } diff --git a/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt b/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt index 349af1f..8536e1d 100644 --- a/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt +++ b/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt @@ -3,8 +3,8 @@ package fr.dcproject.component.comment.article.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.comment.article.CommentArticleRepository -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.voter.assert +import fr.dcproject.component.comment.generic.CommentAccessControl +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -17,10 +17,10 @@ object GetCitizenArticleComments { @Location("/citizens/{citizen}/comments/articles") class CitizenCommentArticleRequest(val citizen: Citizen) - fun Route.getCitizenArticleComments(repo: CommentArticleRepository, voter: CommentVoter) { + fun Route.getCitizenArticleComments(repo: CommentArticleRepository, ac: CommentAccessControl) { get { repo.findByCitizen(it.citizen).let { comments -> - voter.assert { canView(comments.result, citizenOrNull) } + ac.assert { canView(comments.result, citizenOrNull) } call.respond(comments) } } diff --git a/src/main/kotlin/component/comment/generic/CommentVoter.kt b/src/main/kotlin/component/comment/generic/CommentAccessControl.kt similarity index 84% rename from src/main/kotlin/component/comment/generic/CommentVoter.kt rename to src/main/kotlin/component/comment/generic/CommentAccessControl.kt index ca82c52..2fa3994 100644 --- a/src/main/kotlin/component/comment/generic/CommentVoter.kt +++ b/src/main/kotlin/component/comment/generic/CommentAccessControl.kt @@ -2,24 +2,24 @@ package fr.dcproject.component.comment.generic import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.HasTarget -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse import fr.postgresjson.entity.EntityCreatedBy import fr.postgresjson.entity.EntityDeletedAt -class CommentVoter : Voter() { - fun canView(subjects: List, citizen: CitizenI?): VoterResponse +class CommentAccessControl : AccessControl() { + fun canView(subjects: List, citizen: CitizenI?): AccessResponse where S : CommentI, S : EntityDeletedAt = canAll(subjects) { canView(it, citizen) } - fun canView(subject: S, citizen: CitizenI?): VoterResponse + fun canView(subject: S, citizen: CitizenI?): AccessResponse where S : CommentI, S : EntityDeletedAt = when { subject.isDeleted() -> denied("Your cannot view a deleted comment", "comment.view.deleted") else -> granted() } - fun canCreate(subject: S, citizen: CitizenI?): VoterResponse + fun canCreate(subject: S, citizen: CitizenI?): AccessResponse where S : CommentI, S : EntityCreatedBy, S : CommentWithParentI<*>, @@ -31,7 +31,7 @@ class CommentVoter : Voter() { else -> granted() } - fun canUpdate(subject: S, citizen: CitizenI?): VoterResponse + fun canUpdate(subject: S, citizen: CitizenI?): AccessResponse where S : CommentI, S : EntityCreatedBy = when { citizen == null -> denied("You must be connected to update comment", "comment.update.notConnected") diff --git a/src/main/kotlin/component/comment/generic/routes/CreateCommentChildren.kt b/src/main/kotlin/component/comment/generic/routes/CreateCommentChildren.kt index a6c0389..3185e62 100644 --- a/src/main/kotlin/component/comment/generic/routes/CreateCommentChildren.kt +++ b/src/main/kotlin/component/comment/generic/routes/CreateCommentChildren.kt @@ -2,11 +2,11 @@ package fr.dcproject.component.comment.generic.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentForUpdate import fr.dcproject.component.comment.generic.CommentRef import fr.dcproject.component.comment.generic.CommentRepository -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.features.NotFoundException import io.ktor.http.HttpStatusCode @@ -24,7 +24,7 @@ object CreateCommentChildren { class Input(val content: String) } - fun Route.createCommentChildren(repo: CommentRepository, voter: CommentVoter) { + fun Route.createCommentChildren(repo: CommentRepository, ac: CommentAccessControl) { post { val parent = repo.findById(it.comment.id) ?: throw NotFoundException("Comment not found") val newComment = CommentForUpdate( @@ -33,7 +33,7 @@ object CreateCommentChildren { parent = parent ) - voter.assert { canCreate(newComment, citizenOrNull) } + ac.assert { canCreate(newComment, citizenOrNull) } repo.comment(newComment) call.respond(HttpStatusCode.Created, newComment) diff --git a/src/main/kotlin/component/comment/generic/routes/EditComment.kt b/src/main/kotlin/component/comment/generic/routes/EditComment.kt index 86862b8..556cc5b 100644 --- a/src/main/kotlin/component/comment/generic/routes/EditComment.kt +++ b/src/main/kotlin/component/comment/generic/routes/EditComment.kt @@ -1,10 +1,10 @@ package fr.dcproject.component.comment.generic.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentRef import fr.dcproject.component.comment.generic.CommentRepository -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.features.NotFoundException import io.ktor.http.HttpStatusCode @@ -20,10 +20,10 @@ object EditComment { @Location("/comments/{comment}") class EditCommentRequest(val comment: CommentRef) - fun Route.editComment(repo: CommentRepository, voter: CommentVoter) { + fun Route.editComment(repo: CommentRepository, ac: CommentAccessControl) { put { val comment = repo.findById(it.comment.id) ?: throw NotFoundException("Comment not found") - voter.assert { canUpdate(comment, citizenOrNull) } + ac.assert { canUpdate(comment, citizenOrNull) } comment.content = call.receiveText() repo.edit(comment) diff --git a/src/main/kotlin/component/comment/generic/routes/GetCommentChildren.kt b/src/main/kotlin/component/comment/generic/routes/GetCommentChildren.kt index d9b0716..dfef745 100644 --- a/src/main/kotlin/component/comment/generic/routes/GetCommentChildren.kt +++ b/src/main/kotlin/component/comment/generic/routes/GetCommentChildren.kt @@ -1,11 +1,11 @@ package fr.dcproject.component.comment.generic.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentRepository -import fr.dcproject.component.comment.generic.CommentVoter import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -25,7 +25,7 @@ object GetCommentChildren { val search: String? = null ) : PaginatedRequestI by PaginatedRequest(page, limit) - fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) { + fun Route.getChildrenComments(repo: CommentRepository, ac: CommentAccessControl) { get { val comments = repo.findByParent( @@ -34,7 +34,7 @@ object GetCommentChildren { it.limit ) - voter.assert { canView(comments.result, citizenOrNull) } + ac.assert { canView(comments.result, citizenOrNull) } call.respond(HttpStatusCode.OK, comments) } diff --git a/src/main/kotlin/component/comment/generic/routes/GetOneComment.kt b/src/main/kotlin/component/comment/generic/routes/GetOneComment.kt index 826596b..fa02f76 100644 --- a/src/main/kotlin/component/comment/generic/routes/GetOneComment.kt +++ b/src/main/kotlin/component/comment/generic/routes/GetOneComment.kt @@ -1,10 +1,10 @@ package fr.dcproject.component.comment.generic.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentRef import fr.dcproject.component.comment.generic.CommentRepository -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.features.NotFoundException import io.ktor.http.HttpStatusCode @@ -19,10 +19,10 @@ object GetOneComment { @Location("/comments/{comment}") class CommentRequest(val comment: CommentRef) - fun Route.getOneComment(repo: CommentRepository, voter: CommentVoter) { + fun Route.getOneComment(repo: CommentRepository, ac: CommentAccessControl) { get { val comment = repo.findById(it.comment.id) ?: throw NotFoundException("Comment ${it.comment.id} not found") - voter.assert { canView(comment, citizenOrNull) } + ac.assert { canView(comment, citizenOrNull) } call.respond(HttpStatusCode.OK, comment) } diff --git a/src/main/kotlin/component/follow/FollowVoter.kt b/src/main/kotlin/component/follow/FollowAccessControl.kt similarity index 65% rename from src/main/kotlin/component/follow/FollowVoter.kt rename to src/main/kotlin/component/follow/FollowAccessControl.kt index f0f512f..91fe910 100644 --- a/src/main/kotlin/component/follow/FollowVoter.kt +++ b/src/main/kotlin/component/follow/FollowAccessControl.kt @@ -1,25 +1,25 @@ package fr.dcproject.component.follow import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse import fr.dcproject.component.follow.Follow as FollowEntity -class FollowVoter : Voter() { - fun canCreate(subject: FollowI, citizen: CitizenI?): VoterResponse { +class FollowAccessControl : AccessControl() { + fun canCreate(subject: FollowI, citizen: CitizenI?): AccessResponse { return if (citizen == null) denied("You must be connected to follow", "follow.create.notConnected") else granted() } - fun canDelete(subject: FollowI, citizen: CitizenI?): VoterResponse { + fun canDelete(subject: FollowI, citizen: CitizenI?): AccessResponse { return if (citizen == null) denied("You must be connected to unfollow", "follow.delete.notConnected") else granted() } - fun > canView(subjects: List, citizen: CitizenI?): VoterResponse = + fun > canView(subjects: List, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun canView(subject: FollowEntity<*>, citizen: CitizenI?): VoterResponse { + fun canView(subject: FollowEntity<*>, citizen: CitizenI?): AccessResponse { return if ((citizen != null && subject.createdBy.id == citizen.id) || !subject.createdBy.followAnonymous) granted() else denied("You cannot view an anonymous follow", "follow.view.anonymous") } diff --git a/src/main/kotlin/component/follow/routes/article/FollowArticle.kt b/src/main/kotlin/component/follow/routes/article/FollowArticle.kt index 159942a..c43c5c9 100644 --- a/src/main/kotlin/component/follow/routes/article/FollowArticle.kt +++ b/src/main/kotlin/component/follow/routes/article/FollowArticle.kt @@ -3,10 +3,10 @@ package fr.dcproject.component.follow.routes.article import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowArticleRepository import fr.dcproject.component.follow.FollowForUpdate -import fr.dcproject.component.follow.FollowVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -20,10 +20,10 @@ object FollowArticle { @Location("/articles/{article}/follows") class ArticleFollowRequest(val article: ArticleRef) - fun Route.followArticle(repo: FollowArticleRepository, voter: FollowVoter) { + fun Route.followArticle(repo: FollowArticleRepository, ac: FollowAccessControl) { post { val follow = FollowForUpdate(target = it.article, createdBy = this.citizen) - voter.assert { canCreate(follow, citizenOrNull) } + ac.assert { canCreate(follow, citizenOrNull) } repo.follow(follow) call.respond(HttpStatusCode.Created) } diff --git a/src/main/kotlin/component/follow/routes/article/GetFollowArticle.kt b/src/main/kotlin/component/follow/routes/article/GetFollowArticle.kt index dc64741..5592ad3 100644 --- a/src/main/kotlin/component/follow/routes/article/GetFollowArticle.kt +++ b/src/main/kotlin/component/follow/routes/article/GetFollowArticle.kt @@ -3,9 +3,9 @@ package fr.dcproject.component.follow.routes.article import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowArticleRepository -import fr.dcproject.component.follow.FollowVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -19,10 +19,10 @@ object GetFollowArticle { @Location("/articles/{article}/follows") class ArticleFollowRequest(val article: ArticleRef) - fun Route.getFollowArticle(repo: FollowArticleRepository, voter: FollowVoter) { + fun Route.getFollowArticle(repo: FollowArticleRepository, ac: FollowAccessControl) { get { repo.findFollow(citizen, it.article)?.let { follow -> - voter.assert { canView(follow, citizenOrNull) } + ac.assert { canView(follow, citizenOrNull) } call.respond(follow) } ?: call.respond(HttpStatusCode.NoContent) } diff --git a/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt b/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt index d8ae528..6aaa267 100644 --- a/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt +++ b/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt @@ -2,9 +2,9 @@ package fr.dcproject.component.follow.routes.article import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowArticleRepository -import fr.dcproject.component.follow.FollowVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -17,10 +17,10 @@ object GetMyFollowsArticle { @Location("/citizens/{citizen}/follows/articles") class CitizenFollowArticleRequest(val citizen: Citizen) - fun Route.getMyFollowsArticle(repo: FollowArticleRepository, voter: FollowVoter) { + fun Route.getMyFollowsArticle(repo: FollowArticleRepository, ac: FollowAccessControl) { get { val follows = repo.findByCitizen(it.citizen) - voter.assert { canView(follows.result, citizenOrNull) } + ac.assert { canView(follows.result, citizenOrNull) } call.respond(follows) } } diff --git a/src/main/kotlin/component/follow/routes/article/UnfollowArticle.kt b/src/main/kotlin/component/follow/routes/article/UnfollowArticle.kt index 943c48a..d353171 100644 --- a/src/main/kotlin/component/follow/routes/article/UnfollowArticle.kt +++ b/src/main/kotlin/component/follow/routes/article/UnfollowArticle.kt @@ -3,10 +3,10 @@ package fr.dcproject.component.follow.routes.article import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowArticleRepository import fr.dcproject.component.follow.FollowForUpdate -import fr.dcproject.component.follow.FollowVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -20,10 +20,10 @@ object UnfollowArticle { @Location("/articles/{article}/follows") class ArticleFollowRequest(val article: ArticleRef) - fun Route.unfollowArticle(repo: FollowArticleRepository, voter: FollowVoter) { + fun Route.unfollowArticle(repo: FollowArticleRepository, ac: FollowAccessControl) { delete { val follow = FollowForUpdate(target = it.article, createdBy = this.citizen) - voter.assert { canDelete(follow, citizenOrNull) } + ac.assert { canDelete(follow, citizenOrNull) } repo.unfollow(follow) call.respond(HttpStatusCode.NoContent) } diff --git a/src/main/kotlin/component/follow/routes/constitution/FollowConstitution.kt b/src/main/kotlin/component/follow/routes/constitution/FollowConstitution.kt index 1130c85..7ea62a7 100644 --- a/src/main/kotlin/component/follow/routes/constitution/FollowConstitution.kt +++ b/src/main/kotlin/component/follow/routes/constitution/FollowConstitution.kt @@ -2,11 +2,11 @@ package fr.dcproject.component.follow.routes.constitution import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowConstitutionRepository import fr.dcproject.component.follow.FollowForUpdate -import fr.dcproject.component.follow.FollowVoter import fr.dcproject.entity.ConstitutionRef -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -20,10 +20,10 @@ object FollowConstitution { @Location("/constitutions/{constitution}/follows") class ConstitutionFollowRequest(val constitution: ConstitutionRef) - fun Route.followConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) { + fun Route.followConstitution(repo: FollowConstitutionRepository, ac: FollowAccessControl) { post { val follow = FollowForUpdate(target = it.constitution, createdBy = this.citizen) - voter.assert { canCreate(follow, citizenOrNull) } + ac.assert { canCreate(follow, citizenOrNull) } repo.follow(follow) call.respond(HttpStatusCode.Created) } diff --git a/src/main/kotlin/component/follow/routes/constitution/GetFollowConstitution.kt b/src/main/kotlin/component/follow/routes/constitution/GetFollowConstitution.kt index 9988adc..fc121ec 100644 --- a/src/main/kotlin/component/follow/routes/constitution/GetFollowConstitution.kt +++ b/src/main/kotlin/component/follow/routes/constitution/GetFollowConstitution.kt @@ -2,10 +2,10 @@ package fr.dcproject.component.follow.routes.constitution import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowConstitutionRepository -import fr.dcproject.component.follow.FollowVoter import fr.dcproject.entity.ConstitutionRef -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -19,10 +19,10 @@ object GetFollowConstitution { @Location("/constitutions/{constitution}/follows") class ConstitutionFollowRequest(val constitution: ConstitutionRef) - fun Route.getFollowConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) { + fun Route.getFollowConstitution(repo: FollowConstitutionRepository, ac: FollowAccessControl) { get { repo.findFollow(citizen, it.constitution)?.let { follow -> - voter.assert { canView(follow, citizenOrNull) } + ac.assert { canView(follow, citizenOrNull) } call.respond(follow) } ?: call.respond(HttpStatusCode.NotFound) } diff --git a/src/main/kotlin/component/follow/routes/constitution/GetMyFollowsConstitution.kt b/src/main/kotlin/component/follow/routes/constitution/GetMyFollowsConstitution.kt index 4cd78c2..7bb15a0 100644 --- a/src/main/kotlin/component/follow/routes/constitution/GetMyFollowsConstitution.kt +++ b/src/main/kotlin/component/follow/routes/constitution/GetMyFollowsConstitution.kt @@ -2,9 +2,9 @@ package fr.dcproject.component.follow.routes.constitution import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowConstitutionRepository -import fr.dcproject.component.follow.FollowVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -17,10 +17,10 @@ object GetMyFollowsConstitution { @Location("/citizens/{citizen}/follows/constitutions") class CitizenFollowConstitutionRequest(val citizen: CitizenRef) - fun Route.getMyFollowsConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) { + fun Route.getMyFollowsConstitution(repo: FollowConstitutionRepository, ac: FollowAccessControl) { get { val follows = repo.findByCitizen(it.citizen) - voter.assert { canView(follows.result, citizenOrNull) } + ac.assert { canView(follows.result, citizenOrNull) } call.respond(follows) } } diff --git a/src/main/kotlin/component/follow/routes/constitution/UnfollowConstitution.kt b/src/main/kotlin/component/follow/routes/constitution/UnfollowConstitution.kt index 9f80002..261fbab 100644 --- a/src/main/kotlin/component/follow/routes/constitution/UnfollowConstitution.kt +++ b/src/main/kotlin/component/follow/routes/constitution/UnfollowConstitution.kt @@ -2,11 +2,11 @@ package fr.dcproject.component.follow.routes.constitution import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowConstitutionRepository import fr.dcproject.component.follow.FollowForUpdate -import fr.dcproject.component.follow.FollowVoter import fr.dcproject.entity.ConstitutionRef -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -20,10 +20,10 @@ object UnfollowConstitution { @Location("/constitutions/{constitution}/follows") class ConstitutionUnfollowRequest(val constitution: ConstitutionRef) - fun Route.unfollowConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) { + fun Route.unfollowConstitution(repo: FollowConstitutionRepository, ac: FollowAccessControl) { delete { val follow = FollowForUpdate(target = it.constitution, createdBy = this.citizen) - voter.assert { canDelete(follow, citizenOrNull) } + ac.assert { canDelete(follow, citizenOrNull) } repo.unfollow(follow) call.respond(HttpStatusCode.NoContent) } diff --git a/src/main/kotlin/component/opinion/OpinionVoter.kt b/src/main/kotlin/component/opinion/OpinionAccessControl.kt similarity index 70% rename from src/main/kotlin/component/opinion/OpinionVoter.kt rename to src/main/kotlin/component/opinion/OpinionAccessControl.kt index e72d192..3294d36 100644 --- a/src/main/kotlin/component/opinion/OpinionVoter.kt +++ b/src/main/kotlin/component/opinion/OpinionAccessControl.kt @@ -3,17 +3,17 @@ package fr.dcproject.component.opinion import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.opinion.entity.OpinionI import fr.dcproject.entity.HasTarget -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse import fr.postgresjson.entity.EntityCreatedBy import fr.postgresjson.entity.EntityDeletedAt -class OpinionVoter : Voter() { +class OpinionAccessControl : AccessControl() { - fun canCreate(subjects: List, citizen: CitizenI?): VoterResponse where S : OpinionI, S : HasTarget<*> = + fun canCreate(subjects: List, citizen: CitizenI?): AccessResponse where S : OpinionI, S : HasTarget<*> = canAll(subjects) { canCreate(it, citizen) } - fun canCreate(subject: S, citizen: CitizenI?): VoterResponse where S : OpinionI, S : HasTarget<*> { + fun canCreate(subject: S, citizen: CitizenI?): AccessResponse where S : OpinionI, S : HasTarget<*> { val target = subject.target return when { citizen == null -> denied("You must be connected to make an opinion", "opinion.create.notConnected") @@ -22,12 +22,12 @@ class OpinionVoter : Voter() { } } - fun > canView(subjects: SS, citizen: CitizenI?): VoterResponse = + fun > canView(subjects: SS, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun canView(subject: S, citizen: CitizenI?): VoterResponse = granted() + fun canView(subject: S, citizen: CitizenI?): AccessResponse = granted() - fun canDelete(subject: S, citizen: CitizenI?): VoterResponse where S : EntityCreatedBy, S : OpinionI = when { + fun canDelete(subject: S, citizen: CitizenI?): AccessResponse where S : EntityCreatedBy, S : OpinionI = when { citizen == null -> denied("You must be connected to delete opinion", "opinion.delete.notConnected") subject.createdBy.id != citizen.id -> denied("You can only delete your opinions", "opinion.delete.notYours") else -> granted() diff --git a/src/main/kotlin/component/opinion/OpinionChoiceVoter.kt b/src/main/kotlin/component/opinion/OpinionChoiceAccessControl.kt similarity index 55% rename from src/main/kotlin/component/opinion/OpinionChoiceVoter.kt rename to src/main/kotlin/component/opinion/OpinionChoiceAccessControl.kt index 24a9428..ac3367b 100644 --- a/src/main/kotlin/component/opinion/OpinionChoiceVoter.kt +++ b/src/main/kotlin/component/opinion/OpinionChoiceAccessControl.kt @@ -2,14 +2,14 @@ package fr.dcproject.component.opinion import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.opinion.entity.OpinionChoice -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse -class OpinionChoiceVoter : Voter() { - fun canView(subjects: List, citizen: CitizenI?): VoterResponse = +class OpinionChoiceAccessControl : AccessControl() { + fun canView(subjects: List, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun canView(subject: OpinionChoice, citizen: CitizenI?): VoterResponse { + fun canView(subject: OpinionChoice, citizen: CitizenI?): AccessResponse { return granted() } } diff --git a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt index 0825064..65449c6 100644 --- a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt +++ b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt @@ -2,10 +2,10 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.OpinionAccessControl import fr.dcproject.component.opinion.entity.Opinion +import fr.dcproject.security.assert import fr.dcproject.utils.toUUID -import fr.dcproject.voter.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -27,10 +27,10 @@ object GetCitizenOpinions { val id: List = id.toUUID() } - fun Route.getCitizenOpinions(repo: OpinionArticleRepository, voter: OpinionVoter) { + fun Route.getCitizenOpinions(repo: OpinionArticleRepository, ac: OpinionAccessControl) { get { val opinionsEntities: List> = repo.findCitizenOpinionsByTargets(it.citizen, it.id) - voter.assert { canView(opinionsEntities, citizenOrNull) } + ac.assert { canView(opinionsEntities, citizenOrNull) } call.respond(opinionsEntities) } diff --git a/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt b/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt index 747cb11..cf3f513 100644 --- a/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt +++ b/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt @@ -3,10 +3,10 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.CitizenRef -import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.OpinionAccessControl import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -27,10 +27,10 @@ object GetMyOpinionsArticle { limit: Int = 50 ) : PaginatedRequestI by PaginatedRequest(page, limit) - fun Route.getMyOpinionsArticle(repo: OpinionArticleRepository, voter: OpinionVoter) { + fun Route.getMyOpinionsArticle(repo: OpinionArticleRepository, ac: OpinionAccessControl) { get { val opinions = repo.findCitizenOpinions(citizen, it.page, it.limit) - voter.assert { canView(opinions.result, citizenOrNull) } + ac.assert { canView(opinions.result, citizenOrNull) } call.respond(opinions) } } diff --git a/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt b/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt index fb83c69..f1217c1 100644 --- a/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt +++ b/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt @@ -1,9 +1,9 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.opinion.OpinionChoiceVoter +import fr.dcproject.component.opinion.OpinionChoiceAccessControl import fr.dcproject.component.opinion.entity.OpinionChoice -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -16,9 +16,9 @@ object GetOpinionChoice { @Location("/opinions/{opinionChoice}") class OpinionChoiceRequest(val opinionChoice: OpinionChoice) - fun Route.getOpinionChoice(voter: OpinionChoiceVoter) { + fun Route.getOpinionChoice(ac: OpinionChoiceAccessControl) { get { - voter.assert { canView(it.opinionChoice, citizenOrNull) } + ac.assert { canView(it.opinionChoice, citizenOrNull) } call.respond(it.opinionChoice) } diff --git a/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt b/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt index b909f8b..85134c3 100644 --- a/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt +++ b/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt @@ -1,9 +1,9 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.OpinionChoiceAccessControl import fr.dcproject.component.opinion.OpinionChoiceRepository -import fr.dcproject.component.opinion.OpinionChoiceVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -16,10 +16,10 @@ object GetOpinionChoices { @Location("/opinions") class OpinionChoicesRequest(val targets: List = emptyList()) - fun Route.getOpinionChoices(repo: OpinionChoiceRepository, voter: OpinionChoiceVoter) { + fun Route.getOpinionChoices(repo: OpinionChoiceRepository, ac: OpinionChoiceAccessControl) { get { val opinionChoices = repo.findOpinionsChoices(it.targets) - voter.assert { canView(opinionChoices, citizenOrNull) } + ac.assert { canView(opinionChoices, citizenOrNull) } call.respond(opinionChoices) } diff --git a/src/main/kotlin/component/opinion/routes/OpinionArticle.kt b/src/main/kotlin/component/opinion/routes/OpinionArticle.kt index 0a88b3f..a8c6246 100644 --- a/src/main/kotlin/component/opinion/routes/OpinionArticle.kt +++ b/src/main/kotlin/component/opinion/routes/OpinionArticle.kt @@ -3,11 +3,11 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.OpinionAccessControl import fr.dcproject.component.opinion.entity.OpinionChoiceRef import fr.dcproject.component.opinion.entity.OpinionForUpdate +import fr.dcproject.security.assert import fr.dcproject.utils.toUUID -import fr.dcproject.voter.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -31,7 +31,7 @@ object OpinionArticle { } } - fun Route.setOpinionOnArticle(repo: OpinionArticleRepository, voter: OpinionVoter) { + fun Route.setOpinionOnArticle(repo: OpinionArticleRepository, ac: OpinionAccessControl) { put { call.receive().ids.map { id -> OpinionForUpdate( @@ -40,7 +40,7 @@ object OpinionArticle { createdBy = citizen ) }.let { opinions -> - voter.assert { canCreate(opinions, citizenOrNull) } + ac.assert { canCreate(opinions, citizenOrNull) } repo.updateOpinions(opinions) }.let { call.respond(HttpStatusCode.Created, it) diff --git a/src/main/kotlin/component/vote/VoteVoter.kt b/src/main/kotlin/component/vote/VoteAccessControl.kt similarity index 74% rename from src/main/kotlin/component/vote/VoteVoter.kt rename to src/main/kotlin/component/vote/VoteAccessControl.kt index 7f92730..7b0a246 100644 --- a/src/main/kotlin/component/vote/VoteVoter.kt +++ b/src/main/kotlin/component/vote/VoteAccessControl.kt @@ -3,22 +3,22 @@ package fr.dcproject.component.vote import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.vote.entity.VoteForUpdateI import fr.dcproject.entity.TargetI -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse import fr.postgresjson.entity.EntityDeletedAt import fr.dcproject.component.vote.entity.Vote as VoteEntity -class VoteVoter : Voter() { - fun canCreate(subject: VoteForUpdateI, citizen: CitizenI?): VoterResponse where S : EntityDeletedAt, S : TargetI = when { +class VoteAccessControl : AccessControl() { + fun canCreate(subject: VoteForUpdateI, citizen: CitizenI?): AccessResponse where S : EntityDeletedAt, S : TargetI = when { citizen == null -> denied("You must be connected for vote", "vote.create.connected") subject.target.isDeleted() -> denied("You cannot vote on deleted target", "vote.create.isDeleted") else -> granted() } - fun > canView(subjects: List, citizen: CitizenI?): VoterResponse = + fun > canView(subjects: List, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun canView(subject: VoteEntity<*>, citizen: CitizenI?): VoterResponse = when { + fun canView(subject: VoteEntity<*>, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected for view your votes", "vote.view.connected") subject.createdBy.id != citizen.id -> denied("You can only display your votes", "vote.view.onlyYours") else -> granted() diff --git a/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt b/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt index e7b7bc5..e044dcf 100644 --- a/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt +++ b/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt @@ -2,10 +2,10 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteRepository -import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.security.assert import fr.dcproject.utils.toUUID -import fr.dcproject.voter.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -21,11 +21,11 @@ object GetCitizenVotes { val id: List = id.toUUID() } - fun Route.getCitizenVote(repo: VoteRepository, voter: VoteVoter) { + fun Route.getCitizenVote(repo: VoteRepository, ac: VoteAccessControl) { get { val votes = repo.findCitizenVotesByTargets(it.citizen, it.id) if (votes.isNotEmpty()) { - voter.assert { canView(votes, citizenOrNull) } + ac.assert { canView(votes, citizenOrNull) } } call.respond(votes) } diff --git a/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt b/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt index 4a62ba7..5661f7c 100644 --- a/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt +++ b/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt @@ -2,11 +2,11 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteArticleRepository -import fr.dcproject.component.vote.VoteVoter import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -24,10 +24,10 @@ object GetCitizenVotesOnArticle { val search: String? = null ) : PaginatedRequestI by PaginatedRequest(page, limit) - fun Route.getCitizenVotesOnArticle(repo: VoteArticleRepository, voter: VoteVoter) { + fun Route.getCitizenVotesOnArticle(repo: VoteArticleRepository, ac: VoteAccessControl) { get { val votes = repo.findByCitizen(it.citizen, it.page, it.limit) - voter.assert { canView(votes.result, citizenOrNull) } + ac.assert { canView(votes.result, citizenOrNull) } call.respond(votes) } diff --git a/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt b/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt index 73f231b..3473c10 100644 --- a/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt +++ b/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt @@ -3,10 +3,10 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteArticleRepository -import fr.dcproject.component.vote.VoteVoter import fr.dcproject.component.vote.entity.VoteForUpdate -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -23,7 +23,7 @@ object PutVoteOnArticle { data class Content(var note: Int) } - fun Route.putVoteOnArticle(repo: VoteArticleRepository, voter: VoteVoter) { + fun Route.putVoteOnArticle(repo: VoteArticleRepository, ac: VoteAccessControl) { put { val content = call.receive() val vote = VoteForUpdate( @@ -31,7 +31,7 @@ object PutVoteOnArticle { note = content.note, createdBy = this.citizen ) - voter.assert { canCreate(vote, citizenOrNull) } + ac.assert { canCreate(vote, citizenOrNull) } val votes = repo.vote(vote) call.respond(HttpStatusCode.Created, votes) } diff --git a/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt b/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt index 1dc4c7e..9a38d0e 100644 --- a/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt +++ b/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt @@ -3,10 +3,10 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.comment.generic.CommentRepository +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteCommentRepository -import fr.dcproject.component.vote.VoteVoter import fr.dcproject.component.vote.entity.VoteForUpdate -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -24,7 +24,7 @@ object PutVoteOnComment { data class Content(var note: Int) } - fun Route.putVoteOnComment(voteCommentRepo: VoteCommentRepository, commentRepo: CommentRepository, voter: VoteVoter) { + fun Route.putVoteOnComment(voteCommentRepo: VoteCommentRepository, commentRepo: CommentRepository, ac: VoteAccessControl) { put { val comment = commentRepo.findById(it.comment)!! val content = call.receive() @@ -33,7 +33,7 @@ object PutVoteOnComment { note = content.note, createdBy = this.citizen ) - voter.assert { canCreate(vote, citizenOrNull) } + ac.assert { canCreate(vote, citizenOrNull) } val votes = voteCommentRepo.vote(vote) call.respond(HttpStatusCode.Created, votes) } diff --git a/src/main/kotlin/component/vote/routes/VoteConstitution.kt b/src/main/kotlin/component/vote/routes/VoteConstitution.kt index d26fb15..d29f63a 100644 --- a/src/main/kotlin/component/vote/routes/VoteConstitution.kt +++ b/src/main/kotlin/component/vote/routes/VoteConstitution.kt @@ -2,11 +2,11 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteConstitutionRepository -import fr.dcproject.component.vote.VoteVoter import fr.dcproject.component.vote.entity.VoteForUpdate import fr.dcproject.component.vote.routes.VoteConstitution.ConstitutionVoteRequest.Input -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -24,7 +24,7 @@ object VoteConstitution { data class Input(var note: Int) } - fun Route.voteConstitution(repo: VoteConstitutionRepository, voter: VoteVoter) { + fun Route.voteConstitution(repo: VoteConstitutionRepository, ac: VoteAccessControl) { put { val content = call.receive() val vote = VoteForUpdate( @@ -32,7 +32,7 @@ object VoteConstitution { note = content.note, createdBy = this.citizen ) - voter.assert { canCreate(vote, citizenOrNull) } + ac.assert { canCreate(vote, citizenOrNull) } repo.vote(vote) call.respond(HttpStatusCode.Created) } diff --git a/src/main/kotlin/component/workgroup/WorkgroupVoter.kt b/src/main/kotlin/component/workgroup/WorkgroupAccessControl.kt similarity index 86% rename from src/main/kotlin/component/workgroup/WorkgroupVoter.kt rename to src/main/kotlin/component/workgroup/WorkgroupAccessControl.kt index 6d0419c..8f8c6c4 100644 --- a/src/main/kotlin/component/workgroup/WorkgroupVoter.kt +++ b/src/main/kotlin/component/workgroup/WorkgroupAccessControl.kt @@ -2,48 +2,48 @@ package fr.dcproject.component.workgroup import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member.Role -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse -class WorkgroupVoter : Voter() { - fun canCreate(subject: WorkgroupI, citizen: CitizenI?): VoterResponse { +class WorkgroupAccessControl : AccessControl() { + fun canCreate(subject: WorkgroupI, citizen: CitizenI?): AccessResponse { if (citizen == null) return denied("You must be connected to create workgroup", "workgroup.create.notConnected") return granted() } - fun > canView(subjects: List, citizen: CitizenI?): VoterResponse = + fun > canView(subjects: List, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun canView(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = + fun canView(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): AccessResponse = if (subject.isDeleted()) denied("You cannot view a deleted workgroup", "workgroup.view.deleted") else if (!subject.anonymous) granted() else if (subject.anonymous && citizen != null && subject.isMember(citizen)) granted() else denied("You cannot view anonymous workgroup", "workgroup.view.anonymous") - fun canDelete(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse { + fun canDelete(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): AccessResponse { if (citizen == null) return denied("You must be connected to delete workgroup", "workgroup.delete.notConnected") return if (subject.hasRole(Role.MASTER, citizen)) granted() else denied("You must hase role MASTER to delete workgroup", "workgroup.delete.role") } - fun canUpdate(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse { + fun canUpdate(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): AccessResponse { if (citizen == null) return denied("You must be connected to update workgroup", "workgroup.update.notConnected") return if (subject.hasRole(Role.MASTER, citizen)) granted() else denied("You must hase role MASTER to delete workgroup", "workgroup.delete.role") } - fun canAddMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = when { + fun canAddMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected to add member to the workgroup", "workgroup.addMember.notConnected") subject.hasRole(Role.MASTER, citizen) -> granted() else -> denied("You must have MASTER Role for add member to workgroup", "workgroup.addMember.role") } - fun canUpdateMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = when { + fun canUpdateMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected to update member of the workgroup", "workgroup.updateMember.notConnected") subject.hasRole(Role.MASTER, citizen) -> granted() else -> denied("You must have MASTER Role for update members of workgroup", "workgroup.updateMember.role") } - fun canRemoveMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = when { + fun canRemoveMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected to remove member of the workgroup", "workgroup.removeMember.notConnected") subject.hasRole(Role.MASTER, citizen) -> granted() else -> denied("You must have MASTER Role for remove members of workgroup", "workgroup.removeMember.role") diff --git a/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt index 199e24b..7013258 100644 --- a/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt @@ -2,11 +2,11 @@ package fr.dcproject.component.workgroup.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupSimple -import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.routes.CreateWorkgroup.PostWorkgroupRequest.Input -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -30,7 +30,7 @@ object CreateWorkgroup { ) } - fun Route.createWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.createWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { post { call.receive().run { WorkgroupSimple( @@ -42,7 +42,7 @@ object CreateWorkgroup { citizen ) }.let { workgroup -> - voter.assert { canCreate(workgroup, citizenOrNull) } + ac.assert { canCreate(workgroup, citizenOrNull) } repo.upsert(workgroup) }.let { call.respond(HttpStatusCode.Created, it) diff --git a/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt index ca15b08..321d086 100644 --- a/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt @@ -1,9 +1,9 @@ package fr.dcproject.component.workgroup.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -18,10 +18,10 @@ object DeleteWorkgroup { @Location("/workgroups/{workgroupId}") class DeleteWorkgroupRequest(val workgroupId: UUID) - fun Route.deleteWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.deleteWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { delete { repo.findById(it.workgroupId)?.let { workgroup -> - voter.assert { canDelete(workgroup, citizenOrNull) } + ac.assert { canDelete(workgroup, citizenOrNull) } repo.delete(workgroup) call.respond(HttpStatusCode.NoContent) } ?: call.respond(HttpStatusCode.NotFound) diff --git a/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt index c805056..9652c0d 100644 --- a/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt @@ -1,10 +1,10 @@ package fr.dcproject.component.workgroup.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.routes.EditWorkgroup.PutWorkgroupRequest.Input -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -28,7 +28,7 @@ object EditWorkgroup { ) } - fun Route.editWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.editWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { put { repo.findById(it.workgroupId)?.let { old -> call.receive().run { @@ -38,7 +38,7 @@ object EditWorkgroup { logo = logo ?: old.logo, anonymous = anonymous ?: old.anonymous ).let { workgroup -> - voter.assert { canUpdate(workgroup, citizenOrNull) } + ac.assert { canUpdate(workgroup, citizenOrNull) } repo.upsert(workgroup) call.respond(HttpStatusCode.OK, it) } diff --git a/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt index 2ec6098..6d770b4 100644 --- a/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt @@ -1,9 +1,9 @@ package fr.dcproject.component.workgroup.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -18,10 +18,10 @@ object GetWorkgroup { @Location("/workgroups/{workgroupId}") class WorkgroupRequest(val workgroupId: UUID) - fun Route.getWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.getWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { get { repo.findById(it.workgroupId)?.let { workgroup -> - voter.assert { canView(workgroup, citizenOrNull) } + ac.assert { canView(workgroup, citizenOrNull) } call.respond(workgroup) } ?: call.respond(HttpStatusCode.NotFound) } diff --git a/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt b/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt index 62b5da8..0bcab68 100644 --- a/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt +++ b/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt @@ -1,10 +1,10 @@ package fr.dcproject.component.workgroup.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.security.assert import fr.dcproject.utils.toUUID -import fr.dcproject.voter.assert import fr.postgresjson.repository.RepositoryI import io.ktor.application.call import io.ktor.locations.KtorExperimentalLocationsAPI @@ -31,7 +31,7 @@ object GetWorkgroups { val members: List? = members?.toUUID() } - fun Route.getWorkgroups(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.getWorkgroups(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { get { val workgroups = repo.find( @@ -42,7 +42,7 @@ object GetWorkgroups { it.search, WorkgroupRepository.Filter(createdById = it.createdBy, members = it.members) ) - voter.assert { canView(workgroups.result, citizenOrNull) } + ac.assert { canView(workgroups.result, citizenOrNull) } call.respond(workgroups) } } diff --git a/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt index 78e2319..8f10bac 100644 --- a/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt @@ -2,10 +2,10 @@ package fr.dcproject.component.workgroup.routes.members import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.ApplicationCall import io.ktor.application.call import io.ktor.http.HttpStatusCode @@ -40,12 +40,12 @@ object AddMemberToWorkgroup { } @KtorExperimentalLocationsAPI - fun Route.addMemberToWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.addMemberToWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { /* Add members to workgroup */ post { repo.findById(it.workgroupId)?.let { workgroup -> call.getMembersFromRequest().let { members -> - voter.assert { canAddMembers(workgroup, citizenOrNull) } + ac.assert { canAddMembers(workgroup, citizenOrNull) } repo.addMembers(workgroup, members) }.let { members -> call.respond(HttpStatusCode.Created, members) diff --git a/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt index f324ffe..cbc3268 100644 --- a/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt @@ -2,10 +2,10 @@ package fr.dcproject.component.workgroup.routes.members import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.ApplicationCall import io.ktor.application.call import io.ktor.http.HttpStatusCode @@ -38,12 +38,12 @@ object DeleteMembersOfWorkgroup { ) } - fun Route.deleteMemberOfWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.deleteMemberOfWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { /* Delete members of workgroup */ delete { repo.findById(it.workgroupId)?.let { workgroup -> call.getMembersFromRequest().let { members -> - voter.assert { canView(workgroup, citizenOrNull) } + ac.assert { canView(workgroup, citizenOrNull) } repo.removeMembers(workgroup, members) }.let { members -> call.respond(HttpStatusCode.OK, members) diff --git a/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt index fa14be7..d35d2ba 100644 --- a/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt @@ -2,10 +2,10 @@ package fr.dcproject.component.workgroup.routes.members import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.ApplicationCall import io.ktor.application.call import io.ktor.http.HttpStatusCode @@ -38,12 +38,12 @@ object UpdateMemberOfWorkgroup { ) } - fun Route.updateMemberOfWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { + fun Route.updateMemberOfWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { /* Update members of workgroup */ put { repo.findById(it.workgroupId)?.let { workgroup -> call.getMembersFromRequest().let { members -> - voter.assert { canUpdateMembers(workgroup, citizenOrNull) } + ac.assert { canUpdateMembers(workgroup, citizenOrNull) } repo.updateMembers(workgroup, members) }.let { members -> call.respond(HttpStatusCode.OK, members) diff --git a/src/main/kotlin/routes/CommentConstitution.kt b/src/main/kotlin/routes/CommentConstitution.kt index 7b49b4e..e775417 100644 --- a/src/main/kotlin/routes/CommentConstitution.kt +++ b/src/main/kotlin/routes/CommentConstitution.kt @@ -3,11 +3,11 @@ package fr.dcproject.routes import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentForUpdate -import fr.dcproject.component.comment.generic.CommentVoter import fr.dcproject.entity.ConstitutionRef import fr.dcproject.repository.CommentConstitutionRepository -import fr.dcproject.voter.assert +import fr.dcproject.security.assert import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -28,10 +28,10 @@ object CommentConstitutionPaths { } @KtorExperimentalLocationsAPI -fun Route.commentConstitution(repo: CommentConstitutionRepository, voter: CommentVoter) { +fun Route.commentConstitution(repo: CommentConstitutionRepository, ac: CommentAccessControl) { get { val comments = repo.findByTarget(it.constitution) - voter.assert { canView(comments.result, citizenOrNull) } + ac.assert { canView(comments.result, citizenOrNull) } call.respond(HttpStatusCode.OK, comments) } @@ -42,7 +42,7 @@ fun Route.commentConstitution(repo: CommentConstitutionRepository, voter: Commen createdBy = citizen, content = content ) - voter.assert { canCreate(comment, citizenOrNull) } + ac.assert { canCreate(comment, citizenOrNull) } repo.comment(comment) call.respond(HttpStatusCode.Created, comment) @@ -50,7 +50,7 @@ fun Route.commentConstitution(repo: CommentConstitutionRepository, voter: Commen get { val comments = repo.findByCitizen(it.citizen) - voter.assert { canView(comments.result, citizenOrNull) } + ac.assert { canView(comments.result, citizenOrNull) } call.respond(comments) } } diff --git a/src/main/kotlin/routes/Constitution.kt b/src/main/kotlin/routes/Constitution.kt index 03e552e..e0140e4 100644 --- a/src/main/kotlin/routes/Constitution.kt +++ b/src/main/kotlin/routes/Constitution.kt @@ -6,8 +6,8 @@ import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.CitizenWithUserI import fr.dcproject.entity.ConstitutionSimple import fr.dcproject.entity.ConstitutionSimple.TitleSimple -import fr.dcproject.security.voter.ConstitutionVoter -import fr.dcproject.voter.assert +import fr.dcproject.security.assert +import fr.dcproject.security.voter.ConstitutionAccessControl import fr.postgresjson.entity.UuidEntity import fr.postgresjson.repository.RepositoryI import io.ktor.application.ApplicationCall @@ -88,21 +88,21 @@ object ConstitutionPaths { } @KtorExperimentalLocationsAPI -fun Route.constitution(repo: ConstitutionRepository, voter: ConstitutionVoter) { +fun Route.constitution(repo: ConstitutionRepository, ac: ConstitutionAccessControl) { get { val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search) - voter.assert { canView(constitutions.result, citizenOrNull) } + ac.assert { canView(constitutions.result, citizenOrNull) } call.respond(constitutions) } get { - voter.assert { canView(it.constitution, citizenOrNull) } + ac.assert { canView(it.constitution, citizenOrNull) } call.respond(it.constitution) } post { it.getNewConstitution(call).let { constitution -> - voter.assert { canCreate(constitution, citizenOrNull) } + ac.assert { canCreate(constitution, citizenOrNull) } repo.upsert(constitution) call.respond(constitution) } diff --git a/src/main/kotlin/voter/VoterModule.kt b/src/main/kotlin/security/AccessControlModule.kt similarity index 51% rename from src/main/kotlin/voter/VoterModule.kt rename to src/main/kotlin/security/AccessControlModule.kt index b85d526..1e3ff9c 100644 --- a/src/main/kotlin/voter/VoterModule.kt +++ b/src/main/kotlin/security/AccessControlModule.kt @@ -1,13 +1,13 @@ -package fr.dcproject.voter +package fr.dcproject.security -/** Responses of voters */ -enum class Vote { +/** Responses of AccessControl */ +enum class AccessDecision { GRANTED, DENIED; /** Helper to convert true/false to GRANTED/DENIED */ companion object { - fun toVote(lambda: () -> Boolean): Vote = when (lambda()) { + fun toVote(lambda: () -> Boolean): AccessDecision = when (lambda()) { true -> GRANTED false -> DENIED } @@ -22,7 +22,7 @@ enum class Vote { } } -abstract class Voter { +abstract class AccessControl { /** * A Shortcut for return a GrantedResponse */ @@ -37,20 +37,20 @@ abstract class Voter { * * If the list of responses is empty, return GRANTED */ - private fun VoterResponses.getOneResponse(): VoterResponse = this.firstOrNull { it.vote == Vote.DENIED } ?: granted() + private fun AccessResponses.getOneResponse(): AccessResponse = this.firstOrNull { it.decision == AccessDecision.DENIED } ?: granted() /** * An helper to convert a list of subject into one response */ - protected fun , T> canAll(items: S, action: (T) -> VoterResponse): VoterResponse = items + protected fun , T> canAll(items: S, action: (T) -> AccessResponse): AccessResponse = items .map { action(it) } .getOneResponse() } /** - * Throw an Exception if voter return a DENIED response + * Throw an Exception if AccessControl return a DENIED response */ -fun T.assert(action: T.() -> VoterResponse) { +fun T.assert(action: T.() -> AccessResponse) { action().assert() } @@ -59,84 +59,84 @@ fun T.assert(action: T.() -> VoterResponse) { * * If the list of responses is empty, return GRANTED */ -fun VoterResponses.getOneResponse(): VoterResponse = this.firstOrNull { it.vote == Vote.DENIED } ?: GrantedResponse(first().voter) +fun AccessResponses.getOneResponse(): AccessResponse = this.firstOrNull { it.decision == AccessDecision.DENIED } ?: GrantedResponse(first().accessControl) /** * Throw an Exception if one response is DENIED */ -fun VoterResponses.assert() = this.getOneResponse().assert() +fun AccessResponses.assert() = this.getOneResponse().assert() -class VoterDeniedException(private val voterResponses: VoterResponses) : Throwable(voterResponses.first().message) { - constructor(voterResponse: VoterResponse) : this(listOf(voterResponse)) +class AccessDeniedException(private val accessResponses: AccessResponses) : Throwable(accessResponses.first().message) { + constructor(accessResponse: AccessResponse) : this(listOf(accessResponse)) /** * Get first response */ - fun first(): VoterResponse = voterResponses.first() + fun first(): AccessResponse = accessResponses.first() /** * Check if the error code is present into the responses */ - fun hasErrorCode(code: String): Boolean = voterResponses - .filter { it.vote == Vote.DENIED } + fun hasErrorCode(code: String): Boolean = accessResponses + .filter { it.decision == AccessDecision.DENIED } .any { it.code == code } /** * Find and return the response than match with the error code */ - fun getErrorCode(code: String): VoterResponse? = voterResponses - .firstOrNull { it.vote == Vote.DENIED && it.code == code } + fun getErrorCode(code: String): AccessResponse? = accessResponses + .firstOrNull { it.decision == AccessDecision.DENIED && it.code == code } /** * Get a list of messages of all responses */ - fun getMessages(): List = voterResponses + fun getMessages(): List = accessResponses .mapNotNull { it.message } /** * Get the first message */ - fun getFirstMessage(): String? = voterResponses + fun getFirstMessage(): String? = accessResponses .first() .message } /** - * The response that all Voter method return + * The response that all AccessControl method return * @see GrantedResponse * @see DeniedResponse */ -sealed class VoterResponse( - val vote: Vote, - val voter: Voter, +sealed class AccessResponse( + val decision: AccessDecision, + val accessControl: AccessControl, val message: String?, val code: String? ) { /** * Convert response as boolean */ - fun toBoolean(): Boolean = vote.toBoolean() + fun toBoolean(): Boolean = decision.toBoolean() /** * Throw Exception if response if DENIED */ fun assert() { - if (this.vote == Vote.DENIED) { - throw VoterDeniedException(this) + if (this.decision == AccessDecision.DENIED) { + throw AccessDeniedException(this) } } } class GrantedResponse( - voter: Voter, + accessControl: AccessControl, message: String? = null, code: String? = null -) : VoterResponse(Vote.GRANTED, voter, message, code) +) : AccessResponse(AccessDecision.GRANTED, accessControl, message, code) class DeniedResponse( - voter: Voter, + accessControl: AccessControl, message: String, code: String -) : VoterResponse(Vote.DENIED, voter, message, code) +) : AccessResponse(AccessDecision.DENIED, accessControl, message, code) -typealias VoterResponses = List +typealias AccessResponses = List diff --git a/src/main/kotlin/voter/ConstitutionVoter.kt b/src/main/kotlin/security/voter/ConstitutionAccessControl.kt similarity index 78% rename from src/main/kotlin/voter/ConstitutionVoter.kt rename to src/main/kotlin/security/voter/ConstitutionAccessControl.kt index 1133ada..057d84d 100644 --- a/src/main/kotlin/voter/ConstitutionVoter.kt +++ b/src/main/kotlin/security/voter/ConstitutionAccessControl.kt @@ -3,30 +3,30 @@ package fr.dcproject.security.voter import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.ConstitutionS import fr.dcproject.entity.ConstitutionSimple -import fr.dcproject.voter.Voter -import fr.dcproject.voter.VoterResponse +import fr.dcproject.security.AccessControl +import fr.dcproject.security.AccessResponse -class ConstitutionVoter : Voter() { - fun canCreate(subject: ConstitutionS, citizen: CitizenI?): VoterResponse = when { +class ConstitutionAccessControl : AccessControl() { + fun canCreate(subject: ConstitutionS, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected to create constitution", "constitution.create.notConnected") else -> granted() } - fun > canView(subjects: List, citizen: CitizenI?): VoterResponse = + fun > canView(subjects: List, citizen: CitizenI?): AccessResponse = canAll(subjects) { canView(it, citizen) } - fun canView(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): VoterResponse = when { + fun canView(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): AccessResponse = when { subject.isDeleted() -> denied("You cannot view a deleted constitution", "constitution.view.deleted") else -> granted() } - fun canDelete(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): VoterResponse = when { + fun canDelete(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected to delete constitution", "constitution.delete.notConnected") subject.createdBy.id != citizen.id -> denied("You cannot delete the constitution of other citizen", "constitution.delete.otherCitizen") else -> granted() } - fun canUpdate(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): VoterResponse = when { + fun canUpdate(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): AccessResponse = when { citizen == null -> denied("You must be connected to update constitution", "constitution.update.notConnected") subject.createdBy.id != citizen.id -> denied("You cannot update the constitution of other citizen", "constitution.update.otherCitizen") else -> granted() diff --git a/src/test/kotlin/unit/voter/ArticleVoterTest.kt b/src/test/kotlin/unit/security/ArticleAccessControlTest.kt similarity index 76% rename from src/test/kotlin/unit/voter/ArticleVoterTest.kt rename to src/test/kotlin/unit/security/ArticleAccessControlTest.kt index 30c2409..2436f0a 100644 --- a/src/test/kotlin/unit/voter/ArticleVoterTest.kt +++ b/src/test/kotlin/unit/security/ArticleAccessControlTest.kt @@ -1,13 +1,13 @@ -package unit.voter +package unit.security +import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.ArticleForView -import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.auth.User import fr.dcproject.component.auth.UserI import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import fr.postgresjson.connexion.Paginated import io.mockk.every import io.mockk.mockk @@ -23,8 +23,8 @@ import fr.dcproject.component.article.ArticleRepository as ArticleRepo @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class ArticleVoterTest { +@Tag("security") +internal class ArticleAccessControlTest { private val tesla = CitizenCart( id = UUID.fromString("e6efc288-4283-4729-a268-6debb18de1a0"), user = User( @@ -50,35 +50,35 @@ internal class ArticleVoterTest { @Test fun `creator can be view the article`() { val article = getArticle(tesla).copy(draft = true) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canView(article, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `other user can be view the article`() { val article = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canView(article, einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test - fun `other user can be view the article list`(): Unit = listOf(ArticleVoter(mockk())).run { + fun `other user can be view the article list`(): Unit = listOf(ArticleAccessControl(mockk())).run { val article = getArticle(tesla) val article2 = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canView(listOf(article, article2), einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `the no creator can not be view the article on draft`() { val article = getArticle(tesla).copy(draft = true) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canView(article, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test @@ -86,31 +86,31 @@ internal class ArticleVoterTest { val article = getArticle(tesla) val article2 = getArticle(tesla).copy(draft = true) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canView(listOf(article, article2), einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can not view deleted article`() { val article = getArticle(tesla).copy(deletedAt = DateTime.now()) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canView(article, tesla) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can delete article if owner`() { val article = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canDelete(article, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not delete article if not owner`() { val article = getArticle(tesla).copy(deletedAt = DateTime.now()) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canDelete(article, einstein) .code `should be` "article.delete.notYours" } @@ -118,15 +118,15 @@ internal class ArticleVoterTest { @Test fun `can create article if logged`() { val article = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canUpsert(article, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not create article if not logged`() { val article = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canUpsert(article, null) .code `should be` "article.create.notConnected" } @@ -134,15 +134,15 @@ internal class ArticleVoterTest { @Test fun `can update article if yours`() { val article = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canUpsert(article, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not update article if not yours`() { val article = getArticle(tesla) - ArticleVoter(getRepo(article)) + ArticleAccessControl(getRepo(article)) .canUpsert(article, einstein) .code `should be` "article.update.notYours" } diff --git a/src/test/kotlin/unit/voter/CitizenVoterTest.kt b/src/test/kotlin/unit/security/CitizenAccessControlTest.kt similarity index 76% rename from src/test/kotlin/unit/voter/CitizenVoterTest.kt rename to src/test/kotlin/unit/security/CitizenAccessControlTest.kt index 50a2801..7fe0a07 100644 --- a/src/test/kotlin/unit/voter/CitizenVoterTest.kt +++ b/src/test/kotlin/unit/security/CitizenAccessControlTest.kt @@ -1,12 +1,12 @@ -package unit.voter +package unit.security import fr.dcproject.component.auth.User import fr.dcproject.component.auth.UserI +import fr.dcproject.component.citizen.CitizenAccessControl import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.component.citizen.CitizenVoter -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -17,8 +17,8 @@ import org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class CitizenVoterTest { +@Tag("security") +internal class CitizenAccessControlTest { private val tesla = CitizenBasic( user = User( username = "nicolas-tesla", @@ -51,50 +51,50 @@ internal class CitizenVoterTest { @Test fun `can be view the citizen`() { - CitizenVoter() + CitizenAccessControl() .canView(subject = einstein, connectedCitizen = tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view the citizen list`() { - CitizenVoter() + CitizenAccessControl() .canView(subjects = listOf(tesla, einstein), connectedCitizen = einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not view deleted citizen`() { - CitizenVoter() + CitizenAccessControl() .canView(subject = curie, connectedCitizen = tesla) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be update itself`() { - CitizenVoter() + CitizenAccessControl() .canUpdate(subject = einstein, connectedCitizen = einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be update other citizen`() { - CitizenVoter() + CitizenAccessControl() .canUpdate(subject = tesla, connectedCitizen = einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be change password of itself`() { - CitizenVoter() + CitizenAccessControl() .canChangePassword(subject = einstein, connectedCitizen = einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be change password of other citizen`() { - CitizenVoter() + CitizenAccessControl() .canChangePassword(subject = tesla, connectedCitizen = einstein) - .vote `should be` DENIED + .decision `should be` DENIED } } diff --git a/src/test/kotlin/unit/voter/CommentVoterTest.kt b/src/test/kotlin/unit/security/CommentAccessControlTest.kt similarity index 81% rename from src/test/kotlin/unit/voter/CommentVoterTest.kt rename to src/test/kotlin/unit/security/CommentAccessControlTest.kt index 2d609d8..16eb5aa 100644 --- a/src/test/kotlin/unit/voter/CommentVoterTest.kt +++ b/src/test/kotlin/unit/security/CommentAccessControlTest.kt @@ -1,4 +1,4 @@ -package unit.voter +package unit.security import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef @@ -7,11 +7,11 @@ import fr.dcproject.component.auth.UserI import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentForUpdate import fr.dcproject.component.comment.generic.CommentForView -import fr.dcproject.component.comment.generic.CommentVoter -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -23,8 +23,8 @@ import java.util.UUID @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class CommentVoterTest { +@Tag("security") +internal class CommentAccessControlTest { private val tesla = Citizen( user = User( username = "nicolas-tesla", @@ -99,57 +99,57 @@ internal class CommentVoterTest { @Test fun `can be view the comment`() { - CommentVoter() + CommentAccessControl() .canView(comment1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view the comment list`() { - CommentVoter() + CommentAccessControl() .canView(listOf(comment1, comment2), einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be update your comment`() { - CommentVoter() + CommentAccessControl() .canUpdate(comment1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be update other comment`() { - CommentVoter() + CommentAccessControl() .canUpdate(comment1, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be create a comment`() { - CommentVoter() + CommentAccessControl() .canCreate(comment1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be create a comment if target is deleted`() { - CommentVoter() + CommentAccessControl() .canCreate(commentTargetDeleted, tesla) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can not be create a comment with other creator`() { - CommentVoter() + CommentAccessControl() .canCreate(comment1, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can not be create a comment if not connected`() { - CommentVoter() + CommentAccessControl() .canCreate(comment1, null) - .vote `should be` DENIED + .decision `should be` DENIED } } diff --git a/src/test/kotlin/unit/voter/FollowVoterTest.kt b/src/test/kotlin/unit/security/FollowAccessControlTest.kt similarity index 81% rename from src/test/kotlin/unit/voter/FollowVoterTest.kt rename to src/test/kotlin/unit/security/FollowAccessControlTest.kt index d7c7113..2ec727d 100644 --- a/src/test/kotlin/unit/voter/FollowVoterTest.kt +++ b/src/test/kotlin/unit/security/FollowAccessControlTest.kt @@ -1,4 +1,4 @@ -package unit.voter +package unit.security import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.User @@ -8,9 +8,9 @@ import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.follow.Follow -import fr.dcproject.component.follow.FollowVoter -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.component.follow.FollowAccessControl +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -22,8 +22,8 @@ import java.util.UUID @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class FollowVoterTest { +@Tag("security") +internal class FollowAccessControlTest { private val tesla = CitizenBasic( user = User( username = "nicolas-tesla", @@ -97,57 +97,57 @@ internal class FollowVoterTest { @Test fun `can be view the follow`() { - FollowVoter() + FollowAccessControl() .canView(follow1, tesla2) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view the follow list`() { - FollowVoter() + FollowAccessControl() .canView(listOf(follow1), tesla2) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view your anonymous follow`() { - FollowVoter() + FollowAccessControl() .canView(followAnon, einstein3) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be view the anonymous follow of other`() { - FollowVoter() + FollowAccessControl() .canView(followAnon, tesla2) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be follow article`() { - FollowVoter() + FollowAccessControl() .canCreate(follow1, tesla2) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be follow article if not connected`() { - FollowVoter() + FollowAccessControl() .canCreate(follow1, null) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be unfollow article`() { - FollowVoter() + FollowAccessControl() .canDelete(follow1, tesla2) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be unfollow article if not connected`() { - FollowVoter() + FollowAccessControl() .canDelete(follow1, null) - .vote `should be` DENIED + .decision `should be` DENIED } } diff --git a/src/test/kotlin/unit/voter/OpinionVoterTest.kt b/src/test/kotlin/unit/security/OpinionAccessControlTest.kt similarity index 79% rename from src/test/kotlin/unit/voter/OpinionVoterTest.kt rename to src/test/kotlin/unit/security/OpinionAccessControlTest.kt index 4c1f694..31b8649 100644 --- a/src/test/kotlin/unit/voter/OpinionVoterTest.kt +++ b/src/test/kotlin/unit/security/OpinionAccessControlTest.kt @@ -1,4 +1,4 @@ -package unit.voter +package unit.security import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.User @@ -6,11 +6,11 @@ import fr.dcproject.component.auth.UserI import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.OpinionAccessControl import fr.dcproject.component.opinion.entity.Opinion import fr.dcproject.component.opinion.entity.OpinionChoice -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -22,8 +22,8 @@ import java.util.UUID @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class OpinionVoterTest { +@Tag("security") +internal class OpinionAccessControlTest { private val tesla = CitizenBasic( user = User( username = "nicolas-tesla", @@ -74,50 +74,50 @@ internal class OpinionVoterTest { @Test fun `can be view the opinion`() { - OpinionVoter() + OpinionAccessControl() .canView(opinion1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view the opinion list`() { - OpinionVoter() + OpinionAccessControl() .canView(listOf(opinion1), tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be opinion an article`() { - OpinionVoter() + OpinionAccessControl() .canCreate(opinion1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be opinion if not connected`() { - OpinionVoter() + OpinionAccessControl() .canCreate(opinion1, null) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be remove opinion`() { - OpinionVoter() + OpinionAccessControl() .canDelete(opinion1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be remove opinion if not connected`() { - OpinionVoter() + OpinionAccessControl() .canDelete(opinion1, null) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can not be remove opinion of other user`() { - OpinionVoter() + OpinionAccessControl() .canDelete(opinion1, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } } diff --git a/src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt b/src/test/kotlin/unit/security/OpinionChoiceAccessControlTest.kt similarity index 83% rename from src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt rename to src/test/kotlin/unit/security/OpinionChoiceAccessControlTest.kt index 136c124..7f2e42f 100644 --- a/src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt +++ b/src/test/kotlin/unit/security/OpinionChoiceAccessControlTest.kt @@ -1,4 +1,4 @@ -package unit.voter +package unit.security import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.User @@ -6,9 +6,9 @@ import fr.dcproject.component.auth.UserI import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.component.opinion.OpinionChoiceVoter +import fr.dcproject.component.opinion.OpinionChoiceAccessControl import fr.dcproject.component.opinion.entity.OpinionChoice -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -20,8 +20,8 @@ import java.util.UUID @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class OpinionChoiceVoterTest { +@Tag("security") +internal class OpinionChoiceAccessControlTest { private val tesla = CitizenBasic( id = UUID.fromString("e6efc288-4283-4729-a268-6debb18de1a0"), user = User( @@ -57,15 +57,15 @@ internal class OpinionChoiceVoterTest { @Test fun `can be view the opinion choice`() { - OpinionChoiceVoter() + OpinionChoiceAccessControl() .canView(choice1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view the opinion choice list`() { - OpinionChoiceVoter() + OpinionChoiceAccessControl() .canView(listOf(choice1), tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } } diff --git a/src/test/kotlin/unit/voter/VoteVoterTest.kt b/src/test/kotlin/unit/security/VoteAccessControlTest.kt similarity index 84% rename from src/test/kotlin/unit/voter/VoteVoterTest.kt rename to src/test/kotlin/unit/security/VoteAccessControlTest.kt index e1c1201..9cc5e65 100644 --- a/src/test/kotlin/unit/voter/VoteVoterTest.kt +++ b/src/test/kotlin/unit/security/VoteAccessControlTest.kt @@ -1,4 +1,4 @@ -package unit.voter +package unit.security import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.User @@ -7,10 +7,10 @@ import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.entity.VoteForUpdate -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -23,8 +23,8 @@ import fr.dcproject.component.vote.entity.Vote as VoteEntity @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class VoteVoterTest { +@Tag("security") +internal class VoteAccessControlTest { private val tesla = Citizen( id = UUID.fromString("a1e35c99-9d33-4fb4-9201-58d7071243bb"), user = User( @@ -101,43 +101,43 @@ internal class VoteVoterTest { @Test fun `can be view your the vote`() { - VoteVoter() + VoteAccessControl() .canView(vote1, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be view vote of other`() { - VoteVoter() + VoteAccessControl() .canView(vote1, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be view your votes list`() { - VoteVoter() + VoteAccessControl() .canView(listOf(vote1), tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be vote an article`() { - VoteVoter() + VoteAccessControl() .canCreate(voteForUpdate, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be vote if not connected`() { - VoteVoter() + VoteAccessControl() .canCreate(voteForUpdate, null) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can not be vote an article if article is deleted`() { - VoteVoter() + VoteAccessControl() .canCreate(voteOnDeleted, tesla) - .vote `should be` DENIED + .decision `should be` DENIED } } diff --git a/src/test/kotlin/unit/voter/WorkgroupVoterTest.kt b/src/test/kotlin/unit/security/WorkgroupAccessControlTest.kt similarity index 77% rename from src/test/kotlin/unit/voter/WorkgroupVoterTest.kt rename to src/test/kotlin/unit/security/WorkgroupAccessControlTest.kt index 26a34b2..1af7325 100644 --- a/src/test/kotlin/unit/voter/WorkgroupVoterTest.kt +++ b/src/test/kotlin/unit/security/WorkgroupAccessControlTest.kt @@ -1,14 +1,14 @@ -package unit.voter +package unit.security import fr.dcproject.component.auth.User import fr.dcproject.component.auth.UserI import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.voter.Vote.DENIED -import fr.dcproject.voter.Vote.GRANTED +import fr.dcproject.security.AccessDecision.DENIED +import fr.dcproject.security.AccessDecision.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -21,8 +21,8 @@ import fr.dcproject.component.workgroup.Workgroup as WorkgroupEntity @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT) -@Tag("voter") -internal class WorkgroupVoterTest { +@Tag("security") +internal class WorkgroupAccessControlTest { private val tesla = CitizenBasic( user = User( username = "nicolas-tesla", @@ -73,78 +73,78 @@ internal class WorkgroupVoterTest { @Test fun `can be view your workgroup`() { - WorkgroupVoter() + WorkgroupAccessControl() .canView(workgroupPublic, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view your workgroup if is not public`() { - WorkgroupVoter() + WorkgroupAccessControl() .canView(workgroupAnon, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be view workgroup of other if is public`() { - WorkgroupVoter() + WorkgroupAccessControl() .canView(workgroupPublic, einstein) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be view workgroup of other if is not public`() { - WorkgroupVoter() + WorkgroupAccessControl() .canView(workgroupAnon, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be view your workgroup list`() { - WorkgroupVoter() + WorkgroupAccessControl() .canView(listOf(workgroupPublic, workgroupAnon), tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can be create workgroup`() { - WorkgroupVoter() + WorkgroupAccessControl() .canCreate(workgroupPublic, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be create workgroup if not connected`() { - WorkgroupVoter() + WorkgroupAccessControl() .canCreate(workgroupPublic, null) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be delete workgroup if owner`() { - WorkgroupVoter() + WorkgroupAccessControl() .canDelete(workgroupPublic, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be delete workgroup if not owner`() { - WorkgroupVoter() + WorkgroupAccessControl() .canDelete(workgroupPublic, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } @Test fun `can be update workgroup if owner`() { - WorkgroupVoter() + WorkgroupAccessControl() .canUpdate(workgroupPublic, tesla) - .vote `should be` GRANTED + .decision `should be` GRANTED } @Test fun `can not be update workgroup if not owner`() { - WorkgroupVoter() + WorkgroupAccessControl() .canUpdate(workgroupPublic, einstein) - .vote `should be` DENIED + .decision `should be` DENIED } }