set all session data in a single paramater, 'hasura.user' (closes #825)

This commit is contained in:
Vamshi Surabhi 2018-10-24 16:09:47 +05:30 committed by GitHub
parent cd030068c2
commit ab9692da4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 40 additions and 26 deletions

View File

@ -0,0 +1,22 @@
Auditing actions on tables in Postgres
======================================
Typically audit logging is added to some of the tables to comply with various certifications.
You may want to capture the user information (role and the session variables) for every change in Postgres that is done through graphql-engine.
For every mutation, hasura roughly executes the following transaction:
.. code-block:: sql
BEGIN;
SET local "hasura.user" = '{"x-hasura-role": "role", ... various session variables}'
SQL related to the mutation
COMMIT;
This information can therefore be captured in any trigger on the underlying tables by using the ``current_setting`` function as follows:
.. code-block:: sql
current_setting('hasura.user');
We've set up some utility functions that'll let you quickly get started with auditing in this `repo <https://github.com/hasura/audit-trigger>`__.

View File

@ -54,3 +54,4 @@ Articles:
Sample apps <sample-apps/index>
Integration/migration tutorials <integrations/index>
Integrating with monitoring frameworks <monitoring/index>
Auditing tables <auditing-tables>

View File

@ -210,16 +210,16 @@ valueParser :: (MonadError QErr m) => PGColType -> Value -> m S.SQLExp
valueParser columnType = \case
-- When it is a special variable
val@(String t)
| isXHasuraTxt t -> asCurrentSetting t
| isReqUserId t -> asCurrentSetting userIdHeader
| isXHasuraTxt t -> return $ fromCurSess t
| isReqUserId t -> return $ fromCurSess userIdHeader
| otherwise -> txtRHSBuilder columnType val
-- Typical value as Aeson's value
val -> txtRHSBuilder columnType val
where
asCurrentSetting hdr = return $ S.SEUnsafe $
"current_setting('hasura." <> dropAndSnakeCase hdr
<> "')::" <> T.pack (show columnType)
curSess = S.SEUnsafe "current_setting('hasura.user')::json"
fromCurSess hdr =
S.SEOpApp (S.SQLOp "->>") [curSess, S.SELit $ T.toLower hdr]
`S.SETyAnn` (S.AnnType $ T.pack $ show columnType)
-- Convert where clause into SQL BoolExp
convFilterExp :: (MonadError QErr m)

View File

@ -65,7 +65,8 @@ $(J.deriveJSON (J.aesonDrop 4 J.camelCase){J.omitNothingFields=True}
)
adminUserInfo :: UserInfo
adminUserInfo = UserInfo adminRole Map.empty
adminUserInfo =
UserInfo adminRole $ Map.singleton "x-hasura-role" "admin"
data PermType
= PTInsert

View File

@ -172,7 +172,7 @@ getUserInfo logger manager rawHeaders = \case
userInfoFromHeaders =
case M.lookup userRoleHeader headers of
Just v -> UserInfo (RoleName v) headers
Nothing -> UserInfo adminRole M.empty
Nothing -> adminUserInfo
userInfoWhenAccessKey key reqKey = do
when (reqKey /= getAccessKey key) $ throw401 $ "invalid " <> accessKeyHeader

View File

@ -10,10 +10,11 @@ import Data.Aeson.Casing
import Data.Aeson.TH
import Language.Haskell.TH.Syntax (Lift)
import qualified Data.Aeson.Text as AT
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Lazy as BL
import qualified Data.HashMap.Strict as Map
import qualified Data.Sequence as Seq
import qualified Data.Text.Lazy as LT
import qualified Data.Vector as V
import Hasura.Prelude
@ -25,7 +26,6 @@ import Hasura.RQL.DDL.Schema.Table
import Hasura.RQL.DML.QueryTemplate
import Hasura.RQL.DML.Returning (encodeJSONVector)
import Hasura.RQL.Types
import Hasura.Server.Utils
import Hasura.SQL.Types
import qualified Database.PG.Query as Q
@ -220,9 +220,9 @@ buildTxAny userInfo sc rq = case rq of
setHeadersTx :: UserInfo -> Q.TxE QErr ()
setHeadersTx userInfo =
forM_ hdrs $ \h -> Q.unitQE defaultTxErrorHandler (mkQ h) () False
Q.unitQE defaultTxErrorHandler setSess () False
where
hdrs = Map.toList $ Map.delete accessKeyHeader
$ userHeaders userInfo
mkQ (h, v) = Q.fromText $
"SET LOCAL hasura." <> dropAndSnakeCase h <> " = " <> pgFmtLit v
toStrictText = LT.toStrict . AT.encodeToLazyText
setSess = Q.fromText $
"SET LOCAL \"hasura.user\" = " <>
pgFmtLit (toStrictText $ userHeaders userInfo)

View File

@ -21,16 +21,6 @@ import qualified Text.Ginger as TG
import Hasura.Prelude
dropAndSnakeCase :: T.Text -> T.Text
dropAndSnakeCase = T.drop 9 . toSnakeCase . T.toLower
toSnakeCase :: T.Text -> T.Text
toSnakeCase = T.pack . map change . T.unpack
where
change '-' = '_'
change c = c
isXHasuraTxt :: T.Text -> Bool
isXHasuraTxt = T.isInfixOf "x-hasura-" . T.toLower