Skip to content

Commit

Permalink
chore(model-server): deduplicate authorization logic
Browse files Browse the repository at this point in the history
The logic determining the verifier was a duplicate of the logic used in the additional validation.

The logic from the validation (aka `ModelixAuthorizationConfig,nullIfInvalid`) is also used elsewhere.
For example, it is used in the workspaces through the modelix-authorization lib.
So it was reused in a custom verifier.

Calling `ModelixAuthorizationConfig.nullIfInvalid` again in `validate` is redundant.
It is now only used to create a custom principal object.
  • Loading branch information
odzhychko committed Sep 27, 2024
1 parent 1490539 commit b08d14a
Showing 1 changed file with 24 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ package org.modelix.authorization

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.exceptions.JWTVerificationException
import com.auth0.jwt.interfaces.DecodedJWT
import com.auth0.jwt.interfaces.JWTVerifier
import com.google.common.cache.CacheBuilder
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
Expand Down Expand Up @@ -80,31 +83,18 @@ object ModelixAuthorization : BaseRouteScopedPlugin<IModelixAuthorizationConfig,
} else {
// "Authorization: Bearer ..." header is provided in the header by OAuth proxy
jwt(MODELIX_JWT_AUTH) {
val jwkProvider = config.getJwkProvider()
val jwtAlgorithm = config.getJwtSignatureAlgorithmOrNull()
// If JWK URI and JWT algorithm is configured only use the configured algorithm.
// This is the case if MODELIX_JWK_URI and MODELIX_JWK_KEY_ID are configured.
if (jwtAlgorithm != null) {
verifier(getVerifierForSpecificAlgorithm(jwtAlgorithm))
} else if (jwkProvider != null) {
verifier(jwkProvider)
} else {
error("Either an JWT algorithm or a JWK URI must be configured.")
}
verifier(config.getVerifier())
challenge { _, _ ->
call.respond(status = HttpStatusCode.Unauthorized, "No or invalid JWT token provided")
// login and token generation is done by OAuth proxy. Only validation is required here.
}
validate {
try {
val token = jwtFromHeaders()
if (token != null) {
return@validate config.nullIfInvalid(token)?.let { AccessTokenPrincipal(it) }
}
jwtFromHeaders()?.let(::AccessTokenPrincipal)
} catch (e: Exception) {
LOG.warn(e) { "Failed to read JWT token" }
null
}
null
}
}
}
Expand Down Expand Up @@ -203,3 +193,21 @@ class ModelixAuthorizationPluginInstance(val config: ModelixAuthorizationConfig)
}
}
}

/**
* Returns an [JWTVerifier] that wraps our common authorization logic,
* so that it can be configured in the verification with Ktor's JWT authorization.
*/
internal fun ModelixAuthorizationConfig.getVerifier() = object : JWTVerifier {
override fun verify(token: String?): DecodedJWT {
val jwt = JWT.decode(token)
return verify(jwt)
}

override fun verify(jwt: DecodedJWT?): DecodedJWT {
if (jwt == null) {
throw JWTVerificationException("No JWT provided.")
}
return this@getVerifier.nullIfInvalid(jwt) ?: throw JWTVerificationException("JWT invalid.")
}
}

0 comments on commit b08d14a

Please sign in to comment.