aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuicommon
diff options
context:
space:
mode:
authorvlad <vlad@driver.xyz>2017-07-13 02:27:55 -0700
committerJakob Odersky <jakob@driver.xyz>2017-07-19 17:28:54 -0700
commit7f7bd651122754a3df47894b64ddb0456561bbe7 (patch)
treea7f7a6acfccb1daa90f5a8afdd26ea3819600d69 /src/main/scala/xyz/driver/pdsuicommon
parent99ebbb98068324c2c26dd59484acbe9a8b62ae59 (diff)
downloadrest-query-7f7bd651122754a3df47894b64ddb0456561bbe7.tar.gz
rest-query-7f7bd651122754a3df47894b64ddb0456561bbe7.tar.bz2
rest-query-7f7bd651122754a3df47894b64ddb0456561bbe7.zip
Updates for authenticationv0.2.2
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuicommon')
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala18
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala8
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala9
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala36
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/User.scala88
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala6
6 files changed, 105 insertions, 60 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
index 6d78ba9..276ef9f 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
@@ -142,7 +142,7 @@ object ACL extends PhiLogging {
extends BaseACL(
label = "criterion",
create = Set(CriteriaCurator, TrialAdmin),
- read = Set(CriteriaCurator, TrialAdmin),
+ read = Set(CriteriaCurator, TrialAdmin, RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist),
update = Set(CriteriaCurator, TrialAdmin),
delete = Set(CriteriaCurator, TrialAdmin)
)
@@ -227,28 +227,26 @@ object ACL extends PhiLogging {
delete: AclCheck = Forbid) {
def isCreateAllow()(implicit requestContext: AuthenticatedRequestContext): Boolean = {
- check("create", create)(requestContext.executor.role)
+ check("create", create)(requestContext.executor.roles)
}
def isReadAllow()(implicit requestContext: AuthenticatedRequestContext): Boolean = {
- check("read", read)(requestContext.executor.role)
+ check("read", read)(requestContext.executor.roles)
}
def isUpdateAllow()(implicit requestContext: AuthenticatedRequestContext): Boolean = {
- check("update", update)(requestContext.executor.role)
+ check("update", update)(requestContext.executor.roles)
}
def isDeleteAllow()(implicit requestContext: AuthenticatedRequestContext): Boolean = {
- check("delete", delete)(requestContext.executor.role)
+ check("delete", delete)(requestContext.executor.roles)
}
- private def check(action: String, isAllowed: AclCheck)(executorRole: Role): Boolean = {
+ private def check(action: String, isAllowed: AclCheck)(executorRoles: Set[Role]): Boolean = {
loggedError(
- isAllowed(executorRole),
- phi"$executorRole has no access to ${Unsafe(action)} a ${Unsafe(label)}"
+ executorRoles.exists(isAllowed),
+ phi"${Unsafe(executorRoles.mkString(", "))} has no access to ${Unsafe(action)} a ${Unsafe(label)}"
)
}
-
}
-
}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala
index e9da132..16265c6 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala
@@ -1,11 +1,14 @@
package xyz.driver.pdsuicommon.auth
+import xyz.driver.entities.users.UserInfo
import xyz.driver.pdsuicommon.logging._
import xyz.driver.pdsuicommon.domain.User
-class AuthenticatedRequestContext(val executor: User, override val requestId: RequestId, val authToken: String = "")
+class AuthenticatedRequestContext(val driverUser: UserInfo, override val requestId: RequestId, val authToken: String)
extends AnonymousRequestContext(requestId) {
+ val executor: User = new User(driverUser)
+
override def equals(that: Any): Boolean = {
that.getClass == this.getClass && {
val another = that.asInstanceOf[AuthenticatedRequestContext]
@@ -22,7 +25,8 @@ class AuthenticatedRequestContext(val executor: User, override val requestId: Re
object AuthenticatedRequestContext {
- def apply(executor: User, authToken: String) = new AuthenticatedRequestContext(executor, RequestId(), authToken)
+ def apply(driverUser: UserInfo, authToken: String = "") =
+ new AuthenticatedRequestContext(driverUser, RequestId(), authToken)
implicit def toPhiString(x: AuthenticatedRequestContext): PhiString = {
phi"AuthenticatedRequestContext(executor=${x.executor}, requestId=${x.requestId})"
diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala
index 159c144..a9430e3 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala
@@ -72,6 +72,14 @@ final case class Computation[+R, +T](future: Future[Either[R, T]]) {
})
}
+ def mapAll[R2, T2](onLeft: R => Computation[R2, T2])(onRight: T => Computation[R2, T2])(
+ onFailure: () => Computation[R2, T2])(implicit ec: ExecutionContext): Computation[R2, T2] = {
+
+ Computation(future.flatMap(_.fold(onLeft, onRight).future).recoverWith {
+ case _ => onFailure().future
+ })
+ }
+
def andThen(f: T => Any)(implicit ec: ExecutionContext): Computation[R, T] = map { a =>
f(a)
a
@@ -98,7 +106,6 @@ final case class Computation[+R, +T](future: Future[Either[R, T]]) {
case Left(x) => x
case Right(x) => x
}
-
}
object Computation {
diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala
deleted file mode 100644
index 337d925..0000000
--- a/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-package xyz.driver.pdsuicommon.domain
-
-import java.nio.charset.Charset
-
-import org.mindrot.jbcrypt.BCrypt
-
-final case class PasswordHash(value: Array[Byte]) {
-
- lazy val hashString: String = new String(value, Charset.forName("UTF-8"))
-
- override def toString: String = {
- s"${this.getClass.getSimpleName}($hashString)"
- }
-
- override def equals(that: Any): Boolean = {
- that match {
- case thatHash: PasswordHash => java.util.Arrays.equals(this.value, thatHash.value)
- case _ => false
- }
- }
-
- override def hashCode(): Int =
- 42 + java.util.Arrays.hashCode(this.value)
-
- def is(password: String): Boolean =
- BCrypt.checkpw(password, hashString)
-}
-
-object PasswordHash {
-
- def apply(password: String): PasswordHash =
- new PasswordHash(getHash(password))
-
- private def getHash(str: String): Array[Byte] =
- BCrypt.hashpw(str, BCrypt.gensalt()).getBytes(Charset.forName("UTF-8"))
-}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
index 4920176..654af1a 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
@@ -2,7 +2,7 @@ package xyz.driver.pdsuicommon.domain
import java.math.BigInteger
import java.security.SecureRandom
-import java.time.LocalDateTime
+import java.time.{Instant, LocalDateTime, ZoneId}
import xyz.driver.pdsuicommon.logging._
import xyz.driver.pdsuicommon.domain.User.Role
@@ -11,10 +11,22 @@ import xyz.driver.pdsuicommon.utils.Utils
final case class User(id: StringId[User],
email: Email,
name: String,
- role: Role,
- passwordHash: PasswordHash,
+ roles: Set[Role],
latestActivity: Option[LocalDateTime],
- deleted: Option[LocalDateTime])
+ deleted: Option[LocalDateTime]) {
+
+ def this(driverUser: xyz.driver.entities.users.UserInfo) {
+ this(
+ id = StringId[xyz.driver.pdsuicommon.domain.User](driverUser.id.value),
+ email = Email(driverUser.email.toString),
+ name = driverUser.name.toString,
+ roles = driverUser.roles.flatMap(User.mapRoles),
+ latestActivity =
+ driverUser.lastLoginTime.map(t => Instant.ofEpochMilli(t.millis).atZone(ZoneId.of("Z")).toLocalDateTime),
+ deleted = Option.empty[LocalDateTime]
+ )
+ }
+}
object User {
@@ -74,7 +86,7 @@ object User {
implicit def toPhiString(x: User): PhiString = {
import x._
- phi"User(id=$id, role=$role)"
+ phi"User(id=$id, roles=${Unsafe(roles.map(_.toString).mkString(", "))})"
}
// SecureRandom is thread-safe, see the implementation
@@ -82,4 +94,70 @@ object User {
def createPassword: String = new BigInteger(240, random).toString(32)
+ def mapRoles(coreRole: xyz.driver.core.auth.Role): Set[xyz.driver.pdsuicommon.domain.User.Role] = {
+ coreRole match {
+ case xyz.driver.entities.auth.AdministratorRole =>
+ Set(
+ xyz.driver.pdsuicommon.domain.User.Role.SystemUser,
+ xyz.driver.pdsuicommon.domain.User.Role.RecordAdmin,
+ xyz.driver.pdsuicommon.domain.User.Role.TrialAdmin,
+ xyz.driver.pdsuicommon.domain.User.Role.TreatmentMatchingAdmin
+ )
+ case xyz.driver.entities.auth.RecordAdmin =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.RecordAdmin)
+ case xyz.driver.entities.auth.RecordCleaner =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.RecordCleaner)
+ case xyz.driver.entities.auth.RecordOrganizer =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.RecordOrganizer)
+ case xyz.driver.entities.auth.DocumentExtractor =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.DocumentExtractor)
+ case xyz.driver.entities.auth.TrialSummarizer =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.TrialSummarizer)
+ case xyz.driver.entities.auth.CriteriaCurator =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.CriteriaCurator)
+ case xyz.driver.entities.auth.TrialAdmin =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.TrialAdmin)
+ case xyz.driver.entities.auth.EligibilityVerifier =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.EligibilityVerifier)
+ case xyz.driver.entities.auth.TreatmentMatchingAdmin =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.TreatmentMatchingAdmin)
+ case xyz.driver.entities.auth.RoutesCurator =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.RoutesCurator)
+ case xyz.driver.entities.auth.ResearchOncologist =>
+ Set(xyz.driver.pdsuicommon.domain.User.Role.ResearchOncologist)
+ case _ =>
+ Set.empty[xyz.driver.pdsuicommon.domain.User.Role]
+ }
+ }
+
+ def mapRolesToDriver(pdsuiRole: xyz.driver.pdsuicommon.domain.User.Role): Set[xyz.driver.core.auth.Role] = {
+ pdsuiRole match {
+ case xyz.driver.pdsuicommon.domain.User.Role.SystemUser =>
+ Set(xyz.driver.entities.auth.AdministratorRole)
+ case xyz.driver.pdsuicommon.domain.User.Role.RecordAdmin =>
+ Set(xyz.driver.entities.auth.RecordAdmin)
+ case xyz.driver.pdsuicommon.domain.User.Role.RecordCleaner =>
+ Set(xyz.driver.entities.auth.RecordCleaner)
+ case xyz.driver.pdsuicommon.domain.User.Role.RecordOrganizer =>
+ Set(xyz.driver.entities.auth.RecordOrganizer)
+ case xyz.driver.pdsuicommon.domain.User.Role.DocumentExtractor =>
+ Set(xyz.driver.entities.auth.DocumentExtractor)
+ case xyz.driver.pdsuicommon.domain.User.Role.TrialSummarizer =>
+ Set(xyz.driver.entities.auth.TrialSummarizer)
+ case xyz.driver.pdsuicommon.domain.User.Role.CriteriaCurator =>
+ Set(xyz.driver.entities.auth.CriteriaCurator)
+ case xyz.driver.pdsuicommon.domain.User.Role.TrialAdmin =>
+ Set(xyz.driver.entities.auth.TrialAdmin)
+ case xyz.driver.pdsuicommon.domain.User.Role.EligibilityVerifier =>
+ Set(xyz.driver.entities.auth.EligibilityVerifier)
+ case xyz.driver.pdsuicommon.domain.User.Role.TreatmentMatchingAdmin =>
+ Set(xyz.driver.entities.auth.TreatmentMatchingAdmin)
+ case xyz.driver.pdsuicommon.domain.User.Role.RoutesCurator =>
+ Set(xyz.driver.entities.auth.RoutesCurator)
+ case xyz.driver.pdsuicommon.domain.User.Role.ResearchOncologist =>
+ Set(xyz.driver.entities.auth.ResearchOncologist)
+ case _ =>
+ Set.empty[xyz.driver.core.auth.Role]
+ }
+ }
}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala b/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala
index 9800903..8231ddb 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala
@@ -40,12 +40,6 @@ object Serialization {
private val emailJsonWrites: Writes[Email] = Writes(email => JsString(email.value))
implicit val emailJsonFormat: Format[Email] = Format(emailJsonReads, emailJsonWrites)
- private val passwordHashJsonReads: Reads[PasswordHash] =
- Reads.StringReads.map(hash => PasswordHash(hash.getBytes("UTF-8")))
- private val passwordHashJsonWrites: Writes[PasswordHash] = Writes(
- passwordHash => JsString(passwordHash.value.toString))
- implicit val passwordHashJsonFormat: Format[PasswordHash] = Format(passwordHashJsonReads, passwordHashJsonWrites)
-
private val caseIdJsonReads: Reads[CaseId] = Reads.StringReads.map(CaseId(_))
private val caseIdJsonWrites: Writes[CaseId] = Writes(caseId => JsString(caseId.id))
implicit val caseIdJsonFormat: Format[CaseId] = Format(caseIdJsonReads, caseIdJsonWrites)