From 64f8223d2e63bbba2feb7ef1ce4eb17bf25bde7c Mon Sep 17 00:00:00 2001 From: Tristan Garwood Date: Fri, 13 Oct 2023 10:11:43 -0400 Subject: [PATCH] ID-813 Add TOS rolling acceptance window. --- .../dsde/workbench/sam/config/AppConfig.scala | 5 ++++- .../workbench/sam/config/TermsOfServiceConfig.scala | 10 ++++++++-- .../dsde/workbench/sam/service/TosService.scala | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/AppConfig.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/AppConfig.scala index a0f1c0a53..601711423 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/AppConfig.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/AppConfig.scala @@ -12,6 +12,7 @@ import org.broadinstitute.dsde.workbench.sam.config.GoogleServicesConfig.googleS import org.broadinstitute.dsde.workbench.sam.dataAccess.DistributedLockConfig import org.broadinstitute.dsde.workbench.sam.model._ +import java.time.Instant import scala.concurrent.duration.Duration /** Created by dvoet on 7/18/17. @@ -119,7 +120,9 @@ object AppConfig { config.getAs[Boolean]("isTosEnabled").getOrElse(true), config.getBoolean("isGracePeriodEnabled"), config.getString("version"), - config.getString("baseUrl") + config.getString("baseUrl"), + // Must be a valid UTC datetime string in ISO 8601 format ex: 2007-12-03T10:15:30.00Z + Instant.parse(config.getString("rollingAcceptanceWindowExpirationDatetime")) ) } diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/TermsOfServiceConfig.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/TermsOfServiceConfig.scala index 2c99ac679..c63e98fb4 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/TermsOfServiceConfig.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/config/TermsOfServiceConfig.scala @@ -1,12 +1,18 @@ package org.broadinstitute.dsde.workbench.sam.config +import java.time.Instant + /** Terms of Service configuration. * @param isGracePeriodEnabled * Set to true if the grace period for ToS acceptance is active * @param version * The latest version of the Terms of Service - * @param url + * @param baseUrl * The url to the Terra Terms of Service. Used for validation and will be displayed to user in error messages + * @param rollingAcceptanceWindowExpiration + * The expiration time for the rolling acceptance window. If the user has not accepted the new ToS by this time, + * they will be denied access to the system. Must be a valid UTC datetime string in ISO 8601 format + * example: 2007-12-03T10:15:30.00Z */ -case class TermsOfServiceConfig(isTosEnabled: Boolean, isGracePeriodEnabled: Boolean, version: String, baseUrl: String) +case class TermsOfServiceConfig(isTosEnabled: Boolean, isGracePeriodEnabled: Boolean, version: String, baseUrl: String, rollingAcceptanceWindowExpiration: Instant) diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/TosService.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/TosService.scala index 5c0216197..247aaaf92 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/TosService.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/TosService.scala @@ -21,6 +21,7 @@ import java.io.{FileNotFoundException, IOException} import scala.concurrent.{Await, ExecutionContext} import java.util.concurrent.TimeUnit import scala.concurrent.duration.Duration +import java.time.Instant import scala.io.Source class TosService(val directoryDao: DirectoryDAO, val tosConfig: TermsOfServiceConfig)( @@ -60,13 +61,15 @@ class TosService(val directoryDao: DirectoryDAO, val tosConfig: TermsOfServiceCo /** If grace period enabled, don't check ToS, return true If ToS disabled, return true Otherwise return true if user has accepted ToS, or is a service account */ private def tosAcceptancePermitsSystemUsage(user: SamUser, userTos: Option[SamUserTos]): Boolean = { + val now = Instant.now() val userIsServiceAccount = StandardSamUserDirectives.SAdomain.matches(user.email.value) // Service Account users do not need to accept ToS val userIsPermitted = userTos.exists { tos => val userHasAcceptedLatestVersion = userHasAcceptedLatestTosVersion(Option(tos)) val userCanUseSystemUnderGracePeriod = tosConfig.isGracePeriodEnabled && tos.action == TosTable.ACCEPT val tosDisabled = !tosConfig.isTosEnabled + val userInsideOfRollingAcceptanceWindow = tosConfig.rollingAcceptanceWindowExpiration.isAfter(now) - userHasAcceptedLatestVersion || userCanUseSystemUnderGracePeriod || tosDisabled + userHasAcceptedLatestVersion || userInsideOfRollingAcceptanceWindow || userCanUseSystemUnderGracePeriod || tosDisabled } userIsPermitted || userIsServiceAccount