graphql-engine/server/src-lib/Hasura/RQL/DDL/Schema/Cache/Permission.hs

107 lines
4.5 KiB
Haskell
Raw Normal View History

{-# LANGUAGE Arrows #-}
module Hasura.RQL.DDL.Schema.Cache.Permission
( buildTablePermissions
, mkPermissionMetadataObject
) where
import Hasura.Prelude
import qualified Data.HashMap.Strict.Extended as M
import qualified Data.Sequence as Seq
import Control.Arrow.Extended
import Data.Aeson
import Data.Text.Extended
import qualified Hasura.Incremental as Inc
import Hasura.Backends.Postgres.Connection
import Hasura.Backends.Postgres.SQL.Types
import Hasura.RQL.DDL.Permission
import Hasura.RQL.DDL.Permission.Internal
import Hasura.RQL.DDL.Schema.Cache.Common
import Hasura.RQL.Types
import Hasura.RQL.Types.Catalog
import Hasura.Session
buildTablePermissions
:: ( ArrowChoice arr, Inc.ArrowDistribute arr, Inc.ArrowCache m arr
, ArrowWriter (Seq CollectedInfo) arr, MonadTx m )
=> ( Inc.Dependency TableCoreCache
, QualifiedTable
, FieldInfoMap (FieldInfo 'Postgres)
, HashSet CatalogPermission
) `arr` (RolePermInfoMap 'Postgres)
buildTablePermissions = Inc.cache proc (tableCache, tableName, tableFields, tablePermissions) ->
(| Inc.keyed (\_ rolePermissions -> do
let (insertPerms, selectPerms, updatePerms, deletePerms) =
partitionPermissions rolePermissions
insertPermInfo <- buildPermission -< (tableCache, tableName, tableFields, insertPerms)
selectPermInfo <- buildPermission -< (tableCache, tableName, tableFields, selectPerms)
updatePermInfo <- buildPermission -< (tableCache, tableName, tableFields, updatePerms)
deletePermInfo <- buildPermission -< (tableCache, tableName, tableFields, deletePerms)
returnA -< RolePermInfo
{ _permIns = insertPermInfo
, _permSel = selectPermInfo
, _permUpd = updatePermInfo
, _permDel = deletePermInfo
})
|) (M.groupOn _cpRole tablePermissions)
where
partitionPermissions = flip foldr ([], [], [], []) $
\perm (insertPerms, selectPerms, updatePerms, deletePerms) -> case _cpPermType perm of
PTInsert -> (perm:insertPerms, selectPerms, updatePerms, deletePerms)
PTSelect -> (insertPerms, perm:selectPerms, updatePerms, deletePerms)
PTUpdate -> (insertPerms, selectPerms, perm:updatePerms, deletePerms)
PTDelete -> (insertPerms, selectPerms, updatePerms, perm:deletePerms)
mkPermissionMetadataObject :: CatalogPermission -> MetadataObject
mkPermissionMetadataObject (CatalogPermission qt rn pt pDef cmnt) =
let objectId = MOTableObj qt $ MTOPerm rn pt
definition = toJSON $ WithTable qt $ PermDef rn pDef cmnt
in MetadataObject objectId definition
withPermission
:: (ArrowChoice arr, ArrowWriter (Seq CollectedInfo) arr)
=> WriterA (Seq SchemaDependency) (ErrorA QErr arr) (a, s) b
-> arr (a, (CatalogPermission, s)) (Maybe b)
withPermission f = proc (e, (permission, s)) -> do
let CatalogPermission tableName roleName permType _ _ = permission
metadataObject = mkPermissionMetadataObject permission
schemaObject = SOTableObj tableName $ TOPerm roleName permType
addPermContext err = "in permission for role " <> roleName <<> ": " <> err
(| withRecordInconsistency (
(| withRecordDependencies (
(| modifyErrA (f -< (e, s))
|) (addTableContext tableName . addPermContext))
|) metadataObject schemaObject)
|) metadataObject
buildPermission
:: ( ArrowChoice arr, Inc.ArrowCache m arr
, ArrowWriter (Seq CollectedInfo) arr
, MonadTx m, IsPerm a, FromJSON a
)
=> ( Inc.Dependency TableCoreCache
, QualifiedTable
, FieldInfoMap (FieldInfo 'Postgres)
, [CatalogPermission]
) `arr` Maybe (PermInfo a)
buildPermission = Inc.cache proc (tableCache, tableName, tableFields, permissions) -> do
(permissions >- noDuplicates mkPermissionMetadataObject)
>-> (| traverseA (\permission@(CatalogPermission _ roleName _ pDef _) ->
(| withPermission (do
backend only insert permissions (rfc #4120) (#4224) * move user info related code to Hasura.User module * the RFC #4120 implementation; insert permissions with admin secret * revert back to old RoleName based schema maps An attempt made to avoid duplication of schema contexts in types if any role doesn't possess any admin secret specific schema * fix compile errors in haskell test * keep 'user_vars' for session variables in http-logs * no-op refacto * tests for admin only inserts * update docs for admin only inserts * updated CHANGELOG.md * default behaviour when admin secret is not set * fix x-hasura-role to X-Hasura-Role in pytests * introduce effective timeout in actions async tests * update docs for admin-secret not configured case * Update docs/graphql/manual/api-reference/schema-metadata-api/permission.rst Co-Authored-By: Marion Schleifer <marion@hasura.io> * Apply suggestions from code review Co-Authored-By: Marion Schleifer <marion@hasura.io> * a complete iteration backend insert permissions accessable via 'x-hasura-backend-privilege' session variable * console changes for backend-only permissions * provide tooltip id; update labels and tooltips; * requested changes * requested changes - remove className from Toggle component - use appropriate function name (capitalizeFirstChar -> capitalize) * use toggle props from definitelyTyped * fix accidental commit * Revert "introduce effective timeout in actions async tests" This reverts commit b7a59c19d643520cfde6af579889e1038038438a. * generate complete schema for both 'default' and 'backend' sessions * Apply suggestions from code review Co-Authored-By: Marion Schleifer <marion@hasura.io> * remove unnecessary import, export Toggle as is * update session variable in tooltip * 'x-hasura-use-backend-only-permissions' variable to switch * update help texts * update docs * update docs * update console help text * regenerate package-lock * serve no backend schema when backend_only: false and header set to true - Few type name refactor as suggested by @0x777 * update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * fix a merge bug where a certain entity didn't get removed Co-authored-by: Marion Schleifer <marion@hasura.io> Co-authored-by: Rishichandra Wawhal <rishi@hasura.io> Co-authored-by: rikinsk <rikin.kachhia@gmail.com> Co-authored-by: Tirumarai Selvan <tiru@hasura.io>
2020-04-24 12:10:53 +03:00
bindErrorA -< when (roleName == adminRoleName) $
throw400 ConstraintViolation "cannot define permission for admin role"
perm <- bindErrorA -< decodeValue pDef
let permDef = PermDef roleName perm Nothing
(info, dependencies) <- liftEitherA <<< Inc.bindDepend -< runExceptT $
runTableCoreCacheRT (buildPermInfo tableName tableFields permDef) tableCache
tellA -< Seq.fromList dependencies
returnA -< info)
|) permission) |)
>-> (\info -> join info >- returnA)