Last active
August 29, 2015 14:07
-
-
Save gbluma/e061ee1f058b737ecf1c to your computer and use it in GitHub Desktop.
A minimal security monad that allows low-security and high-security elements to be mixed, but in all places where the values are mixed, the output adopts the highest-security tag. This is useful in situations where sensitive data pervades many computational contexts and where the security rules are bipolar (strictly public/private, etc.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A minimal security monad that allows low-security and high-security elements | |
* to be mixed, but in all places where the values are mixed, the output | |
* adopts the highest-security tag. This is useful in situations where | |
* sensitive data pervades many computational contexts and where the security | |
* rules are bipolar (strictly public/private, etc.) | |
* | |
* @author Garrett Bluma | |
* @date Apr 9, 2012 (Monad design and implementation) | |
* @revised Oct 2, 2014 (Cleaned up. Added examples) | |
* @copyright Garrett Bluma. (c) 2014 - All rights reserved. | |
*/ | |
// SecurityMonad is a normal Scala monad, therefore it must exhibit a certain | |
// structure. These abstract methods are unnecessary, but helpful for | |
// type-checking and for reference. | |
sealed trait SecurityMonad[+A] { | |
def map[B] (f: A => B) : SecurityMonad[B] | |
def flatMap[B](f: A => SecurityMonad[B]): SecurityMonad[B] | |
} | |
// The LowSM class effectively tags an object as being of a low security (i.e. | |
// public) | |
case class LowSM[+A](a: A) extends SecurityMonad[A] | |
{ // When introducing a new block, wrap it in a low security container | |
def map[B] (f: A => B) : SecurityMonad[B] = LowSM(f(a)) | |
// When binding two computations together, the relationship should allow a | |
// low security object. Further binds will root it out if it is not | |
// sufficient. | |
def flatMap[B] (f: A => SecurityMonad[B]) = f(a) | |
// The decrypt method yields a high security object of the original contents | |
// that were encrpyted. | |
def decrypt[B] = HighSM("[[not implemented]]") | |
} | |
// The HighSM class tags an object as being of a high security (i.e. private) | |
case class HighSM[+A](a: A) extends SecurityMonad[A] | |
{ | |
// When introducing a new block, wrap it in a high security container | |
def map[B] (f: A => B) : SecurityMonad[B] = HighSM(f(a)) | |
// When binding two computations together, the relationship should always | |
// favor higher security | |
def flatMap[B] (f: A => SecurityMonad[B]) = { | |
f(a) match { | |
case LowSM(b) => HighSM(b) | |
case HighSM(b) => HighSM(b) | |
} | |
} | |
// The encrypt method yields a low security object once the contents have | |
// been encrypted. | |
def encrypt[B] = LowSM("[[not implemented]]") | |
} | |
// ------------------------ | |
// test program | |
object main { | |
def main(args:Array[String]) { | |
// Some inline testing to skip a test framework | |
// A low security element and a high security element should always | |
// combine to be the higher security level. | |
// ---------------------------------------------------------------------- | |
// Basic sanity test | |
print("Low * High * High = High --> ") | |
val a:SecurityMonad[Int] = for ( x <- LowSM(9); | |
y <- HighSM(3); | |
z <- HighSM(7) | |
) yield { x * y * z } | |
a match { | |
case LowSM(x) => println("Failed") | |
case HighSM(x) => println("Success") | |
} | |
// ---------------------------------------------------------------------- | |
// Positive test for low-security non-elevation | |
print("Low * Low * Low = Low --> ") | |
val b:SecurityMonad[Int] = for ( x <- LowSM(9); | |
y <- LowSM(3); | |
z <- LowSM(5) | |
) yield { x * y * z } | |
b match { | |
case LowSM(x) => println("Success") | |
case HighSM(x) => println("Failed") | |
} | |
// ---------------------------------------------------------------------- | |
// Test for a single (inner) High security propagates | |
print("Low * High * Low = High --> ") | |
val c:SecurityMonad[Int] = for ( x <- LowSM(9); | |
y <- HighSM(3); | |
z <- LowSM(3) | |
) yield { x * y * z } | |
c match { | |
case LowSM(x) => println("Failed") | |
case HighSM(x) => println("Success") | |
} | |
// ---------------------------------------------------------------------- | |
// try the same as the last test with for-comprehension expanded | |
print("Low * High * Low = High --> ") | |
val d = LowSM(9).flatMap { a => | |
HighSM(3).flatMap { b => | |
LowSM(3).map { c => | |
a * b * c } } } | |
d match { | |
case LowSM(x) => println("Failed") | |
case HighSM(x) => println("Success") | |
} | |
// ---------------------------------------------------------------------- | |
// An extra sanity test using strings instead of Ints | |
print("Low * High * High = High --> ") | |
val e:SecurityMonad[String] = for ( x <- LowSM("Hello"); | |
y <- HighSM("World"); | |
z <- HighSM("!") | |
) yield { x + y + z } | |
e match { | |
case LowSM(x) => println("Failed") | |
case HighSM(x) => println("Success") | |
} | |
println(e); // => HighSM("HelloWorld!") | |
// Output: $ sbt run | |
// | |
// [info] Running main | |
// Low * High * High = High --> Success | |
// Low * Low * Low = Low --> Success | |
// Low * High * Low = High --> Success | |
// Low * High * Low = High --> Success | |
// Low * High * High = High --> Success | |
// HighSM(HelloWorld!) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment