-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support string comparison for jwt-role-claim-key
- Loading branch information
1 parent
2df1676
commit 31933e8
Showing
7 changed files
with
162 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,98 @@ | ||
{-# OPTIONS_GHC -Wno-unused-do-bind #-} | ||
module PostgREST.Config.JSPath | ||
( JSPath | ||
, JSPathExp(..) | ||
, FilterExp(..) | ||
, dumpJSPath | ||
, pRoleClaimKey | ||
) where | ||
|
||
import qualified Text.ParserCombinators.Parsec as P | ||
|
||
import Data.Either.Combinators (mapLeft) | ||
import Text.ParserCombinators.Parsec ((<?>)) | ||
import Text.Read (read) | ||
import Data.Either.Combinators (mapLeft) | ||
import Text.Read (read) | ||
|
||
import Protolude | ||
|
||
|
||
-- | full jspath, e.g. .property[0].attr.detail | ||
-- | full jspath, e.g. .property[0].attr.detail[?(@ == "role1")] | ||
type JSPath = [JSPathExp] | ||
|
||
-- | jspath expression, e.g. .property, .property[0] or ."property-dash" | ||
-- | jspath expression | ||
data JSPathExp | ||
= JSPKey Text | ||
| JSPIdx Int | ||
= JSPKey Text -- .property or ."property-dash" | ||
| JSPIdx Int -- [0] | ||
| JSPFilter FilterExp -- [?(@ == "match")], [?(@ ^== "match-prefix")], etc | ||
|
||
data FilterExp | ||
= EqualsCond Text | ||
| NotEqualsCond Text | ||
| StartsWithCond Text | ||
| EndsWithCond Text | ||
| ContainsCond Text | ||
|
||
dumpJSPath :: JSPathExp -> Text | ||
-- TODO: this needs to be quoted properly for special chars | ||
dumpJSPath (JSPKey k) = "." <> show k | ||
dumpJSPath (JSPIdx i) = "[" <> show i <> "]" | ||
dumpJSPath (JSPFilter cond) = "[?(@" <> expr <> "]" | ||
where | ||
expr = | ||
case cond of | ||
EqualsCond text -> " == " <> text | ||
NotEqualsCond text -> " != " <> text | ||
StartsWithCond text -> " ^== " <> text | ||
EndsWithCond text -> " $== " <> text | ||
ContainsCond text -> " *== " <> text | ||
|
||
|
||
-- Used for the config value "role-claim-key" | ||
pRoleClaimKey :: Text -> Either Text JSPath | ||
pRoleClaimKey selStr = | ||
mapLeft show $ P.parse pJSPath ("failed to parse role-claim-key value (" <> toS selStr <> ")") (toS selStr) | ||
|
||
pJSPath :: P.Parser JSPath | ||
pJSPath = toJSPath <$> (period *> pPath `P.sepBy` period <* P.eof) | ||
where | ||
toJSPath :: [(Text, Maybe Int)] -> JSPath | ||
toJSPath = concatMap (\(key, idx) -> JSPKey key : maybeToList (JSPIdx <$> idx)) | ||
period = P.char '.' <?> "period (.)" | ||
pPath :: P.Parser (Text, Maybe Int) | ||
pPath = (,) <$> pJSPKey <*> P.optionMaybe pJSPIdx | ||
pJSPath = P.many1 pJSPathExp <* P.eof | ||
|
||
pJSPathExp :: P.Parser JSPathExp | ||
pJSPathExp = pJSPKey <|> pJSPFilter <|> pJSPIdx | ||
|
||
pJSPKey :: P.Parser JSPathExp | ||
pJSPKey = do | ||
P.char '.' | ||
val <- toS <$> P.many1 (P.alphaNum <|> P.oneOf "_$@") <|> pQuotedValue | ||
return $ JSPKey val | ||
|
||
pJSPIdx :: P.Parser JSPathExp | ||
pJSPIdx = do | ||
P.char '[' | ||
num <- read <$> P.many1 P.digit | ||
P.char ']' | ||
return $ JSPIdx num | ||
|
||
pJSPKey :: P.Parser Text | ||
pJSPKey = toS <$> P.many1 (P.alphaNum <|> P.oneOf "_$@") <|> pQuotedValue <?> "attribute name [a..z0..9_$@])" | ||
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 | ||
|
||
pJSPIdx :: P.Parser Int | ||
pJSPIdx = P.char '[' *> (read <$> P.many1 P.digit) <* P.char ']' <?> "array index [0..n]" | ||
pFilterConditionParser :: P.Parser FilterExp | ||
pFilterConditionParser = do | ||
P.char '@' | ||
P.spaces | ||
condOp <- P.choice $ map P.string ["==", "!=", "^==", "$==", "*=="] | ||
P.spaces | ||
value <- pQuotedValue | ||
return $ case condOp of | ||
"==" -> EqualsCond value | ||
"!=" -> NotEqualsCond value | ||
"^==" -> StartsWithCond value | ||
"$==" -> EndsWithCond value | ||
"*==" -> ContainsCond value | ||
_ -> EqualsCond value -- Impossible case | ||
|
||
pQuotedValue :: P.Parser Text | ||
pQuotedValue = toS <$> (P.char '"' *> P.many (P.noneOf "\"") <* P.char '"') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters