app/postrun/UpdateProjectPermissions.scala (86 lines of code) (raw):

package postrun import com.sun.security.auth.UnixNumericGroupPrincipal import helpers.PostrunDataCache import models.{PlutoCommission, PlutoWorkingGroup, ProjectEntry, ProjectType} import play.api.Configuration import java.nio.file.attribute.{GroupPrincipal, PosixFileAttributeView, PosixFilePermission, PosixFilePermissions, UserPrincipal} import java.nio.file.{FileSystem, Files, Path, Paths} import scala.concurrent.Future import scala.util.{Failure, Success, Try} import scala.concurrent.ExecutionContext.Implicits.global import cats.implicits._ import org.slf4j.LoggerFactory import sun.nio.fs.UnixUserPrincipals class UpdateProjectPermissions(config:Configuration) extends PojoPostrun { private val logger = LoggerFactory.getLogger(getClass) /** * obtain a PosixFileAttributeView for the given Path. * Included as a seperate method for test mocking * @param path java.nio.Path representing the file we want attributes for * @return the PosixFileAttributeView, or throws an exception */ def attributeViewFor(path:Path) = Files.getFileAttributeView(path, classOf[PosixFileAttributeView]) /** * set the requested group ID and permissions on the given file * @param projectFilePath file to set permissions on * @param wantedGroup a GroupPrincipal object representing the group to set * @param wantedPerms a java.util.Set of PosixFilePermission representing the permissions to apply * @return a Success with no value on success or a Failure with an exception otherwise */ def setPerms(projectFilePath:Path, wantedGroup:GroupPrincipal, wantedPerms:java.util.Set[PosixFilePermission]) = Try { val attrs = attributeViewFor(projectFilePath) attrs.setGroup(wantedGroup) attrs.setPermissions(wantedPerms) } protected def lookupGroupPrincipal(fileSystem:FileSystem, groupName:String) = Try { val lookup = fileSystem.getUserPrincipalLookupService lookup.lookupPrincipalByGroupName(groupName) } /** * look up the required POSIX group specified in the server configuration * @param fileSystem FileSystem instance representing the Unix filesystem in order to look up unix-style groups * @param config play Configuration * @return a Success with the given GroupPrincipal, or a Failure if either the required key is not set or not found */ def getWantedGroup(fileSystem:FileSystem, config:Configuration) = { config .getOptional[String]("postrun.projectPermissions.groupName") .map(groupName=>lookupGroupPrincipal(fileSystem, groupName)) .sequence .flatMap({ case Some(g)=>Success(g) case None=>Failure( new RuntimeException("You need to specify a valid group name in the application.conf under postrun.projectPermissions.groupName") ) }) } /** * look up the required POSIX permissions speficied in the server configuration * @param config play Configuration * @return a Success with a set of PosixFilePermission, or a Failure if either the required key is not set or mis-formatted */ def getWantedPerms(config:Configuration) = { config.getOptional[String]("postrun.projectPermissions.unixPermissions") .map(permString=>Try { PosixFilePermissions.fromString(permString) }) .sequence .flatMap({ case Some(p)=>Success(p) case None=>Failure( new RuntimeException("You need to specify a valid set of unix permissions (e.g. rw-rw-r--) under postrun.projectPermissions.groupName") ) }) } def checkFileExists(filePath:Path) = Try { filePath.toFile.exists() } override def postrun(projectFileName: String, projectEntry: ProjectEntry, projectType: ProjectType, dataCache: PostrunDataCache, workingGroupMaybe: Option[PlutoWorkingGroup], commissionMaybe: Option[PlutoCommission]): Future[Try[PostrunDataCache]] = Future { val projectFilePath = Paths.get(projectFileName) checkFileExists(projectFilePath) match { case Success(true)=> ( getWantedGroup(projectFilePath.getFileSystem, config), getWantedPerms(config) ) match { case (Success(group), Success(permissions))=> setPerms(projectFilePath, group, permissions).map(_=>dataCache) case (Failure(groupErr), Failure(permsErr))=> logger.error(s"Could not get required group or permissions: ${groupErr.getMessage}; ${permsErr.getMessage}") Failure(new RuntimeException("Group and permissions configuration were incorrect, see logs")) case (Failure(groupErr), _)=> logger.error(s"Could not get required group: ${groupErr.getMessage}") Failure(new RuntimeException("Group configuration was incorrect, see logs")) case (_, Failure(permsErr))=> logger.error(s"Could not get required permissions: ${permsErr.getMessage}") Failure(new RuntimeException("Permissions configuration was incorrect, see logs")) } case Success(false)=> Failure(new RuntimeException(s"Project file $projectFilePath did not exist")) case Failure(err)=> logger.error(s"Could not check file existence: ${err.getMessage}") Failure(err) } } }