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 | <undefined> |
User-defined authentication implementation of
org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider
[...]
-| kyuubi.authentication.jdbc.driver.class | <undefined> | Driver
class name for JDBC Authentication Provider.
[...]
-| kyuubi.authentication.jdbc.password | <undefined> | Database
password for JDBC Authentication Provider.
[...]
-| kyuubi.authentication.jdbc.query | <undefined> | 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 | <undefined> | JDBC URL
for JDBC Authentication Provider.
[...]
-| kyuubi.authentication.jdbc.user | <undefined> | Database
user for JDBC Authentication Provider.
[...]
-| kyuubi.authentication.ldap.baseDN | <undefined> | LDAP
base DN.
[...]
-| kyuubi.authentication.ldap.binddn | <undefined> | 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 | <undefined> | 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 | <undefined> | 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 | <undefined> | 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 | <undefined> |
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 | <undefined> | SPACE
character separated LDAP connection URL(s).
[...]
-| kyuubi.authentication.ldap.userDNPattern | <undefined> |
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 | <undefined> | 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 | <undefined> |
User-defined authentication implementation of
org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider for http
basic authentication.
[...]
+| kyuubi.authentication.custom.bearer.class | <undefined> |
User-defined authentication implementation of
org.apache.kyuubi.service.authentication.TokenAuthenticationProvider for http
bearer authentication.
[...]
+| kyuubi.authentication.custom.class | <undefined> |
User-defined authentication implementation of
org.apache.kyuubi.service.authentication.PasswdAuthenticationProvider
[...]
+| kyuubi.authentication.jdbc.driver.class | <undefined> | Driver
class name for JDBC Authentication Provider.
[...]
+| kyuubi.authentication.jdbc.password | <undefined> | Database
password for JDBC Authentication Provider.
[...]
+| kyuubi.authentication.jdbc.query | <undefined> | 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 | <undefined> | JDBC URL
for JDBC Authentication Provider.
[...]
+| kyuubi.authentication.jdbc.user | <undefined> | Database
user for JDBC Authentication Provider.
[...]
+| kyuubi.authentication.ldap.baseDN | <undefined> | LDAP
base DN.
[...]
+| kyuubi.authentication.ldap.binddn | <undefined> | 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 | <undefined> | 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 | <undefined> | 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 | <undefined> | 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 | <undefined> |
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 | <undefined> | SPACE
character separated LDAP connection URL(s).
[...]
+| kyuubi.authentication.ldap.userDNPattern | <undefined> |
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 | <undefined> | 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)
+ }
+}