diff --git a/src/main/scala/org/broadinstitute/dsde/firecloud/FireCloudConfig.scala b/src/main/scala/org/broadinstitute/dsde/firecloud/FireCloudConfig.scala index 4033a9de9..e78494efb 100644 --- a/src/main/scala/org/broadinstitute/dsde/firecloud/FireCloudConfig.scala +++ b/src/main/scala/org/broadinstitute/dsde/firecloud/FireCloudConfig.scala @@ -192,8 +192,10 @@ object FireCloudConfig { val config = configObject.toConfig val rawlsGroup = config.getString("rawlsGroup") val fileName = config.getString("fileName") + val phsId = config.getString("phsId") + val consentGroup = config.getString("consentGroup") - NihAllowlist(name, WorkbenchGroupName(rawlsGroup), fileName) + NihAllowlist(name, WorkbenchGroupName(rawlsGroup), fileName, DbGapPermission(PhsId(phsId), ConsentGroup(consentGroup))) } }.toSet val enabled = nih.optionalBoolean("enabled").getOrElse(true) diff --git a/src/main/scala/org/broadinstitute/dsde/firecloud/service/NihService.scala b/src/main/scala/org/broadinstitute/dsde/firecloud/service/NihService.scala index e48b322a5..9948f11c5 100644 --- a/src/main/scala/org/broadinstitute/dsde/firecloud/service/NihService.scala +++ b/src/main/scala/org/broadinstitute/dsde/firecloud/service/NihService.scala @@ -45,7 +45,7 @@ case class NihStatus(linkedNihUsername: Option[String] = None, linkExpireTime: Option[Long] = None ) -case class NihAllowlist(name: String, groupToSync: WorkbenchGroupName, fileName: String) +case class NihAllowlist(name: String, groupToSync: WorkbenchGroupName, fileName: String, dbGapPermission: DbGapPermission) case class NihDatasetPermission(name: String, authorized: Boolean) @@ -252,11 +252,13 @@ class NihService(val samDao: SamDAO, // This syncs the specified allowlist in full private def syncNihAllowlistAllUsers(nihAllowlist: NihAllowlist): Future[Unit] = { val allowlistUsers = downloadNihAllowlist(nihAllowlist) + val dbGapSamGroup = FireCloudConfig.Nih.dbGapPermissionToGroup.get(nihAllowlist.dbGapPermission).map(WorkbenchGroupName) for { + samEmails <- Future.traverse(dbGapSamGroup.toList)( samDao.getGroupEmail(_)(getAdminAccessToken)) ecmEmails <- getNihAllowlistTerraEmailsFromEcm(allowlistUsers) thurloeEmails <- getNihAllowlistTerraEmailsFromThurloe(allowlistUsers) - members = ecmEmails ++ thurloeEmails + members = ecmEmails ++ thurloeEmails ++ samEmails _ <- ensureAllowlistGroupsExists() // The request to Sam to completely overwrite the group with the list of actively linked users on the allowlist _ <- samDao.overwriteGroupMembers(nihAllowlist.groupToSync, ManagedGroupRoles.Member, members.toList)( diff --git a/src/test/resources/reference.conf b/src/test/resources/reference.conf index adcbde81f..27ac1d289 100644 --- a/src/test/resources/reference.conf +++ b/src/test/resources/reference.conf @@ -63,15 +63,21 @@ nih { whitelists = { "TARGET" { "fileName":"target-whitelist.txt", - "rawlsGroup":"TARGET-dbGaP-Authorized" + "rawlsGroup":"TARGET-dbGaP-Authorized", + "phsId":"phs002410", + "consentGroup":"c1" }, "TCGA" { "fileName":"tcga-whitelist.txt", - "rawlsGroup":"TCGA-dbGaP-Authorized" + "rawlsGroup":"TCGA-dbGaP-Authorized", + "phsId":"phs002409", + "consentGroup":"c1" }, "BROKEN" { "fileName":"broken-whitelist.txt", - "rawlsGroup":"this-doesnt-matter" + "rawlsGroup":"this-doesnt-matter", + "phsId":"phs001234", + "consentGroup":"c2" } } rasIssuer = "https://stsstg.nih.gov" diff --git a/src/test/scala/org/broadinstitute/dsde/firecloud/service/NihServiceUnitSpec.scala b/src/test/scala/org/broadinstitute/dsde/firecloud/service/NihServiceUnitSpec.scala index 9afd0e52d..f19112bd0 100644 --- a/src/test/scala/org/broadinstitute/dsde/firecloud/service/NihServiceUnitSpec.scala +++ b/src/test/scala/org/broadinstitute/dsde/firecloud/service/NihServiceUnitSpec.scala @@ -76,6 +76,7 @@ class NihServiceUnitSpec extends AnyFlatSpec with Matchers with BeforeAndAfterEa val userTcgaAndTarget = genSamUser(); val userTcgaOnly = genSamUser(); val userTargetOnly = genSamUser(); + val userDbGap = genSamUser(); // DateTimes must be modified in seconds instead of days to match implementation val secondsIn30Days = 30.days.toSeconds.toInt @@ -272,6 +273,54 @@ class NihServiceUnitSpec extends AnyFlatSpec with Matchers with BeforeAndAfterEa verifyTargetGroupSynced() } + it should "sync all users by combining dbGap group members with ECM and Thurloe" in { + when(ecmDao.getActiveLinkedEraAccounts(ArgumentMatchers.eq(UserInfo(adminAccessToken, "")))) + .thenReturn(Future.successful(Seq(userTargetOnlyLinkedAccount))) + when(thurloeDao.getAllUserValuesForKey(ArgumentMatchers.eq("linkedNihUsername"))) + .thenReturn( + Future.successful( + linkedAccountsBySamUserId + .removed(WorkbenchUserId(userTargetOnlyLinkedAccount.userId)) + .map(tup => (tup._1.value, tup._2.linkedExternalId)) + ) + ) + when(thurloeDao.getAllUserValuesForKey(ArgumentMatchers.eq("linkExpireTime"))) + .thenReturn( + Future.successful( + linkedAccountsBySamUserId + .removed(WorkbenchUserId(userTargetOnlyLinkedAccount.userId)) + .map(tup => (tup._1.value, (tup._2.linkExpireTime.getMillis / 1000L).toString)) + ) + ) + when(samDao.getGroupEmail(any())(any())).thenReturn( + Future.successful( + userDbGap.email + ) + ) + + val emailsToSync = Set(userTcgaAndTarget.email, userTargetOnly.email, userDbGap.email) + val nihStatus = Await + .result(nihService.syncAllowlistAllUsers("TARGET"), Duration.Inf) + .asInstanceOf[PerRequest.RequestComplete[StatusCode]] + .response + + nihStatus should be(StatusCodes.NoContent) + verify(googleDao, never()).getBucketObjectAsInputStream(FireCloudConfig.Nih.whitelistBucket, "tcga-whitelist.txt") + verify(googleDao, times(1)) + .getBucketObjectAsInputStream(FireCloudConfig.Nih.whitelistBucket, "target-whitelist.txt") + verify(samDao, times(1)).overwriteGroupMembers( + ArgumentMatchers.eq(WorkbenchGroupName("TARGET-dbGaP-Authorized")), + ArgumentMatchers.eq(ManagedGroupRoles.Member), + ArgumentMatchers.argThat((list: List[WorkbenchEmail]) => list.toSet.equals(emailsToSync)) + )(ArgumentMatchers.eq(UserInfo(adminAccessToken, ""))) + verify(samDao, never()).overwriteGroupMembers( + ArgumentMatchers.eq(WorkbenchGroupName("other-group")), + ArgumentMatchers.eq(ManagedGroupRoles.Member), + ArgumentMatchers.argThat((list: List[WorkbenchEmail]) => list.toSet.equals(emailsToSync)) + )(ArgumentMatchers.eq(UserInfo(adminAccessToken, ""))) + } + + it should "respond with NOT FOUND if no allowlist is found" in { val nihStatus = Await .result(nihService.syncAllowlistAllUsers("NOT_FOUND"), Duration.Inf)