diff --git a/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changelog.xml b/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changelog.xml index ee3db6173..a81ed7a3e 100644 --- a/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changelog.xml +++ b/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changelog.xml @@ -24,4 +24,5 @@ + diff --git a/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changesets/20230302_auth0_id.xml b/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changesets/20230302_auth0_id.xml new file mode 100644 index 000000000..7a6ad7fbe --- /dev/null +++ b/src/main/resources/org/broadinstitute/dsde/sam/liquibase/changesets/20230302_auth0_id.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/DirectoryDAO.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/DirectoryDAO.scala index f8e0f2182..d7c50c6ec 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/DirectoryDAO.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/DirectoryDAO.scala @@ -42,6 +42,8 @@ trait DirectoryDAO { def loadUserByGoogleSubjectId(userId: GoogleSubjectId, samRequestContext: SamRequestContext): IO[Option[SamUser]] def loadUserByAzureB2CId(userId: AzureB2CId, samRequestContext: SamRequestContext): IO[Option[SamUser]] def setUserAzureB2CId(userId: WorkbenchUserId, b2cId: AzureB2CId, samRequestContext: SamRequestContext): IO[Unit] + def loadUserByAuth0Id(userId: Auth0Id, samRequestContext: SamRequestContext): IO[Option[SamUser]] + def setUserAuth0Id(userId: WorkbenchUserId, auth0Id: Auth0Id, samRequestContext: SamRequestContext): IO[Unit] def deleteUser(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Unit] def listUsersGroups(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Set[WorkbenchGroupIdentity]] diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala index 1a757474a..d1de5029b 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala @@ -341,7 +341,7 @@ class PostgresDirectoryDAO(protected val writeDbRef: DbReference, protected val val userColumn = UserTable.column val insertUserQuery = - samsql"insert into ${UserTable.table} (${userColumn.id}, ${userColumn.email}, ${userColumn.googleSubjectId}, ${userColumn.enabled}, ${userColumn.azureB2cId}, ${userColumn.acceptedTosVersion}) values (${user.id}, ${user.email}, ${user.googleSubjectId}, ${user.enabled}, ${user.azureB2CId}, ${user.acceptedTosVersion})" + samsql"insert into ${UserTable.table} (${userColumn.id}, ${userColumn.email}, ${userColumn.googleSubjectId}, ${userColumn.enabled}, ${userColumn.azureB2cId}, ${userColumn.acceptedTosVersion}), ${userColumn.auth0Id} values (${user.id}, ${user.email}, ${user.googleSubjectId}, ${user.enabled}, ${user.azureB2CId}, ${user.acceptedTosVersion}, ${user.auth0Id})" Try { insertUserQuery.update().apply() @@ -405,6 +405,35 @@ class PostgresDirectoryDAO(protected val writeDbRef: DbReference, protected val } } + override def loadUserByAuth0Id(userId: Auth0Id, samRequestContext: SamRequestContext): IO[Option[SamUser]] = + readOnlyTransaction("loadUserByAuth0Id", samRequestContext) { implicit session => + val userTable = UserTable.syntax + + val loadUserQuery = samsql"select ${userTable.resultAll} from ${UserTable as userTable} where ${userTable.auth0Id} = ${userId}" + loadUserQuery + .map(UserTable(userTable)) + .single() + .apply() + .map(UserTable.unmarshalUserRecord) + } + + override def setUserByAuth0Id(userId: WorkbenchUserId, auth0Id: Auth0Id, samRequestContext: SamRequestContext): IO[Unit] = + serializableWriteTransaction("setUserByAuth0Id", samRequestContext) { implicit session => + val u = UserTable.column + val results = + samsql"update ${UserTable.table} set ${u.auth0Id} = $auth0Id where ${u.id} = $userId and (${u.auth0Id} is null or ${u.auth0Id} = $auth0Id)" + .update() + .apply() + + if (results != 1) { + throw new WorkbenchException( + s"Cannot update auth0Id for user ${userId} because user does not exist or the auth0Id has already been set for this user" + ) + } else { + () + } + } + override def deleteUser(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Unit] = serializableWriteTransaction("deleteUser", samRequestContext) { implicit session => val userTable = UserTable.syntax diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/db/tables/UserTable.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/db/tables/UserTable.scala index aac63aa24..3903bb8ca 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/db/tables/UserTable.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/db/tables/UserTable.scala @@ -11,7 +11,8 @@ final case class UserRecord( googleSubjectId: Option[GoogleSubjectId], enabled: Boolean, azureB2cId: Option[AzureB2CId], - acceptedTosVersion: Option[String] + acceptedTosVersion: Option[String], + auth0Id: Option[Auth0Id] ) object UserTable extends SQLSyntaxSupportWithDefaultSamDB[UserRecord] { @@ -24,11 +25,20 @@ object UserTable extends SQLSyntaxSupportWithDefaultSamDB[UserRecord] { rs.stringOpt(e.googleSubjectId).map(GoogleSubjectId), rs.get(e.enabled), rs.stringOpt(e.azureB2cId).map(AzureB2CId), - rs.stringOpt(e.acceptedTosVersion) + rs.stringOpt(e.acceptedTosVersion), + rs.stringOpt(e.auth0Id).map(Auth0Id) ) def apply(o: SyntaxProvider[UserRecord])(rs: WrappedResultSet): UserRecord = apply(o.resultName)(rs) def unmarshalUserRecord(userRecord: UserRecord): SamUser = - SamUser(userRecord.id, userRecord.googleSubjectId, userRecord.email, userRecord.azureB2cId, userRecord.enabled, userRecord.acceptedTosVersion) + SamUser( + userRecord.id, + userRecord.googleSubjectId, + userRecord.email, + userRecord.azureB2cId, + userRecord.enabled, + userRecord.acceptedTosVersion, + userRecord.auth0Id + ) } diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/model/SamModel.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/model/SamModel.scala index 1e5385896..2cf19d99c 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/model/SamModel.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/model/SamModel.scala @@ -307,7 +307,8 @@ final case class SamUser( email: WorkbenchEmail, azureB2CId: Option[AzureB2CId], enabled: Boolean, - acceptedTosVersion: Option[String] + acceptedTosVersion: Option[String], + auth0Id: Option[Auth0Id] ) { def toUserIdInfo = UserIdInfo(id, email, googleSubjectId) } diff --git a/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/UserService.scala b/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/UserService.scala index d9f14edf6..0b240e8e1 100644 --- a/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/UserService.scala +++ b/src/main/scala/org/broadinstitute/dsde/workbench/sam/service/UserService.scala @@ -102,6 +102,9 @@ class UserService(val directoryDAO: DirectoryDAO, val cloudExtensions: CloudExte _ <- user.azureB2CId.traverse { azureB2CId => directoryDAO.setUserAzureB2CId(uid, azureB2CId, samRequestContext) } + _ <- user.auth0Id.traverse { auth0Id => + directoryDAO.setUserAuth0Id(uid, auth0Id, samRequestContext) + } _ <- IO.fromFuture(IO(cloudExtensions.onGroupUpdate(groups, samRequestContext))) updatedUser <- directoryDAO.loadUser(uid, samRequestContext) } yield updatedUser.getOrElse(