[KYUUBI-167][FOLLOWUP]populate tokens via spark session cache mgr (#183)

* Prepare releasing v0.6.0

* fix #KYUUBI-167 populate token via spark session cache mgr

* typo

* fix ut

* code cov
diff --git a/.travis.yml b/.travis.yml
index 94a2b44..7d18afe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,18 +28,18 @@
 
 jobs:
   include:
-    - stage: spark2.4
-      language: scala
-      script: ./build/mvn clean install -Pspark-2.4 -Dmaven.javadoc.skip=true -B -V
-    - stage: spark2.3
-      language: scala
-      script: ./build/mvn clean install -Pspark-2.3 -Dmaven.javadoc.skip=true -B -V
-    - stage: spark2.2
-      language: scala
-      script: ./build/mvn clean install -Pspark-2.2 -Dmaven.javadoc.skip=true -B -V
     - stage: spark2.1
       language: scala
       script: ./build/mvn clean install -Pspark-2.1 -Dmaven.javadoc.skip=true -B -V
+    - stage: spark2.2
+      language: scala
+      script: ./build/mvn clean install -Pspark-2.2 -Dmaven.javadoc.skip=true -B -V
+    - stage: spark2.3
+      language: scala
+      script: ./build/mvn clean install -Pspark-2.3 -Dmaven.javadoc.skip=true -B -V
+    - stage: spark2.4
+      language: scala
+      script: ./build/mvn clean install -Pspark-2.4 -Dmaven.javadoc.skip=true -B -V
 
 after_success:
   - bash <(curl -s https://codecov.io/bash)
diff --git a/docs/configurations.md b/docs/configurations.md
index 8466b56..9a30f89 100644
--- a/docs/configurations.md
+++ b/docs/configurations.md
@@ -89,7 +89,6 @@
 spark.kyuubi.<br />backend.session.local.dir|KYUUBI_HOME/<br />local|Default value to set `spark.local.dir`. For YARN mode, this only affect the Kyuubi server side settings according to the rule of Spark treating `spark.local.dir`.
 spark.kyuubi.<br />backend.session.long.cache|${UserGroupInformation.<br />isSecurityEnabled}|Whether to update the tokens of Spark's executor to support long caching SparkSessions iff this is true && `spark.kyuubi.backend.token.update.class` is loadable. This is used towards kerberized hadoop clusters in case of `spark.kyuubi.backend.session.idle.timeout` is set longer than token expiration time limit or SparkSession never idles.
 spark.kyuubi.<br />backend.session.token.update.class|org.apache.spark.<br />scheduler.cluster.<br />CoarseGrainedClusterMessages$<br />UpdateDelegationTokens|`CoarseGrainedClusterMessages` for token update message from the driver of Spark to executors, it is loadable only by higher version Spark release(2.3 and later)
-spark.kyuubi.<br />backend.session.token.renew.interval|2h|Interval for KyuubiServiceCredentialProvider to update tokens ,which is a ServiceCredentialProvider implementation of Apache Spark
 
 #### Operation
 
diff --git a/kyuubi-security/src/main/resources/META-INF/services/org.apache.spark.deploy.yarn.security.ServiceCredentialProvider b/kyuubi-security/src/main/resources/META-INF/services/org.apache.spark.deploy.yarn.security.ServiceCredentialProvider
deleted file mode 100644
index f4f0814..0000000
--- a/kyuubi-security/src/main/resources/META-INF/services/org.apache.spark.deploy.yarn.security.ServiceCredentialProvider
+++ /dev/null
@@ -1 +0,0 @@
-yaooqinn.kyuubi.KyuubiServiceCredentialProvider
\ No newline at end of file
diff --git a/kyuubi-security/src/main/scala/yaooqinn/kyuubi/KyuubiServiceCredentialProvider.scala b/kyuubi-security/src/main/scala/yaooqinn/kyuubi/KyuubiServiceCredentialProvider.scala
deleted file mode 100644
index e48d761..0000000
--- a/kyuubi-security/src/main/scala/yaooqinn/kyuubi/KyuubiServiceCredentialProvider.scala
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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 yaooqinn.kyuubi
-
-import org.apache.hadoop.conf.Configuration
-import org.apache.hadoop.fs.{FileSystem, Path}
-import org.apache.hadoop.mapred.Master
-import org.apache.hadoop.security.{Credentials, UserGroupInformation}
-import org.apache.spark.SparkConf
-import org.apache.spark.deploy.yarn.security.ServiceCredentialProvider
-
-/**
- * An implementation of [[ServiceCredentialProvider]] of Apache Spark, this class will be called
- * in both Kyuubi Server and the ApplicationMasters. Main purpose here is updating the
- * ApplicationMaster's delegation tokens and does not care whether the tokens to be written to HDFS
- * for other executors to do their token update job or not. The reason why we do such thing here is
- * that this part of Spark source code is totally a mess and changed capriciously before the Spark
- * 3.x which is not release yet. So if tokens are written to HDFS, the driver(here as same as Kyuubi
- * Server instance) and executor can update their token purposely. But if they are failed, with some
- * warning messages ApplicationMaster will schedule this task in every hour which would be helpful
- * enough to invoke this class which help us to renew the ApplicationMaster 's delegation tokens.
- * Another un-harmful problem the driver and executors will continuously run token update task in
- * every minute, which is always annoyingly printing 'CredentialUpdater: Scheduling credentials
- * refresh from HDFS in 60000 ms' to logs. Kyuubi will post all delegation tokens to executor side
- * by the server itself but not to the ApplicationMaster, so the ApplicationMaster must update
- * tokens by itself in case of requesting new executors in runtime.
- *
- *
- * In Kyuubi Server:
- *    This is called when SparkContext instantiating itself, with `spark.yarn.credentials.file`,
- *    `spark.yarn.credentials.renewalTime`, `spark.yarn.credentials.updateTime` set. Because
- *    inside Kyuubi we explicitly turn off Other credential providers of Spark, so the renew time
- *    and the update time is decided by [[KyuubiServiceCredentialProvider#obtainCredentials]], a
- *    credentials file will be set to `spark.yarn.credentials.file` but not be created yet. If the
- *    Spark Driver(here as same as Kyuubi Server instance) itself and the executors detect
- *    `spark.yarn.credentials.file` is set, a credential updater thead will start and periodically
- *    get the latest `spark.yarn.credentials.file` to update their own tokens if the file is
- *    present.
- * In ApplicationMaster:
- *    If the ApplicationMaster detects the `spark.yarn.credentials.file` is set, it will launch a
- *    token renew thread to call all token provider's obtainCredentials method, so the class will be
- *    called to update its own delegation token. So when new containers are requested by this
- *    ApplicationMaster, it will add right tokens to them. Kyuubi Server side will generate tokens
- *    and post the via UpdateToken messages to executors, so unlike it does in a normal Spark
- *    application, here the ApplicationMaster only needs to take care of itself.
- */
-class KyuubiServiceCredentialProvider extends ServiceCredentialProvider with Logging {
-
-  /**
-   * Name of the service to provide credentials. This name should unique, Spark internally will
-   * use this name to differentiate credential provider.
-   */
-  override def serviceName: String = "kyuubi"
-
-  /**
-   * Obtain credentials for this service and get the time of the next renewal.
-   * @param hadoopConf Configuration of current Hadoop Compatible system.
-   * @param sparkConf Spark configuration.
-   * @param creds Credentials to add tokens and security keys to.
-   * @return If this Credential is renewable and can be renewed, return the time of the next
-   *         renewal, otherwise None should be returned.
-   */
-  override def obtainCredentials(hadoopConf: Configuration,
-      sparkConf: SparkConf,
-      creds: Credentials): Option[Long] = {
-    try {
-      val tokenRenewer = renewer(hadoopConf)
-      hadoopFStoAccess(sparkConf, hadoopConf).foreach { fs =>
-        fs.addDelegationTokens(tokenRenewer, creds)
-      }
-      UserGroupInformation.getCurrentUser.addCredentials(creds)
-    } catch {
-      case e: Exception =>
-        throw new RuntimeException("Failed to renew token", e)
-    }
-    val interval = sparkConf.getTimeAsMs("spark.kyuubi.backend.session.token.renew.interval", "2h")
-    info(s"Token updated, next renew interval will be ${interval / 1000} seconds")
-    Some(System.currentTimeMillis() + interval)
-  }
-
-  private def renewer(hadoopConf: Configuration): String = {
-    val tokenRenewer = Master.getMasterPrincipal(hadoopConf)
-    if (tokenRenewer == null || tokenRenewer.length() == 0) {
-      val errorMessage = "Can't get Master Kerberos principal for use as renewer."
-      throw new RuntimeException(errorMessage)
-    }
-    tokenRenewer
-  }
-
-  private def hadoopFStoAccess(conf: SparkConf, hadoopConf: Configuration): Set[FileSystem] = {
-    val fileSystems = conf.getOption("spark.yarn.access.hadoopFileSystems")
-      .orElse(conf.getOption("spark.yarn.access.namenodes")) match {
-      case Some(nns) => nns.split(",").map(new Path(_).getFileSystem(hadoopConf)).toSet
-      case _ => Set.empty[FileSystem]
-    }
-
-    fileSystems +
-      conf.getOption("spark.yarn.stagingDir").map(new Path(_).getFileSystem(hadoopConf))
-        .getOrElse(FileSystem.get(hadoopConf))
-  }
-}
diff --git a/kyuubi-security/src/test/scala/yaooqinn/kyuubi/KyuubiServiceCredentialProviderSuite.scala b/kyuubi-security/src/test/scala/yaooqinn/kyuubi/KyuubiServiceCredentialProviderSuite.scala
deleted file mode 100644
index 7b86981..0000000
--- a/kyuubi-security/src/test/scala/yaooqinn/kyuubi/KyuubiServiceCredentialProviderSuite.scala
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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 yaooqinn.kyuubi
-
-import java.net.InetAddress
-
-import org.apache.hadoop.conf.Configuration
-import org.apache.hadoop.security.{Credentials, UserGroupInformation}
-import org.apache.hadoop.yarn.conf.YarnConfiguration
-import org.apache.spark.{SparkConf, SparkFunSuite}
-import org.apache.spark.deploy.yarn.security.ServiceCredentialProvider
-import org.scalatest.mock.MockitoSugar
-
-class KyuubiServiceCredentialProviderSuite extends SparkFunSuite with MockitoSugar {
-  test("obtain credentials") {
-    val sparkConf = new SparkConf()
-    val userName = UserGroupInformation.getCurrentUser.getShortUserName
-    val hadoopConf = new Configuration()
-    val credential = new Credentials()
-    val provider = new KyuubiServiceCredentialProvider
-    val e1 =
-      intercept[RuntimeException](provider.obtainCredentials(hadoopConf, sparkConf, credential))
-    assert(e1.getMessage === "Failed to renew token")
-    hadoopConf.set(YarnConfiguration.RM_PRINCIPAL, "")
-    val e2 =
-      intercept[RuntimeException](provider.obtainCredentials(hadoopConf, sparkConf, credential))
-    assert(e2.getMessage === "Failed to renew token")
-
-    hadoopConf.set(YarnConfiguration.RM_PRINCIPAL,
-      userName + "/" + InetAddress.getLocalHost.getHostName + "@" + "KYUUBI.ORG")
-    assert(provider.isInstanceOf[ServiceCredentialProvider])
-    assert(provider.isInstanceOf[Logging])
-    assert(!provider.credentialsRequired(hadoopConf))
-    assert(provider.serviceName === "kyuubi")
-    val now = System.currentTimeMillis()
-    val renewalTime = provider.obtainCredentials(hadoopConf, sparkConf, credential)
-    assert(renewalTime.isDefined)
-    assert(renewalTime.get - now >= 2L * 60 * 60 *100 )
-    sparkConf.set("spark.yarn.access.hadoopFileSystems", "hdfs://a/b/c")
-    intercept[Exception](provider.obtainCredentials(hadoopConf, sparkConf, credential))
-    sparkConf.set("spark.yarn.access.namenodes", "hdfs://a/b/c, hdfs://d/e/f")
-    intercept[Exception](provider.obtainCredentials(hadoopConf, sparkConf, credential))
-  }
-}
diff --git a/kyuubi-server/pom.xml b/kyuubi-server/pom.xml
index 23ef316..63f8a97 100644
--- a/kyuubi-server/pom.xml
+++ b/kyuubi-server/pom.xml
@@ -40,12 +40,6 @@
         </dependency>
 
         <dependency>
-            <groupId>yaooqinn</groupId>
-            <artifactId>kyuubi-security</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
             <groupId>${spark.group}</groupId>
             <artifactId>spark-yarn_${scala.binary.version}</artifactId>
         </dependency>
@@ -257,7 +251,6 @@
                     <artifactSet>
                         <includes>
                             <include>yaooqinn:kyuubi-common</include>
-                            <include>yaooqinn:kyuubi-security</include>
                         </includes>
                     </artifactSet>
                 </configuration>
diff --git a/kyuubi-server/src/main/scala/org/apache/spark/KyuubiSparkUtil.scala b/kyuubi-server/src/main/scala/org/apache/spark/KyuubiSparkUtil.scala
index a6ff300..4bbac8e 100644
--- a/kyuubi-server/src/main/scala/org/apache/spark/KyuubiSparkUtil.scala
+++ b/kyuubi-server/src/main/scala/org/apache/spark/KyuubiSparkUtil.scala
@@ -329,22 +329,6 @@
       // ForkJoinPool which points to another calling context. Turn off parallel listing seems
       // to be a solution to this issue.
       conf.setIfMissing(RDD_PAR_LISTING, Int.MaxValue.toString)
-
-      val sparkTokenProviders = List("hdfs", "hadoopfs", "hive", "hbase")
-      val tokenProviderPattens = List(
-        "spark.yarn.security.tokens.%s.enabled",
-        "spark.yarn.security.credentials.%s.enabled",
-        "spark.security.credentials.%s.enabled")
-      // Set kyuubi credential renewer on, if we do not explicitly turn it off.
-      tokenProviderPattens.map(_.format("kyuubi")).foreach(conf.setIfMissing(_, "true"))
-      // Force to turn off Spark's internal token providers, because all useful works will be done
-      // in KyuubiServiceCredentialProvider, and those ones in Spark always have impersonation
-      // issue while renew tokens
-      sparkTokenProviders.foreach  { service =>
-          tokenProviderPattens.map(_.format(service)).foreach {
-            conf.set(_, "false")
-          }
-      }
     }
 
     val kyuubiJar = Option(System.getenv("KYUUBI_JAR")).getOrElse("")
@@ -355,12 +339,6 @@
     }
 
     conf.set(SPARK_YARN_DIST_JARS, distJars)
-    // We should obey our client side hadoop settings while running Kyuubi towards HDFS
-    // federations with maybe only on Yarn cluster
-    // see https://github.com/apache/spark/pull/24120
-    val hadoopConf = newConfiguration(conf)
-    Option(hadoopConf.get("fs.defaultFS"))
-      .foreach(conf.setIfMissing("spark.hadoop.fs.defaultFS", _))
   }
 
   @tailrec
diff --git a/kyuubi-server/src/main/scala/org/apache/spark/scheduler/cluster/KyuubiSparkExecutorUtils.scala b/kyuubi-server/src/main/scala/org/apache/spark/scheduler/cluster/KyuubiSparkExecutorUtils.scala
index a63b0db..b34ad97 100644
--- a/kyuubi-server/src/main/scala/org/apache/spark/scheduler/cluster/KyuubiSparkExecutorUtils.scala
+++ b/kyuubi-server/src/main/scala/org/apache/spark/scheduler/cluster/KyuubiSparkExecutorUtils.scala
@@ -22,7 +22,7 @@
 import scala.collection.mutable
 import scala.util.control.NonFatal
 
-import org.apache.hadoop.security.UserGroupInformation
+import org.apache.hadoop.security.{Credentials, UserGroupInformation}
 import org.apache.spark.KyuubiConf._
 import org.apache.spark.SparkContext
 
@@ -43,13 +43,21 @@
    * @param user the UserGroupInformation associated with the current KyuubiSession
    */
   def populateTokens(sc: SparkContext, user: UserGroupInformation): Unit = {
+    populateTokens(sc, user.getCredentials)
+  }
+
+  /**
+   * Populate the tokens contained in the current KyuubiSession's ugi to the all the alive
+   * executors associated with its own SparkContext.
+   */
+  def populateTokens(sc: SparkContext, creds: Credentials): Unit = {
     val schedulerBackend = sc.schedulerBackend
     schedulerBackend match {
       case backend: CoarseGrainedSchedulerBackend =>
         try {
           val byteStream = new ByteArrayOutputStream
           val dataStream = new DataOutputStream(byteStream)
-          user.getCredentials.writeTokenStorageToStream(dataStream)
+          creds.writeTokenStorageToStream(dataStream)
           val tokens = byteStream.toByteArray
           val executorField =
             classOf[CoarseGrainedSchedulerBackend].getName.replace('.', '$') + "$$executorDataMap"
diff --git a/kyuubi-server/src/main/scala/yaooqinn/kyuubi/session/security/HDFSTokenCollector.scala b/kyuubi-server/src/main/scala/yaooqinn/kyuubi/session/security/HDFSTokenCollector.scala
index a92c52c..6f22ce2 100644
--- a/kyuubi-server/src/main/scala/yaooqinn/kyuubi/session/security/HDFSTokenCollector.scala
+++ b/kyuubi-server/src/main/scala/yaooqinn/kyuubi/session/security/HDFSTokenCollector.scala
@@ -56,7 +56,7 @@
     tokenRenewer
   }
 
-  override def obtainTokens(conf: SparkConf): Unit = {
+  override def obtainTokens(conf: SparkConf): Unit = try {
     val hadoopConf = newConfiguration(conf)
     val tokenRenewer = renewer(hadoopConf)
     val creds = new Credentials()
@@ -64,5 +64,8 @@
       fs.addDelegationTokens(tokenRenewer, creds)
     }
     UserGroupInformation.getCurrentUser.addCredentials(creds)
+  } catch {
+    case e: Exception =>
+      error("Failed to obtain HDFS tokens", e)
   }
 }
diff --git a/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManager.scala b/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManager.scala
index a2d7a48..5b617a6 100644
--- a/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManager.scala
+++ b/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManager.scala
@@ -25,8 +25,10 @@
 import scala.collection.JavaConverters._
 
 import com.google.common.util.concurrent.ThreadFactoryBuilder
+import org.apache.hadoop.security.Credentials
+import org.apache.spark.{KyuubiSparkUtil, SparkConf}
 import org.apache.spark.KyuubiConf._
-import org.apache.spark.SparkConf
+import org.apache.spark.scheduler.cluster.KyuubiSparkExecutorUtils
 import org.apache.spark.sql.SparkSession
 
 import yaooqinn.kyuubi.Logging
@@ -46,24 +48,34 @@
   private val userLatestLogout = new ConcurrentHashMap[String, Long]
   private var idleTimeout: Long = _
 
+  private val userToCredentials = new ConcurrentHashMap[String, Credentials]
+  private var needPopulateToken: Boolean = _
+
   private val sessionCleaner = new Runnable {
     override def run(): Unit = {
       userToSession.asScala.foreach {
         case (user, (session, _)) if session.sparkContext.isStopped =>
-          warn(s"SparkSession for $user might already be stopped by forces outside Kyuubi," +
+          warn(s"SparkSession for $user might already be stopped outside Kyuubi," +
             s" cleaning it..")
           removeSparkSession(user)
-        case (user, (_, times)) if times.get() > 0 =>
+        case (user, (session, times)) if times.get() > 0 || !userLatestLogout.containsKey(user) =>
           debug(s"There are $times active connection(s) bound to the SparkSession instance" +
             s" of $user ")
-        case (user, (_, _)) if !userLatestLogout.containsKey(user) =>
+          if (needPopulateToken) {
+            val credentials = userToCredentials.getOrDefault(user, new Credentials)
+            KyuubiSparkExecutorUtils.populateTokens(session.sparkContext, credentials)
+          }
         case (user, (session, _))
           if userLatestLogout.get(user) + idleTimeout <= System.currentTimeMillis() =>
           info(s"Stopping idle SparkSession for user [$user].")
           removeSparkSession(user)
           session.stop()
           System.setProperty("SPARK_YARN_MODE", "true")
-        case _ =>
+        case (user, (session, _)) =>
+          if (needPopulateToken) {
+            val credentials = userToCredentials.getOrDefault(user, new Credentials)
+            KyuubiSparkExecutorUtils.populateTokens(session.sparkContext, credentials)
+          }
       }
     }
   }
@@ -105,8 +117,14 @@
     }
   }
 
+  def setupCredentials(user: String, creds: Credentials): Unit = {
+    userToCredentials.put(user, creds)
+  }
+
   override def init(conf: SparkConf): Unit = {
     idleTimeout = math.max(conf.getTimeAsMs(BACKEND_SESSION_IDLE_TIMEOUT.key), 60 * 1000)
+    needPopulateToken = conf.get(BACKEND_SESSION_LONG_CACHE).toBoolean &&
+      KyuubiSparkUtil.classIsLoadable(conf.get(BACKEND_SESSION_TOKEN_UPDATE_CLASS))
     super.init(conf)
   }
 
@@ -114,7 +132,6 @@
    * Periodically close idle SparkSessions in 'spark.kyuubi.session.clean.interval(default 1min)'
    */
   override def start(): Unit = {
-    // at least 1 minutes
     val interval = math.max(conf.getTimeAsSeconds(BACKEND_SESSION_CHECK_INTERVAL.key), 1)
     info(s"Scheduling SparkSession cache cleaning every $interval seconds")
     cacheManager.scheduleAtFixedRate(sessionCleaner, interval, interval, TimeUnit.SECONDS)
diff --git a/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionWithUGI.scala b/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionWithUGI.scala
index 1a92c1a..75420e3 100644
--- a/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionWithUGI.scala
+++ b/kyuubi-server/src/main/scala/yaooqinn/kyuubi/spark/SparkSessionWithUGI.scala
@@ -101,6 +101,9 @@
         case _ =>
       }
     }
+    // proxy user does not have rights to get token as real user
+    conf.remove(KEYTAB)
+    conf.remove(PRINCIPAL)
   }
 
   /**
@@ -204,6 +207,8 @@
   def init(sessionConf: Map[String, String]): Unit = {
     getOrCreate(sessionConf)
 
+    cache.setupCredentials(userName, user.getCredentials)
+
     try {
       initialDatabase.foreach { db =>
         KyuubiHadoopUtil.doAs(user) {
diff --git a/kyuubi-server/src/test/scala/yaooqinn/kyuubi/session/security/TokenCollectorSuite.scala b/kyuubi-server/src/test/scala/yaooqinn/kyuubi/session/security/TokenCollectorSuite.scala
index ca77d36..0a0474f 100644
--- a/kyuubi-server/src/test/scala/yaooqinn/kyuubi/session/security/TokenCollectorSuite.scala
+++ b/kyuubi-server/src/test/scala/yaooqinn/kyuubi/session/security/TokenCollectorSuite.scala
@@ -45,7 +45,7 @@
 
     tryWithSecurityEnabled {
 
-      intercept[ServiceException](TokenCollector.obtainTokenIfRequired(conf))
+      TokenCollector.obtainTokenIfRequired(conf)
       conf.set("spark.hadoop.yarn.resourcemanager.principal", "yarn/_HOST@KENT.KYUUBI.COM")
       TokenCollector.obtainTokenIfRequired(conf)
       conf.set("spark.yarn.access.namenodes", "file:///test")
diff --git a/kyuubi-server/src/test/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManagerSuite.scala b/kyuubi-server/src/test/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManagerSuite.scala
index f65250b..b77c21e 100644
--- a/kyuubi-server/src/test/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManagerSuite.scala
+++ b/kyuubi-server/src/test/scala/yaooqinn/kyuubi/spark/SparkSessionCacheManagerSuite.scala
@@ -18,6 +18,7 @@
 package yaooqinn.kyuubi.spark
 
 import org.apache.spark._
+import org.apache.spark.KyuubiConf._
 import org.apache.spark.sql.SparkSession
 import org.mockito.Mockito._
 import org.scalatest.Matchers
@@ -51,6 +52,7 @@
   test("start cache") {
     val cache = new SparkSessionCacheManager()
     val conf = new SparkConf()
+    conf.set(BACKEND_SESSION_LONG_CACHE, "true")
     KyuubiSparkUtil.setupCommonConfig(conf)
     cache.init(conf)
     cache.start()
diff --git a/pom.xml b/pom.xml
index 80c33c6..2ff271c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,6 @@
     <version>0.6.0-SNAPSHOT</version>
     <modules>
         <module>kyuubi-common</module>
-        <module>kyuubi-security</module>
         <module>kyuubi-server</module>
     </modules>
     <packaging>pom</packaging>