You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kyuubi.apache.org by fe...@apache.org on 2022/08/18 12:29:21 UTC
[incubator-kyuubi] branch master updated: [KYUUBI #3020] kyuubi ldap add new config property kyuubi.authentication.ldap.bindpw and kyuubi.authentication.ldap.attrs
This is an automated email from the ASF dual-hosted git repository.
feiwang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-kyuubi.git
The following commit(s) were added to refs/heads/master by this push:
new 5d88c7b20 [KYUUBI #3020] kyuubi ldap add new config property kyuubi.authentication.ldap.bindpw and kyuubi.authentication.ldap.attrs
5d88c7b20 is described below
commit 5d88c7b207b97ea2f11b43811f47b2619d04f14e
Author: pengqli <pe...@cisco.com>
AuthorDate: Thu Aug 18 20:29:12 2022 +0800
[KYUUBI #3020] kyuubi ldap add new config property kyuubi.authentication.ldap.bindpw and kyuubi.authentication.ldap.attrs
### _Why are the changes needed?_
Among the kyuubi ldap configuration parameters, there is currently "kyuubi.authentication.ldap.base.dn=", but there is no place corresponding to the CN password setting. similar to hive
"hive.server2.authentication.ldap.binddn",
"hive.server2.authentication.ldap.bindpw".
### _How was this patch tested?_
- [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible
- [x] Add screenshots for manual tests if appropriate
- [ ] [Run test](https://kyuubi.apache.org/docs/latest/develop_tools/testing.html#running-tests) locally before make a pull request
Closes #3213 from dev-lpq/branch-ldap-1.6.
Closes #3020
31817cc6 [pengqli] upgrade ldap to support ldap before 1.6.0
31094030 [pengqli] upgrade ldap to support ldap before 1.6.0
f62e4c96 [pengqli] upgrade ldap to support ldap before 1.6.0
e03e036e [pengqli] add AUTHENTICATION_LDAP_GUIDKEY deprecated
6f680dfc [pengqli] add ldap config AUTHENTICATION_LDAP_BINDDN
19f8e6ce [pengqli] add ldap config AUTHENTICATION_LDAP_BINDDN
07df56b8 [pengqli] upgrade LdapAuthenticationProviderImpl
1a48f418 [pengqli] upgrade settings.md
8e9b5721 [pengqli] upgrade ldap ldapBindpw
5793a811 [pengqli] upgrade ldap ldapBindpw
822d4c30 [pengqli] upgrade docs/deployment/settings.md
c2b20418 [pengqli] upgrade ldap WithLdapServer UTs
5d7a301c [pengqli] add AUTHENTICATION_LDAP_PASSWORD into serverOnlyConfEntries
10b42b1b [pengqli] upgrade AuthenticationProviderFactorySuite UTs
490bfae8 [pengqli] kyuubi ldap add new config property kyuubi.authentication.ldap.bindnpw and kyuubi.authentication.ldap.attrs
5e071252 [pengqli] upgrafe config kyuubi.authentication.ldap.attrs
4e771ec6 [pengqli] kyuubi ldap add new config property kyuubi.authentication.ldap.bindnpw and kyuubi.authentication.ldap.attrs
Authored-by: pengqli <pe...@cisco.com>
Signed-off-by: Fei Wang <fw...@ebay.com>
---
docs/deployment/settings.md | 5 +-
.../org/apache/kyuubi/config/KyuubiConf.scala | 38 ++++++++-
.../LdapAuthenticationProviderImpl.scala | 93 +++++++++++++++++-----
.../AuthenticationProviderFactorySuite.scala | 29 ++++++-
.../LdapAuthenticationProviderImplSuite.scala | 80 ++++++++++++++++++-
.../service/authentication/WithLdapServer.scala | 53 +++++++++++-
.../org/apache/kyuubi/RestClientTestHelper.scala | 4 +
.../KyuubiOperationKerberosAndPlainAuthSuite.scala | 4 +
...rationThriftHttpKerberosAndPlainAuthSuite.scala | 4 +
.../server/rest/client/BatchRestApiSuite.scala | 2 +-
10 files changed, 279 insertions(+), 33 deletions(-)
diff --git a/docs/deployment/settings.md b/docs/deployment/settings.md
index 9dc974787..e0a499bdd 100644
--- a/docs/deployment/settings.md
+++ b/docs/deployment/settings.md
@@ -143,9 +143,12 @@ kyuubi.authentication.jdbc.password|<undefined>|Database password for JDBC
kyuubi.authentication.jdbc.query|<undefined>|Query SQL template with placeholders for JDBC Authentication Provider to execute. Authentication passes if at least one row fetched in the result set.Available placeholders are: <ul><li>`${username}`</li><li>`${password}`</li></ul>eg.: query sql `SELECT 1 FROM auth_table WHERE user=${username} AND passwd=MD5(CONCAT(salt,${password}));` will be prepared as: `SELECT 1 FROM auth_table WHERE user=? AND passwd=MD5(CONCAT(salt,?));` with value [...]
kyuubi.authentication.jdbc.url|<undefined>|JDBC URL for JDBC Authentication Provider.|string|1.6.0
kyuubi.authentication.jdbc.username|<undefined>|Database username for JDBC Authentication Provider.|string|1.6.0
+kyuubi.authentication.ldap.attrs|mail|Specifies part of the search as an attribute returned by LDAP. For example: mail,name.|seq|1.6.0
kyuubi.authentication.ldap.base.dn|<undefined>|LDAP base DN.|string|1.0.0
+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. For example: uid=admin,cn=Directory Manager,ou=users,dc=example,dc=com|string|1.6.0
+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.|string|1.6.0
kyuubi.authentication.ldap.domain|<undefined>|LDAP domain.|string|1.0.0
-kyuubi.authentication.ldap.guidKey|uid|LDAP attribute name whose values are unique in this LDAP server.For example:uid or cn.|string|1.2.0
+kyuubi.authentication.ldap.guidKey|uid|(deprecated)LDAP attribute name whose values are unique in this LDAP server.For example:uid or cn.|string|1.2.0
kyuubi.authentication.ldap.url|<undefined>|SPACE character separated LDAP connection URL(s).|string|1.0.0
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>|string|1.0.0
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 7b72f4d2d..844302cc9 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
@@ -639,14 +639,41 @@ object KyuubiConf {
.stringConf
.createOptional
+ @deprecated(s"using kyuubi.authentication.ldap.binddn instead", "1.6.0")
val AUTHENTICATION_LDAP_GUIDKEY: ConfigEntry[String] =
buildConf("kyuubi.authentication.ldap.guidKey")
- .doc("LDAP attribute name whose values are unique in this LDAP server." +
+ .doc("(deprecated)LDAP attribute name whose values are unique in this LDAP server." +
"For example:uid or cn.")
.version("1.2.0")
.stringConf
.createWithDefault("uid")
+ val AUTHENTICATION_LDAP_BINDDN: OptionalConfigEntry[String] =
+ buildConf("kyuubi.authentication.ldap.binddn")
+ .doc("The user with which to bind to the LDAP server, and search for the full domain name " +
+ "of the user being authenticated." +
+ " For example: uid=admin,cn=Directory Manager,ou=users,dc=example,dc=com")
+ .version("1.6.0")
+ .stringConf
+ .createOptional
+
+ val AUTHENTICATION_LDAP_PASSWORD: OptionalConfigEntry[String] =
+ buildConf("kyuubi.authentication.ldap.bindpw")
+ .doc("The password for the bind user," +
+ " to be used to search for the full name of the user being authenticated.")
+ .version("1.6.0")
+ .stringConf
+ .createOptional
+
+ val AUTHENTICATION_LDAP_ATTRIBUTES: ConfigEntry[Seq[String]] =
+ buildConf("kyuubi.authentication.ldap.attrs")
+ .doc("Specifies part of the search as an attribute returned by LDAP." +
+ " For example: mail,name.")
+ .version("1.6.0")
+ .stringConf
+ .toSequence()
+ .createWithDefault(Seq("mail"))
+
val AUTHENTICATION_JDBC_DRIVER: OptionalConfigEntry[String] =
buildConf("kyuubi.authentication.jdbc.driver.class")
.doc("Driver class name for JDBC Authentication Provider.")
@@ -1923,7 +1950,8 @@ object KyuubiConf {
SERVER_LIMIT_CONNECTIONS_PER_IPADDRESS,
SERVER_LIMIT_CONNECTIONS_PER_USER_IPADDRESS,
SERVER_LIMIT_CONNECTIONS_PER_USER,
- SESSION_LOCAL_DIR_ALLOW_LIST)
+ SESSION_LOCAL_DIR_ALLOW_LIST,
+ AUTHENTICATION_LDAP_PASSWORD)
/**
* Holds information about keys that have been deprecated.
@@ -1992,7 +2020,11 @@ object KyuubiConf {
DeprecatedConfig(
"kyuubi.ha.zookeeper.acl.enabled",
"1.3.2",
- "Use kyuubi.ha.zookeeper.auth.type and kyuubi.ha.zookeeper.engine.auth.type instead"))
+ "Use kyuubi.ha.zookeeper.auth.type and kyuubi.ha.zookeeper.engine.auth.type instead"),
+ DeprecatedConfig(
+ AUTHENTICATION_LDAP_GUIDKEY.key,
+ "1.6.0",
+ s"using ${AUTHENTICATION_LDAP_BINDDN} instead"))
Map(configs.map { cfg => cfg.key -> cfg }: _*)
}
diff --git a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImpl.scala b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImpl.scala
index b5e08def5..9bd80cdd7 100644
--- a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImpl.scala
+++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImpl.scala
@@ -17,8 +17,9 @@
package org.apache.kyuubi.service.authentication
-import javax.naming.{Context, NamingException}
-import javax.naming.directory.InitialDirContext
+import javax.naming.{Context, NamingEnumeration, NamingException}
+import javax.naming.directory.{InitialDirContext, SearchControls, SearchResult}
+import javax.naming.ldap.InitialLdapContext
import javax.security.sasl.AuthenticationException
import org.apache.commons.lang3.StringUtils
@@ -58,29 +59,79 @@ class LdapAuthenticationProviderImpl(conf: KyuubiConf) extends PasswdAuthenticat
conf.get(AUTHENTICATION_LDAP_URL).foreach(env.put(Context.PROVIDER_URL, _))
val domain = conf.get(AUTHENTICATION_LDAP_DOMAIN)
- val u =
- if (!hasDomain(user) && domain.nonEmpty) {
- user + "@" + domain.get
+ val mail = if (!hasDomain(user) && domain.nonEmpty) (user + "@" + domain.get) else user
+ var bindDn = conf.get(AUTHENTICATION_LDAP_BINDDN).getOrElse("")
+ val guidKey = conf.get(AUTHENTICATION_LDAP_GUIDKEY)
+
+ if ("".equals(bindDn)) {
+ bindDn = conf.get(AUTHENTICATION_LDAP_BASEDN) match {
+ case Some(dn) => guidKey + "=" + mail + "," + dn
+ case _ => mail
+ }
+ env.put(Context.SECURITY_PRINCIPAL, bindDn)
+ env.put(Context.SECURITY_CREDENTIALS, password)
+ try {
+ val ctx = new InitialDirContext(env)
+ ctx.close()
+ } catch {
+ case e: NamingException =>
+ throw new AuthenticationException(
+ s"Error validating LDAP user: $user," +
+ s" bindDn: $bindDn.",
+ e)
+ }
+ } else {
+ val baseDn = conf.get(AUTHENTICATION_LDAP_BASEDN).getOrElse("")
+ val bindPw = conf.get(AUTHENTICATION_LDAP_PASSWORD).getOrElse("")
+ val attrs = conf.get(AUTHENTICATION_LDAP_ATTRIBUTES).toArray
+ env.put(Context.SECURITY_PRINCIPAL, bindDn)
+ env.put(Context.SECURITY_CREDENTIALS, bindPw)
+ var nameEnuResults: NamingEnumeration[SearchResult] = null
+ try {
+ val ctx = new InitialLdapContext(env, null)
+ val sc = new SearchControls
+ sc.setReturningAttributes(attrs)
+ sc.setSearchScope(SearchControls.SUBTREE_SCOPE)
+ val searchFilter = String.format("(%s=%s)", "mail", mail)
+ nameEnuResults = ctx.search(baseDn, searchFilter, sc)
+ } catch {
+ case e: NamingException =>
+ throw new AuthenticationException(
+ s"LDAP InitialLdapContext failed, Error validating LDAP user: $user," +
+ s" bindDn: $bindDn.",
+ e)
+ }
+ if (nameEnuResults != null && nameEnuResults.hasMore) {
+ try {
+ val searchResult = nameEnuResults.next
+ val attrs = searchResult.getAttributes.getAll
+ if (!attrs.hasMore) {
+ throw new AuthenticationException(
+ s"LDAP attributes are empty, please check config " +
+ s"AUTHENTICATION_LDAP_ATTRIBUTES.key, Error validating LDAP user: $user," +
+ s" bindDn: $bindDn.")
+ }
+ while (attrs.hasMore) {
+ attrs.next
+ env.put(Context.SECURITY_PRINCIPAL, searchResult.getNameInNamespace)
+ env.put(Context.SECURITY_CREDENTIALS, password)
+ val ctx = new InitialDirContext(env)
+ ctx.close()
+ }
+ } catch {
+ case e: NamingException =>
+ throw new AuthenticationException(
+ s"LDAP InitialDirContext failed, Error validating LDAP user: $user," +
+ s" bindDn: $bindDn.",
+ e)
+ }
} else {
- user
+ throw new AuthenticationException(
+ s"LDAP InitialLdapContext search results are empty, Error validating LDAP user: $user," +
+ s" bindDn: $bindDn.")
}
-
- val guidKey = conf.get(AUTHENTICATION_LDAP_GUIDKEY)
- val bindDn = conf.get(AUTHENTICATION_LDAP_BASEDN) match {
- case Some(dn) => guidKey + "=" + u + "," + dn
- case _ => u
}
- env.put(Context.SECURITY_PRINCIPAL, bindDn)
- env.put(Context.SECURITY_CREDENTIALS, password)
-
- try {
- val ctx = new InitialDirContext(env)
- ctx.close()
- } catch {
- case e: NamingException =>
- throw new AuthenticationException(s"Error validating LDAP user: $bindDn", e)
- }
}
private def hasDomain(userName: String): Boolean = ServiceUtils.indexOfDomainMatch(userName) > 0
diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala
index 0bd29ac56..4e829cf55 100644
--- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala
+++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/AuthenticationProviderFactorySuite.scala
@@ -21,18 +21,41 @@ import javax.security.sasl.AuthenticationException
import org.apache.kyuubi.{KyuubiFunSuite, Utils}
import org.apache.kyuubi.config.KyuubiConf
+import org.apache.kyuubi.config.KyuubiConf._
class AuthenticationProviderFactorySuite extends KyuubiFunSuite {
import AuthenticationProviderFactory._
- test("get auth provider") {
- val conf = KyuubiConf()
+ private val conf = new KyuubiConf()
+
+ override def beforeAll(): Unit = {
+ super.beforeAll()
+ }
+
+ test("get auth provider before 1.6.0") {
+ conf.set(AUTHENTICATION_LDAP_BASEDN, "test")
+ val p1 = getAuthenticationProvider(AuthMethods.withName("NONE"), conf)
+ p1.authenticate(Utils.currentUser, "")
+ val p2 = getAuthenticationProvider(AuthMethods.withName("LDAP"), conf)
+ val e1 = intercept[AuthenticationException](p2.authenticate("test", "test"))
+ assert(e1.getMessage.contains("Error validating LDAP user"))
+ val e2 = intercept[AuthenticationException](
+ AuthenticationProviderFactory.getAuthenticationProvider(null, conf))
+ assert(e2.getMessage === "Not a valid authentication method")
+ }
+
+ test("get auth provider on since 1.6.0") {
+ conf.set(AUTHENTICATION_LDAP_BASEDN, "test")
+ conf.set(AUTHENTICATION_LDAP_BINDDN, "test")
+ conf.set(AUTHENTICATION_LDAP_PASSWORD, "test")
+ conf.set(AUTHENTICATION_LDAP_DOMAIN, "test")
+ conf.set(AUTHENTICATION_LDAP_ATTRIBUTES, Seq("test"))
val p1 = getAuthenticationProvider(AuthMethods.withName("NONE"), conf)
p1.authenticate(Utils.currentUser, "")
val p2 = getAuthenticationProvider(AuthMethods.withName("LDAP"), conf)
val e1 = intercept[AuthenticationException](p2.authenticate("test", "test"))
- assert(e1.getMessage.contains("Error validating LDAP user:"))
+ assert(e1.getMessage.contains("Error validating LDAP user"))
val e2 = intercept[AuthenticationException](
AuthenticationProviderFactory.getAuthenticationProvider(null, conf))
assert(e2.getMessage === "Not a valid authentication method")
diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImplSuite.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImplSuite.scala
index 639411628..97adf51eb 100644
--- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImplSuite.scala
+++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/LdapAuthenticationProviderImplSuite.scala
@@ -42,14 +42,14 @@ class LdapAuthenticationProviderImplSuite extends WithLdapServer {
assert(ldapServer.getListenPort > 0)
}
- test("authenticate tests") {
+ test("Kyubbi ldap authenticate tests before 1.6.0") {
val providerImpl = new LdapAuthenticationProviderImpl(conf)
val e1 = intercept[AuthenticationException](providerImpl.authenticate("", ""))
assert(e1.getMessage.contains("user is null"))
val e2 = intercept[AuthenticationException](providerImpl.authenticate("kyuubi", ""))
assert(e2.getMessage.contains("password is null"))
- val user = "uid=kentyao,ou=users"
+ val user = "uid=kentyao,dc=example,dc=com"
providerImpl.authenticate(user, "kentyao")
val e3 = intercept[AuthenticationException](
providerImpl.authenticate(user, "kent"))
@@ -68,6 +68,7 @@ class LdapAuthenticationProviderImplSuite extends WithLdapServer {
val providerImpl3 = new LdapAuthenticationProviderImpl(conf)
val e5 = intercept[AuthenticationException](
providerImpl3.authenticate("kentyao", "kentyao"))
+ conf.set(AUTHENTICATION_LDAP_URL, ldapUrl)
assert(e5.getMessage.contains(user))
assert(e5.getCause.isInstanceOf[CommunicationException])
@@ -76,4 +77,79 @@ class LdapAuthenticationProviderImplSuite extends WithLdapServer {
val providerImpl4 = new LdapAuthenticationProviderImpl(conf)
intercept[AuthenticationException](providerImpl4.authenticate("kentyao", "kentyao"))
}
+
+ test("Kyubbi ldap authenticate tests since 1.6.0") {
+ conf.set(AUTHENTICATION_LDAP_BASEDN, ldapBaseDn)
+ conf.set(AUTHENTICATION_LDAP_ATTRIBUTES, ldapAttrs)
+ conf.set(AUTHENTICATION_LDAP_BINDDN, ldapBinddn)
+ conf.set(AUTHENTICATION_LDAP_PASSWORD, ldapBindpw)
+ conf.set(AUTHENTICATION_LDAP_DOMAIN, ldapDomain)
+ val providerImpl = new LdapAuthenticationProviderImpl(conf)
+ val e1 = intercept[AuthenticationException](providerImpl.authenticate("", ""))
+ assert(e1.getMessage.contains("user is null"))
+ val e2 = intercept[AuthenticationException](providerImpl.authenticate("kyuubi", ""))
+ assert(e2.getMessage.contains("password is null"))
+
+ providerImpl.authenticate(ldapUser, ldapUserPasswd)
+
+ conf.set(AUTHENTICATION_LDAP_BASEDN, "dc=com")
+ val providerImpl1 = new LdapAuthenticationProviderImpl(conf)
+ val e3 = intercept[AuthenticationException](
+ providerImpl1.authenticate(ldapUser, ldapUserPasswd))
+ assert(e3.getMessage contains (ldapUser))
+ assert(e3.getMessage contains "Error validating LDAP user")
+ assert(e3.getCause.isInstanceOf[javax.naming.NameNotFoundException])
+ conf.set(AUTHENTICATION_LDAP_BASEDN, ldapBaseDn)
+
+ conf.set(
+ AUTHENTICATION_LDAP_BINDDN,
+ s"uid=admin,cn=Directory Manager,ou=users,dc=example,dc=com")
+ conf.set(AUTHENTICATION_LDAP_PASSWORD, "adminPasswordTest")
+ val providerImpl2 = new LdapAuthenticationProviderImpl(conf)
+ val e4 = intercept[AuthenticationException](
+ providerImpl2.authenticate(ldapUser, ldapUserPasswd))
+ assert(e4.getMessage contains (ldapUser))
+ assert(e4.getMessage contains "Error validating LDAP user")
+ assert(e4.getCause.isInstanceOf[javax.naming.AuthenticationException])
+ conf.set(AUTHENTICATION_LDAP_PASSWORD, ldapBindpw)
+
+ val providerImpl3 = new LdapAuthenticationProviderImpl(conf)
+ val e5 = intercept[AuthenticationException](
+ providerImpl3.authenticate(ldapUser, "kent"))
+ assert(e5.getMessage contains (ldapUser))
+ assert(e5.getMessage contains "Error validating LDAP user")
+ assert(e5.getCause.isInstanceOf[javax.naming.AuthenticationException])
+
+ val providerImpl4 = new LdapAuthenticationProviderImpl(conf)
+ val e6 = intercept[AuthenticationException](
+ providerImpl4.authenticate("kent", ldapUserPasswd))
+ assert(e6.getMessage contains ("kent"))
+ assert(e6.getMessage contains "Error validating LDAP user")
+
+ conf.set(AUTHENTICATION_LDAP_DOMAIN, "kyuubi.com")
+ val providerImpl5 = new LdapAuthenticationProviderImpl(conf)
+ val e7 =
+ intercept[AuthenticationException](providerImpl5.authenticate(ldapUser, ldapUserPasswd))
+ assert(e7.getMessage contains "Error validating LDAP user")
+ conf.set(AUTHENTICATION_LDAP_DOMAIN, "example")
+
+ conf.set(AUTHENTICATION_LDAP_ATTRIBUTES, Seq("cn"))
+ val providerImpl6 = new LdapAuthenticationProviderImpl(conf)
+ providerImpl6.authenticate(ldapUser, ldapUserPasswd)
+ conf.set(AUTHENTICATION_LDAP_ATTRIBUTES, Seq("mail"))
+
+ conf.set(AUTHENTICATION_LDAP_ATTRIBUTES, Seq("mobile"))
+ val providerImpl7 = new LdapAuthenticationProviderImpl(conf)
+ val e8 =
+ intercept[AuthenticationException](providerImpl7.authenticate(ldapUser, ldapUserPasswd))
+ assert(e8.getMessage contains "Error validating LDAP user")
+ conf.set(AUTHENTICATION_LDAP_ATTRIBUTES, Seq("mail"))
+
+ conf.unset(AUTHENTICATION_LDAP_URL)
+ val providerImpl8 = new LdapAuthenticationProviderImpl(conf)
+ val e9 = intercept[AuthenticationException](
+ providerImpl8.authenticate(ldapUser, ldapUserPasswd))
+ assert(e9.getMessage.contains(ldapUser))
+ assert(e9.getCause.isInstanceOf[CommunicationException])
+ }
}
diff --git a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/WithLdapServer.scala b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/WithLdapServer.scala
index 0bb38684e..814364470 100644
--- a/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/WithLdapServer.scala
+++ b/kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/WithLdapServer.scala
@@ -23,17 +23,23 @@ import org.apache.kyuubi.{KyuubiFunSuite, Utils}
trait WithLdapServer extends KyuubiFunSuite {
protected var ldapServer: InMemoryDirectoryServer = _
- protected val ldapBaseDn = "ou=users"
+ protected val ldapBaseDn = "dc=example,dc=com"
protected val ldapUser = Utils.currentUser
protected val ldapUserPasswd = "ldapPassword"
+ protected val ldapBinddn = "uid=admin,cn=Directory Manager,ou=users,dc=example,dc=com"
+ protected val ldapBindpw = "adminPassword"
+ protected val ldapBaseUserDn = "ou=users,dc=example,dc=com"
+ protected val ldapDomain = "example"
+ protected val ldapAttrs = Seq("mail")
protected def ldapUrl = s"ldap://localhost:${ldapServer.getListenPort}"
override def beforeAll(): Unit = {
val config = new InMemoryDirectoryServerConfig(ldapBaseDn)
- config.addAdditionalBindCredentials(s"uid=$ldapUser,ou=users", ldapUserPasswd)
+ config.addAdditionalBindCredentials(ldapBinddn, ldapBindpw)
ldapServer = new InMemoryDirectoryServer(config)
ldapServer.startListening()
+ addLdapUser(ldapServer, ldapBaseDn, ldapBaseUserDn, ldapDomain, ldapUser, ldapUserPasswd)
super.beforeAll()
}
@@ -41,4 +47,47 @@ trait WithLdapServer extends KyuubiFunSuite {
ldapServer.close()
super.afterAll()
}
+
+ def addLdapUser(
+ ldapServer: InMemoryDirectoryServer,
+ ldapBaseDn: String,
+ ldapBaseUserDn: String,
+ ldapDomain: String,
+ ldapUser: String,
+ ldapUserPasswd: String): Unit = {
+ ldapServer.add(
+ s"dn: $ldapBaseDn",
+ "objectClass: domain",
+ "objectClass: top",
+ "dc: example")
+ ldapServer.add(
+ s"dn: $ldapBaseUserDn",
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: users")
+ ldapServer.add(
+ s"dn: cn=$ldapUser,$ldapBaseUserDn",
+ s"cn: $ldapUser",
+ s"sn: $ldapUser",
+ s"userPassword: $ldapUserPasswd",
+ "objectClass: person")
+ ldapServer.add(
+ s"dn: uid=$ldapUser,cn=$ldapUser,$ldapBaseUserDn",
+ s"uid: $ldapUser",
+ s"mail: $ldapUser@$ldapDomain",
+ s"cn: $ldapUser",
+ s"sn: $ldapUser",
+ s"userPassword: $ldapUserPasswd",
+ "objectClass: person",
+ "objectClass: inetOrgPerson")
+ ldapServer.add(
+ s"dn: uid=$ldapUser,$ldapBaseDn",
+ s"uid: $ldapUser",
+ s"mail: $ldapUser@$ldapDomain",
+ s"cn: $ldapUser",
+ s"sn: $ldapUser",
+ s"userPassword: $ldapUserPasswd",
+ "objectClass: person",
+ "objectClass: inetOrgPerson")
+ }
}
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala
index d15993797..f6c3c22f5 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/RestClientTestHelper.scala
@@ -56,6 +56,10 @@ trait RestClientTestHelper extends RestFrontendTestHelper with KerberizedTestHel
.set(
KyuubiConf.AUTHENTICATION_CUSTOM_CLASS,
classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_BINDDN, ldapBinddn)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_PASSWORD, ldapBindpw)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_DOMAIN, ldapDomain)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_ATTRIBUTES, ldapAttrs)
}
}
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiOperationKerberosAndPlainAuthSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiOperationKerberosAndPlainAuthSuite.scala
index 4e9c5dd78..4bcf09c5c 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiOperationKerberosAndPlainAuthSuite.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/KyuubiOperationKerberosAndPlainAuthSuite.scala
@@ -67,6 +67,10 @@ class KyuubiOperationKerberosAndPlainAuthSuite extends WithKyuubiServer with Ker
.set(
KyuubiConf.AUTHENTICATION_CUSTOM_CLASS,
classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_BINDDN, ldapBinddn)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_PASSWORD, ldapBindpw)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_DOMAIN, ldapDomain)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_ATTRIBUTES, ldapAttrs)
}
test("test with KERBEROS TGT cache authentication") {
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/thrift/http/KyuubiOperationThriftHttpKerberosAndPlainAuthSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/thrift/http/KyuubiOperationThriftHttpKerberosAndPlainAuthSuite.scala
index e0f32e843..ec9dc4070 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/thrift/http/KyuubiOperationThriftHttpKerberosAndPlainAuthSuite.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/operation/thrift/http/KyuubiOperationThriftHttpKerberosAndPlainAuthSuite.scala
@@ -56,6 +56,10 @@ class KyuubiOperationThriftHttpKerberosAndPlainAuthSuite
classOf[UserDefineAuthenticationProviderImpl].getCanonicalName)
.set(KyuubiConf.SERVER_SPNEGO_KEYTAB, testKeytab)
.set(KyuubiConf.SERVER_SPNEGO_PRINCIPAL, testSpnegoPrincipal)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_BINDDN, ldapBinddn)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_PASSWORD, ldapBindpw)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_DOMAIN, ldapDomain)
+ .set(KyuubiConf.AUTHENTICATION_LDAP_ATTRIBUTES, ldapAttrs)
}
override protected def getJdbcUrl: String =
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/BatchRestApiSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/BatchRestApiSuite.scala
index d144d61be..4148223ea 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/BatchRestApiSuite.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/rest/client/BatchRestApiSuite.scala
@@ -80,7 +80,7 @@ class BatchRestApiSuite extends RestClientTestHelper with BatchTestHelper {
// get batch by id
batchRestApi.getBatchById("1")
}
- assert(e.getCause.toString.contains(s"Error validating LDAP user: uid=${customUser}"))
+ assert(e.getCause.toString.contains(s"Error validating LDAP user: ${customUser}"))
basicKyuubiRestClient.close()