AuthZ as an Effect

January 13, 2019

sealed trait AuthZError
case object InsufficientPermissions extends AuthZError

class AuthZ[A]( requiredPermissions: Set[String]
              , k: => A
              ) {
  def run(permissions: Set[String]): Either[AuthZError, A] =
    if ((requiredPermissions -- permissions).isEmpty) {
      Right(k)
    } else {
      Left(InsufficientPermissions)
    }
}

Example

import scala.collection.mutable.{ Map => MMap }
val database: MMap[String, String] =
  MMap( "foo" -> "Foo"
      , "bar" -> "Bar"
      )

def get(key: String): AuthZ[Option[String]] =
  new AuthZ(Set("read"), database.get(key))

def set(key: String, value: String): AuthZ[Unit] =
  new AuthZ(Set("write"), database.put(key, value))

Usage

val permissions: Map[String, Set[String]] =
  Map( "jdoe"   -> Set("read", "write")
     , "msmith" -> Set("read")
     )

println(get("foo").run(permissions("jdoe"))) // Right(Some(Foo))
println(get("foo").run(permissions("msmith"))) // Right(Some(Foo))

println(set("foo", "Foo1").run(permissions("jdoe"))) // Right(())
println(set("foo", "Foo2").run(permissions("msmith"))) // Left(InsufficientPermissions)

println(get("foo").run(permissions("jdoe"))) // Right(Some(Foo1))
println(get("foo").run(permissions("msmith"))) // Right(Some(Foo1))

Demo

This file is literate Scala, and can be run using Codedown:

$ curl https://earldouglas.com/posts/reference/authz.md |
  codedown scala |
  xargs -0 scala -e
Right(Some(Foo))
Right(Some(Foo))
Right(())
Left(InsufficientPermissions)
Right(Some(Foo1))
Right(Some(Foo1))