Skip to content

Instantly share code, notes, and snippets.

@Shreemanarjun
Last active August 16, 2024 06:46
Show Gist options
  • Select an option

  • Save Shreemanarjun/bfe4ffb6664bdcd4514ab53e9007f299 to your computer and use it in GitHub Desktop.

Select an option

Save Shreemanarjun/bfe4ffb6664bdcd4514ab53e9007f299 to your computer and use it in GitHub Desktop.

Revisions

  1. Shreemanarjun revised this gist Aug 14, 2024. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions rolebasedAuthPlugin.Kt
    Original file line number Diff line number Diff line change
    @@ -82,6 +82,7 @@ val RoleBasedAuthorizationPlugin = createRouteScopedPlugin(
    val definedRoles = pluginConfig.authorityConfigs.map { it.userRole }

    pluginConfig.apply {
    //After the JWT Token Verified do check on roles and access levels
    on(AuthenticationChecked) { call ->
    /// get the token role from claim
    val tokenRule = call.getRoleFromToken()
  2. Shreemanarjun created this gist Aug 14, 2024.
    181 changes: 181 additions & 0 deletions rolebasedAuthPlugin.Kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,181 @@
    package example.com.plugins

    import io.ktor.http.*
    import io.ktor.server.application.*
    import io.ktor.server.auth.*
    import io.ktor.server.auth.jwt.*
    import io.ktor.server.request.*
    import io.ktor.server.response.*


    routing {

    authenticate("authJWT") {
    authorized(
    //Define the user role and its acces levels for authority
    authorityWithAccessLevels = setOf(
    AuthorityWithAccessLevel(
    UserRole.PATIENT,
    accessLevels = setOf(AccessLevel.Read),
    )
    ),
    build = {
    patientRoute()
    })
    }


    }



    ///authorization plugin for Route
    fun Route.authorized(
    authorityWithAccessLevels: Set<AuthorityWithAccessLevel>,
    build: Route.() -> Unit,
    ) {
    install(RoleBasedAuthorizationPlugin) {
    authorityConfigs = authorityWithAccessLevels
    build()
    }
    }

    @Serializable
    enum class UserRole {
    //Patient
    PATIENT,

    //Doctor
    DOCTOR,

    //Pharmacy
    PHARMACY,

    //Diagnostic Center
    DIAGNOSTICS,

    //Admin
    ADMIN,
    }

    /**
    * User With Access Levels
    *
    * */
    enum class AccessLevel {
    Read, Write, Delete, Update
    }

    data class AuthorityWithAccessLevel(var userRole: UserRole, var accessLevels: Set<AccessLevel> = emptySet())


    class PluginConfiguration {
    var authorityConfigs: Set<AuthorityWithAccessLevel> = emptySet()

    }

    val RoleBasedAuthorizationPlugin = createRouteScopedPlugin(
    name = "Role Based Authentication Plugin",
    createConfiguration = ::PluginConfiguration
    ) {
    ///get the user defined roles here
    val definedRoles = pluginConfig.authorityConfigs.map { it.userRole }

    pluginConfig.apply {
    on(AuthenticationChecked) { call ->
    /// get the token role from claim
    val tokenRule = call.getRoleFromToken()
    println("token rule: $tokenRule")
    if (tokenRule != null) {
    /// Check whether current user token have the required role
    val authorized = definedRoles.contains(tokenRule)
    println("authorized token: $authorized")
    when {
    !authorized -> {
    call.respond(
    status = HttpStatusCode.Forbidden,
    MyResult.Error(
    exception = "Invalid Role",
    message = "User doesn't have permission to authenticate! ${
    call.request.uri
    }",
    reasons = listOf("${definedRoles.joinToString()} role not found")
    )
    )
    }
    //User have authorized according to role defined
    else -> {
    //get all the requested access levels of user
    val currentRequestedAccessLevels = call.getAuthorityAccess()
    //get all the aceess levels defined in the route
    val authorizedaccessLevels =
    pluginConfig.authorityConfigs.find { it.userRole == tokenRule }?.accessLevels

    if (!authorizedaccessLevels!!.containsAll(currentRequestedAccessLevels)) {

    call.respond(
    status = HttpStatusCode.Forbidden,
    MyResult.Error(
    exception = "User $tokenRule doesn't have permission to ${currentRequestedAccessLevels.joinToString()}",
    message = "User doesn't have permission to authenticate! ${
    call.request.uri
    }",
    reasons = listOf("${currentRequestedAccessLevels.joinToString()} access not found")
    )
    )
    }
    }
    }



    }
    else {
    call.respond(
    status = HttpStatusCode.BadRequest,
    MyResult.Error(
    exception = "Invalid Role",
    message = "Check Header",
    reasons = listOf("$definedRoles role not found ")
    )
    )
    }


    }
    }
    }

    fun ApplicationCall.getAuthorityAccess(): Set<AccessLevel> {
    val currentAccessLevel = mutableSetOf<AccessLevel>()
    when (this.request.httpMethod) {
    HttpMethod.Get, HttpMethod.Head -> {
    currentAccessLevel.add(AccessLevel.Read)
    }

    HttpMethod.Put -> {
    currentAccessLevel.add(AccessLevel.Write)
    }

    HttpMethod.Delete -> {
    currentAccessLevel.add(AccessLevel.Delete)
    }

    HttpMethod.Patch, HttpMethod.Post -> {
    currentAccessLevel.add(AccessLevel.Update)
    }


    }
    return currentAccessLevel
    }

    fun ApplicationCall.getRoleFromToken(): UserRole? {
    val role = this.principal<JWTPrincipal>()?.payload?.getClaim("role")?.asString()
    if (role != null) {
    println("role in claim $role")
    println("getRoleFromToken: ${UserRole.valueOf(role)}")
    return UserRole.valueOf(role)
    }
    return null
    }