packages feed

project-m36-1.2.0: test/AccessControl.hs

import TutorialD.Interpreter.TestBase
import ProjectM36.Client
import ProjectM36.Relation
import qualified ProjectM36.Attribute as A
import Test.HUnit
import System.Exit

main :: IO ()
main = do
  tcounts <- runTestTT (TestList [testDBCFunctionACL,
                                 testRelVarAccess,
                                 testFunctionAccess])
  if errors tcounts + failures tcounts > 0 then exitFailure else exitSuccess

testDBCFunctionACL :: Test
testDBCFunctionACL = TestCase $ do
  (sessionId, conn) <- dateExamplesConnection emptyNotificationCallback
  -- add a less-privileged role
  let user1 = "user1"
  res <- executeAlterLoginRolesExpr sessionId conn (AddLoginRoleExpr user1 False)
  assertEqual "add role" (Right QuietSuccessResult) res
  let user1conn = setRoleName user1 conn
  -- test that the role does *not* have access to a dbc function
  res' <- executeDatabaseContextExpr sessionId user1conn (ExecuteDatabaseContextFunction "deleteAll" [])
  assertEqual "failure to run dbc function" (Left (AccessDeniedError (SomeFunctionPermission ExecuteFunctionPermission))) res'
  -- test that the role cannot create a dbc function
  res'' <- executeDatabaseContextIOExpr sessionId user1conn (AddDatabaseContextFunction "failure" [] "")
  assertEqual "failure to add dbc function" (Left (AccessDeniedError (SomeFunctionPermission AlterFunctionPermission))) res''
  -- grant permission to the role to execute the function
  res''' <- executeDatabaseContextExpr sessionId conn (AlterACL (GrantDBCFunctionAccessExpr user1 "deleteAll" ExecuteDBCFunctionPermission False))
  assertEqual "success adding function permission" (Right ()) res'''
  
  -- fail again because of two-tiered ACLs necessary to execute the dbc function
  res'''' <- executeDatabaseContextExpr sessionId user1conn (ExecuteDatabaseContextFunction "deleteAll" [])
  assertEqual "failure of calling deleteAll" (Left (AccessDeniedError (SomeFunctionPermission ExecuteFunctionPermission))) res''''

  -- grant the remaining, necessary permission
  res'''''' <- executeDatabaseContextExpr sessionId conn (AlterACL (GrantAccessExpr user1 (SomeFunctionPermission ExecuteFunctionPermission) False))
  assertEqual "success adding function permission" (Right ()) res''''''

  -- successfully call the dbc function
  res''''''' <- executeDatabaseContextExpr sessionId user1conn (ExecuteDatabaseContextFunction "deleteAll" [])
  assertEqual "success calling deleteAll" (Right ()) res'''''''


testRelVarAccess :: Test
testRelVarAccess = TestCase $ do
  (sessionId, conn) <- dateExamplesConnection emptyNotificationCallback
  -- add a less-privileged role
  let user1 = "user1"
  res <- executeAlterLoginRolesExpr sessionId conn (AddLoginRoleExpr user1 False)
  assertEqual "add role" (Right QuietSuccessResult) res
  let user1conn = setRoleName user1 conn

  -- check that the user cannot view the relvars
  res' <- executeRelationalExpr sessionId user1conn (RelationVariable "x" ())

  assertEqual "reject relvar access" (Left (AccessDeniedError (SomeRelVarPermission AccessRelVarsPermission))) res'

  -- grant relvars access
  res'' <- executeDatabaseContextExpr sessionId conn (AlterACL (GrantAccessExpr user1 (SomeRelVarPermission AccessRelVarsPermission) False))

  assertEqual "grant rv access" (Right ()) res''

  -- check that the user can view the relvars
  res''' <- executeRelationalExpr sessionId user1conn (RelationVariable "true" ())

  assertEqual "accept relvar access" (Right relationTrue) res'''
  
testFunctionAccess :: Test
testFunctionAccess = TestCase $ do
  (sessionId, conn) <- dateExamplesConnection emptyNotificationCallback
  -- add a less-privileged role
  let user1 = "user1"
  res <- executeAlterLoginRolesExpr sessionId conn (AddLoginRoleExpr user1 False)
  assertEqual "add role" (Right QuietSuccessResult) res
  let user1conn = setRoleName user1 conn

  -- check that function view access is denied
  res' <- databaseContextFunctionsAsRelation sessionId user1conn 
  assertEqual "rejected dbc function view" (Left (AccessDeniedError (SomeFunctionPermission ViewFunctionPermission))) res'
  
  -- grant function view
  res'' <- executeDatabaseContextExpr sessionId conn (AlterACL (GrantAccessExpr user1 (SomeFunctionPermission ViewFunctionPermission) False))
  assertEqual "grant function access" (Right ()) res''

  -- check that function view works
  res''' <- databaseContextFunctionsAsRelation sessionId user1conn 
  assertEqual "dbc function view" (mkRelationFromList (A.attributesFromList [Attribute "name" TextAtomType, Attribute "arguments" TextAtomType]) []) res'''

  -- check that function execute is denied
  res'''' <- executeDatabaseContextExpr sessionId user1conn (ExecuteDatabaseContextFunction "deleteAll" [])
  assertEqual "failure to run dbc function" (Left (AccessDeniedError (SomeFunctionPermission ExecuteFunctionPermission))) res''''

  -- grant permission to the role to execute the function
  res''''' <- executeDatabaseContextExpr sessionId conn (AlterACL (GrantDBCFunctionAccessExpr user1 "deleteAll" ExecuteDBCFunctionPermission False))
  assertEqual "success adding dbcfunction permission" (Right ()) res'''''

  res'''''' <- executeDatabaseContextExpr sessionId conn (AlterACL (GrantAccessExpr user1 (SomeFunctionPermission ExecuteFunctionPermission) False))
  assertEqual "success adding function permission" (Right ()) res''''''

  -- check that function execute works
  res''''''' <- executeDatabaseContextExpr sessionId user1conn (ExecuteDatabaseContextFunction "deleteAll" [])
  assertEqual "success calling deleteAll" (Right ()) res'''''''