aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/com/drivergrp/core/auth.scala
blob: 84d943d4edec2969ae3902e805570756b996cb33 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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)
    }
  }
}