Skip to content

Commit

Permalink
add feature flag for row permission checks
Browse files Browse the repository at this point in the history
  • Loading branch information
zingmane committed May 13, 2024
1 parent b68220b commit c46f55b
Show file tree
Hide file tree
Showing 14 changed files with 95 additions and 42 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,20 @@ or with automatic redeploy on code changes
TODO add documentation for authentication and permission handling. Currently the docs are filed in confluence and hackmd.io.
## Feature Flags
Feature flags are used to enable or disable certain features. They have to be configured in the configuration file.Feature flags are:
- `isRowPermissionCheckEnabled`: Enable or disable row permission checks (default: false)
- `isPublicFileServerEnabled`: Enable or disable the public file server. If enabled, files are accessible without authentication (default: false)
## Highlevel Features
* Content Creation System
* Content Translation System
* Digital Asset Management
* Editing Publishing Workflow
* Workspaces & Custom Projections
- Content Creation System
- Content Translation System
- Digital Asset Management
- Editing Publishing Workflow
- Workspaces & Custom Projections
## License
Expand Down
4 changes: 2 additions & 2 deletions conf-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"uploadsDirectory": "uploads/",
"workingDirectory": "./",
"rolePermissionsPath": "./role-permissions.json",
"isPublicFileServer": false,
"isRowPermissionCheck": false,
"isPublicFileServerEnabled": false,
"isRowPermissionCheckEnabled": false,
"openApiUrl": "https://my.domain.com/api/docs",
"database": {
"host": "localhost",
Expand Down
12 changes: 8 additions & 4 deletions src/main/scala/com/campudus/tableaux/Starter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ class Starter extends ScalaVerticle with LazyLogging {
val authConfig = config.getJsonObject("auth", Json.obj())
val rolePermissionsPath = getStringDefault(config, "rolePermissionsPath", Starter.DEFAULT_ROLE_PERMISSIONS_PATH)
val openApiUrl = Option(getStringDefault(config, "openApiUrl", null))
val isPublicFileServer = config.getBoolean("isPublicFileServer", Starter.DEFAULT_IS_PUBLIC_FILE_SERVER)
val isRowPermissionCheck = config.getBoolean("isRowPermissionCheck", Starter.DEFAULT_IS_PUBLIC_FILE_SERVER)

// feature flags
val isPublicFileServerEnabled =
config.getBoolean("isPublicFileServerEnabled", Starter.DEFAULT_IS_PUBLIC_FILE_SERVER)
val isRowPermissionCheckEnabled =
config.getBoolean("isRowPermissionCheckEnabled", Starter.DEFAULT_IS_PUBLIC_FILE_SERVER)

val rolePermissions = FileUtils(vertxAccessContainer()).readJsonFile(rolePermissionsPath, Json.emptyObj())

Expand All @@ -68,8 +72,8 @@ class Starter extends ScalaVerticle with LazyLogging {
uploadsDirectory = uploadsDirectory,
rolePermissions = rolePermissions,
openApiUrl = openApiUrl,
isPublicFileServer = isPublicFileServer,
isRowPermissionCheck = isRowPermissionCheck
isPublicFileServerEnabled = isPublicFileServerEnabled,
isRowPermissionCheckEnabled = isRowPermissionCheckEnabled
)

connection = SQLConnection(vertxAccessContainer(), databaseConfig)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/com/campudus/tableaux/TableauxConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class TableauxConfig(
uploadsDirectory: String,
val rolePermissions: JsonObject,
val openApiUrl: Option[String] = None,
val isPublicFileServer: Boolean = false,
val isRowPermissionCheck: Boolean = false
val isPublicFileServerEnabled: Boolean = false,
var isRowPermissionCheckEnabled: Boolean = false
) extends VertxAccess {

def uploadsDirectoryPath(): Path = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ object TableauxModel {

type RowPermissionSeq = Seq[String]

def apply(connection: DatabaseConnection, structureModel: StructureModel)(
def apply(connection: DatabaseConnection, structureModel: StructureModel, config: TableauxConfig)(
implicit roleModel: RoleModel
): TableauxModel = {
new TableauxModel(connection, structureModel)
new TableauxModel(connection, structureModel, config)
}
}

Expand Down Expand Up @@ -69,6 +69,8 @@ sealed trait StructureDelegateModel extends DatabaseQuery {

protected val structureModel: StructureModel

protected val config: TableauxConfig

protected[this] implicit def roleModel: RoleModel

def createTable(name: String, hidden: Boolean)(implicit user: TableauxUser): Future[Table] = {
Expand Down Expand Up @@ -123,7 +125,8 @@ sealed trait StructureDelegateModel extends DatabaseQuery {

class TableauxModel(
override protected[this] val connection: DatabaseConnection,
override protected[this] val structureModel: StructureModel
override protected[this] val structureModel: StructureModel,
override protected[this] val config: TableauxConfig
)(override implicit val roleModel: RoleModel)
extends DatabaseQuery
with StructureDelegateModel {
Expand Down Expand Up @@ -1004,11 +1007,18 @@ class TableauxModel(
}
}

rowPermissions <- retrieveRowModel.retrieveRowPermissions(column.table.id, rowId)
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(rowPermissions), isInternalCall)
filteredValue <- removeUnauthorizedLinkAndConcatValues(column, value, true)
resultValue <-
if (config.isRowPermissionCheckEnabled) {
for {
rowPermissions <- retrieveRowModel.retrieveRowPermissions(column.table.id, rowId)
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(rowPermissions), isInternalCall)
filteredValue <- removeUnauthorizedLinkAndConcatValues(column, value, true)
} yield filteredValue
} else {
Future.successful(value)
}
} yield {
Cell(column, rowId, filteredValue)
Cell(column, rowId, resultValue)
}
}

Expand Down Expand Up @@ -1153,9 +1163,16 @@ class TableauxModel(
isInternalCall = false
)
row <- retrieveRow(table, filteredColumns, rowId)
// _ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(row.rowPermissions), isInternalCall = false)
// mutatedRow <- removeUnauthorizedLinkAndConcatValuesFromRow(filteredColumns, row)
} yield row
resultRow <-
if (config.isRowPermissionCheckEnabled) {
for {
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(row.rowPermissions), isInternalCall = false)
mutatedRow <- removeUnauthorizedLinkAndConcatValuesFromRow(filteredColumns, row)
} yield mutatedRow
} else {
Future.successful(row)
}
} yield resultRow
}

private def retrieveRow(table: Table, columns: Seq[ColumnType[_]], rowId: RowId)(
Expand Down Expand Up @@ -1210,10 +1227,14 @@ class TableauxModel(
linkDirection
)
rowSeq <- mapRawRows(table, representingColumns, rawRows)
// rowSeqWithoutUnauthorizedValues <- removeUnauthorizedForeignValuesFromRows(representingColumns, rowSeq)
resultRowSeq <-
if (config.isRowPermissionCheckEnabled) {
removeUnauthorizedForeignValuesFromRows(representingColumns, rowSeq)
} else {
Future.successful(rowSeq)
}
} yield {
val filteredForeignRows =
roleModel.filterDomainObjects(ViewRow, rowSeq, ComparisonObjects(), false)
val filteredForeignRows = roleModel.filterDomainObjects(ViewRow, resultRowSeq, ComparisonObjects(), false)
val rowsSeq = RowSeq(filteredForeignRows, Page(pagination, Some(totalSize)))
copyFirstColumnOfRowsSeq(rowsSeq)
}
Expand All @@ -1239,9 +1260,14 @@ class TableauxModel(
isInternalCall = false
)
rowSeq <- retrieveRows(table, filteredColumns, finalFlagOpt, archivedFlagOpt, pagination)
// mutatedRows <- removeUnauthorizedForeignValuesFromRows(filteredColumns, rowSeq.rows)
resultRows <-
if (config.isRowPermissionCheckEnabled) {
removeUnauthorizedForeignValuesFromRows(filteredColumns, rowSeq.rows)
} else {
Future.successful(rowSeq.rows)
}
} yield {
val filteredRows = roleModel.filterDomainObjects(ViewRow, rowSeq.rows, ComparisonObjects(), false)
val filteredRows = roleModel.filterDomainObjects(ViewRow, resultRows, ComparisonObjects(), false)
RowSeq(filteredRows, rowSeq.page)
}
}
Expand Down Expand Up @@ -1539,8 +1565,15 @@ class TableauxModel(
typeOpt: Option[String]
)(implicit user: TableauxUser): Future[Seq[History]] = {
for {
rowPermissions <- retrieveRowModel.retrieveRowPermissions(table.id, rowId)
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(rowPermissions))
_ <-
if (config.isRowPermissionCheckEnabled) {
for {
rowPermissions <- retrieveRowModel.retrieveRowPermissions(table.id, rowId)
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(rowPermissions))
} yield ()
} else {
Future.successful(())
}
column <- retrieveColumn(table, columnId)
_ <- checkColumnTypeForLangtag(column, langtagOpt)
_ <- roleModel.checkAuthorization(ViewCellValue, ComparisonObjects(table, column))
Expand All @@ -1555,8 +1588,15 @@ class TableauxModel(
typeOpt: Option[String]
)(implicit user: TableauxUser): Future[Seq[History]] = {
for {
rowPermissions <- retrieveRowModel.retrieveRowPermissions(table.id, rowId)
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(rowPermissions))
_ <-
if (config.isRowPermissionCheckEnabled) {
for {
rowPermissions <- retrieveRowModel.retrieveRowPermissions(table.id, rowId)
_ <- roleModel.checkAuthorization(ViewRow, ComparisonObjects(rowPermissions))
} yield ()
} else {
Future.successful(())
}
columns <- retrieveColumns(table)
cellHistorySeq <- retrieveHistoryModel.retrieveRow(table, rowId, langtagOpt, typeOpt)
filteredCellHistorySeq = filterCellHistoriesForColumns(cellHistorySeq, columns)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/com/campudus/tableaux/router/MediaRouter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class MediaRouter(override val config: TableauxConfig, val controller: MediaCont
router.get(folders).handler(retrieveRootFolder)
router.getWithRegex(folder).handler(retrieveFolder)
router.getWithRegex(file).handler(retrieveFile)
if (!config.isPublicFileServer) {
if (!config.isPublicFileServerEnabled) {
router.getWithRegex(fileLangStatic).handler(serveFile)
}

Expand Down Expand Up @@ -84,7 +84,7 @@ class MediaRouter(override val config: TableauxConfig, val controller: MediaCont
val router = Router.router(vertx)

// RETRIEVE
if (config.isPublicFileServer) {
if (config.isPublicFileServerEnabled) {
router.getWithRegex(fileLangStatic).handler(serveFile)
}
router
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object RouterRegistry extends LazyLogging {

val systemModel = SystemModel(dbConnection)
val structureModel = StructureModel(dbConnection)
val tableauxModel = TableauxModel(dbConnection, structureModel)
val tableauxModel = TableauxModel(dbConnection, structureModel, tableauxConfig)
val folderModel = FolderModel(dbConnection)
val fileModel = FileModel(dbConnection)
val attachmentModel = AttachmentModel(dbConnection, fileModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ trait SystemControllerAuthTest extends TableauxTestBase {
val dbConnection = DatabaseConnection(this.vertxAccess(), sqlConnection)
val systemModel = SystemModel(dbConnection)
val structureModel = StructureModel(dbConnection)
val tableauxModel = TableauxModel(dbConnection, structureModel)
val tableauxModel = TableauxModel(dbConnection, structureModel, tableauxConfig)
val serviceModel = ServiceModel(dbConnection)

SystemController(tableauxConfig, systemModel, tableauxModel, structureModel, serviceModel, roleModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ trait TableauxControllerAuthTest extends TableauxTestBase {
val sqlConnection = SQLConnection(this.vertxAccess(), databaseConfig)
val dbConnection = DatabaseConnection(this.vertxAccess(), sqlConnection)
val structureModel = StructureModel(dbConnection)
val tableauxModel = TableauxModel(dbConnection, structureModel)
val tableauxModel = TableauxModel(dbConnection, structureModel, tableauxConfig)

TableauxController(tableauxConfig, tableauxModel, roleModel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ class RetrieveRowsTest extends TableauxTestBase {
val sqlConnection = SQLConnection(this.vertxAccess(), databaseConfig)
val dbConnection = DatabaseConnection(this.vertxAccess(), sqlConnection)
val structureModel = StructureModel(dbConnection)
val tableauxModel = TableauxModel(dbConnection, structureModel)
val tableauxModel = TableauxModel(dbConnection, structureModel, tableauxConfig)

TableauxController(tableauxConfig, tableauxModel, roleModel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ trait TestHelper extends TableauxTestBase {
def createTableauxController(roleConfig: String = defaultViewTableRole)(
implicit roleModel: RoleModel = initRoleModel(roleConfig)
): TableauxController = {
// mutate TableauxConfig to test with enabled row permission check
tableauxConfig.isRowPermissionCheckEnabled = true
val sqlConnection = SQLConnection(this.vertxAccess(), databaseConfig)
val dbConnection = DatabaseConnection(this.vertxAccess(), sqlConnection)
val structureModel = StructureModel(dbConnection)
val tableauxModel = TableauxModel(dbConnection, structureModel)
val tableauxModel = TableauxModel(dbConnection, structureModel, tableauxConfig)

TableauxController(tableauxConfig, tableauxModel, roleModel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CacheVerticleTest extends VertxAccess with TestAssertionHelper {
"workingDirectory",
"uploadsDirectory",
rolePermissions,
isRowPermissionCheck = false
isRowPermissionCheckEnabled = false
)
private var deploymentId: String = "CacheVerticleTest"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class TableauxControllerTest extends TableauxTestBase {
val dbConnection = DatabaseConnection(this.vertxAccess(), sqlConnection)
implicit val roleModel = RoleModel(tableauxConfig.rolePermissions)

val model = TableauxModel(dbConnection, StructureModel(dbConnection))
val model = TableauxModel(dbConnection, StructureModel(dbConnection), tableauxConfig)

TableauxController(tableauxConfig, model, roleModel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ trait TableauxTestBase
config.getString("workingDirectory"),
config.getString("uploadsDirectory"),
rolePermissions,
isRowPermissionCheck = false
isRowPermissionCheckEnabled = false
)

val async = context.async()
Expand Down

0 comments on commit c46f55b

Please sign in to comment.