move JWT secret into ENV #87
@@ -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
|
||||
|
||||
@@ -124,7 +124,7 @@ fun Application.module(env: Env = PROD) {
|
||||
}
|
||||
}
|
||||
|
||||
install(Authentication, jwtInstallation(get()))
|
||||
install(Authentication, jwtInstallation(get(), get()))
|
||||
|
||||
install(AutoHeadResponse)
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<JwtConfig>().verifier
|
||||
}
|
||||
// SQL connection
|
||||
single {
|
||||
val config: Configuration = get()
|
||||
|
||||
@@ -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<JwtConfig>().run {
|
||||
JWT.create()
|
||||
.withSubject("Authentication")
|
||||
.withIssuer(issuer)
|
||||
.withClaim("id", id.toString())
|
||||
.withExpiresAt(getExpiration())
|
||||
.sign(algorithm)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
@@ -144,5 +144,4 @@ class `Check auth on all routes` : BaseTest() {
|
||||
listOf("example123")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,10 +15,11 @@ fun TestApplicationRequest.`authenticated as`(
|
||||
val username = "$firstName-$lastName".toLowerCase()
|
||||
val repo: CitizenRepository by lazy<CitizenRepository> { GlobalContext.get().koin.get() }
|
||||
val citizen = repo.findByUsername(username) ?: error("Citizen not exist with username $username")
|
||||
val algorithm = GlobalContext.get().koin.get<JwtConfig>().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")
|
||||
|
||||
|
||||
@@ -37,3 +37,9 @@ mail {
|
||||
key = "abcd"
|
||||
}
|
||||
}
|
||||
|
||||
jwt {
|
||||
secret = "zAP5MBA4B4Ijz0MZaS48"
|
||||
issuer = "dc-project.fr"
|
||||
validity = 36000000
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user