Skip to content

Instantly share code, notes, and snippets.

@halfninja
Created November 2, 2015 11:51
Show Gist options
  • Save halfninja/0ca39e1afb95e10d82ce to your computer and use it in GitHub Desktop.
Save halfninja/0ca39e1afb95e10d82ce to your computer and use it in GitHub Desktop.
Prototype compile-time security checking. Checks are done outside of the service, but the compiler will prevent you from calling the methods unless you have acquired authorization from the auth service.
import scala.annotation.implicitNotFound
@implicitNotFound("Required authorization not found.")
case class Authorization[+A <: Role]()
object Authorization {
def of[T <: Role]: Authorization[T] = new Authorization[T]()
}
// Whatever set of roles you like
trait Role
trait Admin extends Role
trait Sysadmin extends Role
trait President extends Role
trait Saxophonist extends Role
// A service that you need permission to use
class SecureService {
def broadcast(msg: String)(implicit auth: Authorization[Sysadmin]): Unit =
println(s"*** ${msg} ***")
// An action that requires sysadmin AND president
def deleteEverything()(implicit auth: Authorization[President]): Unit =
println("Goodbye, everything!")
}
/** Some security service that checks if this user has the given role */
class AuthService {
/**
* Returns a type if you have all the given roles.
*/
def checkRoles[T <: Role](user: String): Option[Authorization[_ <: T]] =
Some(Authorization.of[T])
}
// Example use
val service = new SecureService()
val auth = new AuthService()
auth.checkRoles[President with Sysadmin]("robonixon").map { implicit s =>
service.broadcast("About to delete everything")
service.deleteEverything()
}.getOrElse {
println("Stairway denied")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment