All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.fuelyour.vertxkuickstartcore.tools.JwtAuthHelper.kt Maven / Gradle / Ivy

package dev.fuelyour.vertxkuickstartcore.tools

import dev.fuelyour.vertxkuickstartcore.exceptions.AuthorizationException
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.core.json.JsonArray
import io.vertx.core.json.JsonObject
import io.vertx.ext.auth.PubSecKeyOptions
import io.vertx.ext.auth.jwt.JWTAuth
import io.vertx.ext.auth.jwt.JWTAuthOptions
import io.vertx.ext.jwt.JWTOptions
import io.vertx.ext.web.RoutingContext
import io.vertx.ext.web.handler.JWTAuthHandler
import java.time.LocalDateTime
import java.time.ZoneOffset

/**
 * Verifies authentication according to information specified in the swagger doc.
 */
class JwtAuthHelper(
    config: JsonObject,
    vertx: Vertx
) : SwaggerAuthHandler {

    val EXPIRATION_MILLIS = 1000 * 60 * 60 * 30

    private val authProvider = JWTAuth.create(
        vertx, JWTAuthOptions()
            .addPubSecKey(
                PubSecKeyOptions()
                    .setAlgorithm("HS256")
                    .setPublicKey(config.getString("JWT_PUB_KEY"))
                    .setSecretKey(config.getString("JWT_PRIVATE_KEY"))
                    .setSymmetric(true)
            )
    )

    fun generateToken(json: JsonObject): String {
        json.put("created", getCurrentUTCMillis())
        return authProvider.generateToken(json, JWTOptions())
    }

    fun isTokenExpired(created: Long): Boolean {
        return getCurrentUTCMillis() - created > EXPIRATION_MILLIS
    }

    private fun getCurrentUTCMillis(): Long {
        val now = LocalDateTime.now(ZoneOffset.UTC)
        return now.atZone(ZoneOffset.UTC)?.toInstant()?.toEpochMilli()!!
    }

    override fun createAuthHandlers(roles: Roles): RouteHandlers =
        listOf(
            JWTAuthHandler.create(authProvider) as Handler,
            object : Handler {
                override fun handle(context: RoutingContext) {
                    val userRoles = context.user().principal()
                        .getJsonArray("roles", JsonArray()) ?: JsonArray()
                    authenticateUserRoles(roles, userRoles)
                }
            }
        )

    fun authenticateUserRoles(
        requiredRoles: Roles,
        userRoles: JsonArray
    ) {
        with(requiredRoles) {
            if ((taggedWith("oneOf") && !userRoles.oneOf(rolesIn("oneOf"))) ||
                (taggedWith("anyOf") && !userRoles.anyOf(rolesIn("anyOf"))) ||
                (taggedWith("allOf") && !userRoles.allOf(rolesIn("allOf")))
            )
                throw AuthorizationException()
        }
    }

    private fun Roles.taggedWith(tag: String): Boolean =
        this[tag] != null

    private fun Roles.rolesIn(tag: String): JsonArray =
        JsonArray(this[tag])

    private fun JsonArray.oneOf(other: JsonArray): Boolean {
        var hasOne = false
        other.forEach {
            if (this.contains(it)) {
                if (hasOne)
                    return false
                hasOne = true
            }
        }
        return hasOne
    }

    private fun JsonArray.anyOf(other: JsonArray): Boolean {
        other.forEach { if (this.contains(it)) return true }
        return false
    }

    private fun JsonArray.allOf(other: JsonArray) = this == other
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy