You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@kyuubi.apache.org by GitBox <gi...@apache.org> on 2022/08/20 08:34:53 UTC
[GitHub] [incubator-kyuubi] bowenliang123 commented on a diff in pull request #3278: [KYUUBI #3222][FOLLOWUP] Introdude JdbcUtils to simplify code
bowenliang123 commented on code in PR #3278:
URL: https://github.com/apache/incubator-kyuubi/pull/3278#discussion_r950058901
##########
kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/JdbcAuthenticationProviderImpl.scala:
##########
@@ -101,104 +106,31 @@ class JdbcAuthenticationProviderImpl(conf: KyuubiConf) extends PasswdAuthenticat
debug(configLog("Driver Class", driverClass.orNull))
debug(configLog("JDBC URL", jdbcUrl.orNull))
- debug(configLog("Database username", jdbcUsername.orNull))
- debug(configLog("Database password length", jdbcUserPassword.getOrElse("").length.toString))
- debug(configLog("Query SQL", authQuerySql.orNull))
+ debug(configLog("Database username", username.orNull))
+ debug(configLog("Database password", redactedPasswd))
+ debug(configLog("Query SQL", authQuery.orNull))
// Check if JDBC parameters valid
- if (driverClass.isEmpty) {
- throw new IllegalArgumentException("JDBC driver class is not configured.")
- }
-
- if (jdbcUrl.isEmpty) {
- throw new IllegalArgumentException("JDBC url is not configured")
- }
-
- if (jdbcUsername.isEmpty || jdbcUserPassword.isEmpty) {
- throw new IllegalArgumentException("JDBC username or password is not configured")
+ require(driverClass.nonEmpty, "JDBC driver class is not configured.")
+ require(jdbcUrl.nonEmpty, "JDBC url is not configured.")
+ require(username.nonEmpty, "JDBC username is not configured")
+ // allow empty password
+ require(authQuery.nonEmpty, "Query SQL is not configured")
+
+ val query = authQuery.get.trim.toLowerCase
+ // allow simple select query sql only, complex query like CTE is not allowed
+ require(query.startsWith("select"), "Query SQL must start with 'SELECT'")
+ if (!query.contains("where")) {
+ warn("Query SQL does not contains 'WHERE' keyword")
}
-
- // Check Query SQL
- if (authQuerySql.isEmpty) {
- throw new IllegalArgumentException("Query SQL is not configured")
- }
- val querySqlInLowerCase = authQuerySql.get.trim.toLowerCase
- if (!querySqlInLowerCase.startsWith("select")) { // allow select query sql only
- throw new IllegalArgumentException("Query SQL must start with \"SELECT\"");
- }
- if (!querySqlInLowerCase.contains("where")) {
- warn("Query SQL does not contains \"WHERE\" keyword");
- }
- if (!querySqlInLowerCase.contains("${username}")) {
- warn("Query SQL does not contains \"${username}\" placeholder");
- }
- }
-
- private def getPlaceholderList(sql: String): List[String] = {
- SQL_PLACEHOLDER_REGEX.findAllMatchIn(sql)
- .map(m => m.matched)
- .toList
- }
-
- private def getAndPrepareQueryStatement(
- connection: Connection,
- user: String,
- password: String): PreparedStatement = {
-
- val preparedSql: String = {
- SQL_PLACEHOLDER_REGEX.replaceAllIn(authQuerySql.get, "?")
- }
- debug(s"prepared auth query sql: $preparedSql")
-
- val stmt = connection.prepareStatement(preparedSql)
- stmt.setMaxRows(1) // minimum result size required for authentication
-
- // Extract placeholder list and fill parameters to placeholders
- val placeholderList: List[String] = getPlaceholderList(authQuerySql.get)
- for (i <- placeholderList.indices) {
- val param = placeholderList(i) match {
- case USERNAME_SQL_PLACEHOLDER => user
- case PASSWORD_SQL_PLACEHOLDER => password
- case otherPlaceholder =>
- throw new IllegalArgumentException(
- s"Unrecognized Placeholder In Query SQL: $otherPlaceholder")
- }
-
- stmt.setString(i + 1, param)
- }
-
- stmt
- }
-
- private def closeDbConnection(connection: Connection, statement: Statement): Unit = {
- if (statement != null && !statement.isClosed) {
- try {
- statement.close()
- } catch {
- case e: Exception =>
- error("Cannot close PreparedStatement to auth database ", e)
- }
- }
-
- if (connection != null && !connection.isClosed) {
- try {
- connection.close()
- } catch {
- case e: Exception =>
- error("Cannot close connection to auth database ", e)
- }
+ if (!query.contains("${username}")) {
+ warn("Query SQL does not contains '${username}' placeholder")
}
Review Comment:
```suggestion
}
if (!query.contains("${password}")) {
warn("Query SQL does not contains '${password}' placeholder")
}
```
How about adding check for ${password} placeholder here, as auth method checked password not blank in first place? @pan3793
##########
kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/JdbcAuthenticationProviderImplSuite.scala:
##########
@@ -17,51 +17,55 @@
package org.apache.kyuubi.service.authentication
-import java.sql.{Connection, DriverManager}
+import java.sql.DriverManager
import java.util.Properties
import javax.security.sasl.AuthenticationException
+import javax.sql.DataSource
-import org.apache.kyuubi.KyuubiFunSuite
+import com.zaxxer.hikari.util.DriverDataSource
+
+import org.apache.kyuubi.{KyuubiFunSuite, Utils}
import org.apache.kyuubi.config.KyuubiConf
import org.apache.kyuubi.config.KyuubiConf._
+import org.apache.kyuubi.util.JdbcUtils
class JdbcAuthenticationProviderImplSuite extends KyuubiFunSuite {
protected val dbUser: String = "liangbowen"
protected val dbPasswd: String = "liangbowen"
- protected var jdbcUrl: String = _
+ protected val authDbName: String = "auth_db"
+ protected val jdbcUrl: String = s"jdbc:derby:memory:$authDbName;create=true"
Review Comment:
```suggestion
protected val dbUrl: String = s"jdbc:derby:memory:$authDbName"
protected val jdbcUrl: String = s"$dbUrl;create=true"
```
##########
kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/JdbcAuthenticationProviderImpl.scala:
##########
@@ -62,37 +77,27 @@ class JdbcAuthenticationProviderImpl(conf: KyuubiConf) extends PasswdAuthenticat
s" or contains blank space")
}
- if (StringUtils.isBlank(password)) {
- throw new AuthenticationException(s"Error validating, password is null" +
- s" or contains blank space")
- }
-
- var connection: Connection = null
- var queryStatement: PreparedStatement = null
-
try {
- connection = hikariDataSource.getConnection
-
- queryStatement = getAndPrepareQueryStatement(connection, user, password)
-
- val resultSet = queryStatement.executeQuery()
-
- if (resultSet == null || !resultSet.next()) {
- // auth failed
- throw new AuthenticationException(s"Password does not match or no such user. user:" +
- s" $user , password length: ${password.length}")
+ debug(s"prepared auth query: $preparedQuery")
+ JdbcUtils.executeQuery(preparedQuery) { stmt =>
Review Comment:
shall we a add a query time out for `JdbcUtils.executeQuery` to prevent blocking out of connection timeout ?
##########
kyuubi-common/src/test/scala/org/apache/kyuubi/util/JdbcUtilsSuite.scala:
##########
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kyuubi.util
+
+import java.sql.DriverManager
+import java.util.Properties
+import javax.sql.DataSource
+
+import com.zaxxer.hikari.util.DriverDataSource
+
+import org.apache.kyuubi.KyuubiFunSuite
+
+class JdbcUtilsSuite extends KyuubiFunSuite {
+
+ private val connUrl = s"jdbc:derby:memory:jdbc_utils_test;create=true"
+ private val shutdownUrl = s"jdbc:derby:memory:jdbc_utils_test;shutdown=true"
Review Comment:
```suggestion
private val dbUrl = s"jdbc:derby:memory:jdbc_utils_test"
private val connUrl = s"$dbUrl;create=true"
private val shutdownUrl = s"$dbUrl;shutdown=true"
```
##########
kyuubi-common/src/test/scala/org/apache/kyuubi/service/authentication/JdbcAuthenticationProviderImplSuite.scala:
##########
@@ -70,16 +74,12 @@ class JdbcAuthenticationProviderImplSuite extends KyuubiFunSuite {
super.afterAll()
// cleanup db
- try {
+ Utils.tryLogNonFatalError {
DriverManager.getConnection(s"jdbc:derby:memory:$authDbName;shutdown=true")
Review Comment:
```suggestion
DriverManager.getConnection(s"$dbUrl;shutdown=true")
```
##########
kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/JdbcAuthenticationProviderImpl.scala:
##########
@@ -62,37 +77,27 @@ class JdbcAuthenticationProviderImpl(conf: KyuubiConf) extends PasswdAuthenticat
s" or contains blank space")
}
- if (StringUtils.isBlank(password)) {
Review Comment:
Shall we bring back password not blank checking? If auth method allow passing with missing password, the whole authentication relies on the confidentiality of username alone. @pan3793
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@kyuubi.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@kyuubi.apache.org
For additional commands, e-mail: notifications-help@kyuubi.apache.org