From 9d3eeeb04b26250e3063836f76fef393600344e7 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 8 Apr 2021 17:55:05 +0200 Subject: [PATCH] Add validation on route ChangePasswordCitizenRequest --- .../fr/dcproject/common/validation/Password.kt | 2 +- .../component/citizen/routes/ChangeMyPassword.kt | 14 ++++++++++++-- src/main/resources/openapi.yaml | 4 ++++ src/test/kotlin/integration/Citizen routes.kt | 4 ++-- src/test/kotlin/integration/Login routes.kt | 2 +- src/test/kotlin/integration/steps/given/Citizen.kt | 4 ++-- .../kotlin/integration/steps/given/Workgroup.kt | 2 +- 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/fr/dcproject/common/validation/Password.kt b/src/main/kotlin/fr/dcproject/common/validation/Password.kt index b08bb7d..718d60b 100644 --- a/src/main/kotlin/fr/dcproject/common/validation/Password.kt +++ b/src/main/kotlin/fr/dcproject/common/validation/Password.kt @@ -10,7 +10,7 @@ fun ValidationBuilder.passwordScore(minScore: Int) = fun String.passwordScore(): Int { var score: Int = length val alphaNum = ('a'..'z').toList() + ('A'..'Z').toList() + ('0'..'9').toList() - val specialCount = (length - toList().intersect(alphaNum).size) + val specialCount = length - toList().intersect(alphaNum).size score += specialCount.let { if (it > 3) 3 else it } val hasAlphaLower = toList().intersect(('a'..'z').toList()).size.let { if (it > 2) 2 else it } diff --git a/src/main/kotlin/fr/dcproject/component/citizen/routes/ChangeMyPassword.kt b/src/main/kotlin/fr/dcproject/component/citizen/routes/ChangeMyPassword.kt index 6a360de..cca3586 100644 --- a/src/main/kotlin/fr/dcproject/component/citizen/routes/ChangeMyPassword.kt +++ b/src/main/kotlin/fr/dcproject/component/citizen/routes/ChangeMyPassword.kt @@ -1,7 +1,9 @@ package fr.dcproject.component.citizen.routes +import fr.dcproject.application.http.badRequestIfNotValid import fr.dcproject.common.security.assert import fr.dcproject.common.utils.receiveOrBadRequest +import fr.dcproject.common.validation.passwordScore import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.database.UserRepository @@ -9,6 +11,7 @@ import fr.dcproject.component.auth.database.UserWithPassword import fr.dcproject.component.auth.mustBeAuth import fr.dcproject.component.citizen.CitizenAccessControl import fr.dcproject.component.citizen.database.CitizenRef +import io.konform.validation.Validation import io.ktor.application.call import io.ktor.auth.UserPasswordCredential import io.ktor.features.BadRequestException @@ -25,14 +28,21 @@ object ChangeMyPassword { @Location("/citizens/{citizen}/password/change") class ChangePasswordCitizenRequest(citizen: UUID) { val citizen = CitizenRef(citizen) - data class Input(val oldPassword: String, val newPassword: String) + data class Input(val oldPassword: String, val newPassword: String) { + fun validate() = Validation { + Input::newPassword { + passwordScore(15) + } + }.validate(this) + } } fun Route.changeMyPassword(ac: CitizenAccessControl, userRepository: UserRepository) { put { mustBeAuth() - ac.assert { canChangePassword(it.citizen, citizenOrNull) } val content = call.receiveOrBadRequest() + .apply { validate().badRequestIfNotValid() } + ac.assert { canChangePassword(it.citizen, citizenOrNull) } userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) ?: throw BadRequestException("Bad Password") userRepository.changePassword( UserWithPassword( diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index f1deaca..5800f17 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -484,6 +484,10 @@ paths: description: Password changed 400: description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/400' 401: $ref: '#/components/responses/401' 404: diff --git a/src/test/kotlin/integration/Citizen routes.kt b/src/test/kotlin/integration/Citizen routes.kt index dfd2d26..62f9843 100644 --- a/src/test/kotlin/integration/Citizen routes.kt +++ b/src/test/kotlin/integration/Citizen routes.kt @@ -69,8 +69,8 @@ class `Citizen routes` : BaseTest() { `with body`( """ { - "oldPassword": "azerty", - "newPassword": "qwerty" + "oldPassword": "Azerty123!", + "newPassword": "Qwerty123!" } """ ) diff --git a/src/test/kotlin/integration/Login routes.kt b/src/test/kotlin/integration/Login routes.kt index 7336f9b..131b278 100644 --- a/src/test/kotlin/integration/Login routes.kt +++ b/src/test/kotlin/integration/Login routes.kt @@ -27,7 +27,7 @@ class `Login routes` : BaseTest() { """ { "username": "niels-bohr", - "password": "azerty" + "password": "Azerty123!" } """ ) diff --git a/src/test/kotlin/integration/steps/given/Citizen.kt b/src/test/kotlin/integration/steps/given/Citizen.kt index 951491c..730ae70 100644 --- a/src/test/kotlin/integration/steps/given/Citizen.kt +++ b/src/test/kotlin/integration/steps/given/Citizen.kt @@ -23,7 +23,7 @@ fun TestApplicationEngine.`Given I have citizen`( val user = UserForCreate( id = id.toUUID(), username = "$firstName-$lastName".toLowerCase(), - password = "azerty", + password = "Azerty123!", ) val citizen = CitizenForCreate( id = id.toUUID(), @@ -53,7 +53,7 @@ fun createCitizen(name: CitizenI.Name? = null, id: UUID = UUID.randomUUID()): Ci last ), email = "$first@fakeemail.com", - user = UserForCreate(username = username, password = "azerty") + user = UserForCreate(username = username, password = "Azerty123!") ).let { citizenRepository.insertWithUser(it) ?: error("Unable to create User") } diff --git a/src/test/kotlin/integration/steps/given/Workgroup.kt b/src/test/kotlin/integration/steps/given/Workgroup.kt index 33548c7..5871439 100644 --- a/src/test/kotlin/integration/steps/given/Workgroup.kt +++ b/src/test/kotlin/integration/steps/given/Workgroup.kt @@ -65,7 +65,7 @@ private fun createWorkgroup( .toLowerCase().replace(' ', '-') val user = UserForCreate( username = username, - password = "azerty", + password = "Azerty123!", ) CitizenForCreate( name = creatorName,