Skip to content

Commit

Permalink
Merge pull request #492 from guardian/bump-pan-domain-auth
Browse files Browse the repository at this point in the history
bump pan-domain-auth and permissions
  • Loading branch information
aracho1 authored Jun 14, 2023
2 parents 58b7366 + ae8987a commit fadea3b
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 151 deletions.
11 changes: 3 additions & 8 deletions app/AppComponents.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import com.gu.editorial.permissions.client.PermissionsUser
import com.amazonaws.auth.{AWSCredentialsProvider, DefaultAWSCredentialsProviderChain}
import com.gu.pandomainauth.PanDomainAuthSettingsRefresher
import com.gu.permissions.{PermissionsConfig, PermissionsProvider}
import controllers.AssetsComponents
import model.jobs.JobRunner
import modules.clustersync.ClusterSynchronisation
Expand All @@ -13,6 +14,7 @@ import play.api.routing.Router
import play.filters.HttpFiltersComponents
import router.Routes
import services._

import scala.language.postfixOps

class AppComponents(context: Context, config: Config)
Expand All @@ -30,13 +32,6 @@ class AppComponents(context: Context, config: Config)
new JobRunner(context.lifecycle)
new SponsorshipLifecycleJobs(context.lifecycle)

// This is requried because there's an issue in the permissions client
// which causes the permissions to come back as denied for the first person
// to request them. Seems to be a timing bug...
//
// This should only be a temporary fix @ 2016/02/09
Permissions.list(PermissionsUser("preload@permissions"))

val panDomainSettings = new PanDomainAuthSettingsRefresher(
domain = config.pandaDomain,
system = config.pandaSystemIdentifier,
Expand Down
52 changes: 24 additions & 28 deletions app/controllers/App.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import permissions._
import play.api.libs.ws.WSClient

import scala.collection.mutable.ListBuffer
import scala.concurrent.ExecutionContext
import scala.concurrent.{ExecutionContext, Future}

class App(
val wsClient: WSClient,
Expand All @@ -34,39 +34,35 @@ class App(
case None => routes.Assets.versioned(jsFileName).toString
}

Permissions.getPermissionsForUser(req.user.email).map { permissions =>
val userPermissions = Permissions.getPermissionsForUser(req.user.email)

val allTags = TagType.list.map(_.name)
var permittedTags = ListBuffer[String]()
val allTags = TagType.list.map(_.name)
var permittedTags = ListBuffer[String]()

for (tag <- allTags) {
TagTypePermissionMap(tag) match {
case Some(p) => {
permissions.get(p.name).map { hasPermission =>
if (hasPermission) {
permittedTags += tag
}
}
for (tag <- allTags) {
TagTypePermissionMap(tag) match {
case Some(permissionDefinition) =>
if (userPermissions.get(permissionDefinition.name).contains(true)) {
permittedTags += tag
}
case None => permittedTags += tag
}
case None => permittedTags += tag
}

val clientConfig = ClientConfig(
username = req.user.email,
capiUrl = Config().capiUrl,
capiPreviewUrl = "/support/previewCapi",
capiKey = Config().capiKey,
tagTypes = allTags,
permittedTagTypes = permittedTags.toList,
permissions = permissions,
reauthUrl = "/reauth",
tagSearchPageSize = Config().tagSearchPageSize
)

Ok(views.html.Application.app("Tag Manager", jsLocation, Json.toJson(clientConfig).toString()))
}

val clientConfig = ClientConfig(
username = req.user.email,
capiUrl = Config().capiUrl,
capiPreviewUrl = "/support/previewCapi",
capiKey = Config().capiKey,
tagTypes = allTags,
permittedTagTypes = permittedTags.toList,
permissions = userPermissions,
reauthUrl = "/reauth",
tagSearchPageSize = Config().tagSearchPageSize
)

val result = views.html.Application.app("Tag Manager", jsLocation, Json.toJson(clientConfig).toString())
Future.successful(Ok(result))
}

def hello = AuthAction {
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/Migration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Migration(

def migratePaidContent = APIAuthAction(parse.multipartFormData) { req =>
req.body.file("migrationFile").map{ jsonFile =>
val jsonString = Source.fromFile(jsonFile.ref.file, "UTF-8").getLines().mkString("\n")
val jsonString = Source.fromFile(jsonFile.ref.path.toFile, "UTF-8").getLines().mkString("\n")

val json = Json.parse(jsonString)
val sponsorships = json.as[List[Sponsorship]]
Expand Down
105 changes: 45 additions & 60 deletions app/permissions/PermissionActionCheck.scala
Original file line number Diff line number Diff line change
@@ -1,91 +1,76 @@
package permissions

import com.gu.editorial.permissions.client.{PermissionAuthorisation, PermissionDenied, PermissionGranted}
import com.gu.permissions.PermissionDefinition
import com.gu.pandomainauth.action.UserRequest
import play.api.Logging
import play.api.mvc.{ActionFilter, Results}

import scala.concurrent.{Future, ExecutionContext}

trait PermissionActionFilter extends ActionFilter[UserRequest] with Logging {
val testAccess: String => Future[PermissionAuthorisation]
val testAccess: String => Boolean
val restrictedAction: String

override def filter[A](request: UserRequest[A]) =
if(request.user.email == "hmac-authed-service") {
if (request.user.email == "hmac-authed-service") {
Future.successful(None)
} else {
testAccess(request.user.email).map {
case PermissionGranted => None
case PermissionDenied =>
logger.info(s"user not authorized to $restrictedAction")
Some(Results.Unauthorized)}(executionContext)
val hasAccess = testAccess(request.user.email)
if (hasAccess) {
Future.successful(None)
} else {
logger.info(s"user not authorized to $restrictedAction")
Future.successful(Some(Results.Unauthorized))
}
}
}
abstract class BasePermissionCheck(
val permission: PermissionDefinition,
val restrictedAction: String
)(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {

// Tag Edit
case class CreateTagPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagEdit)
val restrictedAction = "create tag"
val testAccess: String => Boolean = Permissions.testUser(permission)
}

case class UpdateTagPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagEdit)
val restrictedAction = "update tag"
}
// Tag Edit
case class CreateTagPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagEdit, "create tag")

case class UpdateTagPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagEdit, "update tag")

// Tag Admin
case class AddEditionToSectionPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "add edition to section"
}

case class RemoveEditionFromSectionPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "remove edition from section"
}
case class AddEditionToSectionPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "add edition to section")

case class DeleteTagPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "delete tag"
}
case class RemoveEditionFromSectionPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "remove edition from section")

case class DeleteJobPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "delete job"
}
case class DeleteTagPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "delete tag")

case class MergeTagPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "merge tag"
}
case class DeleteJobPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "delete job")

case class JobDeletePermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "job delete"
}
case class MergeTagPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "merge tag")

case class JobRollbackPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "job rollback"
}
case class JobDeletePermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "job delete")

case class ModifySectionExpiryPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "trigger unexpiry of section content"
}
case class JobRollbackPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "job rollback")

case class ManageSponsorshipsPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.CommercialTags)
val restrictedAction = "manage sponsorships"
}
case class ModifySectionExpiryPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin,"trigger unexpiry of section content")

case class TriggerMigrationPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "manage sponsorships"
}
// Other Permissions
case class ManageSponsorshipsPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.CommercialTags, "manage sponsorships")

case class PillarPermissionsCheck()(implicit val executionContext: ExecutionContext) extends PermissionActionFilter {
val testAccess: String => Future[PermissionAuthorisation] = Permissions.testUser(Permissions.TagAdmin)
val restrictedAction = "manage pillars"
}
case class TriggerMigrationPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "trigger migration")

case class PillarPermissionsCheck()(implicit executionContext: ExecutionContext)
extends BasePermissionCheck(Permissions.TagAdmin, "manage pillars")
46 changes: 19 additions & 27 deletions app/permissions/Permissions.scala
Original file line number Diff line number Diff line change
@@ -1,40 +1,32 @@
package permissions

import com.gu.editorial.permissions.client._
import com.amazonaws.auth.{AWSCredentialsProvider, DefaultAWSCredentialsProviderChain}
import com.gu.permissions.{PermissionDefinition, PermissionsConfig, PermissionsProvider}
import services.Config

import scala.concurrent.Future
object Permissions {
val app = "tag-manager"

object Permissions extends PermissionsProvider {
val TagEdit: PermissionDefinition = PermissionDefinition("tag_edit", app)
val TagAdmin: PermissionDefinition = PermissionDefinition("tag_admin", app)
val CommercialTags: PermissionDefinition = PermissionDefinition("commercial_tags", app)
val TagUnaccessible: PermissionDefinition = PermissionDefinition("tag_no_one", app)

lazy val TagEdit = Permission("tag_edit", "tag-manager", PermissionDenied)
lazy val TagAdmin = Permission("tag_admin", "tag-manager", PermissionDenied)
lazy val CommercialTags = Permission("commercial_tags", "tag-manager", PermissionDenied)
lazy val TagUnaccessible = Permission("tag_no_one", "tag-manager", PermissionDenied)

lazy val all = Seq(TagAdmin)

implicit def config = PermissionsConfig(
app = "tag-manager",
all = all,
s3BucketPrefix = Config().permissionsStage,
s3Region = Some("eu-west-1")
private val permissionDefinitions = Map(
"tag_edit" -> TagEdit,
"tag_admin" -> TagAdmin,
"commercial_tags" -> CommercialTags,
"tag_no_one" -> TagUnaccessible
)

def testUser(permission: Permission)(email: String): Future[PermissionAuthorisation] = {
println("Permissions for: " + email)
implicit val permissionsUser: PermissionsUser = PermissionsUser(email)

Permissions.get(permission)
}
private val credentials: AWSCredentialsProvider = new DefaultAWSCredentialsProviderChain()

def getPermissionsForUser(email: String): Future[Map[String, Boolean]] = {
implicit val permissionsUser: PermissionsUser = PermissionsUser(email)
private val permissions: PermissionsProvider = PermissionsProvider(PermissionsConfig(Config().permissionsStage, Config().aws.region, credentials))

Permissions.list.map(_.filter(_._1.app == "tag-manager").flatMap( _ match {
case (p: Permission, PermissionGranted) => Map(p.name -> true)
case (p: Permission, PermissionDenied) => Map(p.name -> false)
}))
def testUser(permission:PermissionDefinition)(email: String): Boolean = {
println("Permissions for: " + email)
permissions.hasPermission(permission, email)
}
def getPermissionsForUser(email: String): Map[String, Boolean] = permissionDefinitions.transform((_, permission) => permissions.hasPermission(permission, email))
}

25 changes: 15 additions & 10 deletions app/permissions/SectionSpecificPermissions.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package permissions

import com.gu.editorial.permissions.client.{Permission, PermissionAuthorisation, PermissionDenied, PermissionGranted}
import com.gu.pandomainauth.action.UserRequest
import com.gu.permissions.PermissionDefinition
import play.api.mvc.{ActionFilter, AnyContent, Result, Results}

import scala.concurrent.{Future, ExecutionContext}

object SectionPermissionMap {
def apply(isMicrosite: Boolean): Option[Permission] = {
def apply(isMicrosite: Boolean): Option[PermissionDefinition] = {
isMicrosite match {
case true => None
case _ => Some(Permissions.TagAdmin)
Expand All @@ -17,21 +17,26 @@ object SectionPermissionMap {

trait SectionSpecificPermissionActionFilter extends ActionFilter[UserRequest] {

val testAccess: (Permission => (String => Future[PermissionAuthorisation]))
val testAccess: PermissionDefinition => String => Boolean;
val restrictedAction: String

def commonTestAccess: PermissionDefinition => String => Boolean =
Permissions.testUser

override def filter[A](request: UserRequest[A]): Future[Option[Result]] = {
request.body match {
case b: AnyContent => {
b.asJson.map { json =>
val isMicrosite = (json \ "isMicrosite").as[Boolean]

val permission = SectionPermissionMap(isMicrosite).getOrElse { return Future.successful(None) }

testAccess(permission)(request.user.email).map {
case PermissionGranted => None
case PermissionDenied => Some(Results.Unauthorized)
}(executionContext)
val hasAccess = testAccess(permission)(request.user.email)

if (hasAccess) {
return Future.successful(None)
} else {
return Future.successful(Some(Results.Unauthorized))
}
}.getOrElse {
Future.successful(Some(Results.BadRequest("Expecting Json data")))
}
Expand All @@ -42,11 +47,11 @@ trait SectionSpecificPermissionActionFilter extends ActionFilter[UserRequest] {
}

case class UpdateSectionPermissionsCheck()(implicit val executionContext: ExecutionContext) extends SectionSpecificPermissionActionFilter {
val testAccess: (Permission => (String => Future[PermissionAuthorisation])) = Permissions.testUser
val testAccess: PermissionDefinition => String => Boolean = commonTestAccess
val restrictedAction = "update section"
}

case class CreateSectionPermissionsCheck()(implicit val executionContext: ExecutionContext) extends SectionSpecificPermissionActionFilter {
val testAccess: (Permission => (String => Future[PermissionAuthorisation])) = Permissions.testUser
val testAccess: PermissionDefinition => String => Boolean = commonTestAccess
val restrictedAction = "create section"
}
Loading

0 comments on commit fadea3b

Please sign in to comment.