Fix security

This commit is contained in:
2020-10-04 01:10:22 +02:00
parent 317e029f79
commit 74923891d0
6 changed files with 48 additions and 22 deletions

View File

@@ -36,9 +36,11 @@ class ArticleForUpdate(
tags: List<String> = emptyList(),
val draft: Boolean = false,
val createdBy: CitizenRef,
val workgroup: WorkgroupRef? = null
) : ArticleRefVersioning(id) {
val workgroup: WorkgroupRef? = null,
versionId: UUID?
) : ArticleRefVersioning(id, versionId = versionId ?: UUID.randomUUID()) {
val tags: List<String> = tags.distinct()
val isNew = versionId == null
}
open class ArticleSimple(

View File

@@ -11,6 +11,7 @@ import fr.dcproject.event.raiseEvent
import fr.dcproject.repository.Article.Filter
import fr.dcproject.repository.Workgroup as WorkgroupRepository
import fr.dcproject.security.voter.ArticleVoter.Action.CREATE
import fr.dcproject.security.voter.ArticleVoter.Action.UPDATE
import fr.dcproject.security.voter.ArticleVoter.Action.VIEW
import fr.dcproject.views.ArticleViewManager
import fr.ktorVoter.assertCan
@@ -81,18 +82,17 @@ object ArticlesPaths {
suspend fun getNewArticle(call: ApplicationCall): ArticleForUpdate = call.receive<Article>().run {
ArticleForUpdate(
id ?: UUID.randomUUID(),
title,
anonymous,
content,
description,
tags,
draft,
id = id ?: UUID.randomUUID(),
title = title,
anonymous = anonymous,
content = content,
description = description,
tags = tags,
draft = draft,
createdBy = call.citizen,
workgroup = if (workgroup != null) workgroupRepository.findById(workgroup.id) as WorkgroupSimple<CitizenRef> else null
).also {
it.versionId = versionId ?: UUID.randomUUID()
}
workgroup = if (workgroup != null) workgroupRepository.findById(workgroup.id) as WorkgroupSimple<CitizenRef> else null,
versionId = versionId
)
}
}
}
@@ -134,7 +134,11 @@ fun Route.article(repo: ArticleRepository, viewManager: ArticleViewManager) {
post<ArticlesPaths.PostArticleRequest> {
it.getNewArticle(call).also { article ->
assertCan(CREATE, article)
if(article.isNew) {
assertCan(CREATE, article)
} else {
assertCan(UPDATE, article)
}
val newArticle = repo.upsert(article) ?: error("Article not updated")
call.respond(article)
raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle))

View File

@@ -1,18 +1,26 @@
package fr.dcproject.security.voter
import fr.dcproject.citizenOrNull
import fr.dcproject.entity.ArticleAuthI
import fr.dcproject.entity.ArticleForUpdate
import fr.dcproject.entity.ArticleI
import fr.dcproject.entity.Citizen as CitizenEntity
import fr.dcproject.entity.CitizenI
import fr.dcproject.entity.UserI
import fr.dcproject.repository.Article as ArticleRepo
import fr.dcproject.user
import fr.ktorVoter.ActionI
import fr.ktorVoter.Vote
import fr.ktorVoter.Voter
import fr.ktorVoter.checkClass
import io.ktor.application.ApplicationCall
import org.koin.core.KoinComponent
import org.koin.core.inject
import fr.dcproject.entity.Comment as CommentEntity
import fr.dcproject.entity.Vote as VoteEntity
class ArticleVoter : Voter {
class ArticleVoter : Voter, KoinComponent {
private val articleRepo: ArticleRepo by inject()
enum class Action : ActionI {
CREATE,
UPDATE,
@@ -30,7 +38,7 @@ class ArticleVoter : Voter {
if (action == Action.CREATE && user is UserI) return Vote.GRANTED
if (action == Action.VIEW) return view(subject, user)
if (action == Action.DELETE) return delete(subject, user)
if (action == Action.UPDATE) return update(subject, user)
if (action == Action.UPDATE) return update(subject, call.citizenOrNull)
if (action is CommentVoter.Action) return voteForComment(action, subject)
if (action is VoteVoter.Action) return voteForVote(action, subject)
if (action is Action) return Vote.DENIED
@@ -58,11 +66,16 @@ class ArticleVoter : Voter {
return Vote.DENIED
}
private fun update(subject: Any?, user: UserI?): Vote {
checkClass(ArticleAuthI::class, subject)
if (subject is ArticleAuthI<*>) {
if (user is UserI && subject.createdBy.user.id == user.id) {
return Vote.GRANTED
private fun update(subject: Any?, citizen: CitizenEntity?): Vote {
checkClass(ArticleForUpdate::class, subject)
if (subject is ArticleForUpdate) {
/* The new Article must by created by the same citizen of the connected citizen */
if (citizen is CitizenI && subject.createdBy.id == citizen.id) {
/* The creator must be the same of the creator of preview version of article */
if(articleRepo.findVerionsByVersionsId(1, 1, subject.versionId).result.first().createdBy.id == citizen.id) {
return Vote.GRANTED
}
return Vote.DENIED
}
}
return Vote.DENIED

View File

@@ -73,7 +73,8 @@ class ArticleSteps : En, KoinTest {
content = "bla bla bla",
description = "A super article",
createdBy = createdBy,
workgroup = workgroup
workgroup = workgroup,
versionId = UUID.randomUUID()
)
get<ArticleRepository>().upsert(article)
}