From 75dab65ced61edfce80cb387b12a8265125840dd Mon Sep 17 00:00:00 2001 From: Taimoor Zaeem Date: Thu, 11 Jun 2026 11:52:13 +0500 Subject: [PATCH] Revert "add: string slicing operator for `jwt-role-claim-key`" This reverts commit fe0386e9c4c3d41fd1caa22beb597ff0bafcd5fd. As discussed in https://github.com/PostgREST/postgrest/pull/4984#issuecomment-4652725178. --- CHANGELOG.md | 1 - docs/references/auth.rst | 16 ----------- src/PostgREST/Config/JSPath.hs | 49 ++++++++-------------------------- test/io/fixtures/fixtures.yaml | 38 -------------------------- 4 files changed, 11 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2fd8a2786..323f322794 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,6 @@ All notable changes to this project will be documented in this file. From versio ### Added - Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359 -- Add string slicing operator for `jwt-role-claim-key` by @taimoorzaeem in #4599 - Optimize requests with `Prefer: count=exact` that do not use ranges or `db-max-rows` by @laurenceisla in #3957 + Removed unnecessary double count when building the `Content-Range`. - Add config `client-error-verbosity` to customize error verbosity by @taimoorzaeem in #4088, #3980, #3824 diff --git a/docs/references/auth.rst b/docs/references/auth.rst index 30551abeb9..4970dd39a3 100644 --- a/docs/references/auth.rst +++ b/docs/references/auth.rst @@ -234,17 +234,6 @@ The DSL follows the `JSONPath `_ expres - ``==^`` selects the first array element that ends with the right operand - ``*==`` selects the first array element that contains the right operand -The selected role value can also be sliced using the slice operator ``[a:b]``. It is similar to `slice operator in python `_. Negative index values are also supported. The syntax is as: - -- ``[a:b]`` take slice from index ``a`` up to ``b`` -- ``[a:]`` take slice from index ``a`` to end -- ``[:b]`` take slice from start to index ``b`` -- ``[:]`` select everything, no slicing - -.. important:: - - Make sure that you are not taking a slice where the start index comes after the end index like ``[11:2]``. The result of this would be empty string and so no role would get selected. - Usage examples: .. code:: bash @@ -266,11 +255,6 @@ Usage examples: jwt-role-claim-key = ".postgrest.roles[?(@ ==^ \"hor\")]" jwt-role-claim-key = ".postgrest.roles[?(@ *== \"utho\")]" - # {"postgrest":{"wlcg": ["/groupa", "/groupb/"]}} - # skip the "/" character using slice operator - jwt-role-claim-key = ".postgrest.wlcg[0][1:]" - jwt-role-claim-key = ".postgrest.wlcg[1][1:-1]" - .. note:: The string comparison operators are implemented as a custom extension to the JSPath and does not strictly follow the `RFC 9535 `_. diff --git a/src/PostgREST/Config/JSPath.hs b/src/PostgREST/Config/JSPath.hs index 8116a2d21f..e28e5c3667 100644 --- a/src/PostgREST/Config/JSPath.hs +++ b/src/PostgREST/Config/JSPath.hs @@ -29,10 +29,9 @@ type JSPath = [JSPathExp] -- NOTE: We only accept one JSPFilter expr (at the end of input) -- | jspath expression data JSPathExp - = JSPKey Text -- .property or ."property-dash" - | JSPIdx Int -- [0] - | JSPSlice (Maybe Int) (Maybe Int) -- [0:5] or [0:] or [:5] or [:] - | JSPFilter FilterExp -- [?(@ == "match")] + = JSPKey Text -- .property or ."property-dash" + | JSPIdx Int -- [0] + | JSPFilter FilterExp -- [?(@ == "match")] data FilterExp = EqualsCond Text @@ -45,7 +44,6 @@ dumpJSPath :: JSPathExp -> Text -- TODO: this needs to be quoted properly for special chars dumpJSPath (JSPKey k) = "." <> show k dumpJSPath (JSPIdx i) = "[" <> show i <> "]" -dumpJSPath (JSPSlice s e) = "[" <> maybe "" show s <> ":" <> maybe "" show e <> "]" dumpJSPath (JSPFilter cond) = "[?(@" <> expr <> ")]" where expr = @@ -61,25 +59,12 @@ walkJSPath :: Maybe JSON.Value -> JSPath -> Maybe JSON.Value walkJSPath x [] = x walkJSPath (Just (JSON.Object o)) (JSPKey key:rest) = walkJSPath (KM.lookup (K.fromText key) o) rest walkJSPath (Just (JSON.Array ar)) (JSPIdx idx:rest) = walkJSPath (ar V.!? idx) rest -walkJSPath (Just (JSON.String str)) (JSPSlice start end:rest) = - let - len = T.length str - - norm :: Maybe Int -> Maybe Int -- Normalize negative indices to positive - norm = fmap (\i -> max 0 $ min len $ if i < 0 then len + i else i) - - s = fromMaybe 0 $ norm start -- normalized start index - e = fromMaybe len $ norm end -- normalized end index - slicedString = if s >= e then T.empty else T.take (e-s) $ T.drop s str - in - walkJSPath (Just $ JSON.String slicedString) rest - -walkJSPath (Just (JSON.Array ar)) (JSPFilter jspFilter:rest) = case jspFilter of - EqualsCond txt -> walkJSPath (findFirstMatch (==) txt ar) rest - NotEqualsCond txt -> walkJSPath (findFirstMatch (/=) txt ar) rest - StartsWithCond txt -> walkJSPath (findFirstMatch T.isPrefixOf txt ar) rest - EndsWithCond txt -> walkJSPath (findFirstMatch T.isSuffixOf txt ar) rest - ContainsCond txt -> walkJSPath (findFirstMatch T.isInfixOf txt ar) rest +walkJSPath (Just (JSON.Array ar)) [JSPFilter jspFilter] = case jspFilter of + EqualsCond txt -> findFirstMatch (==) txt ar + NotEqualsCond txt -> findFirstMatch (/=) txt ar + StartsWithCond txt -> findFirstMatch T.isPrefixOf txt ar + EndsWithCond txt -> findFirstMatch T.isSuffixOf txt ar + ContainsCond txt -> findFirstMatch T.isInfixOf txt ar where findFirstMatch matchWith pattern = find (\case JSON.String txt -> pattern `matchWith` txt @@ -95,7 +80,7 @@ pJSPath :: P.Parser JSPath pJSPath = P.many1 pJSPathExp <* P.eof pJSPathExp :: P.Parser JSPathExp -pJSPathExp = P.try pJSPKey <|> P.try pJSPFilter <|> P.try pJSPIdx <|> pJSPSlice +pJSPathExp = pJSPKey <|> pJSPFilter <|> pJSPIdx pJSPKey :: P.Parser JSPathExp pJSPKey = do @@ -110,25 +95,13 @@ pJSPIdx = do P.char ']' return (JSPIdx num) "pJSPIdx: JSPath array index" -pJSPSlice :: P.Parser JSPathExp -pJSPSlice = do - P.char '[' - startSign <- P.optionMaybe $ P.char '-' - startIndex <- P.optionMaybe (read <$> P.many1 P.digit) - P.char ':' - endSign <- P.optionMaybe $ P.char '-' - endIndex <- P.optionMaybe (read <$> P.many1 P.digit) - P.char ']' - let start' = if isJust startSign then ((-1) *) <$> startIndex else startIndex - end' = if isJust endSign then ((-1) *) <$> endIndex else endIndex - return (JSPSlice start' end') "pJSPSlice: JSPath string slice" - pJSPFilter :: P.Parser JSPathExp pJSPFilter = do P.try $ P.string "[?(" condition <- pFilterConditionParser P.char ')' P.char ']' + P.eof -- this should be the last jspath expression return (JSPFilter condition) "pJSPFilter: JSPath filter exp" pFilterConditionParser :: P.Parser FilterExp diff --git a/test/io/fixtures/fixtures.yaml b/test/io/fixtures/fixtures.yaml index 50fe14cdc1..640a584b40 100644 --- a/test/io/fixtures/fixtures.yaml +++ b/test/io/fixtures/fixtures.yaml @@ -194,44 +194,6 @@ roleclaims: roles: - obj_key: obj_value expected_status: 401 # fails because it compares an object with a string - - key: '.realm_access.roles[0][7:]' - data: - realm_access: - roles: - - prefix_postgrest_test_author - expected_status: 200 # passes because it removes the "prefix_" part using slice - - key: '.realm_access.roles[0][:-7]' - data: - realm_access: - roles: - - postgrest_test_author_suffix - expected_status: 200 # passes because it removes the "_suffix" part using slice - - key: '.realm_access.roles[0][7:-7]' - data: - realm_access: - roles: - - prefix_postgrest_test_author_suffix - expected_status: 200 # passes because it removes the "prefix_" and "_suffix" part using slice - - key: '.realm_access.roles[0][:]' - data: - realm_access: - roles: - - postgrest_test_author - expected_status: 200 # passes because nothing gets sliced - - key: '.realm_access.roles[?(@ *== "_test_")][7:]' - data: - realm_access: - roles: - - other - - prefix_postgrest_test_author - expected_status: 200 # passes on both comparison operators and slicing - - key: '.realm_access.roles[?(@ *== "_test_")][200:]' - data: - realm_access: - roles: - - other - - prefix_postgrest_test_author - expected_status: 401 # fails due to slicing results in empty string jwtaudroleclaims: - key: '.aud'