Skip to content

Commit

Permalink
create, load, delete policies (#342)
Browse files Browse the repository at this point in the history
* long overdue commit; create, load, delete policy queries

* add back name col to policy table, adjust queries accordingly

* Adding PostgresGroupDAO

* use groupDAO, move a couple more fns into it and out of database support; tests pass

* Added a clarifying comment for policy group names

* address PR comments

* remove unused import
  • Loading branch information
marctalbott authored and gpolumbo-broad committed Aug 23, 2019
1 parent 9c35288 commit 7a427ed
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -194,18 +194,21 @@
<constraints nullable="false" foreignKeyName="FK_SRP_RESOURCE" referencedTableName="SAM_RESOURCE" referencedColumnNames="id"/>
</column>
<column name="group_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="FK_SRP_GROUP" referencedTableName="SAM_GROUP" referencedColumnNames="id"/>
<constraints nullable="false" foreignKeyName="FK_SRP_GROUP" referencedTableName="SAM_GROUP" referencedColumnNames="id" deleteCascade="true"/>
</column>
<column name="name" type="VARCHAR">
<constraints nullable="false"/>
</column>
<column name="public" type="BOOLEAN">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>

<changeSet logicalFilePath="dummy" author="dvoet" id="policy_role_table">
<createTable tableName="SAM_POLICY_ROLE">
<column name="resource_policy_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="FK_SPR_POLICY" referencedTableName="SAM_RESOURCE_POLICY" referencedColumnNames="id" primaryKey="true"/>
<constraints nullable="false" foreignKeyName="FK_SPR_POLICY" referencedTableName="SAM_RESOURCE_POLICY" referencedColumnNames="id" primaryKey="true" deleteCascade="true"/>
</column>
<column name="resource_role_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="FK_SPR_ROLE" referencedTableName="SAM_RESOURCE_ROLE" referencedColumnNames="id" primaryKey="true"/>
Expand All @@ -216,7 +219,7 @@
<changeSet logicalFilePath="dummy" author="dvoet" id="policy_action_table">
<createTable tableName="SAM_POLICY_ACTION">
<column name="resource_policy_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="FK_SPA_POLICY" referencedTableName="SAM_RESOURCE_POLICY" referencedColumnNames="id" primaryKey="true"/>
<constraints nullable="false" foreignKeyName="FK_SPA_POLICY" referencedTableName="SAM_RESOURCE_POLICY" referencedColumnNames="id" primaryKey="true" deleteCascade="true"/>
</column>
<column name="resource_action_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="FK_SPA_ACTION" referencedTableName="SAM_RESOURCE_ACTION" referencedColumnNames="id" primaryKey="true"/>
Expand Down
28 changes: 16 additions & 12 deletions src/main/scala/org/broadinstitute/dsde/workbench/sam/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.broadinstitute.dsde.workbench.newrelic.NewRelicMetrics
import org.broadinstitute.dsde.workbench.sam.api.{SamRoutes, StandardUserInfoDirectives}
import org.broadinstitute.dsde.workbench.sam.config.{AppConfig, GoogleConfig}
import org.broadinstitute.dsde.workbench.sam.db.DbReference
import org.broadinstitute.dsde.workbench.sam.db.dao.PostgresGroupDAO
import org.broadinstitute.dsde.workbench.sam.directory._
import org.broadinstitute.dsde.workbench.sam.google._
import org.broadinstitute.dsde.workbench.sam.model._
Expand Down Expand Up @@ -206,8 +207,9 @@ object Boot extends IOApp with LazyLogging {
ldapExecutionContext <- ExecutionContexts.fixedThreadPool[IO](appConfig.directoryConfig.connectionPoolSize)
postgresExecutionContext <- ExecutionContexts.fixedThreadPool[IO](DBs.config.getInt(s"db.${dbName.name}.poolMaxSize"))

directoryDAO = createDirectoryDAO(appConfig, ldapExecutionContext, ldapConnectionPool, dbReference, postgresExecutionContext, memberOfCache, newRelicMetrics)
accessPolicyDAO = createAccessPolicyDAO(appConfig, ldapExecutionContext, ldapConnectionPool, dbReference, postgresExecutionContext, memberOfCache, resourceCache, newRelicMetrics)
postgresGroupDAO = new PostgresGroupDAO(dbReference, postgresExecutionContext)
directoryDAO = createDirectoryDAO(appConfig, ldapExecutionContext, ldapConnectionPool, dbReference, postgresExecutionContext, memberOfCache, newRelicMetrics, postgresGroupDAO)
accessPolicyDAO = createAccessPolicyDAO(appConfig, ldapExecutionContext, ldapConnectionPool, dbReference, postgresExecutionContext, memberOfCache, resourceCache, newRelicMetrics, postgresGroupDAO)
} yield (directoryDAO, accessPolicyDAO, ldapExecutionContext)
}

Expand All @@ -217,22 +219,24 @@ object Boot extends IOApp with LazyLogging {
dbReference: DbReference,
postgresExecutionContext: ExecutionContext,
memberOfCache: Cache[WorkbenchSubject, Set[String]],
newRelicMetrics: NewRelicMetrics): DirectoryDAO = {
newRelicMetrics: NewRelicMetrics,
postgresGroupDAO: PostgresGroupDAO): DirectoryDAO = {
val ldapDirectoryDAO = new LdapDirectoryDAO(ldapConnectionPool, appConfig.directoryConfig, ldapExecutionContext, memberOfCache)
val postgresDirectoryDAO = new PostgresDirectoryDAO(dbReference, postgresExecutionContext)
val postgresDirectoryDAO = new PostgresDirectoryDAO(dbReference, postgresExecutionContext, postgresGroupDAO)
DaoWithShadow(ldapDirectoryDAO, postgresDirectoryDAO, new NewRelicShadowResultReporter("directoryDAO", newRelicMetrics), timer.clock)
}

private def createAccessPolicyDAO(appConfig: AppConfig,
ldapExecutionContext: ExecutionContext,
ldapConnectionPool: LDAPConnectionPool,
dbReference: DbReference,
postgresExecutionContext: ExecutionContext,
memberOfCache: Cache[WorkbenchSubject, Set[String]],
resourceCache: Cache[FullyQualifiedResourceId, Resource],
newRelicMetrics: NewRelicMetrics): AccessPolicyDAO = {
ldapExecutionContext: ExecutionContext,
ldapConnectionPool: LDAPConnectionPool,
dbReference: DbReference,
postgresExecutionContext: ExecutionContext,
memberOfCache: Cache[WorkbenchSubject, Set[String]],
resourceCache: Cache[FullyQualifiedResourceId, Resource],
newRelicMetrics: NewRelicMetrics,
postgresGroupDAO: PostgresGroupDAO): AccessPolicyDAO = {
val ldapAccessPolicyDao = new LdapAccessPolicyDAO(ldapConnectionPool, appConfig.directoryConfig, ldapExecutionContext, memberOfCache, resourceCache)
val foregroundPostgresAccessPolicyDAO = new PostgresAccessPolicyDAO(dbReference, postgresExecutionContext)
val foregroundPostgresAccessPolicyDAO = new PostgresAccessPolicyDAO(dbReference, postgresExecutionContext, postgresGroupDAO)
DaoWithShadow(ldapAccessPolicyDao, foregroundPostgresAccessPolicyDAO, new NewRelicShadowResultReporter("directoryDAO", newRelicMetrics), timer.clock)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.broadinstitute.dsde.workbench.sam.db.dao
import cats.effect.{ContextShift, IO}
import org.broadinstitute.dsde.workbench.model._
import org.broadinstitute.dsde.workbench.sam.db.{DbReference, SamTypeBinders}
import org.broadinstitute.dsde.workbench.sam.db.tables._
import org.broadinstitute.dsde.workbench.sam.util.DatabaseSupport
import scalikejdbc.{DBSession, SQLSyntax}
import org.broadinstitute.dsde.workbench.sam.db.SamParameterBinderFactory.SqlInterpolationWithSamBinders
import org.broadinstitute.dsde.workbench.sam.model.FullyQualifiedPolicyId

import scala.concurrent.ExecutionContext

class PostgresGroupDAO(protected val dbRef: DbReference,
protected val ecForDatabaseIO: ExecutionContext)(implicit executionContext: ExecutionContext) extends DatabaseSupport {
implicit val cs: ContextShift[IO] = IO.contextShift(executionContext)

def insertGroupMembers(groupId: GroupPK, members: Set[WorkbenchSubject])(implicit session: DBSession): Int = {
if (members.isEmpty) {
0
} else {
val memberUsers: List[SQLSyntax] = members.collect {
case userId: WorkbenchUserId => samsqls"(${groupId}, ${userId}, ${None})"
}.toList

val memberGroupPKQueries = members.collect {
case id: WorkbenchGroupIdentity => samsqls"(${workbenchGroupIdentityToGroupPK(id)})"
}

import SamTypeBinders._
// TODO: is there a way to do this without needing N subqueries?
val memberGroupPKs: List[GroupPK] = if (memberGroupPKQueries.nonEmpty) {
val g = GroupTable.syntax("g")
samsql"select ${g.result.id} from ${GroupTable as g} where ${g.id} in (${memberGroupPKQueries})"
.map(rs => rs.get[GroupPK](g.resultName.id)).list().apply()
} else {
List.empty
}

val memberGroups: List[SQLSyntax] = memberGroupPKs.map { groupPK =>
samsqls"(${groupId}, ${None}, ${groupPK})"
}

if (memberGroups.size != memberGroupPKQueries.size) {
throw new WorkbenchException(s"Some member groups not found.")
} else {
val gm = GroupMemberTable.column
samsql"insert into ${GroupMemberTable.table} (${gm.groupId}, ${gm.memberUserId}, ${gm.memberGroupId}) values ${memberUsers ++ memberGroups}"
.update().apply()
}
}
}

def workbenchGroupIdentityToGroupPK(groupId: WorkbenchGroupIdentity): SQLSyntax = {
groupId match {
case group: WorkbenchGroupName => GroupTable.groupPKQueryForGroup(group)
case policy: FullyQualifiedPolicyId => groupPKQueryForPolicy(policy)
}
}

private def groupPKQueryForPolicy(policyId: FullyQualifiedPolicyId,
resourceTypeTableAlias: String = "rt",
resourceTableAlias: String = "r",
policyTableAlias: String = "p",
groupTableAlias: String = "g"): SQLSyntax = {
val rt = ResourceTypeTable.syntax(resourceTypeTableAlias)
val r = ResourceTable.syntax(resourceTableAlias)
val p = PolicyTable.syntax(policyTableAlias)
val g = GroupTable.syntax(groupTableAlias)
samsqls"""select ${p.groupId}
from ${ResourceTypeTable as rt}
join ${ResourceTable as r} on ${rt.id} = ${r.resourceTypeId}
join ${PolicyTable as p} on ${r.id} = ${p.resourceId}
join ${GroupTable as g} on ${g.id} = ${p.groupId}
where ${rt.name} = ${policyId.resource.resourceTypeName}
and ${r.name} = ${policyId.resource.resourceId}
and ${g.name} = ${policyId.accessPolicyName}"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ final case class PolicyPK(value: Long) extends DatabaseKey
final case class PolicyRecord(id: PolicyPK,
resourceId: ResourcePK,
groupId: GroupPK,
name: AccessPolicyName)
name: AccessPolicyName,
public: Boolean)

object PolicyTable extends SQLSyntaxSupportWithDefaultSamDB[PolicyRecord] {
override def tableName: String = "SAM_RESOURCE_POLICY"
Expand All @@ -18,6 +19,7 @@ object PolicyTable extends SQLSyntaxSupportWithDefaultSamDB[PolicyRecord] {
rs.get(e.id),
rs.get(e.resourceId),
rs.get(e.groupId),
rs.get(e.name)
rs.get(e.name),
rs.get(e.public)
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.broadinstitute.dsde.workbench.sam.db.tables

import org.broadinstitute.dsde.workbench.sam.db.{DatabaseKey, SamTypeBinders}
import org.broadinstitute.dsde.workbench.sam.model.{ResourceId, ResourceTypeName}
import org.broadinstitute.dsde.workbench.sam.model.{FullyQualifiedResourceId, ResourceId}
import org.broadinstitute.dsde.workbench.sam.db.SamParameterBinderFactory.SqlInterpolationWithSamBinders
import scalikejdbc._

Expand All @@ -20,10 +20,9 @@ object ResourceTable extends SQLSyntaxSupportWithDefaultSamDB[ResourceRecord] {
rs.get(e.resourceTypeId)
)

def pkQuery(resourceId: ResourceId, resourceTypeName: ResourceTypeName, resourceTableAlias: String = "r"): SQLSyntax = {
val r = ResourceTable.syntax(resourceTableAlias)
samsqls"""select ${r.id}
from ${ResourceTable as r}
where ${r.name} = ${resourceId} and ${r.resourceTypeId} = (${ResourceTypeTable.pkQuery(resourceTypeName)})"""
def loadResourcePK(resource: FullyQualifiedResourceId): SQLSyntax = {
val r = ResourceTable.syntax("r")
val rt = ResourceTypeTable.syntax("rt")
samsqls"select ${r.id} from ${ResourceTable as r} join ${ResourceTypeTable as rt} on ${r.resourceTypeId} = ${rt.id} where ${r.name} = ${resource.resourceId} and ${rt.name} = ${resource.resourceTypeName}"
}
}
Loading

0 comments on commit 7a427ed

Please sign in to comment.