From b899d7cddebd97d5a522cf0e63c8ca918186be36 Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Mon, 5 Feb 2024 16:01:37 +0800 Subject: [PATCH 01/10] [KYUUBI #6041] RESTful API supports isolated authentication configuration --- docs/configuration/settings.md | 1 + .../org/apache/kyuubi/config/KyuubiConf.scala | 8 +++++ .../server/KyuubiRestFrontendService.scala | 6 ++-- .../server/http/ThriftHttpServlet.scala | 7 +++-- .../authentication/AuthenticationFilter.scala | 6 ++-- .../KyuubiHttpAuthenticationFactory.scala | 4 +-- .../apache/kyuubi/RestClientTestHelper.scala | 4 ++- .../KyuubiRestAuthenticationSuite.scala | 30 +++++++++++++++++++ .../KyuubiRestFrontendServiceSuite.scala | 8 ++--- .../server/api/v1/AdminResourceSuite.scala | 2 +- .../server/api/v1/BatchesResourceSuite.scala | 2 +- .../AuthenticationFilterSuite.scala | 5 +++- .../server/rest/client/AdminCtlSuite.scala | 2 +- .../rest/client/AdminRestApiSuite.scala | 2 +- 14 files changed, 67 insertions(+), 20 deletions(-) diff --git a/docs/configuration/settings.md b/docs/configuration/settings.md index b3a9ff337db..663043e61d5 100644 --- a/docs/configuration/settings.md +++ b/docs/configuration/settings.md @@ -246,6 +246,7 @@ You can configure the Kyuubi properties in `$KYUUBI_HOME/conf/kyuubi-defaults.co | kyuubi.frontend.mysql.worker.keepalive.time | PT1M | Time(ms) that an idle async thread of the command execution thread pool will wait for a new task to arrive before terminating in MySQL frontend service | duration | 1.4.0 | | kyuubi.frontend.protocols | THRIFT_BINARY,REST | A comma-separated list for all frontend protocols | seq | 1.4.0 | | kyuubi.frontend.proxy.http.client.ip.header | X-Real-IP | The HTTP header to record the real client IP address. If your server is behind a load balancer or other proxy, the server will see this load balancer or proxy IP address as the client IP address, to get around this common issue, most load balancers or proxies offer the ability to record the real remote IP address in an HTTP header that will be added to the request for other devices to use. Note that, because the header value can be specified to any IP address, so it will not be used for authentication. | string | 1.6.0 | +| kyuubi.frontend.rest.authentication | NONE | A comma-separated list of client authentication types. It fallback to `kyuubi.authentication` if not configure. | seq | 1.9.0 | | kyuubi.frontend.rest.bind.host | <undefined> | Hostname or IP of the machine on which to run the REST frontend service. | string | 1.4.0 | | kyuubi.frontend.rest.bind.port | 10099 | Port of the machine on which to run the REST frontend service. | int | 1.4.0 | | kyuubi.frontend.rest.max.worker.threads | 999 | Maximum number of threads in the frontend worker thread pool for the rest frontend service | int | 1.6.2 | diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala index 9f09e9bb636..c943823133b 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala @@ -797,6 +797,14 @@ object KyuubiConf { .checkValues(AuthTypes) .createWithDefault(Seq(AuthTypes.NONE.toString)) + val FRONTEND_REST_AUTHENTICATION_METHOD: ConfigEntry[Seq[String]] = + buildConf("kyuubi.frontend.rest.authentication") + .doc("A comma-separated list of 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 " + diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala index 83aee66fef0..b9211d17e6e 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala @@ -72,7 +72,7 @@ class KyuubiRestFrontendService(override val serverable: Serverable) private lazy val port: Int = conf.get(FRONTEND_REST_BIND_PORT) private[kyuubi] lazy val securityEnabled = { - val authTypes = conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName) + val authTypes = conf.get(FRONTEND_REST_AUTHENTICATION_METHOD).map(AuthTypes.withName) AuthUtils.kerberosEnabled(authTypes) || !AuthUtils.effectivePlainAuthType(authTypes).contains(AuthTypes.NONE) } @@ -103,7 +103,9 @@ class KyuubiRestFrontendService(override val serverable: Serverable) private def startInternal(): Unit = { val contextHandler = ApiRootResource.getServletHandler(this) - val holder = new FilterHolder(new AuthenticationFilter(conf)) + val holder = new FilterHolder(new AuthenticationFilter( + conf, + conf.get(FRONTEND_REST_AUTHENTICATION_METHOD).map(AuthTypes.withName))) contextHandler.addFilter(holder, "/v1/*", EnumSet.allOf(classOf[DispatcherType])) val authenticationFactory = new KyuubiHttpAuthenticationFactory(conf) server.addHandler(authenticationFactory.httpHandlerWrapperFactory.wrapHandler(contextHandler)) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala index 980f35d70b5..8b22a717dee 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala @@ -30,11 +30,11 @@ import org.apache.hadoop.hive.shims.Utils 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.{AUTHENTICATION_METHOD, FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER} 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 -import org.apache.kyuubi.service.authentication.KyuubiAuthenticationFactory +import org.apache.kyuubi.service.authentication.{AuthTypes, KyuubiAuthenticationFactory} import org.apache.kyuubi.shaded.thrift.TProcessor import org.apache.kyuubi.shaded.thrift.protocol.TProtocolFactory import org.apache.kyuubi.shaded.thrift.server.TServlet @@ -56,7 +56,8 @@ class ThriftHttpServlet( private var isCookieSecure = false private var isHttpOnlyCookie = false private val X_FORWARDED_FOR_HEADER = "X-Forwarded-For" - private val authenticationFilter = new AuthenticationFilter(conf) + private val authenticationFilter = + new AuthenticationFilter(conf, conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)) override def init(): Unit = { isCookieAuthEnabled = conf.get(KyuubiConf.FRONTEND_THRIFT_HTTP_COOKIE_AUTH_ENABLED) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala index 15b387607ea..1339a75334d 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala @@ -26,12 +26,13 @@ import scala.collection.mutable 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.FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER 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) extends Filter with Logging { +class AuthenticationFilter(conf: KyuubiConf, authTypes: Seq[AuthTypes.Value]) extends Filter + with Logging { import AuthenticationFilter._ import AuthSchemes._ @@ -55,7 +56,6 @@ class AuthenticationFilter(conf: KyuubiConf) extends Filter with Logging { } private[kyuubi] def initAuthHandlers(): Unit = { - val authTypes = conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName) val spnegoKerberosEnabled = authTypes.contains(KERBEROS) val basicAuthTypeOpt = { if (authTypes == Set(NOSASL)) { diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala index ca95fda3d9a..250ee5d6462 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala @@ -25,14 +25,14 @@ import org.eclipse.jetty.server.{Handler, Request} import org.eclipse.jetty.server.handler.HandlerWrapper import org.apache.kyuubi.config.KyuubiConf -import org.apache.kyuubi.config.KyuubiConf.{AUTHENTICATION_METHOD, ENGINE_SECURITY_ENABLED} +import org.apache.kyuubi.config.KyuubiConf.{ENGINE_SECURITY_ENABLED, FRONTEND_REST_AUTHENTICATION_METHOD} import org.apache.kyuubi.metrics.MetricsConstants.{REST_CONN_FAIL, REST_CONN_OPEN, REST_CONN_TOTAL} import org.apache.kyuubi.metrics.MetricsSystem import org.apache.kyuubi.service.authentication.{AuthTypes, InternalSecurityAccessor} import org.apache.kyuubi.service.authentication.AuthTypes.KERBEROS class KyuubiHttpAuthenticationFactory(conf: KyuubiConf) { - private val authTypes = conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName) + private val authTypes = conf.get(FRONTEND_REST_AUTHENTICATION_METHOD).map(AuthTypes.withName) private val kerberosEnabled = authTypes.contains(KERBEROS) private val ugi = UserGroupInformation.getCurrentUser diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala index 8344cdef01d..f063a0e1ff1 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala @@ -48,7 +48,9 @@ trait RestClientTestHelper extends RestFrontendTestHelper with KerberizedTestHel UserGroupInformation.setConfiguration(config) assert(UserGroupInformation.isSecurityEnabled) - val conf = KyuubiConf().set(KyuubiConf.AUTHENTICATION_METHOD, Seq("KERBEROS", "LDAP", "CUSTOM")) + val conf = KyuubiConf().set( + KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, + Seq("KERBEROS", "LDAP", "CUSTOM")) .set(KyuubiConf.SERVER_KEYTAB.key, testKeytab) .set(KyuubiConf.SERVER_PRINCIPAL, testPrincipal) .set(KyuubiConf.SERVER_SPNEGO_KEYTAB, testKeytab) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala index 260264b6797..965e4ccd669 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala @@ -182,3 +182,33 @@ class KyuubiRestAuthenticationSuite extends RestClientTestHelper { assert(HttpServletResponse.SC_UNAUTHORIZED == response.getStatus) } } + +class NoneKyuubiRestAuthenticationSuite extends RestClientTestHelper { + + override protected val otherConfigs: Map[String, String] = { + Map(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "NONE") + } + + test("test disable restful api authentication") { + val response = webTarget.path("api/v1/sessions/count") + .request() + .get() + + assert(HttpServletResponse.SC_OK == response.getStatus) + } +} + +class KerberosKyuubiRestAuthenticationSuite extends RestClientTestHelper { + + override protected val otherConfigs: Map[String, String] = { + Map(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "KERBEROS") + } + + test("test without authorization when rest api authentication with KERBEROS") { + val response = webTarget.path("api/v1/sessions/count") + .request() + .get() + + assert(HttpServletResponse.SC_UNAUTHORIZED == response.getStatus) + } +} diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala index b60517a06d8..5786b57d358 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala @@ -26,7 +26,7 @@ import org.apache.kyuubi.service.authentication.AnonymousAuthenticationProviderI class KyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(AUTHENTICATION_METHOD, Seq("NONE")) + .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("NONE")) test("version") { val resp = v1Call("version") @@ -61,7 +61,7 @@ class KyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { class KerberosKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(AUTHENTICATION_METHOD, Seq("KERBEROS")) + .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("KERBEROS")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) test("security enabled - KERBEROS") { @@ -72,7 +72,7 @@ class KerberosKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { class NoneKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(AUTHENTICATION_METHOD, Seq("NONE")) + .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("NONE")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) test("security enabled - NONE") { @@ -83,7 +83,7 @@ class NoneKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { class KerberosAndCustomKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(AUTHENTICATION_METHOD, Seq("KERBEROS,CUSTOM")) + .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("KERBEROS,CUSTOM")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) test("security enabled - KERBEROS,CUSTOM") { diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala index 95aa3de025d..2318ad5cf53 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala @@ -51,7 +51,7 @@ class AdminResourceSuite extends KyuubiFunSuite with RestFrontendTestHelper { private val engineMgr = new KyuubiApplicationManager() override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(AUTHENTICATION_METHOD, Seq("CUSTOM")) + .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("CUSTOM")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) .set(SERVER_ADMINISTRATORS, Set("admin001")) .set(ENGINE_IDLE_TIMEOUT, Duration.ofMinutes(3).toMillis) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala index f1ee71bec9f..1f913068dac 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala @@ -85,7 +85,7 @@ abstract class BatchesResourceSuiteBase extends KyuubiFunSuite override protected lazy val conf: KyuubiConf = { val testResourceDir = Paths.get(sparkBatchTestResource.get).getParent val kyuubiConf = KyuubiConf() - .set(AUTHENTICATION_METHOD, Seq("CUSTOM")) + .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("CUSTOM")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) .set(SERVER_ADMINISTRATORS, Set("admin")) .set(BATCH_IMPL_VERSION, batchVersion) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala index de4b056ff46..62f4fa16aab 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala @@ -19,11 +19,14 @@ package org.apache.kyuubi.server.http.authentication import org.apache.kyuubi.KyuubiFunSuite import org.apache.kyuubi.config.KyuubiConf +import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD import org.apache.kyuubi.service.authentication.AuthTypes class AuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { - val filter = new AuthenticationFilter(KyuubiConf()) + val conf = KyuubiConf() + val filter = + new AuthenticationFilter(conf, conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)) filter.addAuthHandler(new BasicAuthenticationHandler(null)) assert(filter.authSchemeHandlers.isEmpty) filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP)) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala index 0c262d2389a..76649ad33e7 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala @@ -56,7 +56,7 @@ class AdminCtlSuite extends RestClientTestHelper with TestPrematureExit { val id = UUID.randomUUID().toString conf.set(HighAvailabilityConf.HA_NAMESPACE, "kyuubi_test") conf.set(KyuubiConf.ENGINE_IDLE_TIMEOUT, 180000L) - conf.set(KyuubiConf.AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) + conf.set(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) conf.set(KyuubiConf.GROUP_PROVIDER, "hadoop") val user = ldapUser diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala index 43eb06482e7..f6b51f5a85c 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala @@ -50,7 +50,7 @@ class AdminRestApiSuite extends RestClientTestHelper { val id = UUID.randomUUID().toString conf.set(HighAvailabilityConf.HA_NAMESPACE, "kyuubi_test") conf.set(KyuubiConf.ENGINE_IDLE_TIMEOUT, 180000L) - conf.set(KyuubiConf.AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) + conf.set(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) conf.set(KyuubiConf.GROUP_PROVIDER, "hadoop") val user = ldapUser val engine = From 8a877afe98709989a880afe28f18bb0090a8a7bc Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Tue, 20 Feb 2024 20:05:59 +0800 Subject: [PATCH 02/10] fix test --- docs/configuration/settings.md | 2 +- .../main/scala/org/apache/kyuubi/config/KyuubiConf.scala | 2 +- .../kyuubi/operation/KyuubiRestAuthenticationSuite.scala | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/configuration/settings.md b/docs/configuration/settings.md index 663043e61d5..df42b153ead 100644 --- a/docs/configuration/settings.md +++ b/docs/configuration/settings.md @@ -246,7 +246,7 @@ You can configure the Kyuubi properties in `$KYUUBI_HOME/conf/kyuubi-defaults.co | kyuubi.frontend.mysql.worker.keepalive.time | PT1M | Time(ms) that an idle async thread of the command execution thread pool will wait for a new task to arrive before terminating in MySQL frontend service | duration | 1.4.0 | | kyuubi.frontend.protocols | THRIFT_BINARY,REST | A comma-separated list for all frontend protocols | seq | 1.4.0 | | kyuubi.frontend.proxy.http.client.ip.header | X-Real-IP | The HTTP header to record the real client IP address. If your server is behind a load balancer or other proxy, the server will see this load balancer or proxy IP address as the client IP address, to get around this common issue, most load balancers or proxies offer the ability to record the real remote IP address in an HTTP header that will be added to the request for other devices to use. Note that, because the header value can be specified to any IP address, so it will not be used for authentication. | string | 1.6.0 | -| kyuubi.frontend.rest.authentication | NONE | A comma-separated list of client authentication types. It fallback to `kyuubi.authentication` if not configure. | seq | 1.9.0 | +| kyuubi.frontend.rest.authentication | NONE | A comma-separated list of rest protocol client authentication types. It fallback to `kyuubi.authentication` if not configure. | seq | 1.9.0 | | kyuubi.frontend.rest.bind.host | <undefined> | Hostname or IP of the machine on which to run the REST frontend service. | string | 1.4.0 | | kyuubi.frontend.rest.bind.port | 10099 | Port of the machine on which to run the REST frontend service. | int | 1.4.0 | | kyuubi.frontend.rest.max.worker.threads | 999 | Maximum number of threads in the frontend worker thread pool for the rest frontend service | int | 1.6.2 | diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala index c943823133b..136cd10c840 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala @@ -799,7 +799,7 @@ object KyuubiConf { val FRONTEND_REST_AUTHENTICATION_METHOD: ConfigEntry[Seq[String]] = buildConf("kyuubi.frontend.rest.authentication") - .doc("A comma-separated list of client authentication types." + + .doc("A comma-separated list of rest protocol client authentication types." + " It fallback to `kyuubi.authentication` if not configure.") .version("1.9.0") .serverOnly diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala index 965e4ccd669..fb9e574ba61 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala @@ -186,7 +186,9 @@ class KyuubiRestAuthenticationSuite extends RestClientTestHelper { class NoneKyuubiRestAuthenticationSuite extends RestClientTestHelper { override protected val otherConfigs: Map[String, String] = { - Map(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "NONE") + Map( + KyuubiConf.AUTHENTICATION_METHOD.key -> "KERBEROS", + KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "NONE") } test("test disable restful api authentication") { @@ -201,7 +203,7 @@ class NoneKyuubiRestAuthenticationSuite extends RestClientTestHelper { class KerberosKyuubiRestAuthenticationSuite extends RestClientTestHelper { override protected val otherConfigs: Map[String, String] = { - Map(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "KERBEROS") + Map(KyuubiConf.AUTHENTICATION_METHOD.key -> "KERBEROS") } test("test without authorization when rest api authentication with KERBEROS") { From 30bc5646ed2a27e0baa715d1fe7a8dfae39d1352 Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Thu, 22 Feb 2024 15:49:46 +0800 Subject: [PATCH 03/10] support rest api user defined authentication --- docs/configuration/settings.md | 1 + .../org/apache/kyuubi/config/KyuubiConf.scala | 8 ++++++ .../kyuubi/service/TFrontendService.scala | 3 ++- .../AuthenticationProviderFactory.scala | 12 ++++++--- .../KyuubiAuthenticationFactory.scala | 7 ++++- .../authentication/PlainSASLHelper.scala | 19 +++++++++++--- .../AuthenticationProviderFactorySuite.scala | 7 ++--- ...ustomAuthenticationProviderImplSuite.scala | 26 +++++++++++++++++-- .../KyuubiAuthenticationFactorySuite.scala | 18 +++++++------ .../authentication/PlainSASLHelperSuite.scala | 9 ++++--- .../server/KyuubiRestFrontendService.scala | 9 ++++--- .../server/KyuubiTHttpFrontendService.scala | 4 +++ .../server/http/ThriftHttpServlet.scala | 6 ++++- .../authentication/AuthenticationFilter.scala | 8 ++++-- .../BasicAuthenticationHandler.scala | 5 ++-- .../AuthenticationFilterSuite.scala | 12 ++++++--- 16 files changed, 116 insertions(+), 38 deletions(-) diff --git a/docs/configuration/settings.md b/docs/configuration/settings.md index df42b153ead..58890b14fa0 100644 --- a/docs/configuration/settings.md +++ b/docs/configuration/settings.md @@ -247,6 +247,7 @@ You can configure the Kyuubi properties in `$KYUUBI_HOME/conf/kyuubi-defaults.co | kyuubi.frontend.protocols | THRIFT_BINARY,REST | A comma-separated list for all frontend protocols
  • THRIFT_BINARY - HiveServer2 compatible thrift binary protocol.
  • THRIFT_HTTP - HiveServer2 compatible thrift http protocol.
  • REST - Kyuubi defined REST API(experimental).
  • MYSQL - MySQL compatible text protocol(experimental).
  • TRINO - Trino compatible http protocol(experimental).
| seq | 1.4.0 | | kyuubi.frontend.proxy.http.client.ip.header | X-Real-IP | The HTTP header to record the real client IP address. If your server is behind a load balancer or other proxy, the server will see this load balancer or proxy IP address as the client IP address, to get around this common issue, most load balancers or proxies offer the ability to record the real remote IP address in an HTTP header that will be added to the request for other devices to use. Note that, because the header value can be specified to any IP address, so it will not be used for authentication. | string | 1.6.0 | | kyuubi.frontend.rest.authentication | NONE | A comma-separated list of rest protocol client authentication types. It fallback to `kyuubi.authentication` if not configure. | seq | 1.9.0 | +| kyuubi.frontend.rest.authentication.custom.class | <undefined> | User-defined authentication implementation of org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider for rest protocol. | string | 1.9.0 | | kyuubi.frontend.rest.bind.host | <undefined> | Hostname or IP of the machine on which to run the REST frontend service. | string | 1.4.0 | | kyuubi.frontend.rest.bind.port | 10099 | Port of the machine on which to run the REST frontend service. | int | 1.4.0 | | kyuubi.frontend.rest.max.worker.threads | 999 | Maximum number of threads in the frontend worker thread pool for the rest frontend service | int | 1.6.2 | diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala index 136cd10c840..f2e4a4db988 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala @@ -814,6 +814,14 @@ 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 AUTHENTICATION_LDAP_URL: OptionalConfigEntry[String] = buildConf("kyuubi.authentication.ldap.url") .doc("SPACE character separated LDAP connection URL(s).") diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TFrontendService.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TFrontendService.scala index 9aefe63c8b6..77b2f4ceec0 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TFrontendService.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TFrontendService.scala @@ -28,6 +28,7 @@ import org.apache.hadoop.conf.Configuration import org.apache.kyuubi.{KyuubiSQLException, Logging, Utils} import org.apache.kyuubi.Utils.stringifyException import org.apache.kyuubi.config.KyuubiConf.{FRONTEND_ADVERTISED_HOST, FRONTEND_CONNECTION_URL_USE_HOSTNAME, PROXY_USER, SESSION_CLOSE_ON_DISCONNECT} +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_BINARY import org.apache.kyuubi.config.KyuubiReservedKeys._ import org.apache.kyuubi.operation.{FetchOrientation, OperationHandle} import org.apache.kyuubi.service.authentication.{AuthUtils, KyuubiAuthenticationFactory} @@ -57,7 +58,7 @@ abstract class TFrontendService(name: String) protected lazy val serverSocket = new ServerSocket(portNum, -1, serverAddr) protected lazy val actualPort: Int = serverSocket.getLocalPort protected lazy val authFactory: KyuubiAuthenticationFactory = - new KyuubiAuthenticationFactory(conf, isServer()) + new KyuubiAuthenticationFactory(conf, THRIFT_BINARY, isServer()) protected def hadoopConf: Configuration = _hadoopConf diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactory.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactory.scala index ffdd9b8bb90..7262e2dbb2f 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactory.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactory.scala @@ -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} import org.apache.kyuubi.service.authentication.AuthMethods.AuthMethod import org.apache.kyuubi.util.ClassUtils @@ -31,9 +32,10 @@ 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) } @@ -41,12 +43,16 @@ object AuthenticationProviderFactory { 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 _ => conf.get(KyuubiConf.AUTHENTICATION_CUSTOM_CLASS) + } if (className.isEmpty) { throw new AuthenticationException( "authentication.custom.class must be set when auth method was CUSTOM.") diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactory.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactory.scala index 978527b8818..3a846f8bfd1 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactory.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactory.scala @@ -24,12 +24,16 @@ 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 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, + protocol: FrontendProtocol, + isServer: Boolean = true) extends Logging { val authTypes: Seq[AuthType] = conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName) val saslDisabled: Boolean = AuthUtils.saslDisabled(authTypes) @@ -85,6 +89,7 @@ class KyuubiAuthenticationFactory(conf: KyuubiConf, isServer: Boolean = true) ex transportFactory = PlainSASLHelper.getTransportFactory( plainAuthType.toString, conf, + protocol, Option(transportFactory), isServer).asInstanceOf[TSaslServerTransport.Factory] diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/PlainSASLHelper.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/PlainSASLHelper.scala index 2d880a344e6..7d3efeab7cc 100644 --- a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/PlainSASLHelper.scala +++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/PlainSASLHelper.scala @@ -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.FrontendProtocol 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 @@ -42,11 +43,16 @@ object PlainSASLHelper { private class PlainServerCallbackHandler private ( authMethod: AuthMethod, conf: KyuubiConf, + protocol: FrontendProtocol, isServer: Boolean) extends CallbackHandler { - def this(authMethodStr: String, conf: KyuubiConf, isServer: Boolean) = - this(AuthMethods.withName(authMethodStr), conf, isServer) + def this( + authMethodStr: String, + conf: KyuubiConf, + protocol: FrontendProtocol, + isServer: Boolean) = + this(AuthMethods.withName(authMethodStr), conf, protocol, isServer) @throws[UnsupportedCallbackException] override def handle(callbacks: Array[Callback]): Unit = { @@ -64,7 +70,11 @@ object PlainSASLHelper { } } val provider = - AuthenticationProviderFactory.getAuthenticationProvider(authMethod, conf, isServer) + AuthenticationProviderFactory.getAuthenticationProvider( + authMethod, + conf, + protocol, + isServer) provider.authenticate(username, password) if (ac != null) ac.setAuthorized(true) } @@ -77,11 +87,12 @@ object PlainSASLHelper { def getTransportFactory( authTypeStr: String, conf: KyuubiConf, + protocol: FrontendProtocol, transportFactory: Option[TSaslServerTransport.Factory] = None, isServer: Boolean = true): TTransportFactory = { val saslFactory = transportFactory.getOrElse(new TSaslServerTransport.Factory()) try { - val handler = new PlainServerCallbackHandler(authTypeStr, conf, isServer) + val handler = new PlainServerCallbackHandler(authTypeStr, conf, protocol, isServer) val props = new java.util.HashMap[String, String] saslFactory.addServerDefinition("PLAIN", authTypeStr, null, props, handler) } catch { diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala index 0bd29ac56a9..b8de4eaa880 100644 --- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala +++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala @@ -21,6 +21,7 @@ import javax.security.sasl.AuthenticationException import org.apache.kyuubi.{KyuubiFunSuite, Utils} import org.apache.kyuubi.config.KyuubiConf +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_BINARY class AuthenticationProviderFactorySuite extends KyuubiFunSuite { @@ -28,13 +29,13 @@ class AuthenticationProviderFactorySuite extends KyuubiFunSuite { test("get auth provider") { val conf = KyuubiConf() - val p1 = getAuthenticationProvider(AuthMethods.withName("NONE"), conf) + val p1 = getAuthenticationProvider(AuthMethods.withName("NONE"), conf, THRIFT_BINARY) p1.authenticate(Utils.currentUser, "") - val p2 = getAuthenticationProvider(AuthMethods.withName("LDAP"), conf) + val p2 = getAuthenticationProvider(AuthMethods.withName("LDAP"), conf, THRIFT_BINARY) val e1 = intercept[AuthenticationException](p2.authenticate("test", "test")) assert(e1.getMessage.contains("Error validating LDAP user:")) val e2 = intercept[AuthenticationException]( - AuthenticationProviderFactory.getAuthenticationProvider(null, conf)) + AuthenticationProviderFactory.getAuthenticationProvider(null, conf, THRIFT_BINARY)) assert(e2.getMessage === "Not a valid authentication method") } diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/CustomAuthenticationProviderImplSuite.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/CustomAuthenticationProviderImplSuite.scala index 6135535e1d7..68457e7667f 100644 --- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/CustomAuthenticationProviderImplSuite.scala +++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/CustomAuthenticationProviderImplSuite.scala @@ -21,6 +21,7 @@ import javax.security.sasl.AuthenticationException import org.apache.kyuubi.KyuubiFunSuite import org.apache.kyuubi.config.KyuubiConf +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.{REST, THRIFT_BINARY} import org.apache.kyuubi.service.authentication.AuthenticationProviderFactory.getAuthenticationProvider class CustomAuthenticationProviderImplSuite extends KyuubiFunSuite { @@ -28,14 +29,35 @@ class CustomAuthenticationProviderImplSuite extends KyuubiFunSuite { val conf = KyuubiConf() val e1 = intercept[AuthenticationException]( - getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf)) + getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf, THRIFT_BINARY)) assert(e1.getMessage.contains( "authentication.custom.class must be set when auth method was CUSTOM.")) conf.set( KyuubiConf.AUTHENTICATION_CUSTOM_CLASS, classOf[UserDefineAuthenticationProviderImpl].getCanonicalName) - val p1 = getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf) + val p1 = getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf, THRIFT_BINARY) + val e2 = intercept[AuthenticationException](p1.authenticate("test", "test")) + assert(e2.getMessage.contains("Username or password is not valid!")) + + p1.authenticate("user", "password") + } +} + +class RestCustomAuthenticationProviderImplSuite extends KyuubiFunSuite { + test("Test user defined authentication") { + val conf = KyuubiConf() + + conf.set( + KyuubiConf.FRONTEND_REST_AUTHENTICATION_CUSTOM_CLASS, + Some(classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)) + + val e1 = intercept[AuthenticationException]( + getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf, THRIFT_BINARY)) + assert(e1.getMessage.contains( + "authentication.custom.class must be set when auth method was CUSTOM.")) + + val p1 = getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf, REST) val e2 = intercept[AuthenticationException](p1.authenticate("test", "test")) assert(e2.getMessage.contains("Username or password is not valid!")) diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactorySuite.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactorySuite.scala index 18520b39b64..2b5cb256723 100644 --- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactorySuite.scala +++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactorySuite.scala @@ -22,6 +22,7 @@ import javax.security.auth.login.LoginException import org.apache.kyuubi.{KyuubiFunSuite, KyuubiSQLException} import org.apache.kyuubi.config.KyuubiConf +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_BINARY import org.apache.kyuubi.service.authentication.PlainSASLServer.SaslPlainProvider import org.apache.kyuubi.shaded.thrift.transport.TSaslServerTransport import org.apache.kyuubi.util.AssertionUtils._ @@ -46,7 +47,7 @@ class KyuubiAuthenticationFactorySuite extends KyuubiFunSuite { test("AuthType NONE") { val kyuubiConf = KyuubiConf() - val auth = new KyuubiAuthenticationFactory(kyuubiConf) + val auth = new KyuubiAuthenticationFactory(kyuubiConf, THRIFT_BINARY) auth.getTTransportFactory assert(Security.getProviders.exists(_.isInstanceOf[SaslPlainProvider])) @@ -56,14 +57,15 @@ class KyuubiAuthenticationFactorySuite extends KyuubiFunSuite { test("AuthType Other") { val conf = KyuubiConf().set(KyuubiConf.AUTHENTICATION_METHOD, Seq("INVALID")) - interceptEquals[IllegalArgumentException] { new KyuubiAuthenticationFactory(conf) }( - "The value of kyuubi.authentication should be one of" + - " NOSASL, NONE, LDAP, JDBC, KERBEROS, CUSTOM, but was INVALID") + interceptEquals[IllegalArgumentException] { + new KyuubiAuthenticationFactory(conf, THRIFT_BINARY) + }("The value of kyuubi.authentication should be one of" + + " NOSASL, NONE, LDAP, JDBC, KERBEROS, CUSTOM, but was INVALID") } test("AuthType LDAP") { val conf = KyuubiConf().set(KyuubiConf.AUTHENTICATION_METHOD, Seq("LDAP")) - val authFactory = new KyuubiAuthenticationFactory(conf) + val authFactory = new KyuubiAuthenticationFactory(conf, THRIFT_BINARY) authFactory.getTTransportFactory assert(Security.getProviders.exists(_.isInstanceOf[SaslPlainProvider])) } @@ -71,18 +73,18 @@ class KyuubiAuthenticationFactorySuite extends KyuubiFunSuite { test("AuthType KERBEROS w/o keytab/principal") { val conf = KyuubiConf().set(KyuubiConf.AUTHENTICATION_METHOD, Seq("KERBEROS")) - val factory = new KyuubiAuthenticationFactory(conf) + val factory = new KyuubiAuthenticationFactory(conf, THRIFT_BINARY) val e = intercept[LoginException](factory.getTTransportFactory) assert(e.getMessage startsWith "Kerberos principal should have 3 parts") } test("AuthType is NOSASL if only NOSASL is specified") { val conf = KyuubiConf().set(KyuubiConf.AUTHENTICATION_METHOD, Seq("NOSASL")) - var factory = new KyuubiAuthenticationFactory(conf) + var factory = new KyuubiAuthenticationFactory(conf, THRIFT_BINARY) !factory.getTTransportFactory.isInstanceOf[TSaslServerTransport.Factory] conf.set(KyuubiConf.AUTHENTICATION_METHOD, Seq("NOSASL", "NONE")) - factory = new KyuubiAuthenticationFactory(conf) + factory = new KyuubiAuthenticationFactory(conf, THRIFT_BINARY) factory.getTTransportFactory.isInstanceOf[TSaslServerTransport.Factory] } } diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/PlainSASLHelperSuite.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/PlainSASLHelperSuite.scala index 2a55cc0d7ef..7681ac709df 100644 --- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/PlainSASLHelperSuite.scala +++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/PlainSASLHelperSuite.scala @@ -21,6 +21,7 @@ import java.security.Security import org.apache.kyuubi.{KYUUBI_VERSION, KyuubiFunSuite} import org.apache.kyuubi.config.KyuubiConf +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_BINARY import org.apache.kyuubi.service.{NoopTBinaryFrontendServer, TBinaryFrontendService} import org.apache.kyuubi.service.authentication.PlainSASLServer.SaslPlainProvider import org.apache.kyuubi.shaded.thrift.transport.{TSaslServerTransport, TSocket} @@ -39,20 +40,20 @@ class PlainSASLHelperSuite extends KyuubiFunSuite { val tProcessor = tProcessorFactory.getProcessor(tSocket) assert(tProcessor.isInstanceOf[TSetIpAddressProcessor[_]]) val e = intercept[IllegalArgumentException] { - PlainSASLHelper.getTransportFactory("KERBEROS", conf) + PlainSASLHelper.getTransportFactory("KERBEROS", conf, THRIFT_BINARY) } assert(e.getMessage === "Illegal authentication type KERBEROS for plain transport") val e2 = intercept[IllegalArgumentException] { - PlainSASLHelper.getTransportFactory("NOSASL", conf) + PlainSASLHelper.getTransportFactory("NOSASL", conf, THRIFT_BINARY) } assert(e2.getMessage === "Illegal authentication type NOSASL for plain transport") val e3 = intercept[IllegalArgumentException] { - PlainSASLHelper.getTransportFactory("ELSE", conf) + PlainSASLHelper.getTransportFactory("ELSE", conf, THRIFT_BINARY) } assert(e3.getMessage === "Illegal authentication type ELSE for plain transport") - val tTransportFactory = PlainSASLHelper.getTransportFactory("NONE", conf) + val tTransportFactory = PlainSASLHelper.getTransportFactory("NONE", conf, THRIFT_BINARY) assert(tTransportFactory.isInstanceOf[TSaslServerTransport.Factory]) Security.getProviders.exists(_.isInstanceOf[SaslPlainProvider]) } diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala index b9211d17e6e..5011fca94cf 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala @@ -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} @@ -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)) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala index 2763e9481f9..0b55260a495 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala @@ -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 @@ -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, THRIFT_HTTP, isServer()) private var server: Option[Server] = None private val APPLICATION_THRIFT = "application/x-thrift" diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala index 8b22a717dee..769510455ee 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala @@ -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 @@ -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) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala index 1339a75334d..d484cefa3d6 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala @@ -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 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._ @@ -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) { diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/BasicAuthenticationHandler.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/BasicAuthenticationHandler.scala index 76560cabb55..231cb5248a9 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/BasicAuthenticationHandler.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/BasicAuthenticationHandler.scala @@ -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 = _ @@ -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 diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala index 62f4fa16aab..cb86ff04cce 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala @@ -20,18 +20,22 @@ package org.apache.kyuubi.server.http.authentication import org.apache.kyuubi.KyuubiFunSuite import org.apache.kyuubi.config.KyuubiConf import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.REST import org.apache.kyuubi.service.authentication.AuthTypes class AuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { val conf = KyuubiConf() val filter = - new AuthenticationFilter(conf, conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)) - filter.addAuthHandler(new BasicAuthenticationHandler(null)) + new AuthenticationFilter( + conf, + conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName), + REST) + filter.addAuthHandler(new BasicAuthenticationHandler(null, REST)) assert(filter.authSchemeHandlers.isEmpty) - filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP)) + filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, REST)) assert(filter.authSchemeHandlers.size == 1) - filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP)) + filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, REST)) assert(filter.authSchemeHandlers.size == 1) filter.addAuthHandler(new KerberosAuthenticationHandler()) assert(filter.authSchemeHandlers.size == 1) From 711049c139d8365d98238f01d91e221e7cffa4f1 Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Thu, 22 Feb 2024 16:03:28 +0800 Subject: [PATCH 04/10] Remove unnecessary code changes --- .../scala/org/apache/kyuubi/RestClientTestHelper.scala | 2 +- .../kyuubi/server/KyuubiRestFrontendServiceSuite.scala | 8 ++++---- .../apache/kyuubi/server/api/v1/AdminResourceSuite.scala | 2 +- .../kyuubi/server/api/v1/BatchesResourceSuite.scala | 2 +- .../apache/kyuubi/server/rest/client/AdminCtlSuite.scala | 2 +- .../kyuubi/server/rest/client/AdminRestApiSuite.scala | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala index f063a0e1ff1..26f565b68a5 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala @@ -49,7 +49,7 @@ trait RestClientTestHelper extends RestFrontendTestHelper with KerberizedTestHel assert(UserGroupInformation.isSecurityEnabled) val conf = KyuubiConf().set( - KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, + KyuubiConf.AUTHENTICATION_METHOD, Seq("KERBEROS", "LDAP", "CUSTOM")) .set(KyuubiConf.SERVER_KEYTAB.key, testKeytab) .set(KyuubiConf.SERVER_PRINCIPAL, testPrincipal) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala index 5786b57d358..b60517a06d8 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/KyuubiRestFrontendServiceSuite.scala @@ -26,7 +26,7 @@ import org.apache.kyuubi.service.authentication.AnonymousAuthenticationProviderI class KyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("NONE")) + .set(AUTHENTICATION_METHOD, Seq("NONE")) test("version") { val resp = v1Call("version") @@ -61,7 +61,7 @@ class KyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { class KerberosKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("KERBEROS")) + .set(AUTHENTICATION_METHOD, Seq("KERBEROS")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) test("security enabled - KERBEROS") { @@ -72,7 +72,7 @@ class KerberosKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { class NoneKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("NONE")) + .set(AUTHENTICATION_METHOD, Seq("NONE")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) test("security enabled - NONE") { @@ -83,7 +83,7 @@ class NoneKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { class KerberosAndCustomKyuubiRestFrontendServiceSuite extends RestFrontendTestHelper { override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("KERBEROS,CUSTOM")) + .set(AUTHENTICATION_METHOD, Seq("KERBEROS,CUSTOM")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) test("security enabled - KERBEROS,CUSTOM") { diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala index 2318ad5cf53..95aa3de025d 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/AdminResourceSuite.scala @@ -51,7 +51,7 @@ class AdminResourceSuite extends KyuubiFunSuite with RestFrontendTestHelper { private val engineMgr = new KyuubiApplicationManager() override protected lazy val conf: KyuubiConf = KyuubiConf() - .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("CUSTOM")) + .set(AUTHENTICATION_METHOD, Seq("CUSTOM")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) .set(SERVER_ADMINISTRATORS, Set("admin001")) .set(ENGINE_IDLE_TIMEOUT, Duration.ofMinutes(3).toMillis) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala index 1f913068dac..f1ee71bec9f 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/BatchesResourceSuite.scala @@ -85,7 +85,7 @@ abstract class BatchesResourceSuiteBase extends KyuubiFunSuite override protected lazy val conf: KyuubiConf = { val testResourceDir = Paths.get(sparkBatchTestResource.get).getParent val kyuubiConf = KyuubiConf() - .set(FRONTEND_REST_AUTHENTICATION_METHOD, Seq("CUSTOM")) + .set(AUTHENTICATION_METHOD, Seq("CUSTOM")) .set(AUTHENTICATION_CUSTOM_CLASS, classOf[AnonymousAuthenticationProviderImpl].getName) .set(SERVER_ADMINISTRATORS, Set("admin")) .set(BATCH_IMPL_VERSION, batchVersion) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala index 76649ad33e7..0c262d2389a 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminCtlSuite.scala @@ -56,7 +56,7 @@ class AdminCtlSuite extends RestClientTestHelper with TestPrematureExit { val id = UUID.randomUUID().toString conf.set(HighAvailabilityConf.HA_NAMESPACE, "kyuubi_test") conf.set(KyuubiConf.ENGINE_IDLE_TIMEOUT, 180000L) - conf.set(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) + conf.set(KyuubiConf.AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) conf.set(KyuubiConf.GROUP_PROVIDER, "hadoop") val user = ldapUser diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala index f6b51f5a85c..43eb06482e7 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/AdminRestApiSuite.scala @@ -50,7 +50,7 @@ class AdminRestApiSuite extends RestClientTestHelper { val id = UUID.randomUUID().toString conf.set(HighAvailabilityConf.HA_NAMESPACE, "kyuubi_test") conf.set(KyuubiConf.ENGINE_IDLE_TIMEOUT, 180000L) - conf.set(KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) + conf.set(KyuubiConf.AUTHENTICATION_METHOD, Seq("LDAP", "CUSTOM")) conf.set(KyuubiConf.GROUP_PROVIDER, "hadoop") val user = ldapUser val engine = From 4e050655ef3cba0046ed76ea9b2206cadcb87b46 Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Thu, 22 Feb 2024 16:29:14 +0800 Subject: [PATCH 05/10] Remove unnecessary code changes --- .../apache/kyuubi/RestClientTestHelper.scala | 4 +- ...la => RestAuthenticationFilterSuite.scala} | 2 +- .../ThriftHttpAuthenticationFilterSuite.scala | 45 +++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) rename kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/{AuthenticationFilterSuite.scala => RestAuthenticationFilterSuite.scala} (96%) create mode 100644 kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala index 26f565b68a5..8344cdef01d 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala @@ -48,9 +48,7 @@ trait RestClientTestHelper extends RestFrontendTestHelper with KerberizedTestHel UserGroupInformation.setConfiguration(config) assert(UserGroupInformation.isSecurityEnabled) - val conf = KyuubiConf().set( - KyuubiConf.AUTHENTICATION_METHOD, - Seq("KERBEROS", "LDAP", "CUSTOM")) + val conf = KyuubiConf().set(KyuubiConf.AUTHENTICATION_METHOD, Seq("KERBEROS", "LDAP", "CUSTOM")) .set(KyuubiConf.SERVER_KEYTAB.key, testKeytab) .set(KyuubiConf.SERVER_PRINCIPAL, testPrincipal) .set(KyuubiConf.SERVER_SPNEGO_KEYTAB, testKeytab) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala similarity index 96% rename from kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala rename to kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala index cb86ff04cce..5a96d2108bb 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala @@ -23,7 +23,7 @@ import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.REST import org.apache.kyuubi.service.authentication.AuthTypes -class AuthenticationFilterSuite extends KyuubiFunSuite { +class RestAuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { val conf = KyuubiConf() val filter = diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala new file mode 100644 index 00000000000..6dbe5f4d660 --- /dev/null +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.kyuubi.server.http.authentication + +import org.apache.kyuubi.KyuubiFunSuite +import org.apache.kyuubi.config.KyuubiConf +import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD +import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_HTTP +import org.apache.kyuubi.service.authentication.AuthTypes + +class ThriftHttpAuthenticationFilterSuite extends KyuubiFunSuite { + test("add auth handler and destroy") { + val conf = KyuubiConf() + val filter = + new AuthenticationFilter( + conf, + conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName), + THRIFT_HTTP) + filter.addAuthHandler(new BasicAuthenticationHandler(null, THRIFT_HTTP)) + assert(filter.authSchemeHandlers.isEmpty) + filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, THRIFT_HTTP)) + assert(filter.authSchemeHandlers.size == 1) + filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, THRIFT_HTTP)) + assert(filter.authSchemeHandlers.size == 1) + filter.addAuthHandler(new KerberosAuthenticationHandler()) + assert(filter.authSchemeHandlers.size == 1) + filter.destroy() + assert(filter.authSchemeHandlers.isEmpty) + } +} From dee53411e7d9041b2b7d429694e0635bc2052f8a Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Thu, 22 Feb 2024 16:41:03 +0800 Subject: [PATCH 06/10] clean code --- .../kyuubi/server/KyuubiRestFrontendService.scala | 6 +----- .../kyuubi/server/http/ThriftHttpServlet.scala | 6 +----- .../http/authentication/AuthenticationFilter.scala | 13 +++++++------ .../RestAuthenticationFilterSuite.scala | 7 +------ .../ThriftHttpAuthenticationFilterSuite.scala | 7 +------ 5 files changed, 11 insertions(+), 28 deletions(-) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala index 5011fca94cf..1914e3be140 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala @@ -104,11 +104,7 @@ 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), - REST)) + val holder = new FilterHolder(new AuthenticationFilter(conf, REST)) contextHandler.addFilter(holder, "/v1/*", EnumSet.allOf(classOf[DispatcherType])) val authenticationFactory = new KyuubiHttpAuthenticationFactory(conf) server.addHandler(authenticationFactory.httpHandlerWrapperFactory.wrapHandler(contextHandler)) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala index 769510455ee..91e1cc09cc6 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala @@ -57,11 +57,7 @@ class ThriftHttpServlet( private var isCookieSecure = false 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), - THRIFT_HTTP) + private val authenticationFilter = new AuthenticationFilter(conf, THRIFT_HTTP) override def init(): Unit = { isCookieAuthEnabled = conf.get(KyuubiConf.FRONTEND_THRIFT_HTTP_COOKIE_AUTH_ENABLED) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala index d484cefa3d6..b271cedf220 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala @@ -26,16 +26,13 @@ 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 +import org.apache.kyuubi.config.KyuubiConf.{AUTHENTICATION_METHOD, FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER, FRONTEND_REST_AUTHENTICATION_METHOD} +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], - protocol: FrontendProtocol) extends Filter +class AuthenticationFilter(conf: KyuubiConf, protocol: FrontendProtocol) extends Filter with Logging { import AuthenticationFilter._ import AuthSchemes._ @@ -60,6 +57,10 @@ class AuthenticationFilter( } private[kyuubi] def initAuthHandlers(): Unit = { + val authTypes = protocol match { + case REST => conf.get(FRONTEND_REST_AUTHENTICATION_METHOD).map(AuthTypes.withName) + case _ => conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName) + } val spnegoKerberosEnabled = authTypes.contains(KERBEROS) val basicAuthTypeOpt = { if (authTypes == Set(NOSASL)) { diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala index 5a96d2108bb..f989be02435 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala @@ -19,18 +19,13 @@ package org.apache.kyuubi.server.http.authentication import org.apache.kyuubi.KyuubiFunSuite import org.apache.kyuubi.config.KyuubiConf -import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.REST import org.apache.kyuubi.service.authentication.AuthTypes class RestAuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { val conf = KyuubiConf() - val filter = - new AuthenticationFilter( - conf, - conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName), - REST) + val filter = new AuthenticationFilter(conf, REST) filter.addAuthHandler(new BasicAuthenticationHandler(null, REST)) assert(filter.authSchemeHandlers.isEmpty) filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, REST)) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala index 6dbe5f4d660..59a35a4d71c 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala @@ -19,18 +19,13 @@ package org.apache.kyuubi.server.http.authentication import org.apache.kyuubi.KyuubiFunSuite import org.apache.kyuubi.config.KyuubiConf -import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD import org.apache.kyuubi.config.KyuubiConf.FrontendProtocols.THRIFT_HTTP import org.apache.kyuubi.service.authentication.AuthTypes class ThriftHttpAuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { val conf = KyuubiConf() - val filter = - new AuthenticationFilter( - conf, - conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName), - THRIFT_HTTP) + val filter = new AuthenticationFilter(conf, THRIFT_HTTP) filter.addAuthHandler(new BasicAuthenticationHandler(null, THRIFT_HTTP)) assert(filter.authSchemeHandlers.isEmpty) filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, THRIFT_HTTP)) From 8359674c63775f636ea71697831dbbd49c99298e Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Thu, 22 Feb 2024 16:44:55 +0800 Subject: [PATCH 07/10] clean code --- .../http/authentication/RestAuthenticationFilterSuite.scala | 3 +-- .../authentication/ThriftHttpAuthenticationFilterSuite.scala | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala index f989be02435..ff2a98e63fc 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/RestAuthenticationFilterSuite.scala @@ -24,8 +24,7 @@ import org.apache.kyuubi.service.authentication.AuthTypes class RestAuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { - val conf = KyuubiConf() - val filter = new AuthenticationFilter(conf, REST) + val filter = new AuthenticationFilter(KyuubiConf(), REST) filter.addAuthHandler(new BasicAuthenticationHandler(null, REST)) assert(filter.authSchemeHandlers.isEmpty) filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, REST)) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala index 59a35a4d71c..0dce840ca47 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/http/authentication/ThriftHttpAuthenticationFilterSuite.scala @@ -24,8 +24,7 @@ import org.apache.kyuubi.service.authentication.AuthTypes class ThriftHttpAuthenticationFilterSuite extends KyuubiFunSuite { test("add auth handler and destroy") { - val conf = KyuubiConf() - val filter = new AuthenticationFilter(conf, THRIFT_HTTP) + val filter = new AuthenticationFilter(KyuubiConf(), THRIFT_HTTP) filter.addAuthHandler(new BasicAuthenticationHandler(null, THRIFT_HTTP)) assert(filter.authSchemeHandlers.isEmpty) filter.addAuthHandler(new BasicAuthenticationHandler(AuthTypes.LDAP, THRIFT_HTTP)) From 9ac664ec3e4469ad115a07bd4ad69e14ad7e6958 Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Thu, 22 Feb 2024 17:19:07 +0800 Subject: [PATCH 08/10] remove unused import --- .../org/apache/kyuubi/server/http/ThriftHttpServlet.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala index 91e1cc09cc6..232eca1bc8e 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/ThriftHttpServlet.scala @@ -30,12 +30,12 @@ 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.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 -import org.apache.kyuubi.service.authentication.{AuthTypes, KyuubiAuthenticationFactory} +import org.apache.kyuubi.service.authentication.KyuubiAuthenticationFactory import org.apache.kyuubi.shaded.thrift.TProcessor import org.apache.kyuubi.shaded.thrift.protocol.TProtocolFactory import org.apache.kyuubi.shaded.thrift.server.TServlet From 0cfe358cb00231947d97e62ec9daff824e2a0dc6 Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Fri, 23 Feb 2024 20:24:53 +0800 Subject: [PATCH 09/10] add more test --- .../KyuubiRestAuthenticationSuite.scala | 61 ++++++++++++++++++- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala index fb9e574ba61..296c8746e76 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala @@ -24,6 +24,7 @@ import javax.ws.rs.core.MediaType import scala.collection.JavaConverters._ +import org.apache.hadoop.conf.Configuration import org.apache.hadoop.security.UserGroupInformation import org.apache.kyuubi.RestClientTestHelper @@ -31,7 +32,7 @@ import org.apache.kyuubi.client.api.v1.dto.{SessionHandle, SessionOpenCount, Ses import org.apache.kyuubi.config.KyuubiConf import org.apache.kyuubi.server.http.authentication.AuthSchemes import org.apache.kyuubi.server.http.util.HttpAuthUtils._ -import org.apache.kyuubi.service.authentication.InternalSecurityAccessor +import org.apache.kyuubi.service.authentication.{InternalSecurityAccessor, UserDefineAuthenticationProviderImpl} import org.apache.kyuubi.session.KyuubiSession class KyuubiRestAuthenticationSuite extends RestClientTestHelper { @@ -183,7 +184,7 @@ class KyuubiRestAuthenticationSuite extends RestClientTestHelper { } } -class NoneKyuubiRestAuthenticationSuite extends RestClientTestHelper { +class KyuubiRestIsolatedNoneAuthenticationSuite extends RestClientTestHelper { override protected val otherConfigs: Map[String, String] = { Map( @@ -200,7 +201,7 @@ class NoneKyuubiRestAuthenticationSuite extends RestClientTestHelper { } } -class KerberosKyuubiRestAuthenticationSuite extends RestClientTestHelper { +class KyuubiRestKerberosAuthenticationSuite extends RestClientTestHelper { override protected val otherConfigs: Map[String, String] = { Map(KyuubiConf.AUTHENTICATION_METHOD.key -> "KERBEROS") @@ -214,3 +215,57 @@ class KerberosKyuubiRestAuthenticationSuite extends RestClientTestHelper { assert(HttpServletResponse.SC_UNAUTHORIZED == response.getStatus) } } + +class KyuubiRestIsolatedKerberosAuthenticationSuite extends RestClientTestHelper { + + override protected val otherConfigs: Map[String, String] = { + Map( + KyuubiConf.AUTHENTICATION_METHOD.key -> "NONE", + KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "KERBEROS") + } + + test("test disable restful api authentication") { + val response = webTarget.path("api/v1/sessions/count") + .request() + .get() + + assert(HttpServletResponse.SC_OK == response.getStatus) + } +} + +class KyuubiRestIsolatedAuthenticationSuite extends KyuubiRestAuthenticationSuite { + + override protected val otherConfigs: Map[String, String] = { + Map( + KyuubiConf.ENGINE_SECURITY_ENABLED.key -> "true", + KyuubiConf.ENGINE_SECURITY_SECRET_PROVIDER.key -> "simple", + KyuubiConf.SIMPLE_SECURITY_SECRET_PROVIDER_PROVIDER_SECRET.key -> "_KYUUBI_REST_", + // allow to impersonate other users with spnego authentication + s"hadoop.proxyuser.$clientPrincipalUser.groups" -> "*", + s"hadoop.proxyuser.$clientPrincipalUser.hosts" -> "*") + } + + override protected lazy val conf: KyuubiConf = { + val config = new Configuration() + val authType = "hadoop.security.authentication" + config.set(authType, "KERBEROS") + System.setProperty("java.security.krb5.conf", krb5ConfPath) + UserGroupInformation.setConfiguration(config) + assert(UserGroupInformation.isSecurityEnabled) + + val conf = KyuubiConf().set( + KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD, + Seq("KERBEROS", "LDAP", "CUSTOM")) + .set(KyuubiConf.SERVER_KEYTAB.key, testKeytab) + .set(KyuubiConf.SERVER_PRINCIPAL, testPrincipal) + .set(KyuubiConf.SERVER_SPNEGO_KEYTAB, testKeytab) + .set(KyuubiConf.SERVER_SPNEGO_PRINCIPAL, testSpnegoPrincipal) + .set(KyuubiConf.AUTHENTICATION_LDAP_URL, ldapUrl) + .set(KyuubiConf.AUTHENTICATION_LDAP_BASE_DN, ldapBaseDn.head) + .set( + KyuubiConf.FRONTEND_REST_AUTHENTICATION_CUSTOM_CLASS, + Some(classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)) + otherConfigs.foreach(kv => conf.set(kv._1, kv._2)) + conf + } +} From 8ab6c16f4201b3973c1443892bf5742b770fcc0f Mon Sep 17 00:00:00 2001 From: wangjunbo Date: Fri, 23 Feb 2024 21:22:06 +0800 Subject: [PATCH 10/10] fix test --- .../kyuubi/operation/KyuubiRestAuthenticationSuite.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala index 296c8746e76..0464d0d0f03 100644 --- a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala +++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiRestAuthenticationSuite.scala @@ -207,7 +207,7 @@ class KyuubiRestKerberosAuthenticationSuite extends RestClientTestHelper { Map(KyuubiConf.AUTHENTICATION_METHOD.key -> "KERBEROS") } - test("test without authorization when rest api authentication with KERBEROS") { + test("test without authorization when rest api authentication not isolated with KERBEROS") { val response = webTarget.path("api/v1/sessions/count") .request() .get() @@ -224,12 +224,12 @@ class KyuubiRestIsolatedKerberosAuthenticationSuite extends RestClientTestHelper KyuubiConf.FRONTEND_REST_AUTHENTICATION_METHOD.key -> "KERBEROS") } - test("test disable restful api authentication") { + test("test isolated kerberos restful api authentication") { val response = webTarget.path("api/v1/sessions/count") .request() .get() - assert(HttpServletResponse.SC_OK == response.getStatus) + assert(HttpServletResponse.SC_UNAUTHORIZED == response.getStatus) } }