@@ -35,10 +35,11 @@ import org.scalatest.BeforeAndAfter
3535import org .scalatest .Matchers
3636import org .scalatest .concurrent .Eventually ._
3737
38- import org .apache .spark .{SparkConf , SparkFunSuite }
38+ import org .apache .spark .{SecurityManager , SparkConf , SparkFunSuite }
3939import org .apache .spark .internal .Logging
4040import org .apache .spark .io ._
4141import org .apache .spark .scheduler ._
42+ import org .apache .spark .security .GroupMappingServiceProvider
4243import org .apache .spark .util .{Clock , JsonProtocol , ManualClock , Utils }
4344
4445class FsHistoryProviderSuite extends SparkFunSuite with BeforeAndAfter with Matchers with Logging {
@@ -474,6 +475,102 @@ class FsHistoryProviderSuite extends SparkFunSuite with BeforeAndAfter with Matc
474475 }
475476 }
476477
478+ test(" support history server ui admin acls" ) {
479+ def createAndCheck (conf : SparkConf , properties : (String , String )* )
480+ (checkFn : SecurityManager => Unit ): Unit = {
481+ // Empty the testDir for each test.
482+ if (testDir.exists() && testDir.isDirectory) {
483+ testDir.listFiles().foreach { f => if (f.isFile) f.delete() }
484+ }
485+
486+ var provider : FsHistoryProvider = null
487+ try {
488+ provider = new FsHistoryProvider (conf)
489+ val log = newLogFile(" app1" , Some (" attempt1" ), inProgress = false )
490+ writeFile(log, true , None ,
491+ SparkListenerApplicationStart (" app1" , Some (" app1" ), System .currentTimeMillis(),
492+ " test" , Some (" attempt1" )),
493+ SparkListenerEnvironmentUpdate (Map (
494+ " Spark Properties" -> properties.toSeq,
495+ " JVM Information" -> Seq .empty,
496+ " System Properties" -> Seq .empty,
497+ " Classpath Entries" -> Seq .empty
498+ )),
499+ SparkListenerApplicationEnd (System .currentTimeMillis()))
500+
501+ provider.checkForLogs()
502+ val appUi = provider.getAppUI(" app1" , Some (" attempt1" ))
503+
504+ assert(appUi.nonEmpty)
505+ val securityManager = appUi.get.ui.securityManager
506+ checkFn(securityManager)
507+ } finally {
508+ if (provider != null ) {
509+ provider.stop()
510+ }
511+ }
512+ }
513+
514+ // Test both history ui admin acls and application acls are configured.
515+ val conf1 = createTestConf()
516+ .set(" spark.history.ui.acls.enable" , " true" )
517+ .set(" spark.history.ui.admin.acls" , " user1,user2" )
518+ .set(" spark.history.ui.admin.acls.groups" , " group1" )
519+ .set(" spark.user.groups.mapping" , classOf [TestGroupsMappingProvider ].getName)
520+
521+ createAndCheck(conf1, (" spark.admin.acls" , " user" ), (" spark.admin.acls.groups" , " group" )) {
522+ securityManager =>
523+ // Test whether user has permission to access UI.
524+ securityManager.checkUIViewPermissions(" user1" ) should be (true )
525+ securityManager.checkUIViewPermissions(" user2" ) should be (true )
526+ securityManager.checkUIViewPermissions(" user" ) should be (true )
527+ securityManager.checkUIViewPermissions(" abc" ) should be (false )
528+
529+ // Test whether user with admin group has permission to access UI.
530+ securityManager.checkUIViewPermissions(" user3" ) should be (true )
531+ securityManager.checkUIViewPermissions(" user4" ) should be (true )
532+ securityManager.checkUIViewPermissions(" user5" ) should be (true )
533+ securityManager.checkUIViewPermissions(" user6" ) should be (false )
534+ }
535+
536+ // Test only history ui admin acls are configured.
537+ val conf2 = createTestConf()
538+ .set(" spark.history.ui.acls.enable" , " true" )
539+ .set(" spark.history.ui.admin.acls" , " user1,user2" )
540+ .set(" spark.history.ui.admin.acls.groups" , " group1" )
541+ .set(" spark.user.groups.mapping" , classOf [TestGroupsMappingProvider ].getName)
542+ createAndCheck(conf2) { securityManager =>
543+ // Test whether user has permission to access UI.
544+ securityManager.checkUIViewPermissions(" user1" ) should be (true )
545+ securityManager.checkUIViewPermissions(" user2" ) should be (true )
546+ // Check the unknown "user" should return false
547+ securityManager.checkUIViewPermissions(" user" ) should be (false )
548+
549+ // Test whether user with admin group has permission to access UI.
550+ securityManager.checkUIViewPermissions(" user3" ) should be (true )
551+ securityManager.checkUIViewPermissions(" user4" ) should be (true )
552+ // Check the "user5" without mapping relation should return false
553+ securityManager.checkUIViewPermissions(" user5" ) should be (false )
554+ }
555+
556+ // Test neither history ui admin acls nor application acls are configured.
557+ val conf3 = createTestConf()
558+ .set(" spark.history.ui.acls.enable" , " true" )
559+ .set(" spark.user.groups.mapping" , classOf [TestGroupsMappingProvider ].getName)
560+ createAndCheck(conf3) { securityManager =>
561+ // Test whether user has permission to access UI.
562+ securityManager.checkUIViewPermissions(" user1" ) should be (false )
563+ securityManager.checkUIViewPermissions(" user2" ) should be (false )
564+ securityManager.checkUIViewPermissions(" user" ) should be (false )
565+
566+ // Test whether user with admin group has permission to access UI.
567+ // Check should be failed since we don't have acl group settings.
568+ securityManager.checkUIViewPermissions(" user3" ) should be (false )
569+ securityManager.checkUIViewPermissions(" user4" ) should be (false )
570+ securityManager.checkUIViewPermissions(" user5" ) should be (false )
571+ }
572+ }
573+
477574 /**
478575 * Asks the provider to check for logs and calls a function to perform checks on the updated
479576 * app list. Example:
@@ -532,3 +629,15 @@ class FsHistoryProviderSuite extends SparkFunSuite with BeforeAndAfter with Matc
532629 }
533630
534631}
632+
633+ class TestGroupsMappingProvider extends GroupMappingServiceProvider {
634+ private val mappings = Map (
635+ " user3" -> " group1" ,
636+ " user4" -> " group1" ,
637+ " user5" -> " group" )
638+
639+ override def getGroups (username : String ): Set [String ] = {
640+ mappings.get(username).map(Set (_)).getOrElse(Set .empty)
641+ }
642+ }
643+
0 commit comments