From d1999d84ca64a65951a42ecfaf5176b3f0139e71 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 30 Aug 2019 14:34:24 +0200 Subject: [PATCH] feature #8: Add security for Vote Article --- src/main/kotlin/fr/dcproject/Application.kt | 3 +- .../kotlin/fr/dcproject/routes/VoteArticle.kt | 8 ++++-- .../dcproject/security/voter/ArticleVoter.kt | 28 +++++++++++++++---- .../security/voter/ConstitutionVoter.kt | 23 ++++++++++++--- .../fr/dcproject/security/voter/VoteVoter.kt | 28 +++++++++++++++++++ 5 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 src/main/kotlin/fr/dcproject/security/voter/VoteVoter.kt diff --git a/src/main/kotlin/fr/dcproject/Application.kt b/src/main/kotlin/fr/dcproject/Application.kt index a58ca1a..2b79d01 100644 --- a/src/main/kotlin/fr/dcproject/Application.kt +++ b/src/main/kotlin/fr/dcproject/Application.kt @@ -108,7 +108,8 @@ fun Application.module(env: Env = PROD) { ArticleVoter(), ConstitutionVoter(), CitizenVoter(), - CommentVoter() + CommentVoter(), + VoteVoter() ) } diff --git a/src/main/kotlin/fr/dcproject/routes/VoteArticle.kt b/src/main/kotlin/fr/dcproject/routes/VoteArticle.kt index 2db57dd..f7c7950 100644 --- a/src/main/kotlin/fr/dcproject/routes/VoteArticle.kt +++ b/src/main/kotlin/fr/dcproject/routes/VoteArticle.kt @@ -3,6 +3,8 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.entity.Citizen import fr.dcproject.routes.VoteArticlePaths.ArticleVoteRequest.Content +import fr.dcproject.security.voter.VoteVoter.Action.CREATE +import fr.dcproject.security.voter.assertCan import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -27,11 +29,13 @@ object VoteArticlePaths { fun Route.voteArticle(repo: VoteArticleRepository) { put { val content = call.receive() - repo.vote(VoteEntity( + val vote = VoteEntity( target = it.article, note = content.note, createdBy = this.citizen - )) + ) + assertCan(CREATE, vote) + repo.vote(vote) call.respond(HttpStatusCode.Created) } } \ No newline at end of file diff --git a/src/main/kotlin/fr/dcproject/security/voter/ArticleVoter.kt b/src/main/kotlin/fr/dcproject/security/voter/ArticleVoter.kt index 1d5ad40..6e0362d 100644 --- a/src/main/kotlin/fr/dcproject/security/voter/ArticleVoter.kt +++ b/src/main/kotlin/fr/dcproject/security/voter/ArticleVoter.kt @@ -3,6 +3,7 @@ package fr.dcproject.security.voter import fr.dcproject.entity.User import io.ktor.application.ApplicationCall import fr.dcproject.entity.Article as ArticleEntity +import fr.dcproject.entity.Vote as VoteEntity class ArticleVoter: Voter { enum class Action: ActionI { @@ -13,12 +14,13 @@ class ArticleVoter: Voter { } override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean { - return (action is Action || action is CommentVoter.Action) && subject is Article? + return (action is Action || action is CommentVoter.Action || action is VoteVoter.Action) + && subject is ArticleEntity? } override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote { val user = call.user - if (action == Action.CREATE && user != null) { + if (action == Action.CREATE && user is User) { return Vote.GRANTED } @@ -34,12 +36,26 @@ class ArticleVoter: Voter { return Vote.GRANTED } - if (action == Action.DELETE && user is User && subject is ArticleEntity && subject.createdBy?.userId == user.id) { - return Vote.GRANTED + if (subject is ArticleEntity) { + if (action == Action.DELETE && user is User && subject.createdBy?.userId == user.id) { + return Vote.GRANTED + } + + if (action == Action.UPDATE && user is User && subject.createdBy?.userId == user.id) { + return Vote.GRANTED + } + + return Vote.DENIED } - if (action == Action.UPDATE && user is User && subject is ArticleEntity && subject.createdBy?.userId == user.id) { - return Vote.GRANTED + if (action == VoteVoter.Action.CREATE && subject is VoteEntity<*>) { + val target = subject.target + if (target !is ArticleEntity) { + return Vote.ABSTAIN + } + if (target.isDeleted()) { + return Vote.DENIED + } } if (action is Action) { diff --git a/src/main/kotlin/fr/dcproject/security/voter/ConstitutionVoter.kt b/src/main/kotlin/fr/dcproject/security/voter/ConstitutionVoter.kt index 7bb57b3..f7fd6ca 100644 --- a/src/main/kotlin/fr/dcproject/security/voter/ConstitutionVoter.kt +++ b/src/main/kotlin/fr/dcproject/security/voter/ConstitutionVoter.kt @@ -1,8 +1,9 @@ package fr.dcproject.security.voter -import fr.dcproject.entity.Constitution import fr.dcproject.entity.User import io.ktor.application.ApplicationCall +import fr.dcproject.entity.Constitution as ConstitutionEntity +import fr.dcproject.entity.Vote as VoteEntity class ConstitutionVoter: Voter { enum class Action: ActionI { @@ -13,7 +14,7 @@ class ConstitutionVoter: Voter { } override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean { - return (action is Action || action is CommentVoter.Action) && subject is Constitution? + return (action is Action || action is CommentVoter.Action) && subject is ConstitutionEntity? } override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote { @@ -34,14 +35,28 @@ class ConstitutionVoter: Voter { return Vote.GRANTED } - if (action == Action.DELETE && user is User && subject is Constitution && subject.createdBy?.userId == user.id) { + if (action == Action.DELETE && user is User && subject is ConstitutionEntity && subject.createdBy?.userId == user.id) { return Vote.GRANTED } - if (action == Action.UPDATE && user is User && subject is Constitution && subject.createdBy?.userId == user.id) { + if (action == Action.UPDATE && user is User && subject is ConstitutionEntity && subject.createdBy?.userId == user.id) { return Vote.GRANTED } + if (action == VoteVoter.Action.CREATE && subject is VoteEntity<*>) { + val target = subject.target + if (target !is ConstitutionEntity) { + return Vote.ABSTAIN + } + if (target.isDeleted()) { + return Vote.DENIED + } + } + + if (action is Action) { + return Vote.DENIED + } + return Vote.ABSTAIN } } diff --git a/src/main/kotlin/fr/dcproject/security/voter/VoteVoter.kt b/src/main/kotlin/fr/dcproject/security/voter/VoteVoter.kt new file mode 100644 index 0000000..1c28ed6 --- /dev/null +++ b/src/main/kotlin/fr/dcproject/security/voter/VoteVoter.kt @@ -0,0 +1,28 @@ +package fr.dcproject.security.voter + +import io.ktor.application.ApplicationCall +import fr.dcproject.entity.Vote as VoteEntity + +class VoteVoter: Voter { + enum class Action: ActionI { + CREATE, + VIEW + } + + override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean { + return action is Action && subject is VoteEntity<*>? + } + + override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote { + val user = call.user + if (action == Action.CREATE && user != null) { + return Vote.GRANTED + } + + if (action == Action.VIEW) { + return Vote.GRANTED + } + + return Vote.ABSTAIN + } +}