Skip to content

Commit

Permalink
refactor: use static auth instead of jwt
Browse files Browse the repository at this point in the history
  • Loading branch information
d1snin committed Apr 23, 2024
1 parent 34490a2 commit b6b12dc
Show file tree
Hide file tree
Showing 27 changed files with 105 additions and 482 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,22 @@ public interface BeamClient {

public suspend fun getDaemonStatus(): Result<DaemonStatus>

public suspend fun postSpace(space: SpaceModification, languageCode: LanguageCode? = null): Result<SpaceWithToken>
public suspend fun postSpace(space: SpaceModification, languageCode: LanguageCode? = null): Result<Space>

public suspend fun postSpace(
languageCode: LanguageCode? = null,
configure: suspend SpaceModificationBuilder.() -> Unit
): Result<SpaceWithToken>
): Result<Space>

public suspend fun postRootSpace(
space: RootSpaceModification,
languageCode: LanguageCode? = null
): Result<SpaceWithToken>
): Result<Space>

public suspend fun postRootSpace(
languageCode: LanguageCode? = null,
configure: suspend RootSpaceModificationBuilder.() -> Unit
): Result<SpaceWithToken>
): Result<Space>

public suspend fun getSpace(id: SpaceIdentifier, languageCode: LanguageCode? = null): Result<Space>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class DefaultBeamClient(
public override suspend fun postSpace(
space: SpaceModification,
languageCode: LanguageCode?
): Result<SpaceWithToken> =
): Result<Space> =
runCatching {
httpClient.post(Paths.POST_SPACE) {
contentType(ContentType.Application.Json)
Expand All @@ -102,13 +102,13 @@ public class DefaultBeamClient(
public override suspend fun postSpace(
languageCode: LanguageCode?,
configure: suspend SpaceModificationBuilder.() -> Unit
): Result<SpaceWithToken> =
): Result<Space> =
postSpace(SpaceModificationBuilder().apply { configure() }.buildSpaceModification(), languageCode)

public override suspend fun postRootSpace(
space: RootSpaceModification,
languageCode: LanguageCode?
): Result<SpaceWithToken> =
): Result<Space> =
runCatching {
httpClient.post(Paths.POST_ROOT_SPACE) {
contentType(ContentType.Application.Json)
Expand All @@ -120,7 +120,7 @@ public class DefaultBeamClient(
public override suspend fun postRootSpace(
languageCode: LanguageCode?,
configure: suspend RootSpaceModificationBuilder.() -> Unit
): Result<SpaceWithToken> =
): Result<Space> =
postRootSpace(RootSpaceModificationBuilder().apply { configure() }.buildRootSpaceModification(), languageCode)

public override suspend fun getSpace(id: SpaceIdentifier, languageCode: LanguageCode?): Result<Space> =
Expand Down
17 changes: 1 addition & 16 deletions beam-common/src/commonMain/kotlin/dev/d1s/beam/commons/Space.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,4 @@ public data class SpaceModification(
public data class RootSpaceModification(
override val metadata: Metadata,
override val view: SpaceView
) : ModifiedRootSpace

@Serializable
public data class SpaceWithToken(
override val id: SpaceId,
override val createdAt: ModificationTime,
override val updatedAt: ModificationTime,
override val slug: SpaceSlug,
override val metadata: Metadata,
override val view: SpaceView,
override val role: Role,
public val token: SpaceToken
) : IdentifiedSpace

public fun SpaceWithToken.toSpace(): Space =
Space(id, createdAt, updatedAt, slug, metadata, view, role)
) : ModifiedRootSpace
3 changes: 2 additions & 1 deletion beam-daemon/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dependencies {
val ktorVersion: String by project
val ktorServerLiquibaseVersion: String by project
val ktorWsEventsVersion: String by project
val ktorStaticAuthVersion: String by project

val logbackVersion: String by project
val kmLogVersion: String by project
Expand All @@ -58,7 +59,6 @@ dependencies {

implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.ktor:ktor-server-auth:$ktorVersion")
implementation("io.ktor:ktor-server-auth-jwt:$ktorVersion")
implementation("io.ktor:ktor-server-rate-limit:$ktorVersion")
implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-server-cors:$ktorVersion")
Expand All @@ -68,6 +68,7 @@ dependencies {
implementation("dev.d1s.exkt:exkt-ktor-server-postgres-support:$exktVersion")
implementation("dev.d1s:ktor-server-liquibase:$ktorServerLiquibaseVersion")
implementation("dev.d1s.ktor-ws-events:ktor-ws-events-server:$ktorWsEventsVersion")
implementation("dev.d1s:ktor-static-authentication:$ktorStaticAuthVersion")

implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-cio:$ktorVersion")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class BridgedBeamClient : BeamClient, KoinComponent {
DaemonStatus(VERSION, DaemonState.UP)
}

override suspend fun postSpace(space: SpaceModification, languageCode: LanguageCode?): Result<SpaceWithToken> =
override suspend fun postSpace(space: SpaceModification, languageCode: LanguageCode?): Result<Space> =
readOnlyError()

override suspend fun postSpace(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,76 +16,28 @@

package dev.d1s.beam.daemon.configuration

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import dev.d1s.beam.daemon.service.SpaceService
import dev.d1s.exkt.ktor.server.koin.configuration.ApplicationConfigurer
import dev.d1s.ktor.staticauth.staticToken
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.*
import io.ktor.server.config.*
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.module.Module

object Security : ApplicationConfigurer, KoinComponent {

val jwtAlgorithm get() = _jwtAlgorithm ?: error("Algorithm is not available")

private var _jwtAlgorithm: Algorithm? = null

private val spaceService by inject<SpaceService>()

override fun Application.configure(module: Module, config: ApplicationConfig) {
_jwtAlgorithm = Algorithm.HMAC256(config.jwtSecret)

authentication {
jwt {
realm = config.jwtRealm

val verifier = buildVerifier(config)

verifier(verifier)

validate()
}
}
}

private fun buildVerifier(config: ApplicationConfig) =
JWT.require(jwtAlgorithm)
.withIssuer(config.jwtIssuer)
.build()

private fun JWTAuthenticationProvider.Config.validate() {
validate { credential ->
val payload = credential.payload
val subject = payload.subject

if (
subject != null
&& subject.isNotBlank()
&& spaceService.spaceExists(subject).getOrThrow()
) {
JWTPrincipal(payload)
} else {
null
staticToken {
realm = config.authRealm
token = config.authToken
}
}
}
}

val ApplicationCall.jwtSubject
get() = (principal<JWTPrincipal>()
?: error("No JWT principal")).payload.subject
?: error("No JWT subject")

val ApplicationConfig.jwtRealm
get() = property("security.jwt.realm").getString()

val ApplicationConfig.jwtSecret
get() = property("security.jwt.secret").getString()

val ApplicationConfig.authRealm
get() = property("security.auth.realm").getString()

val ApplicationConfig.jwtIssuer
get() = property("security.jwt.issuer").getString()
val ApplicationConfig.authToken
get() = property("security.auth.token").getString()
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ object Services : ApplicationConfigurer {

override fun Application.configure(module: Module, config: ApplicationConfig) {
module.apply {
singleOf<AuthService>(::DefaultAuthService)
singleOf<BlockService>(::DefaultBlockService)
singleOf<RowService>(::DefaultRowService)
singleOf<SpaceService>(::DefaultSpaceService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package dev.d1s.beam.daemon.route

import dev.d1s.beam.commons.Paths
import dev.d1s.beam.daemon.exception.ForbiddenException
import dev.d1s.beam.daemon.service.AuthService
import dev.d1s.beam.daemon.service.BlockService
import dev.d1s.beam.daemon.util.requiredIdParameter
import dev.d1s.exkt.ktor.server.koin.configuration.Route
Expand All @@ -37,19 +35,13 @@ class DeleteBlockRoute : Route, KoinComponent {

private val blockService by inject<BlockService>()

private val authService by inject<AuthService>()

override fun Routing.apply() {
authenticate {
delete(Paths.DELETE_BLOCK) {
if (authService.isBlockModificationAllowed(call)) {
val blockId = call.requiredIdParameter
blockService.removeBlock(blockId).getOrThrow()
val blockId = call.requiredIdParameter
blockService.removeBlock(blockId).getOrThrow()

call.respond(HttpStatusCode.NoContent)
} else {
throw ForbiddenException()
}
call.respond(HttpStatusCode.NoContent)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
package dev.d1s.beam.daemon.route

import dev.d1s.beam.commons.Paths
import dev.d1s.beam.daemon.configuration.jwtSubject
import dev.d1s.beam.daemon.exception.ForbiddenException
import dev.d1s.beam.daemon.service.AuthService
import dev.d1s.beam.daemon.service.BlockService
import dev.d1s.beam.daemon.util.requiredSpaceIdQueryParameter
import dev.d1s.exkt.ktor.server.koin.configuration.Route
Expand All @@ -38,22 +35,14 @@ class DeleteBlocksRoute : Route, KoinComponent {

private val blockService by inject<BlockService>()

private val authService by inject<AuthService>()

override fun Routing.apply() {
authenticate {
delete(Paths.DELETE_BLOCKS) {
val spaceId = call.requiredSpaceIdQueryParameter

val modificationAllowed = authService.isSpaceModificationAllowed(call.jwtSubject, spaceId).getOrThrow()

if (modificationAllowed) {
blockService.removeAllBlocks(spaceIdentifier = spaceId).getOrThrow()
blockService.removeAllBlocks(spaceIdentifier = spaceId).getOrThrow()

call.respond(HttpStatusCode.NoContent)
} else {
throw ForbiddenException()
}
call.respond(HttpStatusCode.NoContent)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package dev.d1s.beam.daemon.route

import dev.d1s.beam.commons.Paths
import dev.d1s.beam.daemon.exception.ForbiddenException
import dev.d1s.beam.daemon.service.AuthService
import dev.d1s.beam.daemon.service.SpaceService
import dev.d1s.beam.daemon.util.requiredIdParameter
import dev.d1s.exkt.ktor.server.koin.configuration.Route
Expand All @@ -37,19 +35,13 @@ class DeleteSpaceRoute : Route, KoinComponent {

private val spaceService by inject<SpaceService>()

private val authService by inject<AuthService>()

override fun Routing.apply() {
authenticate {
delete(Paths.DELETE_SPACE) {
if (authService.isSpaceModificationAllowed(call)) {
val spaceIdentifier = call.requiredIdParameter
spaceService.removeSpace(spaceIdentifier).getOrThrow()
val spaceIdentifier = call.requiredIdParameter
spaceService.removeSpace(spaceIdentifier).getOrThrow()

call.respond(HttpStatusCode.NoContent)
} else {
throw ForbiddenException()
}
call.respond(HttpStatusCode.NoContent)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
package dev.d1s.beam.daemon.route

import dev.d1s.beam.commons.Paths
import dev.d1s.beam.daemon.configuration.jwtSubject
import dev.d1s.beam.daemon.exception.ForbiddenException
import dev.d1s.beam.daemon.service.AuthService
import dev.d1s.beam.daemon.service.TranslationService
import dev.d1s.beam.daemon.util.requiredLanguageCodeParameter
import dev.d1s.beam.daemon.util.spaceIdQueryParameter
Expand All @@ -39,26 +36,15 @@ class DeleteTranslationRoute : Route, KoinComponent {

private val translationService by inject<TranslationService>()

private val authService by inject<AuthService>()

override fun Routing.apply() {
authenticate {
delete(Paths.DELETE_TRANSLATION) {
val spaceId = call.spaceIdQueryParameter
val languageCode = call.requiredLanguageCodeParameter

val spaceModificationAllowed = authService.isSpaceModificationAllowed(
call.jwtSubject,
spaceId ?: TranslationService.GLOBAL_TRANSLATION_PERMITTED_SPACE
).getOrThrow()

if (spaceModificationAllowed) {
translationService.removeTranslation(spaceId, languageCode).getOrThrow()
translationService.removeTranslation(spaceId, languageCode).getOrThrow()

call.respond(HttpStatusCode.NoContent)
} else {
throw ForbiddenException()
}
call.respond(HttpStatusCode.NoContent)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ import dev.d1s.beam.commons.BlockModification
import dev.d1s.beam.commons.Paths
import dev.d1s.beam.commons.validation.validateBlock
import dev.d1s.beam.daemon.configuration.DtoConverters
import dev.d1s.beam.daemon.configuration.jwtSubject
import dev.d1s.beam.daemon.entity.BlockEntity
import dev.d1s.beam.daemon.exception.ForbiddenException
import dev.d1s.beam.daemon.service.AuthService
import dev.d1s.beam.daemon.service.BlockService
import dev.d1s.beam.daemon.util.languageCodeQueryParameter
import dev.d1s.beam.daemon.validation.orThrow
Expand All @@ -46,8 +43,6 @@ class PostBlockRoute : Route, KoinComponent {

private val blockService by inject<BlockService>()

private val authService by inject<AuthService>()

private val blockModificationDtoConverter by inject<DtoConverter<BlockEntity, BlockModification>>(DtoConverters.BlockModificationDtoConverterQualifier)

override fun Routing.apply() {
Expand All @@ -56,19 +51,12 @@ class PostBlockRoute : Route, KoinComponent {
val body = call.receive<BlockModification>()
validateBlock(body).orThrow()

val spaceModificationAllowed =
authService.isSpaceModificationAllowed(call.jwtSubject, body.spaceId).getOrThrow()

if (spaceModificationAllowed) {
val block = blockModificationDtoConverter.convertToEntity(body)
val block = blockModificationDtoConverter.convertToEntity(body)

val languageCode = call.languageCodeQueryParameter
val createdBlock = blockService.createBlock(block, languageCode).getOrThrow()
val languageCode = call.languageCodeQueryParameter
val createdBlock = blockService.createBlock(block, languageCode).getOrThrow()

call.respond(HttpStatusCode.Created, createdBlock.requiredDto)
} else {
throw ForbiddenException()
}
call.respond(HttpStatusCode.Created, createdBlock.requiredDto)
}
}
}
Expand Down
Loading

0 comments on commit b6b12dc

Please sign in to comment.