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

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


The following commit(s) were added to refs/heads/master by this push:
     new a4390a785a [KYUUBI #6618] Support http bearer token authentication for 
REST protocol
a4390a785a is described below

commit a4390a785a220711083b50ceb2f7c0b16ee07f8c
Author: George314159 <[email protected]>
AuthorDate: Fri Aug 16 11:06:16 2024 +0000

    [KYUUBI #6618] Support http bearer token authentication for REST protocol
    
    # :mag: Description
    ## Issue References ๐Ÿ”—
    
    This pull request fixes #6618
    
    ## Describe Your Solution ๐Ÿ”ง
    
    It is a subtask of #6590
    This PR is to support http bearer token authentication for REST protocol. 
In addition to BasicAuthenticationHandler, BearerAuthenticationHandler will be 
added to handle http bear token authentication. They will both support CUSTOM 
AuthType. In order to distinguish them, two new configurations are added: 
kyuubi.authentication.custom.basic.class and 
kyuubi.authentication.custom.bearer.class. For http bear token custom 
authentication, users could implement the new 'org.apache.kyuubi.serv [...]
    
    ## Types of changes :bookmark:
    
    - [ ] Bugfix (non-breaking change which fixes an issue)
    - [x] New feature (non-breaking change which adds functionality)
    - [ ] Breaking change (fix or feature that would cause existing 
functionality to change)
    
    ## Test Plan ๐Ÿงช
    
    #### Behavior Without This Pull Request :coffin:
    
    #### Behavior With This Pull Request :tada:
    
    #### Related Unit Tests
    
    ---
    
    # Checklist ๐Ÿ“
    
    - [x] This patch was not authored or co-authored using [Generative 
Tooling](https://www.apache.org/legal/generative-tooling.html)
    
    **Be nice. Be informative.**
    
    Closes #6608 from George314159/authentication.
    
    Closes #6618
    
    d07a30f83 [Wang, Fei] fix UT
    6499c9986 [George314159] Update Test Case
    da519a9c6 [George314159] Update based on comments
    f47160148 [Wang, Fei] Refine UT
    544422399 [George314159] Add test suite for custom authentication
    f2bbfbf7e [Wang, Fei] comments & refine
    a733c0e8f [George314159] Remove unused val
    6f669d46c [George314159] Fix
    650b88d4e [George314159] Update based on comments
    5bc2bac58 [George314159] Update based on comments
    1893889db [George314159] Update based on Comments
    ddee882e9 [George314159] Fix Style
    379a563fa [George314159] Support http bearer token authentication
    
    Lead-authored-by: George314159 <[email protected]>
    Co-authored-by: Wang, Fei <[email protected]>
    Signed-off-by: Cheng Pan <[email protected]>
---
 docs/configuration/settings.md                     | 50 +++++++-------
 docs/extensions/server/authentication.rst          |  7 +-
 .../org/apache/kyuubi/config/KyuubiConf.scala      | 19 ++++++
 .../AnonymousAuthenticationProviderImpl.scala      |  9 ++-
 .../AuthenticationProviderFactory.scala            | 33 ++++++++--
 .../service/authentication/BasicPrincipal.scala}   | 23 ++++---
 .../service/authentication/Credential.scala}       | 16 +++--
 .../TokenAuthenticationProvider.scala}             | 25 +++----
 .../AnonymousAuthenticationProviderImplSuite.scala |  5 ++
 .../CustomAuthenticationProviderImplSuite.scala    | 28 +++++++-
 .../UserDefineAuthenticationProviderImpl.scala     | 18 ++++-
 .../server/http/authentication/AuthSchemes.scala   |  2 +-
 .../http/authentication/AuthenticationFilter.scala | 17 ++++-
 .../BasicAuthenticationHandler.scala               |  2 +-
 ...ler.scala => BearerAuthenticationHandler.scala} | 55 ++++++++--------
 .../kyuubi/server/http/util/HttpAuthUtils.scala    | 11 ++++
 .../operation/KyuubiRestAuthenticationSuite.scala  | 77 ++++++++++++++++++++--
 17 files changed, 298 insertions(+), 99 deletions(-)

diff --git a/docs/configuration/settings.md b/docs/configuration/settings.md
index 52f8484b68..2b9a71f10c 100644
--- a/docs/configuration/settings.md
+++ b/docs/configuration/settings.md
@@ -31,30 +31,32 @@ You can configure the Kyuubi properties in 
`$KYUUBI_HOME/conf/kyuubi-defaults.co
 
 ### Authentication
 
-|                      Key                      |      Default      |          
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
-|-----------------------------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
-| kyuubi.authentication                         | NONE              | A 
comma-separated list of client authentication types.<ul> <li>NOSASL: raw 
transport.</li> <li>NONE: no authentication check.</li> <li>KERBEROS: 
Kerberos/GSSAPI authentication.</li> <li>CUSTOM: User-defined 
authentication.</li> <li>JDBC: JDBC query authentication.</li> <li>LDAP: 
Lightweight Directory Access Protocol authentication.</li></ul>The following 
tree describes the catalog of each option.<ul>  <li><code>NOSASL< [...]
-| kyuubi.authentication.custom.class            | &lt;undefined&gt; | 
User-defined authentication implementation of 
org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider           
                                                                                
                                                                                
                                                                                
                                                         [...]
-| kyuubi.authentication.jdbc.driver.class       | &lt;undefined&gt; | Driver 
class name for JDBC Authentication Provider.                                    
                                                                                
                                                                                
                                                                                
                                                                                
                [...]
-| kyuubi.authentication.jdbc.password           | &lt;undefined&gt; | Database 
password for JDBC Authentication Provider.                                      
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
-| kyuubi.authentication.jdbc.query              | &lt;undefined&gt; | Query 
SQL template with placeholders for JDBC Authentication Provider to execute. 
Authentication passes if the result set is not empty.The SQL statement must 
start with the `SELECT` clause. Available placeholders are `${user}` and 
`${password}`.                                                                  
                                                                                
                                [...]
-| kyuubi.authentication.jdbc.url                | &lt;undefined&gt; | JDBC URL 
for JDBC Authentication Provider.                                               
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
-| kyuubi.authentication.jdbc.user               | &lt;undefined&gt; | Database 
user for JDBC Authentication Provider.                                          
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
-| kyuubi.authentication.ldap.baseDN             | &lt;undefined&gt; | LDAP 
base DN.                                                                        
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
-| kyuubi.authentication.ldap.binddn             | &lt;undefined&gt; | The user 
with which to bind to the LDAP server, and search for the full domain name of 
the user being authenticated. This should be the full domain name of the user, 
and should have search access across all users in the LDAP tree. If not 
specified, then the user being authenticated will be used as the bind user. For 
example: CN=bindUser,CN=Users,DC=subdomain,DC=domain,DC=com                     
                         [...]
-| kyuubi.authentication.ldap.bindpw             | &lt;undefined&gt; | The 
password for the bind user, to be used to search for the full name of the user 
being authenticated. If the username is specified, this parameter must also be 
specified.                                                                      
                                                                                
                                                                                
                     [...]
-| kyuubi.authentication.ldap.customLDAPQuery    | &lt;undefined&gt; | A full 
LDAP query that LDAP Atn provider uses to execute against LDAP Server. If this 
query returns a null resultset, the LDAP Provider fails the Authentication 
request, succeeds if the user is part of the resultset.For example: 
`(&(objectClass=group)(objectClass=top)(instanceType=4)(cn=Domain*))`, 
`(&(objectClass=person)(|(sAMAccountName=admin)(|(memberOf=CN=Domain 
Admins,CN=Users,DC=domain,DC=com)(memberOf=CN=Adminis [...]
-| kyuubi.authentication.ldap.domain             | &lt;undefined&gt; | LDAP 
domain.                                                                         
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
-| kyuubi.authentication.ldap.groupClassKey      | groupOfNames      | LDAP 
attribute name on the group entry that is to be used in LDAP group searches. 
For example: group, groupOfNames or groupOfUniqueNames.                         
                                                                                
                                                                                
                                                                                
                     [...]
-| kyuubi.authentication.ldap.groupDNPattern     | &lt;undefined&gt; | 
COLON-separated list of patterns to use to find DNs for group entities in this 
directory. Use %s where the actual group name is to be substituted for. For 
example: CN=%s,CN=Groups,DC=subdomain,DC=domain,DC=com.                         
                                                                                
                                                                                
                            [...]
-| kyuubi.authentication.ldap.groupFilter                           || 
COMMA-separated list of LDAP Group names (short name not full DNs). For 
example: HiveAdmins,HadoopAdmins,Administrators                                 
                                                                                
                                                                                
                                                                                
                               [...]
-| kyuubi.authentication.ldap.groupMembershipKey | member            | LDAP 
attribute name on the group object that contains the list of distinguished 
names for the user, group, and contact objects that are members of the group. 
For example: member, uniqueMember or memberUid                                  
                                                                                
                                                                                
                         [...]
-| kyuubi.authentication.ldap.guidKey            | uid               | LDAP 
attribute name whose values are unique in this LDAP server. For example: uid or 
CN.                                                                             
                                                                                
                                                                                
                                                                                
                  [...]
-| kyuubi.authentication.ldap.url                | &lt;undefined&gt; | SPACE 
character separated LDAP connection URL(s).                                     
                                                                                
                                                                                
                                                                                
                                                                                
                 [...]
-| kyuubi.authentication.ldap.userDNPattern      | &lt;undefined&gt; | 
COLON-separated list of patterns to use to find DNs for users in this 
directory. Use %s where the actual group name is to be substituted for. For 
example: CN=%s,CN=Users,DC=subdomain,DC=domain,DC=com.                          
                                                                                
                                                                                
                                     [...]
-| kyuubi.authentication.ldap.userFilter                            || 
COMMA-separated list of LDAP usernames (just short names, not full DNs). For 
example: hiveuser,impalauser,hiveadmin,hadoopadmin                              
                                                                                
                                                                                
                                                                                
                          [...]
-| kyuubi.authentication.ldap.userMembershipKey  | &lt;undefined&gt; | LDAP 
attribute name on the user object that contains groups of which the user is a 
direct member, except for the primary group, which is represented by the 
primaryGroupId. For example: memberOf                                           
                                                                                
                                                                                
                           [...]
-| kyuubi.authentication.sasl.qop                | auth              | Sasl QOP 
enable higher levels of protection for Kyuubi communication with clients.<ul> 
<li>auth - authentication only (default)</li> <li>auth-int - authentication 
plus integrity protection</li> <li>auth-conf - authentication plus integrity 
and confidentiality protection. This is applicable only if Kyuubi is configured 
to use Kerberos authentication.</li> </ul>                                      
                       [...]
+|                      Key                      |      Default      |          
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
+|-----------------------------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
+| kyuubi.authentication                         | NONE              | A 
comma-separated list of client authentication types.<ul> <li>NOSASL: raw 
transport.</li> <li>NONE: no authentication check.</li> <li>KERBEROS: 
Kerberos/GSSAPI authentication.</li> <li>CUSTOM: User-defined 
authentication.</li> <li>JDBC: JDBC query authentication.</li> <li>LDAP: 
Lightweight Directory Access Protocol authentication.</li></ul>The following 
tree describes the catalog of each option.<ul>  <li><code>NOSASL< [...]
+| kyuubi.authentication.custom.basic.class      | &lt;undefined&gt; | 
User-defined authentication implementation of 
org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider for http 
basic authentication.                                                           
                                                                                
                                                                                
                                                          [...]
+| kyuubi.authentication.custom.bearer.class     | &lt;undefined&gt; | 
User-defined authentication implementation of 
org.apache.kyuubi.service.authentication.TokenAuthenticationProvider for http 
bearer authentication.                                                          
                                                                                
                                                                                
                                                           [...]
+| kyuubi.authentication.custom.class            | &lt;undefined&gt; | 
User-defined authentication implementation of 
org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider           
                                                                                
                                                                                
                                                                                
                                                         [...]
+| kyuubi.authentication.jdbc.driver.class       | &lt;undefined&gt; | Driver 
class name for JDBC Authentication Provider.                                    
                                                                                
                                                                                
                                                                                
                                                                                
                [...]
+| kyuubi.authentication.jdbc.password           | &lt;undefined&gt; | Database 
password for JDBC Authentication Provider.                                      
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
+| kyuubi.authentication.jdbc.query              | &lt;undefined&gt; | Query 
SQL template with placeholders for JDBC Authentication Provider to execute. 
Authentication passes if the result set is not empty.The SQL statement must 
start with the `SELECT` clause. Available placeholders are `${user}` and 
`${password}`.                                                                  
                                                                                
                                [...]
+| kyuubi.authentication.jdbc.url                | &lt;undefined&gt; | JDBC URL 
for JDBC Authentication Provider.                                               
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
+| kyuubi.authentication.jdbc.user               | &lt;undefined&gt; | Database 
user for JDBC Authentication Provider.                                          
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
+| kyuubi.authentication.ldap.baseDN             | &lt;undefined&gt; | LDAP 
base DN.                                                                        
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
+| kyuubi.authentication.ldap.binddn             | &lt;undefined&gt; | The user 
with which to bind to the LDAP server, and search for the full domain name of 
the user being authenticated. This should be the full domain name of the user, 
and should have search access across all users in the LDAP tree. If not 
specified, then the user being authenticated will be used as the bind user. For 
example: CN=bindUser,CN=Users,DC=subdomain,DC=domain,DC=com                     
                         [...]
+| kyuubi.authentication.ldap.bindpw             | &lt;undefined&gt; | The 
password for the bind user, to be used to search for the full name of the user 
being authenticated. If the username is specified, this parameter must also be 
specified.                                                                      
                                                                                
                                                                                
                     [...]
+| kyuubi.authentication.ldap.customLDAPQuery    | &lt;undefined&gt; | A full 
LDAP query that LDAP Atn provider uses to execute against LDAP Server. If this 
query returns a null resultset, the LDAP Provider fails the Authentication 
request, succeeds if the user is part of the resultset.For example: 
`(&(objectClass=group)(objectClass=top)(instanceType=4)(cn=Domain*))`, 
`(&(objectClass=person)(|(sAMAccountName=admin)(|(memberOf=CN=Domain 
Admins,CN=Users,DC=domain,DC=com)(memberOf=CN=Adminis [...]
+| kyuubi.authentication.ldap.domain             | &lt;undefined&gt; | LDAP 
domain.                                                                         
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
+| kyuubi.authentication.ldap.groupClassKey      | groupOfNames      | LDAP 
attribute name on the group entry that is to be used in LDAP group searches. 
For example: group, groupOfNames or groupOfUniqueNames.                         
                                                                                
                                                                                
                                                                                
                     [...]
+| kyuubi.authentication.ldap.groupDNPattern     | &lt;undefined&gt; | 
COLON-separated list of patterns to use to find DNs for group entities in this 
directory. Use %s where the actual group name is to be substituted for. For 
example: CN=%s,CN=Groups,DC=subdomain,DC=domain,DC=com.                         
                                                                                
                                                                                
                            [...]
+| kyuubi.authentication.ldap.groupFilter                           || 
COMMA-separated list of LDAP Group names (short name not full DNs). For 
example: HiveAdmins,HadoopAdmins,Administrators                                 
                                                                                
                                                                                
                                                                                
                               [...]
+| kyuubi.authentication.ldap.groupMembershipKey | member            | LDAP 
attribute name on the group object that contains the list of distinguished 
names for the user, group, and contact objects that are members of the group. 
For example: member, uniqueMember or memberUid                                  
                                                                                
                                                                                
                         [...]
+| kyuubi.authentication.ldap.guidKey            | uid               | LDAP 
attribute name whose values are unique in this LDAP server. For example: uid or 
CN.                                                                             
                                                                                
                                                                                
                                                                                
                  [...]
+| kyuubi.authentication.ldap.url                | &lt;undefined&gt; | SPACE 
character separated LDAP connection URL(s).                                     
                                                                                
                                                                                
                                                                                
                                                                                
                 [...]
+| kyuubi.authentication.ldap.userDNPattern      | &lt;undefined&gt; | 
COLON-separated list of patterns to use to find DNs for users in this 
directory. Use %s where the actual group name is to be substituted for. For 
example: CN=%s,CN=Users,DC=subdomain,DC=domain,DC=com.                          
                                                                                
                                                                                
                                     [...]
+| kyuubi.authentication.ldap.userFilter                            || 
COMMA-separated list of LDAP usernames (just short names, not full DNs). For 
example: hiveuser,impalauser,hiveadmin,hadoopadmin                              
                                                                                
                                                                                
                                                                                
                          [...]
+| kyuubi.authentication.ldap.userMembershipKey  | &lt;undefined&gt; | LDAP 
attribute name on the user object that contains groups of which the user is a 
direct member, except for the primary group, which is represented by the 
primaryGroupId. For example: memberOf                                           
                                                                                
                                                                                
                           [...]
+| kyuubi.authentication.sasl.qop                | auth              | Sasl QOP 
enable higher levels of protection for Kyuubi communication with clients.<ul> 
<li>auth - authentication only (default)</li> <li>auth-int - authentication 
plus integrity protection</li> <li>auth-conf - authentication plus integrity 
and confidentiality protection. This is applicable only if Kyuubi is configured 
to use Kerberos authentication.</li> </ul>                                      
                       [...]
 
 ### Backend
 
diff --git a/docs/extensions/server/authentication.rst 
b/docs/extensions/server/authentication.rst
index d49d57eee3..b460049e88 100644
--- a/docs/extensions/server/authentication.rst
+++ b/docs/extensions/server/authentication.rst
@@ -17,7 +17,8 @@ Configure Kyuubi to use Custom Authentication
 =============================================
 
 Besides the `builtin authentication`_ methods, kyuubi supports custom
-authentication implementations of 
`org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider`.
+authentication implementations of 
`org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider`
+and `org.apache.kyuubi.service.authentication.TokenAuthenticationProvider`.
 
 .. code-block:: scala
 
@@ -58,7 +59,7 @@ To create custom Authenticator class derived from the above 
interface, we need t
       <scope>provided</scope>
    </dependency>
 
-- Implement PasswdAuthenticationProvider - `Sample Code`_
+- Implement PasswdAuthenticationProvider or TokenAuthenticationProvider - 
`Sample Code`_
 
 
 Enable Custom Authentication
@@ -75,6 +76,8 @@ To enable the custom authentication method, we need to
 
    kyuubi.authentication=CUSTOM
    kyuubi.authentication.custom.class=YourAuthenticationProvider
+   kyuubi.authentication.custom.basic.class=YourBasicAuthenticationProvider
+   kyuubi.authentication.custom.bearer.class=YourBearerAuthenticationProvider
 
 - Restart all the kyuubi server instances
 
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 fea28c34bd..c265f92eb8 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
@@ -852,6 +852,25 @@ object KyuubiConf {
       .stringConf
       .createOptional
 
+  val AUTHENTICATION_CUSTOM_BASIC_CLASS: ConfigEntry[Option[String]] =
+    buildConf("kyuubi.authentication.custom.basic.class")
+      .doc("User-defined authentication implementation of " +
+        "org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider 
" +
+        "for http basic authentication.")
+      .version("1.10.0")
+      .serverOnly
+      .fallbackConf(AUTHENTICATION_CUSTOM_CLASS)
+
+  val AUTHENTICATION_CUSTOM_BEARER_CLASS: OptionalConfigEntry[String] =
+    buildConf("kyuubi.authentication.custom.bearer.class")
+      .doc("User-defined authentication implementation of " +
+        "org.apache.kyuubi.service.authentication.TokenAuthenticationProvider 
" +
+        "for http bearer authentication.")
+      .version("1.10.0")
+      .serverOnly
+      .stringConf
+      .createOptional
+
   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/authentication/AnonymousAuthenticationProviderImpl.scala
 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImpl.scala
index 9b39314e9b..b4a0fcaf91 100644
--- 
a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImpl.scala
+++ 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImpl.scala
@@ -17,11 +17,18 @@
 
 package org.apache.kyuubi.service.authentication
 
+import java.security.Principal
+
 /**
  * This authentication provider allows any combination of username and 
password.
  */
-class AnonymousAuthenticationProviderImpl extends PasswdAuthenticationProvider 
{
+class AnonymousAuthenticationProviderImpl extends PasswdAuthenticationProvider
+  with TokenAuthenticationProvider {
   override def authenticate(user: String, password: String): Unit = {
     // no-op authentication
   }
+  override def authenticate(credential: TokenCredential): Principal = {
+    // no-op authentication
+    new BasicPrincipal("anonymous")
+  }
 }
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 ffdd9b8bb9..bbd43bcc74 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
@@ -19,6 +19,8 @@ package org.apache.kyuubi.service.authentication
 
 import javax.security.sasl.AuthenticationException
 
+import org.apache.commons.lang3.StringUtils
+
 import org.apache.kyuubi.config.KyuubiConf
 import org.apache.kyuubi.service.authentication.AuthMethods.AuthMethod
 import org.apache.kyuubi.util.ClassUtils
@@ -47,10 +49,9 @@ object AuthenticationProviderFactory {
     case AuthMethods.JDBC => new JdbcAuthenticationProviderImpl(conf)
     case AuthMethods.CUSTOM =>
       val className = conf.get(KyuubiConf.AUTHENTICATION_CUSTOM_CLASS)
-      if (className.isEmpty) {
-        throw new AuthenticationException(
-          "authentication.custom.class must be set when auth method was 
CUSTOM.")
-      }
+      require(
+        className.nonEmpty,
+        "kyuubi.authentication.custom.class must be set when auth method was 
CUSTOM.")
       ClassUtils.createInstance(className.get, 
classOf[PasswdAuthenticationProvider], conf)
     case _ => throw new AuthenticationException("Not a valid authentication 
method")
   }
@@ -62,4 +63,28 @@ object AuthenticationProviderFactory {
       new AnonymousAuthenticationProviderImpl
     }
   }
+
+  def getHttpBasicAuthenticationProvider(
+      method: AuthMethod,
+      conf: KyuubiConf): 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_BASIC_CLASS)
+      require(
+        className.nonEmpty,
+        "kyuubi.authentication.custom.basic.class must be set for http basic 
authentication.")
+      ClassUtils.createInstance(className.get, 
classOf[PasswdAuthenticationProvider], conf)
+    case _ => throw new AuthenticationException("Not a valid authentication 
method")
+  }
+
+  def getHttpBearerAuthenticationProvider(
+      providerClass: String,
+      conf: KyuubiConf): TokenAuthenticationProvider = {
+    require(
+      !StringUtils.isBlank(providerClass),
+      "kyuubi.authentication.custom.bearer.class must be set for http bearer 
authentication.")
+    ClassUtils.createInstance(providerClass, 
classOf[TokenAuthenticationProvider], conf)
+  }
 }
diff --git 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/BasicPrincipal.scala
similarity index 63%
copy from 
kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
copy to 
kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/BasicPrincipal.scala
index 7a84103cc4..8396ca5a52 100644
--- 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
+++ 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/BasicPrincipal.scala
@@ -17,18 +17,25 @@
 
 package org.apache.kyuubi.service.authentication
 
-import javax.security.sasl.AuthenticationException
+import java.security.Principal
+import java.util.Objects
 
-import org.apache.kyuubi.Logging
+class BasicPrincipal(val name: String) extends Principal {
+  require(name != null, "Principal name cannot be null")
 
-class UserDefineAuthenticationProviderImpl()
-  extends PasswdAuthenticationProvider with Logging {
+  override def getName: String = name
 
-  override def authenticate(user: String, password: String): Unit = {
-    if (user == "user" && password == "password") {
-      info(s"Success log in of user: $user")
+  override def toString: String = name
+
+  override def equals(o: Any): Boolean = {
+    if (this == o) {
+      true
+    } else if (o == null || getClass != o.getClass) {
+      false
     } else {
-      throw new AuthenticationException("Username or password is not valid!")
+      Objects.equals(name, o.asInstanceOf[BasicPrincipal].name)
     }
   }
+
+  override def hashCode: Int = Objects.hashCode(name)
 }
diff --git 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/Credential.scala
similarity index 75%
copy from 
kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
copy to 
kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/Credential.scala
index 7fb155f5b1..4cb52d1f4e 100644
--- 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
+++ 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/Credential.scala
@@ -17,12 +17,16 @@
 
 package org.apache.kyuubi.service.authentication
 
-import org.apache.kyuubi.KyuubiFunSuite
-
-class AnonymousAuthenticationProviderImplSuite extends KyuubiFunSuite {
+trait TokenCredential {
+  def token: String
+  def extraInfo: Map[String, String]
+}
 
-  test("testAuthenticate") {
-    new AnonymousAuthenticationProviderImpl().authenticate("test", "test")
-  }
+case class DefaultTokenCredential(
+    token: String,
+    override val extraInfo: Map[String, String] = Map.empty)
+  extends TokenCredential
 
+object Credential {
+  val CLIENT_IP_KEY: String = "clientIp"
 }
diff --git 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/TokenAuthenticationProvider.scala
similarity index 58%
copy from 
kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
copy to 
kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/TokenAuthenticationProvider.scala
index 7a84103cc4..20f6087db8 100644
--- 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
+++ 
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/TokenAuthenticationProvider.scala
@@ -17,18 +17,21 @@
 
 package org.apache.kyuubi.service.authentication
 
+import java.security.Principal
 import javax.security.sasl.AuthenticationException
 
-import org.apache.kyuubi.Logging
+trait TokenAuthenticationProvider {
 
-class UserDefineAuthenticationProviderImpl()
-  extends PasswdAuthenticationProvider with Logging {
-
-  override def authenticate(user: String, password: String): Unit = {
-    if (user == "user" && password == "password") {
-      info(s"Success log in of user: $user")
-    } else {
-      throw new AuthenticationException("Username or password is not valid!")
-    }
-  }
+  /**
+   * The authenticate method is called by the Kyuubi Server authentication 
layer
+   * to authenticate users for their requests.
+   * If the token is to be granted, return nothing/throw nothing.
+   * When the token is to be disallowed, throw an appropriate 
[[AuthenticationException]].
+   *
+   * @param credential The token received over the connection request
+   *
+   * @throws AuthenticationException When the token is found to be invalid by 
the implementation
+   */
+  @throws[AuthenticationException]
+  def authenticate(credential: TokenCredential): Principal
 }
diff --git 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
 
b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
index 7fb155f5b1..eb1049ab47 100644
--- 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
+++ 
b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AnonymousAuthenticationProviderImplSuite.scala
@@ -25,4 +25,9 @@ class AnonymousAuthenticationProviderImplSuite extends 
KyuubiFunSuite {
     new AnonymousAuthenticationProviderImpl().authenticate("test", "test")
   }
 
+  test("testAuthenticateToken") {
+    new AnonymousAuthenticationProviderImpl()
+      .authenticate(DefaultTokenCredential("test", Map.empty))
+  }
+
 }
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 6135535e1d..24195c464c 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,16 +21,16 @@ import javax.security.sasl.AuthenticationException
 
 import org.apache.kyuubi.KyuubiFunSuite
 import org.apache.kyuubi.config.KyuubiConf
-import 
org.apache.kyuubi.service.authentication.AuthenticationProviderFactory.getAuthenticationProvider
+import 
org.apache.kyuubi.service.authentication.AuthenticationProviderFactory.{getAuthenticationProvider,
 getHttpBearerAuthenticationProvider}
 
 class CustomAuthenticationProviderImplSuite extends KyuubiFunSuite {
   test("Test user defined authentication") {
     val conf = KyuubiConf()
 
-    val e1 = intercept[AuthenticationException](
+    val e1 = intercept[IllegalArgumentException](
       getAuthenticationProvider(AuthMethods.withName("CUSTOM"), conf))
     assert(e1.getMessage.contains(
-      "authentication.custom.class must be set when auth method was CUSTOM."))
+      "kyuubi.authentication.custom.class must be set when auth method was 
CUSTOM."))
 
     conf.set(
       KyuubiConf.AUTHENTICATION_CUSTOM_CLASS,
@@ -41,4 +41,26 @@ class CustomAuthenticationProviderImplSuite extends 
KyuubiFunSuite {
 
     p1.authenticate("user", "password")
   }
+
+  test("Test user defined http bearer authentication") {
+    val conf = KyuubiConf()
+
+    val e1 = intercept[IllegalArgumentException](
+      getHttpBearerAuthenticationProvider("", conf))
+    assert(e1.getMessage.contains(
+      "kyuubi.authentication.custom.bearer.class must be set for http bearer 
authentication."))
+
+    conf.set(
+      KyuubiConf.AUTHENTICATION_CUSTOM_BEARER_CLASS,
+      classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)
+    val p1 = getHttpBearerAuthenticationProvider(
+      classOf[UserDefineAuthenticationProviderImpl].getCanonicalName,
+      conf)
+    val credential = DefaultTokenCredential("test", Map.empty)
+    val e2 = intercept[AuthenticationException](p1.authenticate(credential))
+    assert(e2.getMessage.contains("Token is not valid!"))
+
+    val credential2 = DefaultTokenCredential("token", Map.empty)
+    p1.authenticate(credential2)
+  }
 }
diff --git 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
 
b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
index 7a84103cc4..087ecbaf78 100644
--- 
a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
+++ 
b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/UserDefineAuthenticationProviderImpl.scala
@@ -17,12 +17,14 @@
 
 package org.apache.kyuubi.service.authentication
 
+import java.security.Principal
 import javax.security.sasl.AuthenticationException
 
 import org.apache.kyuubi.Logging
+import 
org.apache.kyuubi.service.authentication.UserDefineTokenAuthenticationProviderImpl.VALID_TOKEN
 
 class UserDefineAuthenticationProviderImpl()
-  extends PasswdAuthenticationProvider with Logging {
+  extends PasswdAuthenticationProvider with TokenAuthenticationProvider with 
Logging {
 
   override def authenticate(user: String, password: String): Unit = {
     if (user == "user" && password == "password") {
@@ -31,4 +33,18 @@ class UserDefineAuthenticationProviderImpl()
       throw new AuthenticationException("Username or password is not valid!")
     }
   }
+
+  override def authenticate(credential: TokenCredential): Principal = {
+    val clientIp = credential.extraInfo.get(Credential.CLIENT_IP_KEY)
+    if (credential.token == VALID_TOKEN) {
+      info(s"Success log in of token: ${credential.token} with clientIp: 
$clientIp")
+      new BasicPrincipal("test")
+    } else {
+      throw new AuthenticationException("Token is not valid!")
+    }
+  }
+}
+
+object UserDefineTokenAuthenticationProviderImpl {
+  val VALID_TOKEN = "token"
 }
diff --git 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthSchemes.scala
 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthSchemes.scala
index 9f73b3af85..f78fe04254 100644
--- 
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthSchemes.scala
+++ 
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthSchemes.scala
@@ -20,5 +20,5 @@ package org.apache.kyuubi.server.http.authentication
 object AuthSchemes extends Enumeration {
   type AuthScheme = Value
 
-  val BASIC, NEGOTIATE, KYUUBI_INTERNAL = Value
+  val BASIC, BEARER, NEGOTIATE, KYUUBI_INTERNAL = Value
 }
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 15b387607e..a2d499ab3e 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
@@ -29,7 +29,7 @@ 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}
+import org.apache.kyuubi.service.authentication.AuthTypes.{CUSTOM, KERBEROS, 
NOSASL}
 
 class AuthenticationFilter(conf: KyuubiConf) extends Filter with Logging {
   import AuthenticationFilter._
@@ -69,8 +69,19 @@ class AuthenticationFilter(conf: KyuubiConf) extends Filter 
with Logging {
       addAuthHandler(kerberosHandler)
     }
     basicAuthTypeOpt.foreach { basicAuthType =>
-      val basicHandler = new BasicAuthenticationHandler(basicAuthType)
-      addAuthHandler(basicHandler)
+      if (basicAuthType.equals(CUSTOM)) {
+        conf.get(KyuubiConf.AUTHENTICATION_CUSTOM_BASIC_CLASS).foreach { _ =>
+          val basicHandler = new BasicAuthenticationHandler(CUSTOM)
+          addAuthHandler(basicHandler)
+        }
+        conf.get(KyuubiConf.AUTHENTICATION_CUSTOM_BEARER_CLASS).foreach { 
bearerClassName =>
+          val bearerHandler = new BearerAuthenticationHandler(bearerClassName)
+          addAuthHandler(bearerHandler)
+        }
+      } else {
+        val basicHandler = new BasicAuthenticationHandler(basicAuthType)
+        addAuthHandler(basicHandler)
+      }
     }
     if (InternalSecurityAccessor.get() != null) {
       val internalHandler = new KyuubiInternalAuthenticationHandler
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 76560cabb5..9d6d0445c8 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
@@ -80,7 +80,7 @@ class BasicAuthenticationHandler(basicAuthType: AuthType)
       } else {
         val Seq(user, password) = creds.toSeq.take(2)
         val passwdAuthenticationProvider = AuthenticationProviderFactory
-          
.getAuthenticationProvider(AuthMethods.withName(basicAuthType.toString), conf)
+          
.getHttpBasicAuthenticationProvider(AuthMethods.withName(basicAuthType.toString),
 conf)
         passwdAuthenticationProvider.authenticate(user, password)
         response.setStatus(HttpServletResponse.SC_OK)
         authUser = user
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/BearerAuthenticationHandler.scala
similarity index 59%
copy from 
kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/BasicAuthenticationHandler.scala
copy to 
kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/BearerAuthenticationHandler.scala
index 76560cabb5..7d22df8684 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/BearerAuthenticationHandler.scala
@@ -17,31 +17,37 @@
 
 package org.apache.kyuubi.server.http.authentication
 
-import java.nio.charset.Charset
-import java.util.Base64
 import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
 
+import org.apache.commons.lang3.StringUtils
+
 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
 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._
+import 
org.apache.kyuubi.service.authentication.{AnonymousAuthenticationProviderImpl, 
AuthenticationProviderFactory, DefaultTokenCredential, 
TokenAuthenticationProvider}
 
-class BasicAuthenticationHandler(basicAuthType: AuthType)
+class BearerAuthenticationHandler(providerClass: String)
   extends AuthenticationHandler with Logging {
-
   private var conf: KyuubiConf = _
-  private val allowAnonymous = basicAuthType == NOSASL || basicAuthType == NONE
+  private val allowAnonymous = 
classOf[AnonymousAuthenticationProviderImpl].getName == providerClass
 
-  override val authScheme: AuthScheme = AuthSchemes.BASIC
+  override val authScheme: AuthScheme = AuthSchemes.BEARER
 
   override def init(conf: KyuubiConf): Unit = {
     this.conf = conf
   }
 
   override def authenticationSupported: Boolean = {
-    basicAuthType != null
+    Option(providerClass).exists { _ =>
+      try {
+        
Class.forName(providerClass).isAssignableFrom(classOf[TokenAuthenticationProvider])
+        true
+      } catch {
+        case _: Throwable => false
+      }
+    }
   }
 
   override def matchAuthScheme(authorization: String): Boolean = {
@@ -64,29 +70,20 @@ class BasicAuthenticationHandler(basicAuthType: AuthType)
   override def authenticate(
       request: HttpServletRequest,
       response: HttpServletResponse): String = {
-    var authUser: String = null
-
-    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(":")
+    var principal: String = null
+    val inputToken = getAuthorization(request)
 
-    if (allowAnonymous) {
-      authUser = 
creds.take(1).headOption.filterNot(_.isEmpty).getOrElse("anonymous")
+    if (!allowAnonymous && StringUtils.isBlank(inputToken)) {
+      response.setHeader(WWW_AUTHENTICATE_HEADER, authScheme.toString)
+      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
     } else {
-      if (creds.size < 2 || creds(0).trim.isEmpty || creds(1).trim.isEmpty) {
-        response.setHeader(WWW_AUTHENTICATE_HEADER, authScheme.toString)
-        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
-      } else {
-        val Seq(user, password) = creds.toSeq.take(2)
-        val passwdAuthenticationProvider = AuthenticationProviderFactory
-          
.getAuthenticationProvider(AuthMethods.withName(basicAuthType.toString), conf)
-        passwdAuthenticationProvider.authenticate(user, password)
-        response.setStatus(HttpServletResponse.SC_OK)
-        authUser = user
-      }
+      val credential = DefaultTokenCredential(inputToken, 
HttpAuthUtils.getCredentialExtraInfo)
+      principal = AuthenticationProviderFactory
+        .getHttpBearerAuthenticationProvider(providerClass, conf)
+        .authenticate(credential).getName
+      response.setStatus(HttpServletResponse.SC_OK)
     }
-    authUser
+    principal
   }
 
   override def destroy(): Unit = {}
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 e840a307c4..60e5143d75 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
@@ -25,6 +25,8 @@ import java.util.{Base64, StringTokenizer}
 import scala.collection.mutable
 
 import org.apache.kyuubi.Logging
+import org.apache.kyuubi.server.http.authentication.{AuthenticationFilter, 
AuthSchemes}
+import org.apache.kyuubi.service.authentication.Credential
 
 object HttpAuthUtils extends Logging {
   // HTTP header used by the server endpoint during an authentication sequence.
@@ -45,6 +47,8 @@ object HttpAuthUtils extends Logging {
       Base64.getEncoder.encode(s"$userId:$password".getBytes()),
       StandardCharsets.UTF_8)
 
+  def bearerAuthorizationHeader(token: String): String = AuthSchemes.BEARER + 
" " + token
+
   private val COOKIE_ATTR_SEPARATOR = "&"
   private val COOKIE_CLIENT_USER_NAME = "cu"
   private val COOKIE_CLIENT_RAND_NUMBER = "rn"
@@ -108,4 +112,11 @@ object HttpAuthUtils extends Logging {
     }
     map
   }
+
+  def getCredentialExtraInfo: Map[String, String] = {
+    Map(Credential.CLIENT_IP_KEY ->
+      Option(
+        
AuthenticationFilter.HTTP_PROXY_HEADER_CLIENT_IP_ADDRESS.get()).getOrElse(
+        AuthenticationFilter.HTTP_CLIENT_IP_ADDRESS.get()))
+  }
 }
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 260264b679..f25d893af4 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
@@ -31,7 +31,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.{AuthTypes, 
InternalSecurityAccessor, UserDefineAuthenticationProviderImpl, 
UserDefineTokenAuthenticationProviderImpl}
 import org.apache.kyuubi.session.KyuubiSession
 
 class KyuubiRestAuthenticationSuite extends RestClientTestHelper {
@@ -46,9 +46,16 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
       s"hadoop.proxyuser.$clientPrincipalUser.hosts" -> "*")
   }
 
+  protected def authMethods = 
conf.get(KyuubiConf.AUTHENTICATION_METHOD).map(AuthTypes.withName)
+  protected def kerberosAuthEnabled: Boolean = 
authMethods.contains(AuthTypes.KERBEROS)
+  protected def nonKerberosAuth = authMethods.filterNot(_ == 
AuthTypes.KERBEROS).headOption
+  protected def ldapAuthEnabled = nonKerberosAuth.contains(AuthTypes.LDAP)
+  protected def customAuthEnabled = nonKerberosAuth.contains(AuthTypes.CUSTOM)
+
   override def beforeAll(): Unit = {
     super.beforeAll()
     InternalSecurityAccessor.initialize(conf, true)
+    assert(kerberosAuthEnabled && (ldapAuthEnabled || customAuthEnabled))
   }
 
   test("test with LDAP authorization") {
@@ -58,9 +65,11 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
       .header(AUTHORIZATION_HEADER, basicAuthorizationHeader(ldapUser, 
ldapUserPasswd))
       .get()
 
-    assert(HttpServletResponse.SC_OK == response.getStatus)
-    val openedSessionCount = response.readEntity(classOf[SessionOpenCount])
-    assert(openedSessionCount.getOpenSessionCount == 0)
+    if (ldapAuthEnabled) {
+      assert(HttpServletResponse.SC_OK == response.getStatus)
+    } else {
+      assert(HttpServletResponse.SC_FORBIDDEN == response.getStatus)
+    }
   }
 
   test("test with CUSTOM authorization") {
@@ -69,7 +78,11 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
       .header(AUTHORIZATION_HEADER, basicAuthorizationHeader(customUser, 
customPasswd))
       .get()
 
-    assert(HttpServletResponse.SC_FORBIDDEN == response.getStatus)
+    if (customAuthEnabled) {
+      assert(HttpServletResponse.SC_OK == response.getStatus)
+    } else {
+      assert(HttpServletResponse.SC_FORBIDDEN == response.getStatus)
+    }
   }
 
   test("test without authorization") {
@@ -182,3 +195,57 @@ class KyuubiRestAuthenticationSuite extends 
RestClientTestHelper {
     assert(HttpServletResponse.SC_UNAUTHORIZED == response.getStatus)
   }
 }
+
+class KyuubiRestCustomAuthenticationTest 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" -> "*",
+    KyuubiConf.AUTHENTICATION_METHOD.key -> "KERBEROS,CUSTOM,LDAP",
+    KyuubiConf.AUTHENTICATION_CUSTOM_BASIC_CLASS.key ->
+      classOf[UserDefineAuthenticationProviderImpl].getCanonicalName,
+    KyuubiConf.AUTHENTICATION_CUSTOM_BEARER_CLASS.key ->
+      classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)
+
+  test("test with valid CUSTOM http bearer authorization") {
+    val response = webTarget.path("api/v1/sessions/count")
+      .request()
+      .header(
+        AUTHORIZATION_HEADER,
+        
bearerAuthorizationHeader(UserDefineTokenAuthenticationProviderImpl.VALID_TOKEN))
+      .get()
+
+    assert(HttpServletResponse.SC_OK == response.getStatus)
+  }
+
+  test("test with invalid CUSTOM http bearer authorization") {
+    val response = webTarget.path("api/v1/sessions/count")
+      .request()
+      .header(AUTHORIZATION_HEADER, bearerAuthorizationHeader("bad token"))
+      .get()
+
+    assert(HttpServletResponse.SC_FORBIDDEN == response.getStatus)
+  }
+
+  test("test with valid CUSTOM http basic authorization") {
+    val response = webTarget.path("api/v1/sessions/count")
+      .request()
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("user", 
"password"))
+      .get()
+
+    assert(HttpServletResponse.SC_OK == response.getStatus)
+  }
+
+  test("test with invalid CUSTOM http basic authorization") {
+    val response = webTarget.path("api/v1/sessions/count")
+      .request()
+      .header(AUTHORIZATION_HEADER, basicAuthorizationHeader("test", "test"))
+      .get()
+
+    assert(HttpServletResponse.SC_FORBIDDEN == response.getStatus)
+  }
+}

Reply via email to