diff --git a/CHANGELOG.md b/CHANGELOG.md index adbc01ffa..d9d561d70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fix `max-affected` preference not failing with RPC when `handling=strict` by @taimoorzaeem in #4100 +- Fix `jwt-aud` config not failing when set to an invalid URI by @taimoorzaeem in #4132 - Fix a property definition's type in OpenAPI not showing the correct base type of a recursive domain by @laurenceisla in #4136 - Fix regression that makes full-text search not work on domain types based on `tsvector` by @laurenceisla in #4135 diff --git a/src/PostgREST/Config.hs b/src/PostgREST/Config.hs index 5709fab7f..f6d08dd5c 100644 --- a/src/PostgREST/Config.hs +++ b/src/PostgREST/Config.hs @@ -48,7 +48,7 @@ import Data.List.NonEmpty (fromList, toList) import Data.Maybe (fromJust) import Data.Scientific (floatingOrInteger) import Jose.Jwk (Jwk, JwkSet) -import Network.URI (escapeURIString, +import Network.URI (escapeURIString, isURI, isUnescapedInURIComponent) import Numeric (readOct, showOct) import System.Environment (getEnvironment) @@ -281,7 +281,7 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = <*> (fromMaybe "postgresql://" <$> optString "db-uri") <*> pure optPath <*> pure Nothing - <*> optString "jwt-aud" + <*> optStringOrURI "jwt-aud" <*> parseRoleClaimKey "jwt-role-claim-key" "role-claim-key" <*> (fmap encodeUtf8 <$> optString "jwt-secret") <*> (fromMaybe False <$> optWithAlias @@ -407,6 +407,20 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = optStringEmptyable :: C.Key -> C.Parser C.Config (Maybe Text) optStringEmptyable k = overrideFromDbOrEnvironment C.optional k coerceText + optStringOrURI :: C.Key -> C.Parser C.Config (Maybe Text) + optStringOrURI k = do + stringOrURI <- mfilter (/= "") <$> overrideFromDbOrEnvironment C.optional k coerceText + -- If the string contains ':' then it should + -- be a valid URI according to RFC 3986 + case stringOrURI of + Just s -> if T.isInfixOf ":" s then validateURI s else return (Just s) + Nothing -> return Nothing + where + validateURI :: Text -> C.Parser C.Config (Maybe Text) + validateURI s = if isURI (T.unpack s) + then return $ Just s + else fail "jwt-aud should be a string or a valid URI" + optInt :: (Read i, Integral i) => C.Key -> C.Parser C.Config (Maybe i) optInt k = join <$> overrideFromDbOrEnvironment C.optional k coerceInt diff --git a/test/io/fixtures.yaml b/test/io/fixtures.yaml index e0e8f04c5..ee00182cc 100644 --- a/test/io/fixtures.yaml +++ b/test/io/fixtures.yaml @@ -41,12 +41,11 @@ cli: use_defaultenv: true env: PGRST_SERVER_UNIX_SOCKET_MODE: '778' -# TODO: Bug needs to be fixed -# - name: invalid jwt-aud -# expect: error -# use_defaultenv: true -# env: -# PGRST_JWT_AUD: 'htp:/@@localhorst.invalid' + - name: invalid jwt-aud + expect: error + use_defaultenv: true + env: + PGRST_JWT_AUD: 'http://%%localhorst.invalid' - name: invalid log-level expect: error use_defaultenv: true diff --git a/test/io/test_cli.py b/test/io/test_cli.py index ec163f8d3..522d2ea8e 100644 --- a/test/io/test_cli.py +++ b/test/io/test_cli.py @@ -277,3 +277,15 @@ def test_schema_cache_snapshot(baseenv, key, snapshot_yaml): Dumper=yaml.SafeDumper if key == "dbTimezones" else ExtraNewLinesDumper, ) assert formatted == snapshot_yaml + + +def test_jwt_aud_config_set_to_invalid_uri(defaultenv): + "PostgREST should exit with an error message in output if jwt-aud config is set to an invalid URI" + env = { + **defaultenv, + "PGRST_JWT_AUD": "foo://%%$$^^.com", + } + + with pytest.raises(PostgrestError): + dump = cli(["--dump-config"], env=env).split("\n") + assert "jwt-aud should be a string or a valid URI" in dump