package com.restapi import com.restapi.config.AppConfig.Companion.appConfig import com.restapi.config.Role import com.restapi.config.Roles import com.restapi.domain.EntityModel import io.javalin.http.Context import io.javalin.http.Handler import io.javalin.http.HttpStatus import io.javalin.security.AccessManager import io.javalin.security.RouteRole import org.slf4j.LoggerFactory import com.restapi.domain.Session.currentRoles import com.restapi.domain.Session.database class AppAccessManager : AccessManager { private val logger = LoggerFactory.getLogger("Access") private fun loadEntityActionRole(entity: String?, action: String?): List { if (entity == null || action == null) return emptyList() return database.find(EntityModel::class.java) .where() .eq("name", entity) .findOne() ?.actions ?.filter { it.equals(action, ignoreCase = true) } ?.map { "role_${entity}_$it" } ?: emptyList() } override fun manage(handler: Handler, ctx: Context, routeRoles: Set) { val pathParamMap = ctx.pathParamMap() val regex = Regex("^[a-zA-Z0-9\\-_\\.]+$") if (pathParamMap.values.count { !regex.matches(it) } > 0) { ctx.status(HttpStatus.FORBIDDEN).result("invalid request") } else { val entity = pathParamMap["entity"] val action = pathParamMap["action"] val allowedRoles = routeRoles.map { it as Roles }.flatMap { it.roles.toList() }.flatMap { role -> when (role) { Role.DbOps -> listOf("ROLE_DB_OPS") Role.Entity -> loadEntityActionRole(entity, action) is Role.Standard -> role.action.toList().map { "ROLE_${entity}_${it}" } is Role.Explicit -> role.roles.toList() + listOf("ROLE_ADMIN") }.map(String::uppercase) } val isAllowed = currentRoles().count { allowedRoles.contains(it) } > 0 logger.debug( "entity - {}, action {}, user roles = {}, allowed = {}, isAllowed? {}, enforce? {}", entity, action, currentRoles(), allowedRoles, isAllowed, appConfig.enforceRoleRestriction() ) if (isAllowed || !appConfig.enforceRoleRestriction() || allowedRoles.isEmpty()) { //if role is allowed, or enforcement is turned off or no roles are explicitly allowed handler.handle(ctx) } else { ctx.status(HttpStatus.FORBIDDEN).result("user not allowed to do this") } } } }