aboutsummaryrefslogblamecommitdiff
path: root/src/main/scala/com/drivergrp/core/auth.scala
blob: 84d943d4edec2969ae3902e805570756b996cb33 (plain) (tree)



































































































                                                                                                                   
package com.drivergrp.core

object auth {

  final case class FullName[+T](firstName: Name[T], middleName: Name[T], lastName: Name[T])

  final case class Email(username: String, domain: String) {
    override def toString = username + "@" + domain
  }

  trait Role {
    val id: Id[Role]
    val name: Name[Role]

    def canEditReport: Boolean    = false
    def canSignOffReport: Boolean = false
    def canAssignRoles: Boolean   = false
  }

  case object ObserverRole extends Role {
    val id   = Id(1L)
    val name = Name("observer")
  }

  case object PatientRole extends Role {
    val id   = Id(2L)
    val name = Name("patient")
  }

  case object CuratorRole extends Role {
    val id   = Id(3L)
    val name = Name("curator")

    override def canEditReport: Boolean = true
  }

  case object PathologistRole extends Role {
    val id   = Id(4L)
    val name = Name("pathologist")

    override def canEditReport: Boolean    = true
    override def canSignOffReport: Boolean = true
  }

  case object AdministratorRole extends Role {
    val id   = Id(5L)
    val name = Name("administrator")

    override def canEditReport: Boolean    = true
    override def canSignOffReport: Boolean = true
    override def canAssignRoles: Boolean   = true
  }

  final case class Avatar(id: Id[Avatar], name: Name[Avatar])

  final case class User(id: Id[User], name: FullName[User], email: Email, avatar: Option[Avatar], roles: Set[Role])

  val TestUser = User(Id[User](1L),
                      FullName[User](Name("James"), Name("Dewey"), Name("Watson")),
                      Email("j.watson", "uchicago.edu"),
                      Some(Avatar(Id[Avatar](1L), Name[Avatar]("Coolface"))),
                      Set(PathologistRole))

  final case class Macaroon(value: String)

  final case class Base64[T](value: String)

  final case class AuthToken(value: Base64[Macaroon])

  object directives {
    import akka.http.scaladsl.server._
    import Directives._

    val AuthenticationTokenHeader = "WWW-Authenticate"

    def authorize(role: Role): Directive1[Id[User]] = {
      headerValueByName(AuthenticationTokenHeader).flatMap { tokenValue =>
        val token = AuthToken(Base64[Macaroon](tokenValue))

        extractUser(token) match {
          case Some(user) =>
            if (user.roles.contains(role)) provide(user.id)
            else reject(ValidationRejection(s"User does not have the required ${role.name} role"))
          case None =>
            reject(ValidationRejection(s"Wasn't able to extract user for the token provided"))
        }
      }
    }

    def extractToken: Directive1[AuthToken] = {
      headerValueByName(AuthenticationTokenHeader).flatMap { token =>
        provide(AuthToken(Base64[Macaroon](token)))
      }
    }

    def extractUser(authToken: AuthToken): Option[User] = {
      Some(TestUser)
    }
  }
}