graphql-engine/server/src-lib/Hasura/RQL/DDL/Schema/Cache/Permission.hs
Rakesh Emmadi d52bfcda4e
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 b7a59c19d6.

* 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 14:40:53 +05:30

106 lines
4.4 KiB
Haskell

{-# 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 qualified Hasura.Incremental as Inc
import Hasura.Db
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
import Hasura.SQL.Types
buildTablePermissions
:: ( ArrowChoice arr, Inc.ArrowDistribute arr, Inc.ArrowCache m arr
, ArrowWriter (Seq CollectedInfo) arr, MonadTx m )
=> ( Inc.Dependency TableCoreCache
, QualifiedTable
, FieldInfoMap FieldInfo
, HashSet CatalogPermission
) `arr` RolePermInfoMap
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
, [CatalogPermission]
) `arr` Maybe (PermInfo a)
buildPermission = Inc.cache proc (tableCache, tableName, tableFields, permissions) -> do
(permissions >- noDuplicates mkPermissionMetadataObject)
>-> (| traverseA (\permission@(CatalogPermission _ roleName _ pDef _) ->
(| withPermission (do
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)