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)
}
}
}
|