aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlad <vlad@driver.xyz>2017-07-13 02:27:55 -0700
committervlad <vlad@driver.xyz>2017-07-13 02:27:55 -0700
commit93eb4829c0d11959709e18a7b489343550633e83 (patch)
tree49ced7ef72180cbd29e2a8126684dedbd958a00c
parent3d902b5197db861c30325c159dc10cfb211ae209 (diff)
downloadrest-query-93eb4829c0d11959709e18a7b489343550633e83.tar.gz
rest-query-93eb4829c0d11959709e18a7b489343550633e83.tar.bz2
rest-query-93eb4829c0d11959709e18a7b489343550633e83.zip
Updates for authentication
-rw-r--r--build.sbt2
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala24
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala6
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/User.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala33
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala19
-rw-r--r--src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala2
7 files changed, 46 insertions, 44 deletions
diff --git a/build.sbt b/build.sbt
index 7772f5b..c0aaf32 100644
--- a/build.sbt
+++ b/build.sbt
@@ -13,6 +13,8 @@ lazy val core = (project in file("."))
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.8.3",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.8.4",
"com.typesafe.play" %% "play" % "2.5.15",
+ "xyz.driver" %% "core" % "0.13.22",
+ "xyz.driver" %% "domain-model" % "0.11.1",
"org.davidbild" %% "tristate-core" % "0.2.0",
"org.davidbild" %% "tristate-play" % "0.2.0" exclude ("com.typesafe.play", "play-json"),
"org.asynchttpclient" % "async-http-client" % "2.0.24",
diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala
index 6d78ba9..0438dfc 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,28 @@ 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 = {
- loggedError(
- isAllowed(executorRole),
- phi"$executorRole has no access to ${Unsafe(action)} a ${Unsafe(label)}"
- )
+ private def check(action: String, isAllowed: AclCheck)(executorRoles: Set[Role]): Boolean = {
+ executorRoles.exists { role =>
+ loggedError(
+ isAllowed(role),
+ phi"$role 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 a1f93cd..912061a 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala
@@ -1,9 +1,10 @@
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)
+class AuthenticatedRequestContext(val executor: User, val driverUser: UserInfo, override val requestId: RequestId)
extends AnonymousRequestContext(requestId) {
override def equals(that: Any): Boolean = {
@@ -22,7 +23,8 @@ class AuthenticatedRequestContext(val executor: User, override val requestId: Re
object AuthenticatedRequestContext {
- def apply(executor: User) = new AuthenticatedRequestContext(executor, RequestId())
+ def apply(executor: User, driverUser: UserInfo) =
+ new AuthenticatedRequestContext(executor, driverUser, RequestId())
implicit def toPhiString(x: AuthenticatedRequestContext): PhiString = {
phi"AuthenticatedRequestContext(executor=${x.executor}, requestId=${x.requestId})"
diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
index 8d2d86d..ffc4bf9 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
@@ -11,7 +11,7 @@ import xyz.driver.pdsuicommon.utils.Utils
case class User(id: StringId[User],
email: Email,
name: String,
- role: Role,
+ roles: Set[Role],
passwordHash: PasswordHash,
latestActivity: Option[LocalDateTime],
deleted: Option[LocalDateTime])
@@ -74,7 +74,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
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala
index f31efb3..05395b4 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala
@@ -11,9 +11,10 @@ import scala.collection._
import scala.util.Try
import User._
import xyz.driver.pdsuicommon.json.JsonValidationException
+import xyz.driver.pdsuicommon.json.Serialization.seqJsonFormat
import xyz.driver.pdsuicommon.validation.{AdditionalConstraints, JsonValidationErrors}
-final case class ApiPartialUser(email: Option[String], name: Option[String], roleId: Option[String]) {
+final case class ApiPartialUser(email: Option[String], name: Option[String], roles: Option[Seq[String]]) {
def applyTo(orig: User): Try[User] = Try {
val validation = Map(
@@ -33,9 +34,9 @@ final case class ApiPartialUser(email: Option[String], name: Option[String], rol
def toDomain(id: StringId[User] = StringId(UUID.randomUUID().toString)): Try[User] = Try {
val validation = Map(
- JsPath \ "email" -> AdditionalConstraints.optionNonEmptyConstraint(email),
- JsPath \ "name" -> AdditionalConstraints.optionNonEmptyConstraint(name),
- JsPath \ "roleId" -> AdditionalConstraints.optionNonEmptyConstraint(roleId)
+ JsPath \ "email" -> AdditionalConstraints.optionNonEmptyConstraint(email),
+ JsPath \ "name" -> AdditionalConstraints.optionNonEmptyConstraint(name),
+ JsPath \ "roles" -> AdditionalConstraints.optionNonEmptyConstraint(roles)
)
val validationErrors: JsonValidationErrors = validation.collect({
@@ -48,7 +49,7 @@ final case class ApiPartialUser(email: Option[String], name: Option[String], rol
id = id,
email = userEmail,
name = name.get,
- role = roleId.map(UserRole.roleFromString).get,
+ roles = roles.toSeq.flatMap(_.map(UserRole.roleFromString)).toSet,
passwordHash = PasswordHash(createPassword),
latestActivity = None,
deleted = None
@@ -63,17 +64,15 @@ object ApiPartialUser {
implicit val format: Format[ApiPartialUser] = (
(JsPath \ "email").formatNullable[String](Format(Reads.email, Writes.StringWrites)) and
- (JsPath \ "name").formatNullable[String](Format(
- Reads.filterNot[String](ValidationError("Username is too long (max length is 255 chars)", 255))(_.length > 255),
- Writes.StringWrites
- )) and
- (JsPath \ "roleId").formatNullable[String](
- Format(Reads
- .of[String]
- .filter(ValidationError("unknown role"))({
- case x if UserRole.roleFromString.isDefinedAt(x) => true
- case _ => false
- }),
- Writes.of[String]))
+ (JsPath \ "name").formatNullable[String](
+ Format(
+ Reads.filterNot[String](ValidationError("Username is too long (max length is 255 chars)", 255))(
+ _.length > 255),
+ Writes.StringWrites
+ )) and
+ (JsPath \ "roleId").formatNullable[Seq[String]](
+ Format(
+ seqJsonFormat[String].filter(ValidationError("unknown role"))(_.forall(UserRole.roleFromString.isDefinedAt)),
+ Writes.of[Seq[String]]))
)(ApiPartialUser.apply, unlift(ApiPartialUser.unapply))
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala
index 8dbedfe..c21edd1 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala
@@ -3,14 +3,17 @@ package xyz.driver.pdsuidomain.formats.json.user
import java.time.{ZoneId, ZonedDateTime}
import xyz.driver.pdsuicommon.domain.User
+import xyz.driver.pdsuicommon.json.Serialization.seqJsonFormat
import play.api.data.validation.ValidationError
import play.api.libs.functional.syntax._
import play.api.libs.json._
+import scala.collection.Seq
+
final case class ApiUser(id: String,
email: String,
name: String,
- roleId: String,
+ roles: Seq[String],
latestActivity: Option[ZonedDateTime])
object ApiUser {
@@ -19,14 +22,10 @@ object ApiUser {
(JsPath \ "id").format[String] and
(JsPath \ "email").format[String](Reads.email) and
(JsPath \ "name").format[String] and
- (JsPath \ "roleId").format[String](
- Format(Reads
- .of[String]
- .filter(ValidationError("unknown role"))({
- case x if UserRole.roleFromString.isDefinedAt(x) => true
- case _ => false
- }),
- Writes.of[String])) and
+ (JsPath \ "roles").format(
+ Format(
+ seqJsonFormat[String].filter(ValidationError("unknown role"))(_.forall(UserRole.roleFromString.isDefinedAt)),
+ Writes.of[Seq[String]])) and
(JsPath \ "latestActivity").formatNullable[ZonedDateTime]
)(ApiUser.apply, unlift(ApiUser.unapply))
@@ -34,7 +33,7 @@ object ApiUser {
user.id.id,
user.email.value,
user.name,
- UserRole.roleToString(user.role),
+ user.roles.map(UserRole.roleToString).toSeq,
user.latestActivity.map(ZonedDateTime.of(_, ZoneId.of("Z")))
)
}
diff --git a/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala
index 1cfb70b..54c46c3 100644
--- a/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala
+++ b/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala
@@ -19,7 +19,7 @@ trait BaseSuite extends FreeSpecLike with DiffUtils with ScalaFutures {
id = StringId("2001"),
email = Email(email),
name = "Test",
- role = role,
+ roles = Set(role),
passwordHash = PasswordHash(password),
latestActivity = Some(LocalDateTime.now(ZoneId.of("Z"))),
deleted = None