Skip to content

Commit

Permalink
more configuration.
Browse files Browse the repository at this point in the history
  • Loading branch information
jvorhauer committed Feb 15, 2024
1 parent aaaf642 commit 129667e
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .run/MainKt.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<envs>
<env name="KONOMAS_JWT_SECRET" value="JUYbWR3sv96qYYmnVrjqvLhJ2p3DFZyMt3oAP7brJc2DVznimERu6TxLebPGXaQy" />
<env name="KONOMAS_SENTRY_DSN" value="https://714ec71a76c871dd162ce11bd6b2d4fd@o4505748569849856.ingest.sentry.io/4506733227802624&quot;" />
</envs>
<option name="MAIN_CLASS_NAME" value="blog.MainKt" />
<module name="konomas.main" />
<shortenClasspath name="NONE" />
<option name="VM_PARAMETERS" value="-Dconfig.resource=/local.conf" />
<method v="2">
<option name="Make" enabled="true" />
</method>
Expand Down
2 changes: 1 addition & 1 deletion deploy/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ spec:
spec:
containers:
- name: konomas
image: ghcr.io/jvorhauer/konomas:1.0.11
image: ghcr.io/jvorhauer/konomas:1.0.12
env:
- name: ASTRA_USERNAME
valueFrom:
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/blog/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import blog.write.Processor
const val pid: String = "27"

object Main {
private val kfg: Konfig = ConfigFactory.load("application.conf").extract("jwt")
private val kfg: Konfig = ConfigFactory.load("application.conf").extract("konomas")

private val behavior: Behavior<Void> = Behaviors.setup { ctx ->
embeddedServer(Netty, port = 8080) {
embeddedServer(Netty, port = kfg.server.port, host = kfg.server.host) {
val reader = Reader()
val processor = ctx.spawn(Processor.create(pid, reader), "konomas")
val scheduler = ctx.system.scheduler()
Expand Down Expand Up @@ -60,9 +60,9 @@ object Main {
Sentry.init {options ->
options.dsn = System.getenv("KONOMAS_SENTRY_DSN")
options.environment = "test"
options.release = "1.0.10"
options.release = "1.0.12"
options.tracesSampleRate = 1.0
options.isDebug = true
options.isDebug = false
}
ActorSystem.create(behavior, "konomas")
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/blog/model/Note.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ data class NoteResponse(
)

fun Route.notesRoute(processor: ActorRef<Command>, reader: Reader, scheduler: Scheduler, kfg: Konfig) =
authenticate(kfg.realm) {
authenticate(kfg.jwt.realm) {
route("/api/notes") {
post {
val cnr = call.receive<CreateNoteRequest>()
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/blog/model/Task.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ data class TaskResponse(
)

fun Route.tasksRoute(processor: ActorRef<Command>, reader: Reader, scheduler: Scheduler, kfg: Konfig) =
authenticate(kfg.realm) {
authenticate(kfg.jwt.realm) {
route("/api/tasks") {
post {
val ctr = call.receive<CreateTaskRequest>()
Expand Down
33 changes: 21 additions & 12 deletions src/main/kotlin/blog/model/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.time.Instant
import java.time.ZoneId
import akka.actor.typed.ActorRef
import akka.actor.typed.Scheduler
import akka.actor.typed.javadsl.AskPattern
import akka.actor.typed.javadsl.AskPattern.ask
import akka.pattern.StatusReply
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
Expand Down Expand Up @@ -95,11 +95,11 @@ fun Route.loginRoute(reader: Reader, kfg: Konfig): Route =
val loginRequest = call.receive<LoginRequest>()
val user: User = reader.findUserByEmail(loginRequest.username) ?: return@post call.respond(HttpStatusCode.Unauthorized, "user not found")
val token: String = JWT.create()
.withAudience(kfg.audience)
.withAudience(kfg.jwt.audience)
.withClaim("uid", user.id)
.withExpiresAt(Instant.now().plusMillis(kfg.expiresIn))
.withIssuer(kfg.issuer)
.sign(Algorithm.HMAC256(kfg.secret))
.withExpiresAt(Instant.now().plusMillis(kfg.jwt.expiresIn))
.withIssuer(kfg.jwt.issuer)
.sign(Algorithm.HMAC256(kfg.jwt.secret))
call.respond(hashMapOf("token" to token))
}
}
Expand All @@ -111,20 +111,29 @@ fun Route.usersRoute(processor: ActorRef<Command>, reader: Reader, scheduler: Sc
val rows = call.request.queryParameters["rows"]?.toInt() ?: 10
call.respond(reader.allUsers(rows, start).map { it.toResponse(reader) })
}
get("{id?}") {
val id = call.parameters["id"] ?: return@get call.respondText("no user id specified", status = HttpStatusCode.BadRequest)
val user: User = reader.find(id.toLong()) ?: return@get call.respondText("user not found for $id", status = HttpStatusCode.NotFound)
call.respond(user.toResponse(reader))
}
authenticate(kfg.realm) {
authenticate(kfg.jwt.realm) {
get("/tasks") {
val userId = user(call) ?: return@get call.respond(HttpStatusCode.Unauthorized, "Unauthorized")
call.respond(reader.findTasksForUser(userId).map { it.toResponse() })
}
get("/me") {
val userId = user(call) ?: return@get call.respond(HttpStatusCode.Unauthorized, "Unauthorized")
val user: User = reader.find(userId) ?: return@get call.respond(HttpStatusCode.NotFound, "User not found")
call.respond(user.toResponse(reader))
}
get("/notes") {
val userId = user(call) ?: return@get call.respond(HttpStatusCode.Unauthorized, "Unauthorized")
call.respond(reader.findNotesForUser(userId).map { it.toResponse() })
}
}
get("{id?}") {
val id = call.parameters["id"] ?: return@get call.respondText("no user id specified", status = HttpStatusCode.BadRequest)
val user: User = reader.find(id.toLong()) ?: return@get call.respondText("user not found for $id", status = HttpStatusCode.NotFound)
call.respond(user.toResponse(reader))
}
post {
val cnu = call.receive<RegisterUserRequest>()
AskPattern.ask(processor, { rt -> cnu.toCommand(rt) }, Duration.ofMinutes(1), scheduler).await().let {
ask(processor, { rt -> cnu.toCommand(rt) }, Duration.ofMinutes(1), scheduler).await().let {
if (it.isSuccess) {
call.response.header("Location", "/api/users/${it.value.id}")
call.respond(HttpStatusCode.Created, it.value)
Expand Down
11 changes: 10 additions & 1 deletion src/main/kotlin/blog/model/model.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,22 @@ data class Counts(
val tasks: Int
)

data class Konfig(
data class Jwt(
val secret: String,
val audience: String,
val realm: String,
val issuer: String,
val expiresIn: Long = 1000L * 60L * 60L * 24L
)
data class Server(
val port: Int,
val host: String
)

data class Konfig(
val jwt: Jwt,
val server: Server
)

val timeout: Duration = Duration.ofSeconds(10)
fun user(call: ApplicationCall): Long? = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
4 changes: 2 additions & 2 deletions src/main/kotlin/blog/module/Authentication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import io.ktor.server.response.*

fun Application.authentication(kfg: Konfig) {
install(Authentication) {
jwt(kfg.realm) {
jwt(kfg.jwt.realm) {
verifier(
JWT.require(Algorithm.HMAC256(kfg.secret)).withAudience(kfg.audience).withIssuer(kfg.issuer).build()
JWT.require(Algorithm.HMAC256(kfg.jwt.secret)).withAudience(kfg.jwt.audience).withIssuer(kfg.jwt.issuer).build()
)
validate { credential ->
if (credential.payload.getClaim("uid").asLong() != null) {
Expand Down
19 changes: 13 additions & 6 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,20 @@ datastax-java-driver {
}
}

jwt {
secret = ${KONOMAS_JWT_SECRET}
issuer = "http://0.0.0.0:8080"
audience = "http://0.0.0.0:8080/api"
realm = "konomauth"
konomas {
jwt {
secret = ${KONOMAS_JWT_SECRET}
issuer = "http://0.0.0.0:8080"
audience = "http://0.0.0.0:8080/api"
realm = "konomauth"
}

server {
port = 8080
host = "0.0.0.0"
}
}

ktor {
development = true
development = false
}
74 changes: 74 additions & 0 deletions src/main/resources/local.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
akka {
extensions = [akka.persistence.Persistence]

log-dead-letters = 10
log-dead-letters-during-shutdown = on
log-config-on-start = off
loggers = ["akka.event.Logging$DefaultLogger"]
loglevel = INFO
stdout-loglevel = INFO

actor {
serializers {
kryo = "io.altoo.akka.serialization.kryo.KryoSerializer"
}
serialization-bindings {
"java.io.Serializable" = kryo
}
}

persistence {
journal {
plugin = "akka.persistence.cassandra.journal"
auto-start-journals = ["akka.persistence.cassandra.journal"]
}
snapshot-store {
plugin = "akka.persistence.snapshot-store.local"
auto-start-snapshot-stores = ["akka.persistence.snapshot-store.local"]
local.dir = "build/snapshot"
}
cassandra {
session-provider = "akka.stream.alpakka.cassandra.DefaultSessionProvider"
session-dispatcher = "akka.persistence.cassandra.default-dispatcher"
datastax-java-driver-config = "datastax-java-driver"
events-by-tag {
pubsub-notification = on
}
}
}
}

datastax-java-driver {
basic {
load-balancing-policy {
local-datacenter = "datacenter1"
}
contact-points = ["127.0.0.1:9042"]
session-keyspace = "akka"
}
advanced {
auth-provider {
class = PlainTextAuthProvider
username = cassandra
password = cassandra
}
reconnect-on-init = true
}
}

konomas {
jwt {
secret = ${KONOMAS_JWT_SECRET}
issuer = "http://localhost:8080"
audience = "http://localhost:8080/api"
realm = "konomauth"
}
server {
port = 8080
host = "localhost"
}
}

ktor {
development = true
}
12 changes: 7 additions & 5 deletions src/test/kotlin/blog/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ object MainTest {
akka.persistence.snapshot-store.local.dir = "build/snapshot-${UUID.randomUUID()}"
""")

private val kfg: Konfig = ConfigFactory.load("application.conf").extract("jwt")
private val kfg: Konfig = ConfigFactory.load("application.conf").extract("konomas")
private fun behavior(): Behavior<Void> = Behaviors.setup { ctx ->
embeddedServer(Netty, port = 8181, host = "localhost") {
embeddedServer(Netty, port = kfg.server.port, host = kfg.server.host) {
val reader = Reader()
val processor = ctx.spawn(Processor.create(pid, reader), "processor")
val scheduler = ctx.system.scheduler()
Expand All @@ -60,7 +60,7 @@ object MainTest {
routing {
usersRoute(processor, reader, scheduler, kfg)
loginRoute(reader, kfg)
authenticate(kfg.realm) {
authenticate(kfg.jwt.realm) {
get("/api/test") {
val principal = call.principal<JWTPrincipal>() ?: return@get call.respond(HttpStatusCode.Unauthorized, "no principal")
val userId: Long? = principal.payload.getClaim("uid").asLong()
Expand Down Expand Up @@ -93,9 +93,11 @@ class MainTests {

@Test
fun testKonfig() {
val kfg = config.extract<Konfig>("jwt")
val kfg = config.extract<Konfig>("konomas")
assertThat(kfg).isNotNull
assertThat(kfg.realm).isEqualTo("konomauth")
assertThat(kfg.jwt.realm).isEqualTo("konomauth")
assertThat(kfg.server.port).isEqualTo(8181)
assertThat(kfg.server.host).isEqualTo("localhost")
println("kfg: $kfg")
}
}
16 changes: 14 additions & 2 deletions src/test/requests/users-v2.http
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Accept: application/json
GET {{host}}/api/users

### get-one-user
GET {{host}}/api/users/543382068392136681
GET {{host}}/api/users/545930050313572977

### login-jurjen
POST {{host}}/api/login
Expand All @@ -19,13 +19,25 @@ Content-Type: application/json

> {% client.global.set("authorized", response.body.token); %}

### get-me
GET {{host}}/api/users/me
Authorization: Bearer {{authorized}}

### get-my-notes
GET {{host}}/api/users/notes
Authorization: Bearer {{authorized}}

### get-my-tasks
GET {{host}}/api/users/tasks
Authorization: Bearer {{authorized}}

### post-new-note
POST {{host}}/api/notes
Content-Type: application/json
Authorization: Bearer {{authorized}}

{
"title": "Jurjen's second Note",
"title": "My First Note",
"body": "Note taking in its simplest form :-)"
}

Expand Down
20 changes: 11 additions & 9 deletions src/test/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ akka {
}
}

jwt {
secret = "geheim!"
issuer = "http://0.0.0.0:8080"
audience = "http://0.0.0.0:8080/api"
realm = "konomauth"
}

server {
port: 8181
konomas {
jwt {
secret = "geheim!"
issuer = "http://0.0.0.0:8080"
audience = "http://0.0.0.0:8080/api"
realm = "konomauth"
}
server {
port = 8181
host = "localhost"
}
}

0 comments on commit 129667e

Please sign in to comment.