From 1bc729366005cfa30de4f1537199dd5782e046bc Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Wed, 31 Mar 2021 17:58:47 +0200 Subject: [PATCH] move JWT secret into ENV --- docker-compose.yml | 3 +++ .../fr/dcproject/application/Application.kt | 2 +- .../fr/dcproject/application/Configuration.kt | 11 +++++++++++ .../kotlin/fr/dcproject/application/KoinModule.kt | 14 ++++++++++++++ .../fr/dcproject/component/auth/jwt/JWTMaker.kt | 15 +++++++++------ .../fr/dcproject/component/auth/jwt/JwtConfig.kt | 10 +++++----- .../component/auth/jwt/JwtInstallation.kt | 7 ++++--- src/main/resources/application.conf | 8 ++++++++ .../integration/Check auth on all routes.kt | 1 - src/test/kotlin/integration/steps/given/Auth.kt | 3 ++- src/test/resources/application-test.conf | 6 ++++++ 11 files changed, 63 insertions(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4d93bf9..a087008 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,6 +38,9 @@ services: REDIS_CONNECTION: ${REDIS_CONNECTION} RABBITMQ_CONNECTION: ${RABBITMQ_CONNECTION} ELASTICSEARCH_CONNECTION: ${ELASTICSEARCH_CONNECTION} + JWT_SECRET: ${JWT_SECRET} + JWT_ISSUER: ${JWT_ISSUER} + JWT_VALIDITY: ${JWT_VALIDITY} depends_on: - elasticsearch - db diff --git a/src/main/kotlin/fr/dcproject/application/Application.kt b/src/main/kotlin/fr/dcproject/application/Application.kt index e769236..539a645 100644 --- a/src/main/kotlin/fr/dcproject/application/Application.kt +++ b/src/main/kotlin/fr/dcproject/application/Application.kt @@ -124,7 +124,7 @@ fun Application.module(env: Env = PROD) { } } - install(Authentication, jwtInstallation(get())) + install(Authentication, jwtInstallation(get(), get())) install(AutoHeadResponse) diff --git a/src/main/kotlin/fr/dcproject/application/Configuration.kt b/src/main/kotlin/fr/dcproject/application/Configuration.kt index 922e199..99fbae3 100644 --- a/src/main/kotlin/fr/dcproject/application/Configuration.kt +++ b/src/main/kotlin/fr/dcproject/application/Configuration.kt @@ -43,4 +43,15 @@ class Configuration(val config: Config) { val rabbitmq: String = config.getString("rabbitmq.connection") val exchangeNotificationName = "notification" val sendGridKey: String = config.getString("mail.sendGrid.key") + + interface Jwt { + val secret: String + val issuer: String + val validityInMs: Int + } + val jwt = object : Jwt { + override val secret = config.getString("jwt.secret") + override val issuer = config.getString("jwt.issuer") + override val validityInMs = config.getInt("jwt.validity") + } } diff --git a/src/main/kotlin/fr/dcproject/application/KoinModule.kt b/src/main/kotlin/fr/dcproject/application/KoinModule.kt index 949b9d5..f2e88e8 100644 --- a/src/main/kotlin/fr/dcproject/application/KoinModule.kt +++ b/src/main/kotlin/fr/dcproject/application/KoinModule.kt @@ -9,6 +9,7 @@ import com.fasterxml.jackson.datatype.joda.JodaModule import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.rabbitmq.client.ConnectionFactory import fr.dcproject.common.email.Mailer +import fr.dcproject.component.auth.jwt.JwtConfig import fr.dcproject.component.notification.NotificationConsumer import fr.dcproject.component.notification.NotificationEmailSender import fr.dcproject.component.notification.NotificationsPush @@ -25,6 +26,19 @@ import org.koin.dsl.module @KtorExperimentalAPI val KoinModule = module { + // JWT + single { + val config: Configuration = get() + JwtConfig( + config.jwt.secret, + config.jwt.issuer, + config.jwt.validityInMs, + ) + } + // JWT Verifier + single { + get().verifier + } // SQL connection single { val config: Configuration = get() diff --git a/src/main/kotlin/fr/dcproject/component/auth/jwt/JWTMaker.kt b/src/main/kotlin/fr/dcproject/component/auth/jwt/JWTMaker.kt index 349e621..ba78c2b 100644 --- a/src/main/kotlin/fr/dcproject/component/auth/jwt/JWTMaker.kt +++ b/src/main/kotlin/fr/dcproject/component/auth/jwt/JWTMaker.kt @@ -2,13 +2,16 @@ package fr.dcproject.component.auth.jwt import com.auth0.jwt.JWT import fr.dcproject.component.auth.database.UserI +import org.koin.core.context.GlobalContext /** * Produce a token for this combination of User and Account */ -fun UserI.makeToken(): String = JWT.create() - .withSubject("Authentication") - .withIssuer(JwtConfig.issuer) - .withClaim("id", id.toString()) - .withExpiresAt(JwtConfig.getExpiration()) - .sign(JwtConfig.algorithm) +fun UserI.makeToken(): String = GlobalContext.get().koin.get().run { + JWT.create() + .withSubject("Authentication") + .withIssuer(issuer) + .withClaim("id", id.toString()) + .withExpiresAt(getExpiration()) + .sign(algorithm) +} diff --git a/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtConfig.kt b/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtConfig.kt index 237cedc..046d2af 100644 --- a/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtConfig.kt +++ b/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtConfig.kt @@ -5,11 +5,11 @@ import com.auth0.jwt.JWTVerifier import com.auth0.jwt.algorithms.Algorithm import java.util.Date -object JwtConfig { - private const val secret = "zAP5MBA4B4Ijz0MZaS48" - const val issuer = "dc-project.fr" - private const val validityInMs = 3_600_000 * 10 // 10 hours - +class JwtConfig( + private val secret: String, + val issuer: String, + private val validityInMs: Int, +) { // TODO change to RSA512 val algorithm: Algorithm = Algorithm.HMAC512(secret) diff --git a/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtInstallation.kt b/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtInstallation.kt index 608138b..1a6451d 100644 --- a/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtInstallation.kt +++ b/src/main/kotlin/fr/dcproject/component/auth/jwt/JwtInstallation.kt @@ -1,5 +1,6 @@ package fr.dcproject.component.auth.jwt +import com.auth0.jwt.JWTVerifier import fr.dcproject.component.auth.database.User import fr.dcproject.component.auth.database.UserRepository import io.ktor.application.ApplicationCall @@ -9,14 +10,14 @@ import io.ktor.http.auth.HttpAuthHeader import io.ktor.routing.Routing import java.util.UUID -fun jwtInstallation(userRepo: UserRepository): Authentication.Configuration.() -> Unit = { +fun jwtInstallation(userRepo: UserRepository, verifier: JWTVerifier): Authentication.Configuration.() -> Unit = { /** * Setup the JWT authentication to be used in [Routing]. * If the token is valid, the corresponding [User] is fetched from the database. * The [User] can then be accessed in each [ApplicationCall]. */ jwt { - verifier(JwtConfig.verifier) + verifier(verifier) realm = "dc-project.fr" validate { it.payload.getClaim("id").asString()?.let { id -> @@ -27,7 +28,7 @@ fun jwtInstallation(userRepo: UserRepository): Authentication.Configuration.() - /* Token in URL */ jwt("url") { - verifier(JwtConfig.verifier) + verifier(verifier) realm = "dc-project.fr" authHeader { call -> call.request.queryParameters["token"]?.let { diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 441fcec..bfd0a1d 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -42,3 +42,11 @@ mail { key = ${?SEND_GRID_KEY} } } + +jwt { + secret = ${?JWT_SECRET} + issuer = "dc-project.fr" + issuer = ${?JWT_ISSUER} + validity = 36000000 + validity = ${?JWT_VALIDITY} +} \ No newline at end of file diff --git a/src/test/kotlin/integration/Check auth on all routes.kt b/src/test/kotlin/integration/Check auth on all routes.kt index 9107bbd..a148b1e 100644 --- a/src/test/kotlin/integration/Check auth on all routes.kt +++ b/src/test/kotlin/integration/Check auth on all routes.kt @@ -144,5 +144,4 @@ class `Check auth on all routes` : BaseTest() { listOf("example123") } } - } diff --git a/src/test/kotlin/integration/steps/given/Auth.kt b/src/test/kotlin/integration/steps/given/Auth.kt index d639f81..f8e1b8b 100644 --- a/src/test/kotlin/integration/steps/given/Auth.kt +++ b/src/test/kotlin/integration/steps/given/Auth.kt @@ -15,10 +15,11 @@ fun TestApplicationRequest.`authenticated as`( val username = "$firstName-$lastName".toLowerCase() val repo: CitizenRepository by lazy { GlobalContext.get().koin.get() } val citizen = repo.findByUsername(username) ?: error("Citizen not exist with username $username") + val algorithm = GlobalContext.get().koin.get().algorithm val jwtAsString: String = JWT.create() .withIssuer("dc-project.fr") .withClaim("id", citizen.user.id.toString()) - .sign(JwtConfig.algorithm) + .sign(algorithm) addHeader(HttpHeaders.Authorization, "Bearer $jwtAsString") diff --git a/src/test/resources/application-test.conf b/src/test/resources/application-test.conf index d860fb3..b04eb5f 100644 --- a/src/test/resources/application-test.conf +++ b/src/test/resources/application-test.conf @@ -37,3 +37,9 @@ mail { key = "abcd" } } + +jwt { + secret = "zAP5MBA4B4Ijz0MZaS48" + issuer = "dc-project.fr" + validity = 36000000 +} -- 2.49.1