Skip to content

Commit

Permalink
support THRIFT_HTTP and REST Protocol isolated authentication con…
Browse files Browse the repository at this point in the history
…figuration `AUTHENTICATION_CUSTOM_CLASS`
  • Loading branch information
wangjunbo committed Feb 21, 2024
1 parent 8a877af commit a8713a6
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,14 @@ object KyuubiConf {
.serverOnly
.fallbackConf(AUTHENTICATION_METHOD)

val FRONTEND_THRIFT_HTTP_AUTHENTICATION_METHOD: ConfigEntry[Seq[String]] =
buildConf("kyuubi.frontend.thrift.http.authentication")
.doc("A comma-separated list of thrift http protocol client authentication types." +
" It fallback to `kyuubi.authentication` if not configure.")
.version("1.9.0")
.serverOnly
.fallbackConf(AUTHENTICATION_METHOD)

val AUTHENTICATION_CUSTOM_CLASS: OptionalConfigEntry[String] =
buildConf("kyuubi.authentication.custom.class")
.doc("User-defined authentication implementation of " +
Expand All @@ -814,6 +822,23 @@ object KyuubiConf {
.stringConf
.createOptional

val FRONTEND_REST_AUTHENTICATION_CUSTOM_CLASS: ConfigEntry[Option[String]] =
buildConf("kyuubi.frontend.rest.authentication.custom.class")
.doc("User-defined authentication implementation of " +
"org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider for rest protocol.")
.version("1.9.0")
.serverOnly
.fallbackConf(AUTHENTICATION_CUSTOM_CLASS)

val FRONTEND_THRIFT_HTTP_AUTHENTICATION_CUSTOM_CLASS: ConfigEntry[Option[String]] =
buildConf("kyuubi.frontend.thrift.http.authentication.custom.class")
.doc("User-defined authentication implementation of " +
"org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider" +
" for thrift http protocol.")
.version("1.9.0")
.serverOnly
.fallbackConf(AUTHENTICATION_CUSTOM_CLASS)

val AUTHENTICATION_LDAP_URL: OptionalConfigEntry[String] =
buildConf("kyuubi.authentication.ldap.url")
.doc("SPACE character separated LDAP connection URL(s).")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package org.apache.kyuubi.service.authentication
import javax.security.sasl.AuthenticationException

import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.{FrontendProtocol, REST, THRIFT_HTTP}
import org.apache.kyuubi.service.authentication.AuthMethods.AuthMethod
import org.apache.kyuubi.util.ClassUtils

Expand All @@ -31,22 +32,28 @@ object AuthenticationProviderFactory {
def getAuthenticationProvider(
method: AuthMethod,
conf: KyuubiConf,
protocol: FrontendProtocol,
isServer: Boolean = true): PasswdAuthenticationProvider = {
if (isServer) {
getAuthenticationProviderForServer(method, conf)
getAuthenticationProviderForServer(method, conf, protocol)
} else {
getAuthenticationProviderForEngine(conf)
}
}

private def getAuthenticationProviderForServer(
method: AuthMethod,
conf: KyuubiConf): PasswdAuthenticationProvider = method match {
conf: KyuubiConf,
protocol: FrontendProtocol): PasswdAuthenticationProvider = method match {
case AuthMethods.NONE => new AnonymousAuthenticationProviderImpl
case AuthMethods.LDAP => new LdapAuthenticationProviderImpl(conf)
case AuthMethods.JDBC => new JdbcAuthenticationProviderImpl(conf)
case AuthMethods.CUSTOM =>
val className = conf.get(KyuubiConf.AUTHENTICATION_CUSTOM_CLASS)
val className = protocol match {
case REST => conf.get(KyuubiConf.FRONTEND_REST_AUTHENTICATION_CUSTOM_CLASS)
case THRIFT_HTTP => conf.get(KyuubiConf.FRONTEND_THRIFT_HTTP_AUTHENTICATION_CUSTOM_CLASS)
case _ => conf.get(KyuubiConf.AUTHENTICATION_CUSTOM_CLASS)
}
if (className.isEmpty) {
throw new AuthenticationException(
"authentication.custom.class must be set when auth method was CUSTOM.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ import javax.security.sasl.Sasl
import org.apache.kyuubi.Logging
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf._
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.{FrontendProtocol, THRIFT_BINARY, THRIFT_HTTP}
import org.apache.kyuubi.service.authentication.AuthTypes._
import org.apache.kyuubi.shaded.hive.service.rpc.thrift.TCLIService.Iface
import org.apache.kyuubi.shaded.thrift.TProcessorFactory
import org.apache.kyuubi.shaded.thrift.transport.{TSaslServerTransport, TTransportException, TTransportFactory}

class KyuubiAuthenticationFactory(conf: KyuubiConf, isServer: Boolean = true) extends Logging {
class KyuubiAuthenticationFactory(
conf: KyuubiConf,
isServer: Boolean = true,
protocol: FrontendProtocol = THRIFT_BINARY) extends Logging {

val authTypes: Seq[AuthType] = conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)
val authTypes: Seq[AuthType] = protocol match {
case THRIFT_HTTP => conf.get(FRONTEND_THRIFT_HTTP_AUTHENTICATION_METHOD).map(AuthTypes.withName)
case _ => conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)
}
val saslDisabled: Boolean = AuthUtils.saslDisabled(authTypes)
val kerberosEnabled: Boolean = AuthUtils.kerberosEnabled(authTypes)
val effectivePlainAuthType: Option[AuthType] = AuthUtils.effectivePlainAuthType(authTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import javax.security.auth.callback.{Callback, CallbackHandler, NameCallback, Pa
import javax.security.sasl.AuthorizeCallback

import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_BINARY
import org.apache.kyuubi.service.authentication.AuthMethods.AuthMethod
import org.apache.kyuubi.service.authentication.PlainSASLServer.SaslPlainProvider
import org.apache.kyuubi.shaded.hive.service.rpc.thrift.TCLIService.Iface
Expand Down Expand Up @@ -64,7 +65,11 @@ object PlainSASLHelper {
}
}
val provider =
AuthenticationProviderFactory.getAuthenticationProvider(authMethod, conf, isServer)
AuthenticationProviderFactory.getAuthenticationProvider(
authMethod,
conf,
THRIFT_BINARY,
isServer)
provider.authenticate(username, password)
if (ac != null) ac.setAuthorized(true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.eclipse.jetty.servlet.{ErrorPageErrorHandler, FilterHolder}
import org.apache.kyuubi.{KyuubiException, Utils}
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf._
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.REST
import org.apache.kyuubi.server.api.v1.ApiRootResource
import org.apache.kyuubi.server.http.authentication.{AuthenticationFilter, KyuubiHttpAuthenticationFactory}
import org.apache.kyuubi.server.ui.{JettyServer, JettyUtils}
Expand Down Expand Up @@ -103,9 +104,11 @@ class KyuubiRestFrontendService(override val serverable: Serverable)

private def startInternal(): Unit = {
val contextHandler = ApiRootResource.getServletHandler(this)
val holder = new FilterHolder(new AuthenticationFilter(
conf,
conf.get(FRONTEND_REST_AUTHENTICATION_METHOD).map(AuthTypes.withName)))
val holder = new FilterHolder(
new AuthenticationFilter(
conf,
conf.get(FRONTEND_REST_AUTHENTICATION_METHOD).map(AuthTypes.withName),
REST))
contextHandler.addFilter(holder, "/v1/*", EnumSet.allOf(classOf[DispatcherType]))
val authenticationFactory = new KyuubiHttpAuthenticationFactory(conf)
server.addHandler(authenticationFactory.httpHandlerWrapperFactory.wrapHandler(contextHandler))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ import org.eclipse.jetty.util.thread.ExecutorThreadPool
import org.apache.kyuubi.KyuubiException
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf._
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_HTTP
import org.apache.kyuubi.metrics.MetricsConstants.{THRIFT_HTTP_CONN_FAIL, THRIFT_HTTP_CONN_OPEN, THRIFT_HTTP_CONN_TOTAL}
import org.apache.kyuubi.metrics.MetricsSystem
import org.apache.kyuubi.server.http.ThriftHttpServlet
import org.apache.kyuubi.server.http.util.SessionManager
import org.apache.kyuubi.service.{Serverable, Service, ServiceUtils, TFrontendService}
import org.apache.kyuubi.service.authentication.KyuubiAuthenticationFactory
import org.apache.kyuubi.shaded.hive.service.rpc.thrift.{TCLIService, TOpenSessionReq}
import org.apache.kyuubi.shaded.thrift.protocol.TBinaryProtocol
import org.apache.kyuubi.util.NamedThreadFactory
Expand All @@ -59,6 +61,8 @@ final class KyuubiTHttpFrontendService(
override protected lazy val portNum: Int = conf.get(FRONTEND_THRIFT_HTTP_BIND_PORT)
override protected lazy val actualPort: Int = portNum
override protected lazy val serverSocket: ServerSocket = null
override protected lazy val authFactory: KyuubiAuthenticationFactory =
new KyuubiAuthenticationFactory(conf, isServer(), THRIFT_HTTP)

private var server: Option[Server] = None
private val APPLICATION_THRIFT = "application/x-thrift"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.apache.hadoop.hive.shims.Utils
import org.apache.kyuubi.Logging
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf.{AUTHENTICATION_METHOD, FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER}
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_HTTP
import org.apache.kyuubi.server.http.authentication.AuthenticationFilter
import org.apache.kyuubi.server.http.util.{CookieSigner, HttpAuthUtils, SessionManager}
import org.apache.kyuubi.server.http.util.HttpAuthUtils.AUTHORIZATION_HEADER
Expand All @@ -57,7 +58,10 @@ class ThriftHttpServlet(
private var isHttpOnlyCookie = false
private val X_FORWARDED_FOR_HEADER = "X-Forwarded-For"
private val authenticationFilter =
new AuthenticationFilter(conf, conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName))
new AuthenticationFilter(
conf,
conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName),
THRIFT_HTTP)

override def init(): Unit = {
isCookieAuthEnabled = conf.get(KyuubiConf.FRONTEND_THRIFT_HTTP_COOKIE_AUTH_ENABLED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ import scala.collection.mutable
import org.apache.kyuubi.Logging
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf.FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.{FrontendProtocol, REST}
import org.apache.kyuubi.server.http.util.HttpAuthUtils.AUTHORIZATION_HEADER
import org.apache.kyuubi.service.authentication.{AuthTypes, InternalSecurityAccessor}
import org.apache.kyuubi.service.authentication.AuthTypes.{KERBEROS, NOSASL}

class AuthenticationFilter(conf: KyuubiConf, authTypes: Seq[AuthTypes.Value]) extends Filter
class AuthenticationFilter(
conf: KyuubiConf,
authTypes: Seq[AuthTypes.Value],
protocol: FrontendProtocol) extends Filter
with Logging {
import AuthenticationFilter._
import AuthSchemes._
Expand Down Expand Up @@ -69,7 +73,7 @@ class AuthenticationFilter(conf: KyuubiConf, authTypes: Seq[AuthTypes.Value]) ex
addAuthHandler(kerberosHandler)
}
basicAuthTypeOpt.foreach { basicAuthType =>
val basicHandler = new BasicAuthenticationHandler(basicAuthType)
val basicHandler = new BasicAuthenticationHandler(basicAuthType, protocol)
addAuthHandler(basicHandler)
}
if (InternalSecurityAccessor.get() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ import javax.servlet.http.{HttpServletRequest, HttpServletResponse}

import org.apache.kyuubi.Logging
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.FrontendProtocol
import org.apache.kyuubi.server.http.authentication.AuthSchemes.AuthScheme
import org.apache.kyuubi.server.http.util.HttpAuthUtils.{AUTHORIZATION_HEADER, WWW_AUTHENTICATE_HEADER}
import org.apache.kyuubi.service.authentication.{AuthenticationProviderFactory, AuthMethods}
import org.apache.kyuubi.service.authentication.AuthTypes._

class BasicAuthenticationHandler(basicAuthType: AuthType)
class BasicAuthenticationHandler(basicAuthType: AuthType, protocol: FrontendProtocol)
extends AuthenticationHandler with Logging {

private var conf: KyuubiConf = _
Expand Down Expand Up @@ -80,7 +81,7 @@ class BasicAuthenticationHandler(basicAuthType: AuthType)
} else {
val Seq(user, password) = creds.toSeq.take(2)
val passwdAuthenticationProvider = AuthenticationProviderFactory
.getAuthenticationProvider(AuthMethods.withName(basicAuthType.toString), conf)
.getAuthenticationProvider(AuthMethods.withName(basicAuthType.toString), conf, protocol)
passwdAuthenticationProvider.authenticate(user, password)
response.setStatus(HttpServletResponse.SC_OK)
authUser = user
Expand Down

0 comments on commit a8713a6

Please sign in to comment.