This is an automated email from the ASF dual-hosted git repository.

chengpan pushed a commit to branch branch-1.8
in repository https://gitbox.apache.org/repos/asf/kyuubi.git


The following commit(s) were added to refs/heads/branch-1.8 by this push:
     new 67493cf13 [KYUUBI #5568] Check administrator only when security is 
enabled
67493cf13 is described below

commit 67493cf130504ab94165490690a05b49eb5f5886
Author: Cheng Pan <[email protected]>
AuthorDate: Thu Nov 2 10:09:01 2023 +0800

    [KYUUBI #5568] Check administrator only when security is enabled
    
    ### _Why are the changes needed?_
    
    This PR aims to improve out-of-box UX.
    
    Currently, administrators' checking is enforced even when security is 
disabled, and we are going to deliver the preview of Web UI in 1.8, it may 
confuse users who use the default configuration to launch Kyuubi sever and 
explore Kyuubi WebUI (because the user "anonymous" can not visit all users' 
sessions/engines without being configured as an administrator).
    
    ### _How was this patch tested?_
    - [ ] Add some test cases that check the changes thoroughly including 
negative and positive cases if possible
    
    - [ ] Add screenshots for manual tests if appropriate
    
    - [x] [Run 
test](https://kyuubi.readthedocs.io/en/master/contributing/code/testing.html#running-tests)
 locally before make a pull request
    
    ### _Was this patch authored or co-authored using generative AI tooling?_
    
    No
    
    Closes #5568 from pan3793/admin.
    
    Closes #5568
    
    2eccf659f [Cheng Pan] code dedup and fix test
    76f4fd4a3 [Cheng Pan] fix test
    d7ca94650 [Cheng Pan] Check administrator only when security is enabled
    
    Authored-by: Cheng Pan <[email protected]>
    Signed-off-by: Cheng Pan <[email protected]>
---
 docs/configuration/settings.md                     |  32 ++---
 .../org/apache/kyuubi/config/KyuubiConf.scala      |   4 +-
 .../KyuubiAuthenticationFactory.scala              |  44 ++-----
 .../kyuubi/server/KyuubiRestFrontendService.scala  |  16 ++-
 .../kyuubi/server/KyuubiTHttpFrontendService.scala |   5 +-
 .../kyuubi/server/api/v1/AdminResource.scala       |  36 +++---
 .../kyuubi/server/api/v1/BatchesResource.scala     |   4 +-
 .../kyuubi/server/http/ThriftHttpServlet.scala     |   4 +-
 .../http/authentication/AuthenticationFilter.scala |   2 +-
 .../authentication/AuthenticationHandler.scala     |  19 +--
 .../BasicAuthenticationHandler.scala               |   4 +-
 .../KerberosAuthenticationHandler.scala            |   8 +-
 .../KyuubiInternalAuthenticationHandler.scala      |   8 +-
 .../kyuubi/server/http/util/HttpAuthUtils.scala    |  22 +++-
 .../operation/KyuubiRestAuthenticationSuite.scala  |  19 +--
 .../kyuubi/server/api/v1/AdminResourceSuite.scala  | 139 ++++++++++-----------
 .../server/api/v1/BatchesResourceSuite.scala       |  66 +++++++---
 .../server/api/v1/SessionsResourceSuite.scala      |   9 +-
 18 files changed, 221 insertions(+), 220 deletions(-)

diff --git a/docs/configuration/settings.md b/docs/configuration/settings.md
index 3ef24d51d..4acf39551 100644
--- a/docs/configuration/settings.md
+++ b/docs/configuration/settings.md
@@ -387,22 +387,22 @@ You can configure the Kyuubi properties in 
`$KYUUBI_HOME/conf/kyuubi-defaults.co
 
 ### Server
 
-|                           Key                            |      Default      
|                                                                               
                                     Meaning                                    
                                                                                
 |   Type   | Since |
-|----------------------------------------------------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-------|
-| kyuubi.server.administrators                                                
|| Comma-separated list of Kyuubi service administrators. We use this config to 
grant admin permission to any service accounts.                                 
                                                                                
  | set      | 1.8.0 |
-| kyuubi.server.info.provider                              | ENGINE            
| The server information provider name, some clients may rely on this 
information to check the server compatibilities and functionalities. 
<li>SERVER: Return Kyuubi server information.</li> <li>ENGINE: Return Kyuubi 
engine information.</li> | string   | 1.6.1 |
-| kyuubi.server.limit.batch.connections.per.ipaddress      | &lt;undefined&gt; 
| Maximum kyuubi server batch connections per ipaddress. Any user exceeding 
this limit will not be allowed to connect.                                      
                                                                                
     | int      | 1.7.0 |
-| kyuubi.server.limit.batch.connections.per.user           | &lt;undefined&gt; 
| Maximum kyuubi server batch connections per user. Any user exceeding this 
limit will not be allowed to connect.                                           
                                                                                
     | int      | 1.7.0 |
-| kyuubi.server.limit.batch.connections.per.user.ipaddress | &lt;undefined&gt; 
| Maximum kyuubi server batch connections per user:ipaddress combination. Any 
user-ipaddress exceeding this limit will not be allowed to connect.             
                                                                                
   | int      | 1.7.0 |
-| kyuubi.server.limit.client.fetch.max.rows                | &lt;undefined&gt; 
| Max rows limit for getting result row set operation. If the max rows 
specified by client-side is larger than the limit, request will fail directly.  
                                                                                
          | int      | 1.8.0 |
-| kyuubi.server.limit.connections.per.ipaddress            | &lt;undefined&gt; 
| Maximum kyuubi server connections per ipaddress. Any user exceeding this 
limit will not be allowed to connect.                                           
                                                                                
      | int      | 1.6.0 |
-| kyuubi.server.limit.connections.per.user                 | &lt;undefined&gt; 
| Maximum kyuubi server connections per user. Any user exceeding this limit 
will not be allowed to connect.                                                 
                                                                                
     | int      | 1.6.0 |
-| kyuubi.server.limit.connections.per.user.ipaddress       | &lt;undefined&gt; 
| Maximum kyuubi server connections per user:ipaddress combination. Any 
user-ipaddress exceeding this limit will not be allowed to connect.             
                                                                                
         | int      | 1.6.0 |
-| kyuubi.server.limit.connections.user.deny.list                              
|| The user in the deny list will be denied to connect to kyuubi server, if the 
user has configured both user.unlimited.list and user.deny.list, the priority 
of the latter is higher.                                                        
    | set      | 1.8.0 |
-| kyuubi.server.limit.connections.user.unlimited.list                         
|| The maximum connections of the user in the white list will not be limited.   
                                                                                
                                                                                
  | set      | 1.7.0 |
-| kyuubi.server.name                                       | &lt;undefined&gt; 
| The name of Kyuubi Server.                                                    
                                                                                
                                                                                
 | string   | 1.5.0 |
-| kyuubi.server.periodicGC.interval                        | PT30M             
| How often to trigger a garbage collection.                                    
                                                                                
                                                                                
 | duration | 1.7.0 |
-| kyuubi.server.redaction.regex                            | &lt;undefined&gt; 
| Regex to decide which Kyuubi contain sensitive information. When this regex 
matches a property key or value, the value is redacted from the various logs.   
                                                                                
             || 1.6.0 |
+|                           Key                            |      Default      
|                                                                               
                                                  Meaning                       
                                                                                
                          |   Type   | Since |
+|----------------------------------------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-------|
+| kyuubi.server.administrators                                                
|| Comma-separated list of Kyuubi service administrators. We use this config to 
grant admin permission to any service accounts when security mechanism is 
enabled. Note, when kyuubi.authentication is configured to NOSASL or NONE, 
everyone is treated as administrator. | set      | 1.8.0 |
+| kyuubi.server.info.provider                              | ENGINE            
| The server information provider name, some clients may rely on this 
information to check the server compatibilities and functionalities. 
<li>SERVER: Return Kyuubi server information.</li> <li>ENGINE: Return Kyuubi 
engine information.</li>                          | string   | 1.6.1 |
+| kyuubi.server.limit.batch.connections.per.ipaddress      | &lt;undefined&gt; 
| Maximum kyuubi server batch connections per ipaddress. Any user exceeding 
this limit will not be allowed to connect.                                      
                                                                                
                              | int      | 1.7.0 |
+| kyuubi.server.limit.batch.connections.per.user           | &lt;undefined&gt; 
| Maximum kyuubi server batch connections per user. Any user exceeding this 
limit will not be allowed to connect.                                           
                                                                                
                              | int      | 1.7.0 |
+| kyuubi.server.limit.batch.connections.per.user.ipaddress | &lt;undefined&gt; 
| Maximum kyuubi server batch connections per user:ipaddress combination. Any 
user-ipaddress exceeding this limit will not be allowed to connect.             
                                                                                
                            | int      | 1.7.0 |
+| kyuubi.server.limit.client.fetch.max.rows                | &lt;undefined&gt; 
| Max rows limit for getting result row set operation. If the max rows 
specified by client-side is larger than the limit, request will fail directly.  
                                                                                
                                   | int      | 1.8.0 |
+| kyuubi.server.limit.connections.per.ipaddress            | &lt;undefined&gt; 
| Maximum kyuubi server connections per ipaddress. Any user exceeding this 
limit will not be allowed to connect.                                           
                                                                                
                               | int      | 1.6.0 |
+| kyuubi.server.limit.connections.per.user                 | &lt;undefined&gt; 
| Maximum kyuubi server connections per user. Any user exceeding this limit 
will not be allowed to connect.                                                 
                                                                                
                              | int      | 1.6.0 |
+| kyuubi.server.limit.connections.per.user.ipaddress       | &lt;undefined&gt; 
| Maximum kyuubi server connections per user:ipaddress combination. Any 
user-ipaddress exceeding this limit will not be allowed to connect.             
                                                                                
                                  | int      | 1.6.0 |
+| kyuubi.server.limit.connections.user.deny.list                              
|| The user in the deny list will be denied to connect to kyuubi server, if the 
user has configured both user.unlimited.list and user.deny.list, the priority 
of the latter is higher.                                                        
                             | set      | 1.8.0 |
+| kyuubi.server.limit.connections.user.unlimited.list                         
|| The maximum connections of the user in the white list will not be limited.   
                                                                                
                                                                                
                           | set      | 1.7.0 |
+| kyuubi.server.name                                       | &lt;undefined&gt; 
| The name of Kyuubi Server.                                                    
                                                                                
                                                                                
                          | string   | 1.5.0 |
+| kyuubi.server.periodicGC.interval                        | PT30M             
| How often to trigger a garbage collection.                                    
                                                                                
                                                                                
                          | duration | 1.7.0 |
+| kyuubi.server.redaction.regex                            | &lt;undefined&gt; 
| Regex to decide which Kyuubi contain sensitive information. When this regex 
matches a property key or value, the value is redacted from the various logs.   
                                                                                
                                      || 1.6.0 |
 
 ### Session
 
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 8f7e4bb4e..bd041425b 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
@@ -2709,7 +2709,9 @@ object KyuubiConf {
   val SERVER_ADMINISTRATORS: ConfigEntry[Set[String]] =
     buildConf("kyuubi.server.administrators")
       .doc("Comma-separated list of Kyuubi service administrators. " +
-        "We use this config to grant admin permission to any service 
accounts.")
+        "We use this config to grant admin permission to any service accounts 
when " +
+        s"security mechanism is enabled. Note, when 
${AUTHENTICATION_METHOD.key} is " +
+        "configured to NOSASL or NONE, everyone is treated as administrator.")
       .version("1.8.0")
       .serverOnly
       .stringConf
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 1b62f6030..2f56f3e4c 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
@@ -37,10 +37,9 @@ import org.apache.kyuubi.service.authentication.AuthTypes._
 
 class KyuubiAuthenticationFactory(conf: KyuubiConf, isServer: Boolean = true) 
extends Logging {
 
-  private val authTypes = 
conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)
-  private val none = authTypes.contains(NONE)
-  private val noSasl = authTypes == Set(NOSASL)
-  private val kerberosEnabled = authTypes.contains(KERBEROS)
+  val authTypes: Set[AuthType] = 
conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)
+  val noSaslEnabled: Boolean = authTypes == Set(NOSASL)
+  val kerberosEnabled: Boolean = authTypes.contains(KERBEROS)
   private val plainAuthTypeOpt = authTypes.filterNot(_.equals(KERBEROS))
     .filterNot(_.equals(NOSASL)).headOption
 
@@ -71,7 +70,7 @@ class KyuubiAuthenticationFactory(conf: KyuubiConf, isServer: 
Boolean = true) ex
   }
 
   def getTTransportFactory: TTransportFactory = {
-    if (noSasl) {
+    if (noSaslEnabled) {
       new TTransportFactory()
     } else {
       var transportFactory: TSaslServerTransport.Factory = null
@@ -119,33 +118,8 @@ class KyuubiAuthenticationFactory(conf: KyuubiConf, 
isServer: Boolean = true) ex
     hadoopAuthServer.map(_.getRemoteAddress).map(_.getHostAddress)
       .orElse(Option(TSetIpAddressProcessor.getUserIpAddress))
   }
-
-  def isNoSaslEnabled: Boolean = {
-    noSasl
-  }
-
-  def isKerberosEnabled: Boolean = {
-    kerberosEnabled
-  }
-
-  def isPlainAuthEnabled: Boolean = {
-    plainAuthTypeOpt.isDefined
-  }
-
-  def isNoneEnabled: Boolean = {
-    none
-  }
-
-  def getValidPasswordAuthMethod: AuthMethod = {
-    debug(authTypes)
-    if (none) AuthMethods.NONE
-    else if (authTypes.contains(LDAP)) AuthMethods.LDAP
-    else if (authTypes.contains(JDBC)) AuthMethods.JDBC
-    else if (authTypes.contains(CUSTOM)) AuthMethods.CUSTOM
-    else throw new IllegalArgumentException("No valid Password Auth detected")
-  }
 }
-object KyuubiAuthenticationFactory {
+object KyuubiAuthenticationFactory extends Logging {
   val HS2_PROXY_USER = "hive.server2.proxy.user"
 
   @throws[KyuubiSQLException]
@@ -177,4 +151,12 @@ object KyuubiAuthenticationFactory {
           e)
     }
   }
+
+  def getValidPasswordAuthMethod(authTypes: Set[AuthType]): AuthMethod = {
+    if (authTypes.contains(NONE)) AuthMethods.NONE
+    else if (authTypes.contains(LDAP)) AuthMethods.LDAP
+    else if (authTypes.contains(JDBC)) AuthMethods.JDBC
+    else if (authTypes.contains(CUSTOM)) AuthMethods.CUSTOM
+    else throw new IllegalArgumentException("No valid Password Auth detected")
+  }
 }
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 c5d44213c..f7a09ee25 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
@@ -35,7 +35,8 @@ 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}
 import org.apache.kyuubi.service.{AbstractFrontendService, Serverable, 
Service, ServiceUtils}
-import org.apache.kyuubi.service.authentication.KyuubiAuthenticationFactory
+import org.apache.kyuubi.service.authentication.{AuthTypes, 
KyuubiAuthenticationFactory}
+import org.apache.kyuubi.service.authentication.AuthTypes.NONE
 import org.apache.kyuubi.session.{KyuubiSessionManager, SessionHandle}
 import org.apache.kyuubi.util.ThreadUtils
 
@@ -70,6 +71,17 @@ class KyuubiRestFrontendService(override val serverable: 
Serverable)
 
   private lazy val port: Int = conf.get(FRONTEND_REST_BIND_PORT)
 
+  private lazy val securityEnabled = {
+    val authTypes = conf.get(AUTHENTICATION_METHOD).map(AuthTypes.withName)
+    KyuubiAuthenticationFactory.getValidPasswordAuthMethod(authTypes) != NONE
+  }
+
+  private lazy val administrators: Set[String] =
+    conf.get(KyuubiConf.SERVER_ADMINISTRATORS) + Utils.currentUser
+
+  def isAdministrator(userName: String): Boolean =
+    if (securityEnabled) administrators.contains(userName) else true
+
   override def initialize(conf: KyuubiConf): Unit = synchronized {
     this.conf = conf
     server = JettyServer(
@@ -240,7 +252,7 @@ class KyuubiRestFrontendService(override val serverable: 
Serverable)
       realUser
     } else {
       sessionConf.get(KyuubiAuthenticationFactory.HS2_PROXY_USER).map { 
proxyUser =>
-        if (!getConf.get(KyuubiConf.SERVER_ADMINISTRATORS).contains(realUser)) 
{
+        if (!isAdministrator(realUser)) {
           KyuubiAuthenticationFactory.verifyProxyAccess(realUser, proxyUser, 
ipAddress, hadoopConf)
         }
         proxyUser
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 79351118c..c32345695 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
@@ -43,6 +43,7 @@ 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.util.NamedThreadFactory
 
 /**
@@ -74,9 +75,9 @@ final class KyuubiTHttpFrontendService(
    */
   override def initialize(conf: KyuubiConf): Unit = synchronized {
     this.conf = conf
-    if (authFactory.isKerberosEnabled) {
+    if (authFactory.kerberosEnabled) {
       try {
-        authFactory.getValidPasswordAuthMethod
+        
KyuubiAuthenticationFactory.getValidPasswordAuthMethod(authFactory.authTypes)
       } catch {
         case _: IllegalArgumentException =>
           throw new AuthenticationException("Kerberos is not supported for 
thrift http mode")
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
index 3c6f2a197..b8ae73ea2 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/AdminResource.scala
@@ -29,7 +29,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse
 import io.swagger.v3.oas.annotations.tags.Tag
 import org.apache.commons.lang3.StringUtils
 
-import org.apache.kyuubi.{KYUUBI_VERSION, Logging, Utils}
+import org.apache.kyuubi.{KYUUBI_VERSION, Logging}
 import org.apache.kyuubi.client.api.v1.dto._
 import org.apache.kyuubi.config.KyuubiConf
 import org.apache.kyuubi.config.KyuubiConf._
@@ -45,8 +45,6 @@ import 
org.apache.kyuubi.shaded.zookeeper.KeeperException.NoNodeException
 @Tag(name = "Admin")
 @Produces(Array(MediaType.APPLICATION_JSON))
 private[v1] class AdminResource extends ApiRequestContext with Logging {
-  private lazy val administrators = 
fe.getConf.get(KyuubiConf.SERVER_ADMINISTRATORS) +
-    Utils.currentUser
 
   @ApiResponse(
     responseCode = "200",
@@ -59,7 +57,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Receive refresh Kyuubi server hadoop conf request from 
$userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to refresh the Kyuubi server hadoop conf")
     }
@@ -78,7 +76,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Receive refresh user defaults conf request from 
$userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to refresh the user defaults conf")
     }
@@ -97,7 +95,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Receive refresh kubernetes conf request from $userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to refresh the kubernetes conf")
     }
@@ -116,7 +114,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Receive refresh unlimited users request from $userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to refresh the unlimited users")
     }
@@ -135,7 +133,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Receive refresh deny users request from $userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to refresh the deny users")
     }
@@ -156,7 +154,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Received listing all live sessions request from 
$userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to list all live sessions")
     }
@@ -178,7 +176,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Received closing a session request from $userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to close the session $sessionHandleStr")
     }
@@ -202,7 +200,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Received listing all of the active operations request from 
$userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to list all the operations")
     }
@@ -229,7 +227,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Received close an operation request from $userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to close the operation $operationHandleStr")
     }
@@ -249,7 +247,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
       @QueryParam("sharelevel") shareLevel: String,
       @QueryParam("subdomain") subdomain: String,
       @QueryParam("hive.server2.proxy.user") hs2ProxyUser: String): Response = 
{
-    val userName = if (isAdministrator(fe.getRealUser())) {
+    val userName = if (fe.isAdministrator(fe.getRealUser())) {
       Option(hs2ProxyUser).getOrElse(fe.getRealUser())
     } else {
       fe.getSessionUser(hs2ProxyUser)
@@ -292,7 +290,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
       val userName = fe.getSessionUser(Map.empty[String, String])
       val ipAddress = fe.getIpAddress
       info(s"Received list all kyuubi engine request from 
$userName/$ipAddress")
-      if (!isAdministrator(userName)) {
+      if (!fe.isAdministrator(userName)) {
         throw new NotAllowedException(
           s"$userName is not allowed to list all kyuubi engine")
       }
@@ -334,7 +332,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
       }
       return engines.toSeq
     }
-    val userName = if (isAdministrator(fe.getRealUser())) {
+    val userName = if (fe.isAdministrator(fe.getRealUser())) {
       Option(hs2ProxyUser).getOrElse(fe.getRealUser())
     } else {
       fe.getSessionUser(hs2ProxyUser)
@@ -394,7 +392,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Received list all live kyuubi servers request from 
$userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to list all live kyuubi servers")
     }
@@ -466,7 +464,7 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
     val userName = fe.getSessionUser(Map.empty[String, String])
     val ipAddress = fe.getIpAddress
     info(s"Received counting batches request from $userName/$ipAddress")
-    if (!isAdministrator(userName)) {
+    if (!fe.isAdministrator(userName)) {
       throw new NotAllowedException(
         s"$userName is not allowed to count the batches")
     }
@@ -475,8 +473,4 @@ private[v1] class AdminResource extends ApiRequestContext 
with Logging {
       .getOrElse(0)
     new Count(batchCount)
   }
-
-  private def isAdministrator(userName: String): Boolean = {
-    administrators.contains(userName)
-  }
 }
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/BatchesResource.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/BatchesResource.scala
index bc6a177e4..5e32016bf 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/BatchesResource.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/BatchesResource.scala
@@ -219,6 +219,8 @@ private[v1] class BatchesResource extends ApiRequestContext 
with Logging {
     }
     request.setBatchType(request.getBatchType.toUpperCase(Locale.ROOT))
 
+    val userName = fe.getSessionUser(request.getConf.asScala.toMap)
+    val ipAddress = fe.getIpAddress
     val userProvidedBatchId = request.getConf.asScala.get(KYUUBI_BATCH_ID_KEY)
     userProvidedBatchId.foreach { batchId =>
       try UUID.fromString(batchId)
@@ -234,8 +236,6 @@ private[v1] class BatchesResource extends ApiRequestContext 
with Logging {
       case Some(batch) =>
         markDuplicated(batch)
       case None =>
-        val userName = fe.getSessionUser(request.getConf.asScala.toMap)
-        val ipAddress = fe.getIpAddress
         val batchId = userProvidedBatchId.getOrElse(UUID.randomUUID().toString)
         request.setConf(
           (request.getConf.asScala ++ Map(
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 bb9f1553d..f65d3b274 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
@@ -35,8 +35,8 @@ 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.server.http.authentication.AuthenticationFilter
-import 
org.apache.kyuubi.server.http.authentication.AuthenticationHandler.AUTHORIZATION_HEADER
 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
 
 class ThriftHttpServlet(
@@ -136,7 +136,7 @@ class ThriftHttpServlet(
       } else SessionManager.setForwardedAddresses(List.empty[String])
 
       // Generate new cookie and add it to the response
-      if (requireNewCookie && !authFactory.isNoSaslEnabled) {
+      if (requireNewCookie && !authFactory.noSaslEnabled) {
         val cookieToken = HttpAuthUtils.createCookieToken(clientUserName)
         val hs2Cookie = createCookie(signer.signCookie(cookieToken))
         if (isHttpOnlyCookie) response.setHeader("SET-COOKIE", 
getHttpOnlyCookieHeader(hs2Cookie))
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 523d24907..15b387607 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,12 +27,12 @@ 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.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 {
   import AuthenticationFilter._
-  import AuthenticationHandler._
   import AuthSchemes._
 
   private[authentication] val authSchemeHandlers =
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationHandler.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationHandler.scala
index bf2cb5bbe..a0b3fb4ab 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationHandler.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationHandler.scala
@@ -20,13 +20,11 @@ package org.apache.kyuubi.server.http.authentication
 import javax.security.sasl.AuthenticationException
 import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
 
-import org.apache.hadoop.security.authentication.server.HttpConstants
-
 import org.apache.kyuubi.config.KyuubiConf
 import org.apache.kyuubi.server.http.authentication.AuthSchemes.AuthScheme
+import org.apache.kyuubi.server.http.util.HttpAuthUtils.AUTHORIZATION_HEADER
 
 trait AuthenticationHandler {
-  import AuthenticationHandler._
 
   /**
    * HTTP header prefix used during the authentication sequence.
@@ -103,23 +101,10 @@ trait AuthenticationHandler {
       authorization = authorization.stripPrefix(":").trim
     }
     // Authorization header must have a payload
-    if (authorization == null || authorization.isEmpty()) {
+    if (authorization == null || authorization.isEmpty) {
       throw new AuthenticationException(
         "Authorization header received from the client does not contain any 
data.")
     }
     authorization
   }
 }
-
-object AuthenticationHandler {
-
-  /**
-   * HTTP header used by the SPNEGO server endpoint during an authentication 
sequence.
-   */
-  final val WWW_AUTHENTICATE: String = HttpConstants.WWW_AUTHENTICATE_HEADER
-
-  /**
-   * HTTP header used by the client endpoint during an authentication sequence.
-   */
-  final val AUTHORIZATION_HEADER = "Authorization"
-}
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 57ce2e60e..76560cabb 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
@@ -24,12 +24,12 @@ import javax.servlet.http.{HttpServletRequest, 
HttpServletResponse}
 import org.apache.kyuubi.Logging
 import org.apache.kyuubi.config.KyuubiConf
 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)
   extends AuthenticationHandler with Logging {
-  import AuthenticationHandler._
 
   private var conf: KyuubiConf = _
   private val allowAnonymous = basicAuthType == NOSASL || basicAuthType == NONE
@@ -75,7 +75,7 @@ class BasicAuthenticationHandler(basicAuthType: AuthType)
       authUser = 
creds.take(1).headOption.filterNot(_.isEmpty).getOrElse("anonymous")
     } else {
       if (creds.size < 2 || creds(0).trim.isEmpty || creds(1).trim.isEmpty) {
-        response.setHeader(WWW_AUTHENTICATE, authScheme.toString)
+        response.setHeader(WWW_AUTHENTICATE_HEADER, authScheme.toString)
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
       } else {
         val Seq(user, password) = creds.toSeq.take(2)
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KerberosAuthenticationHandler.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KerberosAuthenticationHandler.scala
index 04603f30a..7220e3906 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KerberosAuthenticationHandler.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KerberosAuthenticationHandler.scala
@@ -27,15 +27,15 @@ import javax.servlet.ServletException
 import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
 
 import org.apache.hadoop.security.authentication.util.KerberosName
+import org.apache.hadoop.security.authentication.util.KerberosUtil._
 import org.ietf.jgss.{GSSContext, GSSCredential, GSSManager, Oid}
 
 import org.apache.kyuubi.Logging
 import org.apache.kyuubi.config.KyuubiConf
+import org.apache.kyuubi.server.http.authentication.AuthSchemes.AuthScheme
+import org.apache.kyuubi.server.http.util.HttpAuthUtils.{NEGOTIATE, 
WWW_AUTHENTICATE_HEADER}
 
 class KerberosAuthenticationHandler extends AuthenticationHandler with Logging 
{
-  import AuthenticationHandler._
-  import AuthSchemes._
-  import KerberosUtil._
 
   private var gssManager: GSSManager = _
   private var conf: KyuubiConf = _
@@ -143,7 +143,7 @@ class KerberosAuthenticationHandler extends 
AuthenticationHandler with Logging {
       val serverToken = gssContext.acceptSecContext(clientToken, 0, 
clientToken.length)
       if (serverToken != null && serverToken.nonEmpty) {
         val authenticate = Base64.getEncoder.encodeToString(serverToken)
-        response.setHeader(WWW_AUTHENTICATE, s"$NEGOTIATE $authenticate")
+        response.setHeader(WWW_AUTHENTICATE_HEADER, s"$NEGOTIATE 
$authenticate")
       }
       if (!gssContext.isEstablished) {
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiInternalAuthenticationHandler.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiInternalAuthenticationHandler.scala
index 7af6389cc..d910f4a83 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiInternalAuthenticationHandler.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiInternalAuthenticationHandler.scala
@@ -17,17 +17,17 @@
 
 package org.apache.kyuubi.server.http.authentication
 
-import java.nio.charset.Charset
+import java.nio.charset.StandardCharsets
 import java.util.Base64
 import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
 
 import org.apache.kyuubi.Logging
 import org.apache.kyuubi.config.KyuubiConf
 import org.apache.kyuubi.server.http.authentication.AuthSchemes.AuthScheme
+import org.apache.kyuubi.server.http.util.HttpAuthUtils.WWW_AUTHENTICATE_HEADER
 import org.apache.kyuubi.service.authentication.InternalSecurityAccessor
 
 class KyuubiInternalAuthenticationHandler extends AuthenticationHandler with 
Logging {
-  import AuthenticationHandler._
 
   private var conf: KyuubiConf = _
   override val authScheme: AuthScheme = AuthSchemes.KYUUBI_INTERNAL
@@ -48,10 +48,10 @@ class KyuubiInternalAuthenticationHandler extends 
AuthenticationHandler with Log
     val authorization = getAuthorization(request)
     val inputToken = Option(authorization).map(a => 
Base64.getDecoder.decode(a.getBytes()))
       .getOrElse(Array.empty[Byte])
-    val creds = new String(inputToken, Charset.forName("UTF-8")).split(":")
+    val creds = new String(inputToken, StandardCharsets.UTF_8).split(":")
 
     if (creds.size < 2 || creds(0).trim.isEmpty || creds(1).trim.isEmpty) {
-      response.setHeader(WWW_AUTHENTICATE, authScheme.toString)
+      response.setHeader(WWW_AUTHENTICATE_HEADER, authScheme.toString)
       response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
     } else {
       val Seq(user, password) = creds.toSeq.take(2)
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/util/HttpAuthUtils.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/util/HttpAuthUtils.scala
index 7bb117476..e840a307c 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/util/HttpAuthUtils.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/util/HttpAuthUtils.scala
@@ -17,19 +17,33 @@
 
 package org.apache.kyuubi.server.http.util
 
+import java.nio.charset.StandardCharsets
 import java.security.SecureRandom
 import java.util
-import java.util.StringTokenizer
+import java.util.{Base64, StringTokenizer}
 
 import scala.collection.mutable
 
 import org.apache.kyuubi.Logging
 
 object HttpAuthUtils extends Logging {
-  val WWW_AUTHENTICATE = "WWW-Authenticate"
-  val AUTHORIZATION = "Authorization"
-  val BASIC = "Basic"
+  // HTTP header used by the server endpoint during an authentication sequence.
+  val WWW_AUTHENTICATE_HEADER = "WWW-Authenticate"
+  // HTTP header used by the client endpoint during an authentication sequence.
+  val AUTHORIZATION_HEADER = "Authorization"
+  // HTTP header prefix used by the SPNEGO client/server endpoints during an
+  // authentication sequence.
   val NEGOTIATE = "Negotiate"
+  // HTTP header prefix used during the Basic authentication sequence.
+  val BASIC = "Basic"
+  // HTTP header prefix used during the Basic authentication sequence.
+  val DIGEST = "Digest"
+
+  // RFC 7617: The 'Basic' HTTP Authentication Scheme
+  def basicAuthorizationHeader(userId: String, password: String = "none"): 
String =
+    "BASIC " + new String(
+      Base64.getEncoder.encode(s"$userId:$password".getBytes()),
+      StandardCharsets.UTF_8)
 
   private val COOKIE_ATTR_SEPARATOR = "&"
   private val COOKIE_CLIENT_USER_NAME = "cu"
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 089b756f5..260264b67 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
@@ -29,8 +29,8 @@ import org.apache.hadoop.security.UserGroupInformation
 import org.apache.kyuubi.RestClientTestHelper
 import org.apache.kyuubi.client.api.v1.dto.{SessionHandle, SessionOpenCount, 
SessionOpenRequest}
 import org.apache.kyuubi.config.KyuubiConf
-import 
org.apache.kyuubi.server.http.authentication.AuthenticationHandler.AUTHORIZATION_HEADER
 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.session.KyuubiSession
 
@@ -52,13 +52,10 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
   }
 
   test("test with LDAP authorization") {
-    val encodeAuthorization = new String(
-      Base64.getEncoder.encode(
-        s"$ldapUser:$ldapUserPasswd".getBytes()),
-      "UTF-8")
+
     val response = webTarget.path("api/v1/sessions/count")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader(ldapUser, 
ldapUserPasswd))
       .get()
 
     assert(HttpServletResponse.SC_OK == response.getStatus)
@@ -67,13 +64,9 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
   }
 
   test("test with CUSTOM authorization") {
-    val encodeAuthorization = new String(
-      Base64.getEncoder.encode(
-        s"$customUser:$customPasswd".getBytes()),
-      "UTF-8")
     val response = webTarget.path("api/v1/sessions/count")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader(customUser, 
customPasswd))
       .get()
 
     assert(HttpServletResponse.SC_FORBIDDEN == response.getStatus)
@@ -170,7 +163,7 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
       "UTF-8")
     var response = webTarget.path("api/v1/sessions/count")
       .request()
-      .header(AUTHORIZATION_HEADER, s"${AuthSchemes.KYUUBI_INTERNAL.toString} 
$encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, s"${AuthSchemes.KYUUBI_INTERNAL} 
$encodeAuthorization")
       .get()
 
     assert(HttpServletResponse.SC_OK == response.getStatus)
@@ -183,7 +176,7 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
       "UTF-8")
     response = webTarget.path("api/v1/sessions/count")
       .request()
-      .header(AUTHORIZATION_HEADER, s"${AuthSchemes.KYUUBI_INTERNAL.toString} 
$badAuthorization")
+      .header(AUTHORIZATION_HEADER, s"${AuthSchemes.KYUUBI_INTERNAL} 
$badAuthorization")
       .get()
 
     assert(HttpServletResponse.SC_UNAUTHORIZED == response.getStatus)
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 ea87e3ea0..c570f3a72 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
@@ -17,9 +17,8 @@
 
 package org.apache.kyuubi.server.api.v1
 
-import java.nio.charset.StandardCharsets
 import java.time.Duration
-import java.util.{Base64, UUID}
+import java.util.UUID
 import javax.ws.rs.client.Entity
 import javax.ws.rs.core.{GenericType, MediaType}
 
@@ -31,8 +30,9 @@ import org.scalatest.time.SpanSugar.convertIntToGrainOfTime
 import org.scalatestplus.mockito.MockitoSugar.mock
 
 import org.apache.kyuubi.{KYUUBI_VERSION, KyuubiFunSuite, 
RestFrontendTestHelper, Utils}
-import org.apache.kyuubi.client.api.v1.dto.{Engine, OperationData, ServerData, 
SessionData, SessionHandle, SessionOpenRequest}
+import org.apache.kyuubi.client.api.v1.dto._
 import org.apache.kyuubi.config.KyuubiConf
+import org.apache.kyuubi.config.KyuubiConf._
 import 
org.apache.kyuubi.config.KyuubiReservedKeys.KYUUBI_SESSION_CONNECTION_URL_KEY
 import org.apache.kyuubi.engine.{ApplicationManagerInfo, ApplicationState, 
EngineRef, KyuubiApplicationManager}
 import org.apache.kyuubi.engine.EngineType.SPARK_SQL
@@ -42,22 +42,19 @@ import org.apache.kyuubi.ha.client.{DiscoveryPaths, 
ServiceDiscovery}
 import org.apache.kyuubi.ha.client.DiscoveryClientProvider.withDiscoveryClient
 import org.apache.kyuubi.plugin.PluginLoader
 import org.apache.kyuubi.server.KyuubiRestFrontendService
-import 
org.apache.kyuubi.server.http.authentication.AuthenticationHandler.AUTHORIZATION_HEADER
+import org.apache.kyuubi.server.http.util.HttpAuthUtils
+import org.apache.kyuubi.server.http.util.HttpAuthUtils.AUTHORIZATION_HEADER
+import 
org.apache.kyuubi.service.authentication.AnonymousAuthenticationProviderImpl
 
 class AdminResourceSuite extends KyuubiFunSuite with RestFrontendTestHelper {
 
   private val engineMgr = new KyuubiApplicationManager()
 
   override protected lazy val conf: KyuubiConf = KyuubiConf()
-    .set(KyuubiConf.SERVER_ADMINISTRATORS, Set("admin001"))
-    .set(KyuubiConf.ENGINE_IDLE_TIMEOUT, Duration.ofMinutes(3).toMillis)
-
-  private val encodeAuthorization: String = {
-    new String(
-      Base64.getEncoder.encode(
-        s"${Utils.currentUser}:".getBytes()),
-      StandardCharsets.UTF_8)
-  }
+    .set(AUTHENTICATION_METHOD, Set("CUSTOM"))
+    .set(AUTHENTICATION_CUSTOM_CLASS, 
classOf[AnonymousAuthenticationProviderImpl].getName)
+    .set(SERVER_ADMINISTRATORS, Set("admin001"))
+    .set(ENGINE_IDLE_TIMEOUT, Duration.ofMinutes(3).toMillis)
 
   override def beforeAll(): Unit = {
     super.beforeAll()
@@ -74,70 +71,64 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
     var response = webTarget.path("api/v1/admin/refresh/hadoop_conf")
       .request()
       .post(null)
-    assert(405 == response.getStatus)
+    assert(response.getStatus === 401)
 
     response = webTarget.path("api/v1/admin/refresh/hadoop_conf")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .post(null)
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
 
-    val admin001AuthHeader = new String(
-      Base64.getEncoder.encode("admin001".getBytes()),
-      StandardCharsets.UTF_8)
     response = webTarget.path("api/v1/admin/refresh/hadoop_conf")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $admin001AuthHeader")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader("admin001"))
       .post(null)
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
 
-    val admin002AuthHeader = new String(
-      Base64.getEncoder.encode("admin002".getBytes()),
-      StandardCharsets.UTF_8)
     response = webTarget.path("api/v1/admin/refresh/hadoop_conf")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $admin002AuthHeader")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader("admin002"))
       .post(null)
-    assert(405 == response.getStatus)
+    assert(response.getStatus === 405)
   }
 
   test("refresh user defaults config of the kyuubi server") {
     var response = webTarget.path("api/v1/admin/refresh/user_defaults_conf")
       .request()
       .post(null)
-    assert(405 == response.getStatus)
+    assert(response.getStatus === 401)
 
     response = webTarget.path("api/v1/admin/refresh/user_defaults_conf")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .post(null)
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
   }
 
   test("refresh unlimited users of the kyuubi server") {
     var response = webTarget.path("api/v1/admin/refresh/unlimited_users")
       .request()
       .post(null)
-    assert(405 == response.getStatus)
+    assert(response.getStatus === 401)
 
     response = webTarget.path("api/v1/admin/refresh/unlimited_users")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .post(null)
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
   }
 
   test("refresh deny users of the kyuubi server") {
     var response = webTarget.path("api/v1/admin/refresh/deny_users")
       .request()
       .post(null)
-    assert(405 == response.getStatus)
+    assert(response.getStatus === 401)
 
     response = webTarget.path("api/v1/admin/refresh/deny_users")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .post(null)
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
   }
 
   test("list/close sessions") {
@@ -145,13 +136,15 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
 
     var response = webTarget.path("api/v1/sessions")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .post(Entity.entity(requestObj, MediaType.APPLICATION_JSON_TYPE))
+    assert(response.getStatus === 200)
 
     // get session list
     var response2 = webTarget.path("api/v1/admin/sessions").request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
-    assert(200 == response2.getStatus)
+    assert(response2.getStatus === 200)
     val sessions1 = response2.readEntity(new GenericType[Seq[SessionData]]() 
{})
     assert(sessions1.nonEmpty)
     assert(sessions1.head.getConf.get(KYUUBI_SESSION_CONNECTION_URL_KEY) === 
fe.connectionUrl)
@@ -159,13 +152,13 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
     // close an opened session
     val sessionHandle = 
response.readEntity(classOf[SessionHandle]).getIdentifier
     response = 
webTarget.path(s"api/v1/admin/sessions/$sessionHandle").request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .delete()
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
 
     // get session list again
     response2 = webTarget.path("api/v1/admin/sessions").request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
     assert(200 == response2.getStatus)
     val sessions2 = response2.readEntity(classOf[Seq[SessionData]])
@@ -205,26 +198,26 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
     var response = webTarget.path("api/v1/admin/sessions")
       .queryParam("users", "admin")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
     var sessions = response.readEntity(classOf[Seq[SessionData]])
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
     assert(sessions.size == 2)
 
     response = webTarget.path("api/v1/admin/sessions")
       .queryParam("users", "test_user_1,test_user_2")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
     sessions = response.readEntity(classOf[Seq[SessionData]])
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
     assert(sessions.size == 2)
 
     // list operations
     response = webTarget.path("api/v1/admin/operations")
       .queryParam("users", "test_user_1,test_user_2")
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
     var operations = response.readEntity(classOf[Seq[OperationData]])
     assert(operations.size == 2)
@@ -232,10 +225,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
     response = webTarget.path("api/v1/admin/operations")
       .queryParam("sessionHandle", sessionHandle.identifier)
       .request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
     operations = response.readEntity(classOf[Seq[OperationData]])
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
     assert(operations.size == 1)
   }
 
@@ -250,22 +243,22 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
 
     // list operations
     var response = webTarget.path("api/v1/admin/operations").request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
     var operations = response.readEntity(new GenericType[Seq[OperationData]]() 
{})
     assert(operations.nonEmpty)
     assert(operations.map(op => 
op.getIdentifier).contains(operation.identifier.toString))
 
     // close operation
     response = 
webTarget.path(s"api/v1/admin/operations/${operation.identifier}").request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .delete()
-    assert(200 == response.getStatus)
+    assert(response.getStatus === 200)
 
     // list again
     response = webTarget.path("api/v1/admin/operations").request()
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
       .get()
     operations = response.readEntity(new GenericType[Seq[OperationData]]() {})
     assert(!operations.map(op => 
op.getIdentifier).contains(operation.identifier.toString))
@@ -297,10 +290,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
         .queryParam("sharelevel", "USER")
         .queryParam("type", "spark_sql")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .delete()
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       assert(client.pathExists(engineSpace))
       eventually(timeout(5.seconds), interval(100.milliseconds)) {
         assert(client.getChildren(engineSpace).isEmpty, s"refId same with 
$id?")
@@ -343,10 +336,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
         .queryParam("sharelevel", "GROUP")
         .queryParam("type", "spark_sql")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .delete()
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       assert(client.pathExists(engineSpace))
       eventually(timeout(5.seconds), interval(100.milliseconds)) {
         assert(client.getChildren(engineSpace).isEmpty, s"refId same with 
$id?")
@@ -387,10 +380,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
         .queryParam("type", "spark_sql")
         .queryParam("subdomain", id)
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .delete()
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
     }
   }
 
@@ -419,10 +412,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
       val response = webTarget.path("api/v1/admin/engine")
         .queryParam("type", "spark_sql")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val engines = response.readEntity(new GenericType[Seq[Engine]]() {})
       assert(engines.size == 1)
       assert(engines(0).getEngineType == "SPARK_SQL")
@@ -465,10 +458,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
       val response = webTarget.path("api/v1/admin/engine")
         .queryParam("type", "spark_sql")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val engines = response.readEntity(new GenericType[Seq[Engine]]() {})
       assert(engines.size == 1)
       assert(engines(0).getEngineType == "SPARK_SQL")
@@ -524,9 +517,9 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
       val response = webTarget.path("api/v1/admin/engine")
         .queryParam("type", "spark_sql")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val result = response.readEntity(new GenericType[Seq[Engine]]() {})
       assert(result.size == 2)
 
@@ -534,7 +527,7 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
         .queryParam("type", "spark_sql")
         .queryParam("subdomain", id1)
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
       assert(200 == response1.getStatus)
       val result1 = response1.readEntity(new GenericType[Seq[Engine]]() {})
@@ -562,10 +555,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
 
       val response = webTarget.path("api/v1/admin/server")
         .request()
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val result = response.readEntity(new GenericType[Seq[ServerData]]() {})
       assert(result.size == 1)
       val testServer = result.head
@@ -610,10 +603,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
       val response = webTarget.path("api/v1/admin/engine")
         .queryParam("all", "true")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val engines = response.readEntity(new GenericType[Seq[Engine]]() {})
       assert(engines.size == 1)
       assert(engines(0).getEngineType == "SPARK_SQL")
@@ -657,10 +650,10 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
       val response = webTarget.path("api/v1/admin/engine")
         .queryParam("all", "true")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
 
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val engines = response.readEntity(new GenericType[Seq[Engine]]() {})
       assert(engines.size == 1)
       assert(engines(0).getEngineType == "SPARK_SQL")
@@ -717,9 +710,9 @@ class AdminResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
       val response = webTarget.path("api/v1/admin/engine")
         .queryParam("all", "true")
         .request(MediaType.APPLICATION_JSON_TYPE)
-        .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+        .header(AUTHORIZATION_HEADER, 
HttpAuthUtils.basicAuthorizationHeader(Utils.currentUser))
         .get
-      assert(200 == response.getStatus)
+      assert(response.getStatus === 200)
       val result = response.readEntity(new GenericType[Seq[Engine]]() {})
       assert(result.size == 2)
 
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 9ad51cfda..fda47d583 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
@@ -19,7 +19,7 @@ package org.apache.kyuubi.server.api.v1
 
 import java.net.InetAddress
 import java.nio.file.Paths
-import java.util.{Base64, UUID}
+import java.util.UUID
 import javax.ws.rs.client.Entity
 import javax.ws.rs.core.{MediaType, Response}
 
@@ -43,9 +43,9 @@ import org.apache.kyuubi.metrics.{MetricsConstants, 
MetricsSystem}
 import org.apache.kyuubi.operation.{BatchJobSubmission, OperationState}
 import org.apache.kyuubi.operation.OperationState.OperationState
 import org.apache.kyuubi.server.{KyuubiBatchService, KyuubiRestFrontendService}
-import 
org.apache.kyuubi.server.http.authentication.AuthenticationHandler.AUTHORIZATION_HEADER
+import 
org.apache.kyuubi.server.http.util.HttpAuthUtils.{basicAuthorizationHeader, 
AUTHORIZATION_HEADER}
 import org.apache.kyuubi.server.metadata.api.{Metadata, MetadataFilter}
-import org.apache.kyuubi.service.authentication.KyuubiAuthenticationFactory
+import 
org.apache.kyuubi.service.authentication.{AnonymousAuthenticationProviderImpl, 
KyuubiAuthenticationFactory}
 import org.apache.kyuubi.session.{KyuubiBatchSession, KyuubiSessionManager, 
SessionHandle, SessionType}
 
 class BatchesV1ResourceSuite extends BatchesResourceSuiteBase {
@@ -58,8 +58,8 @@ class BatchesV2ResourceSuite extends BatchesResourceSuiteBase 
{
   override def batchVersion: String = "2"
 
   override def customConf: Map[String, String] = Map(
-    KyuubiConf.METADATA_REQUEST_ASYNC_RETRY_ENABLED.key -> "false",
-    KyuubiConf.BATCH_SUBMITTER_ENABLED.key -> "true")
+    METADATA_REQUEST_ASYNC_RETRY_ENABLED.key -> "false",
+    BATCH_SUBMITTER_ENABLED.key -> "true")
 
   override def afterEach(): Unit = {
     val sessionManager = 
fe.be.sessionManager.asInstanceOf[KyuubiSessionManager]
@@ -82,11 +82,13 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
   def customConf: Map[String, String]
 
   override protected lazy val conf: KyuubiConf = {
+    val testResourceDir = Paths.get(sparkBatchTestResource.get).getParent
     val kyuubiConf = KyuubiConf()
-      .set(KyuubiConf.BATCH_IMPL_VERSION, batchVersion)
-      .set(
-        KyuubiConf.SESSION_LOCAL_DIR_ALLOW_LIST,
-        Set(Paths.get(sparkBatchTestResource.get).getParent.toString))
+      .set(AUTHENTICATION_METHOD, Set("CUSTOM"))
+      .set(AUTHENTICATION_CUSTOM_CLASS, 
classOf[AnonymousAuthenticationProviderImpl].getName)
+      .set(SERVER_ADMINISTRATORS, Set("admin"))
+      .set(BATCH_IMPL_VERSION, batchVersion)
+      .set(SESSION_LOCAL_DIR_ALLOW_LIST, Set(testResourceDir.toString))
     customConf.foreach { case (k, v) => kyuubiConf.set(k, v) }
     kyuubiConf
   }
@@ -107,6 +109,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     val response = webTarget.path("api/v1/batches")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .post(Entity.entity(requestObj, MediaType.APPLICATION_JSON_TYPE))
     assert(response.getStatus === 200)
     var batch = response.readEntity(classOf[Batch])
@@ -130,6 +133,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     val proxyUserRequest = requestObj
     val proxyUserResponse = webTarget.path("api/v1/batches")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .post(Entity.entity(proxyUserRequest, MediaType.APPLICATION_JSON_TYPE))
     assert(proxyUserResponse.getStatus === 405)
     var errorMessage = "Failed to validate proxy privilege of anonymous for 
root"
@@ -137,6 +141,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     var getBatchResponse = webTarget.path(s"api/v1/batches/${batch.getId}")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     assert(getBatchResponse.getStatus === 200)
     batch = getBatchResponse.readEntity(classOf[Batch])
@@ -161,6 +166,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // invalid batchId
     getBatchResponse = webTarget.path(s"api/v1/batches/invalidBatchId")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     assert(getBatchResponse.getStatus === 404)
 
@@ -172,6 +178,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
         .queryParam("from", "0")
         .queryParam("size", "1")
         .request(MediaType.APPLICATION_JSON_TYPE)
+        .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
         .get()
       log = logResponse.readEntity(classOf[OperationLog])
       assert(log.getRowCount === 1)
@@ -185,6 +192,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
         .queryParam("from", "-1")
         .queryParam("size", "100")
         .request(MediaType.APPLICATION_JSON_TYPE)
+        .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
         .get()
       log = logResponse.readEntity(classOf[OperationLog])
       if (log.getRowCount > 0) {
@@ -198,11 +206,9 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     }
 
     // invalid user name
-    val encodeAuthorization =
-      new String(Base64.getEncoder.encode(batch.getId.getBytes()), "UTF-8")
     var deleteBatchResponse = webTarget.path(s"api/v1/batches/${batch.getId}")
       .request(MediaType.APPLICATION_JSON_TYPE)
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader(batch.getId))
       .delete()
     assert(deleteBatchResponse.getStatus === 405)
     errorMessage = s"${batch.getId} is not allowed to close the session belong 
to anonymous"
@@ -211,12 +217,14 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // invalid batchId
     deleteBatchResponse = webTarget.path(s"api/v1/batches/notValidUUID")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     assert(deleteBatchResponse.getStatus === 404)
 
     // non-existed batch session
     deleteBatchResponse = 
webTarget.path(s"api/v1/batches/${UUID.randomUUID().toString}")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     assert(deleteBatchResponse.getStatus === 404)
 
@@ -224,6 +232,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     deleteBatchResponse = webTarget.path(s"api/v1/batches/${batch.getId}")
       .queryParam("hive.server2.proxy.user", "invalidProxy")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     assert(deleteBatchResponse.getStatus === 405)
     errorMessage = "Failed to validate proxy privilege of anonymous for 
invalidProxy"
@@ -232,6 +241,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // check close batch session
     deleteBatchResponse = webTarget.path(s"api/v1/batches/${batch.getId}")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     assert(deleteBatchResponse.getStatus === 200)
     val closeBatchResponse = 
deleteBatchResponse.readEntity(classOf[CloseBatchResponse])
@@ -239,6 +249,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // check state after close batch session
     getBatchResponse = webTarget.path(s"api/v1/batches/${batch.getId}")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     assert(getBatchResponse.getStatus === 200)
     batch = getBatchResponse.readEntity(classOf[Batch])
@@ -252,6 +263,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // close the closed batch session
     deleteBatchResponse = webTarget.path(s"api/v1/batches/${batch.getId}")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     assert(deleteBatchResponse.getStatus === 200)
     
assert(!deleteBatchResponse.readEntity(classOf[CloseBatchResponse]).isSuccess)
@@ -267,6 +279,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     val response = webTarget.path("api/v1/batches")
       .request(MediaType.APPLICATION_JSON)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .post(Entity.entity(multipart, MediaType.MULTIPART_FORM_DATA))
     assert(response.getStatus === 200)
     val batch = response.readEntity(classOf[Batch])
@@ -289,6 +302,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     eventually(timeout(5.seconds), interval(200.millis)) {
       val resp = webTarget.path(s"api/v1/batches/${batch.getId}")
         .request(MediaType.APPLICATION_JSON_TYPE)
+        .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
         .get()
       val batchState = resp.readEntity(classOf[Batch]).getState
       assert(batchState === "PENDING" || batchState === "RUNNING")
@@ -296,6 +310,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     webTarget.path(s"api/v1/batches/${batch.getId}")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     eventually(timeout(5.seconds), interval(200.millis)) {
       assert(KyuubiApplicationManager.uploadWorkDir.toFile.listFiles().isEmpty)
@@ -310,6 +325,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     val resp1 = webTarget.path("api/v1/batches")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .post(Entity.entity(reqObj, MediaType.APPLICATION_JSON_TYPE))
     assert(resp1.getStatus === 200)
     val batch1 = resp1.readEntity(classOf[Batch])
@@ -317,6 +333,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     val resp2 = webTarget.path("api/v1/batches")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .post(Entity.entity(reqObj, MediaType.APPLICATION_JSON_TYPE))
     assert(resp2.getStatus === 200)
     val batch2 = resp2.readEntity(classOf[Batch])
@@ -340,6 +357,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "0")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response.getStatus === 200)
@@ -394,6 +412,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "0")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response2.getStatus === 200)
@@ -406,6 +425,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "2")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response3.getStatus === 200)
@@ -418,6 +438,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "3")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response4.getStatus === 200)
@@ -429,6 +450,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "2")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response5.getStatus === 200)
@@ -441,6 +463,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "2")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response6.getStatus === 200)
@@ -455,6 +478,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "2")
       .queryParam("size", "2")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     assert(response7.getStatus === 500)
   }
@@ -485,6 +509,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
         "resource is a required parameter")).foreach { case (req, msg) =>
       val response = webTarget.path("api/v1/batches")
         .request(MediaType.APPLICATION_JSON_TYPE)
+        .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
         .post(Entity.entity(req, MediaType.APPLICATION_JSON_TYPE))
       assert(response.getStatus === 500)
       assert(response.readEntity(classOf[String]).contains(msg))
@@ -498,6 +523,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
         "Invalid batchId: 3ea7ddbe-0c35-45da-85ad-3186770181a7")).foreach { 
case (batchId, msg) =>
       val response = webTarget.path(s"api/v1/batches/$batchId")
         .request(MediaType.APPLICATION_JSON_TYPE)
+        .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
         .get
       assert(response.getStatus === 404)
       assert(response.readEntity(classOf[String]).contains(msg))
@@ -614,6 +640,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "0")
       .queryParam("size", "1")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     batchVersion match {
       case "1" =>
@@ -632,6 +659,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "0")
       .queryParam("size", "1")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     assert(logResponse.getStatus === 404)
     assert(logResponse.readEntity(classOf[String]).contains("Invalid batchId"))
@@ -646,6 +674,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       .queryParam("from", "0")
       .queryParam("size", "1")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
     assert(logResponse.getStatus === 500)
     assert(logResponse.readEntity(classOf[String]).contains(
@@ -668,13 +697,10 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
       engineType = "SPARK")
     sessionManager.insertMetadata(metadata)
 
-    val encodeAuthorization =
-      new String(Base64.getEncoder.encode("kyuubi".getBytes()), "UTF-8")
-
     // delete the batch in the same kyuubi instance but not found in-memory
     var deleteResp = webTarget.path(s"api/v1/batches/${metadata.identifier}")
       .request(MediaType.APPLICATION_JSON_TYPE)
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("kyuubi"))
       .delete()
     assert(deleteResp.getStatus === 200)
     assert(!deleteResp.readEntity(classOf[CloseBatchResponse]).isSuccess)
@@ -682,7 +708,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // delete batch that is not existing
     deleteResp = webTarget.path(s"api/v1/batches/${UUID.randomUUID.toString}")
       .request(MediaType.APPLICATION_JSON_TYPE)
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("kyuubi"))
       .delete()
     assert(deleteResp.getStatus === 404)
     assert(deleteResp.readEntity(classOf[String]).contains("Invalid batchId:"))
@@ -695,7 +721,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     // delete batch that need make redirection
     deleteResp = webTarget.path(s"api/v1/batches/${metadata2.identifier}")
       .request(MediaType.APPLICATION_JSON_TYPE)
-      .header(AUTHORIZATION_HEADER, s"BASIC $encodeAuthorization")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("kyuubi"))
       .delete()
     assert(deleteResp.getStatus === 200)
     assert(deleteResp.readEntity(classOf[CloseBatchResponse]).getMsg.contains(
@@ -710,6 +736,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     val response = webTarget.path("api/v1/batches")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .header(conf.get(FRONTEND_PROXY_HTTP_CLIENT_IP_HEADER), realClientIp)
       .post(Entity.entity(requestObj, MediaType.APPLICATION_JSON_TYPE))
     assert(response.getStatus === 200)
@@ -740,6 +767,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     eventually(timeout(10.seconds)) {
       val response = webTarget.path("api/v1/batches")
         .request(MediaType.APPLICATION_JSON_TYPE)
+        .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
         .post(Entity.entity(requestObj, MediaType.APPLICATION_JSON_TYPE))
       assert(response.getStatus === 200)
       val batch = response.readEntity(classOf[Batch])
@@ -755,6 +783,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
 
     val deleteResp = webTarget.path(s"api/v1/batches/$batchId")
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .delete()
     assert(deleteResp.getStatus === 200)
 
@@ -816,6 +845,7 @@ abstract class BatchesResourceSuiteBase extends 
KyuubiFunSuite
     val response = webTarget.path("api/v1/batches")
       .queryParam("batchName", uniqueName)
       .request(MediaType.APPLICATION_JSON_TYPE)
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("anonymous"))
       .get()
 
     assert(response.getStatus == 200)
diff --git 
a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
 
b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
index b58e87bc8..b993789ba 100644
--- 
a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
+++ 
b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
@@ -35,7 +35,7 @@ import 
org.apache.kyuubi.config.KyuubiReservedKeys.KYUUBI_SESSION_CONNECTION_URL
 import org.apache.kyuubi.engine.ShareLevel
 import org.apache.kyuubi.metrics.{MetricsConstants, MetricsSystem}
 import org.apache.kyuubi.operation.OperationHandle
-import 
org.apache.kyuubi.server.http.authentication.AuthenticationHandler.AUTHORIZATION_HEADER
+import 
org.apache.kyuubi.server.http.util.HttpAuthUtils.{basicAuthorizationHeader, 
AUTHORIZATION_HEADER}
 import org.apache.kyuubi.session.SessionType
 
 class SessionsResourceSuite extends KyuubiFunSuite with RestFrontendTestHelper 
{
@@ -106,14 +106,9 @@ class SessionsResourceSuite extends KyuubiFunSuite with 
RestFrontendTestHelper {
 
   test("get session event") {
     val sessionOpenRequest = new SessionOpenRequest(Map("testConfig" -> 
"testValue").asJava)
-
-    val user = "kyuubi".getBytes()
-
     val sessionOpenResp = webTarget.path("api/v1/sessions")
       .request(MediaType.APPLICATION_JSON_TYPE)
-      .header(
-        AUTHORIZATION_HEADER,
-        s"Basic ${new String(Base64.getEncoder().encode(user), 
StandardCharsets.UTF_8)}")
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("kyuubi"))
       .post(Entity.entity(sessionOpenRequest, MediaType.APPLICATION_JSON_TYPE))
 
     val sessionHandle = 
sessionOpenResp.readEntity(classOf[SessionHandle]).getIdentifier

Reply via email to