feature #8: Add security for Vote Article
This commit is contained in:
@@ -108,7 +108,8 @@ fun Application.module(env: Env = PROD) {
|
|||||||
ArticleVoter(),
|
ArticleVoter(),
|
||||||
ConstitutionVoter(),
|
ConstitutionVoter(),
|
||||||
CitizenVoter(),
|
CitizenVoter(),
|
||||||
CommentVoter()
|
CommentVoter(),
|
||||||
|
VoteVoter()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package fr.dcproject.routes
|
|||||||
import fr.dcproject.citizen
|
import fr.dcproject.citizen
|
||||||
import fr.dcproject.entity.Citizen
|
import fr.dcproject.entity.Citizen
|
||||||
import fr.dcproject.routes.VoteArticlePaths.ArticleVoteRequest.Content
|
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.application.call
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
@@ -27,11 +29,13 @@ object VoteArticlePaths {
|
|||||||
fun Route.voteArticle(repo: VoteArticleRepository) {
|
fun Route.voteArticle(repo: VoteArticleRepository) {
|
||||||
put<VoteArticlePaths.ArticleVoteRequest> {
|
put<VoteArticlePaths.ArticleVoteRequest> {
|
||||||
val content = call.receive<Content>()
|
val content = call.receive<Content>()
|
||||||
repo.vote(VoteEntity(
|
val vote = VoteEntity(
|
||||||
target = it.article,
|
target = it.article,
|
||||||
note = content.note,
|
note = content.note,
|
||||||
createdBy = this.citizen
|
createdBy = this.citizen
|
||||||
))
|
)
|
||||||
|
assertCan(CREATE, vote)
|
||||||
|
repo.vote(vote)
|
||||||
call.respond(HttpStatusCode.Created)
|
call.respond(HttpStatusCode.Created)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package fr.dcproject.security.voter
|
|||||||
import fr.dcproject.entity.User
|
import fr.dcproject.entity.User
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
import fr.dcproject.entity.Article as ArticleEntity
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
|
import fr.dcproject.entity.Vote as VoteEntity
|
||||||
|
|
||||||
class ArticleVoter: Voter {
|
class ArticleVoter: Voter {
|
||||||
enum class Action: ActionI {
|
enum class Action: ActionI {
|
||||||
@@ -13,12 +14,13 @@ class ArticleVoter: Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
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 {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
val user = call.user
|
val user = call.user
|
||||||
if (action == Action.CREATE && user != null) {
|
if (action == Action.CREATE && user is User) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,14 +36,28 @@ class ArticleVoter: Voter {
|
|||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.DELETE && user is User && subject is ArticleEntity && subject.createdBy?.userId == user.id) {
|
if (subject is ArticleEntity) {
|
||||||
|
if (action == Action.DELETE && user is User && subject.createdBy?.userId == user.id) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.UPDATE && user is User && subject is ArticleEntity && subject.createdBy?.userId == user.id) {
|
if (action == Action.UPDATE && user is User && subject.createdBy?.userId == user.id) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (action is Action) {
|
||||||
return Vote.DENIED
|
return Vote.DENIED
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package fr.dcproject.security.voter
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
import fr.dcproject.entity.Constitution
|
|
||||||
import fr.dcproject.entity.User
|
import fr.dcproject.entity.User
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
|
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||||
|
import fr.dcproject.entity.Vote as VoteEntity
|
||||||
|
|
||||||
class ConstitutionVoter: Voter {
|
class ConstitutionVoter: Voter {
|
||||||
enum class Action: ActionI {
|
enum class Action: ActionI {
|
||||||
@@ -13,7 +14,7 @@ class ConstitutionVoter: Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
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 {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
@@ -34,14 +35,28 @@ class ConstitutionVoter: Voter {
|
|||||||
return Vote.GRANTED
|
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
|
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
|
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
|
return Vote.ABSTAIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/main/kotlin/fr/dcproject/security/voter/VoteVoter.kt
Normal file
28
src/main/kotlin/fr/dcproject/security/voter/VoteVoter.kt
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user