@@ -41,10 +41,19 @@ import org.apache.spark.deploy.SparkHadoopUtil
4141 * secure the UI if it has data that other users should not be allowed to see. The javax
4242 * servlet filter specified by the user can authenticate the user and then once the user
4343 * is logged in, Spark can compare that user versus the view acls to make sure they are
44- * authorized to view the UI. The configs 'spark.ui. acls.enable' and 'spark.ui.view.acls'
44+ * authorized to view the UI. The configs 'spark.acls.enable' and 'spark.ui.view.acls'
4545 * control the behavior of the acls. Note that the person who started the application
4646 * always has view access to the UI.
4747 *
48+ * Spark has a set of modify acls (`spark.modify.acls`) that controls which users have permission
49+ * to modify a single application. This would include things like killing the application. By
50+ * default the person who started the application has modify access. For modify access through
51+ * the UI, you must have a filter that does authentication in place for the modify acls to work
52+ * properly.
53+ *
54+ * Spark also has a set of admin acls (`spark.admin.acls`) which is a set of users/administrators
55+ * who always have permission to view or modify the Spark application.
56+ *
4857 * Spark does not currently support encryption after authentication.
4958 *
5059 * At this point spark has multiple communication protocols that need to be secured and
@@ -137,18 +146,32 @@ private[spark] class SecurityManager(sparkConf: SparkConf) extends Logging {
137146 private val sparkSecretLookupKey = " sparkCookie"
138147
139148 private val authOn = sparkConf.getBoolean(" spark.authenticate" , false )
140- private var uiAclsOn = sparkConf.getBoolean(" spark.ui.acls.enable" , false )
149+ // keep spark.ui.acls.enable for backwards compatibility with 1.0
150+ private var aclsOn = sparkConf.getOption(" spark.acls.enable" ).getOrElse(
151+ sparkConf.get(" spark.ui.acls.enable" , " false" )).toBoolean
152+
153+ // admin acls should be set before view or modify acls
154+ private var adminAcls : Set [String ] =
155+ stringToSet(sparkConf.get(" spark.admin.acls" , " " ))
141156
142157 private var viewAcls : Set [String ] = _
158+
159+ // list of users who have permission to modify the application. This should
160+ // apply to both UI and CLI for things like killing the application.
161+ private var modifyAcls : Set [String ] = _
162+
143163 // always add the current user and SPARK_USER to the viewAcls
144- private val defaultAclUsers = Seq [String ](System .getProperty(" user.name" , " " ),
164+ private val defaultAclUsers = Set [String ](System .getProperty(" user.name" , " " ),
145165 Option (System .getenv(" SPARK_USER" )).getOrElse(" " ))
166+
146167 setViewAcls(defaultAclUsers, sparkConf.get(" spark.ui.view.acls" , " " ))
168+ setModifyAcls(defaultAclUsers, sparkConf.get(" spark.modify.acls" , " " ))
147169
148170 private val secretKey = generateSecretKey()
149171 logInfo(" SecurityManager: authentication " + (if (authOn) " enabled" else " disabled" ) +
150- " ; ui acls " + (if (uiAclsOn) " enabled" else " disabled" ) +
151- " ; users with view permissions: " + viewAcls.toString())
172+ " ; ui acls " + (if (aclsOn) " enabled" else " disabled" ) +
173+ " ; users with view permissions: " + viewAcls.toString() +
174+ " ; users with modify permissions: " + modifyAcls.toString())
152175
153176 // Set our own authenticator to properly negotiate user/password for HTTP connections.
154177 // This is needed by the HTTP client fetching from the HttpServer. Put here so its
@@ -169,18 +192,51 @@ private[spark] class SecurityManager(sparkConf: SparkConf) extends Logging {
169192 )
170193 }
171194
172- private [spark] def setViewAcls (defaultUsers : Seq [String ], allowedUsers : String ) {
173- viewAcls = (defaultUsers ++ allowedUsers.split(',' )).map(_.trim()).filter(! _.isEmpty).toSet
195+ /**
196+ * Split a comma separated String, filter out any empty items, and return a Set of strings
197+ */
198+ private def stringToSet (list : String ): Set [String ] = {
199+ list.split(',' ).map(_.trim).filter(! _.isEmpty).toSet
200+ }
201+
202+ /**
203+ * Admin acls should be set before the view or modify acls. If you modify the admin
204+ * acls you should also set the view and modify acls again to pick up the changes.
205+ */
206+ def setViewAcls (defaultUsers : Set [String ], allowedUsers : String ) {
207+ viewAcls = (adminAcls ++ defaultUsers ++ stringToSet(allowedUsers))
174208 logInfo(" Changing view acls to: " + viewAcls.mkString(" ," ))
175209 }
176210
177- private [spark] def setViewAcls (defaultUser : String , allowedUsers : String ) {
178- setViewAcls(Seq [String ](defaultUser), allowedUsers)
211+ def setViewAcls (defaultUser : String , allowedUsers : String ) {
212+ setViewAcls(Set [String ](defaultUser), allowedUsers)
213+ }
214+
215+ def getViewAcls : String = viewAcls.mkString(" ," )
216+
217+ /**
218+ * Admin acls should be set before the view or modify acls. If you modify the admin
219+ * acls you should also set the view and modify acls again to pick up the changes.
220+ */
221+ def setModifyAcls (defaultUsers : Set [String ], allowedUsers : String ) {
222+ modifyAcls = (adminAcls ++ defaultUsers ++ stringToSet(allowedUsers))
223+ logInfo(" Changing modify acls to: " + modifyAcls.mkString(" ," ))
224+ }
225+
226+ def getModifyAcls : String = modifyAcls.mkString(" ," )
227+
228+ /**
229+ * Admin acls should be set before the view or modify acls. If you modify the admin
230+ * acls you should also set the view and modify acls again to pick up the changes.
231+ */
232+ def setAdminAcls (adminUsers : String ) {
233+ adminAcls = stringToSet(adminUsers)
234+ logInfo(" Changing admin acls to: " + adminAcls.mkString(" ," ))
179235 }
180236
181- private [spark] def setUIAcls (aclSetting : Boolean ) {
182- uiAclsOn = aclSetting
183- logInfo(" Changing acls enabled to: " + uiAclsOn )
237+ def setAcls (aclSetting : Boolean ) {
238+ aclsOn = aclSetting
239+ logInfo(" Changing acls enabled to: " + aclsOn )
184240 }
185241
186242 /**
@@ -224,22 +280,39 @@ private[spark] class SecurityManager(sparkConf: SparkConf) extends Logging {
224280 * Check to see if Acls for the UI are enabled
225281 * @return true if UI authentication is enabled, otherwise false
226282 */
227- def uiAclsEnabled (): Boolean = uiAclsOn
283+ def aclsEnabled (): Boolean = aclsOn
228284
229285 /**
230286 * Checks the given user against the view acl list to see if they have
231- * authorization to view the UI. If the UI acls must are disabled
232- * via spark.ui.acls.enable, all users have view access.
287+ * authorization to view the UI. If the UI acls are disabled
288+ * via spark.acls.enable, all users have view access. If the user is null
289+ * it is assumed authentication is off and all users have access.
233290 *
234291 * @param user to see if is authorized
235292 * @return true is the user has permission, otherwise false
236293 */
237294 def checkUIViewPermissions (user : String ): Boolean = {
238- logDebug(" user=" + user + " uiAclsEnabled =" + uiAclsEnabled () + " viewAcls=" +
295+ logDebug(" user=" + user + " aclsEnabled =" + aclsEnabled () + " viewAcls=" +
239296 viewAcls.mkString(" ," ))
240- if (uiAclsEnabled () && (user != null ) && (! viewAcls.contains(user))) false else true
297+ if (aclsEnabled () && (user != null ) && (! viewAcls.contains(user))) false else true
241298 }
242299
300+ /**
301+ * Checks the given user against the modify acl list to see if they have
302+ * authorization to modify the application. If the UI acls are disabled
303+ * via spark.acls.enable, all users have modify access. If the user is null
304+ * it is assumed authentication isn't turned on and all users have access.
305+ *
306+ * @param user to see if is authorized
307+ * @return true is the user has permission, otherwise false
308+ */
309+ def checkModifyPermissions (user : String ): Boolean = {
310+ logDebug(" user=" + user + " aclsEnabled=" + aclsEnabled() + " modifyAcls=" +
311+ modifyAcls.mkString(" ," ))
312+ if (aclsEnabled() && (user != null ) && (! modifyAcls.contains(user))) false else true
313+ }
314+
315+
243316 /**
244317 * Check to see if authentication for the Spark communication protocols is enabled
245318 * @return true if authentication is enabled, otherwise false
0 commit comments