module Feature.Auth.AudienceJwtSecretSpec where import Network.Wai (Application) import Network.HTTP.Types import Protolude hiding (get) import SpecHelper import Test.Hspec import Test.Hspec.Wai import Test.Hspec.Wai.JSON spec :: SpecWith ((), Application) spec = describe "test handling of aud claims in JWT when the jwt-aud config is set" $ do context "when the audience claim is a string" $ do -- this test will stop working 9999999999s after the UNIX EPOCH it "succeeds when the audience claim matches" $ do let jwtPayload = [json|{ "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": "youraudience" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "fails when the audience claim does not match" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": "notyouraudience" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` [json|{"code":"PGRST303","details":null,"hint":null,"message":"JWT not in audience"}|] { matchStatus = 401 } it "fails when the audience claim is empty" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": "" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` [json|{"code":"PGRST303","details":null,"hint":null,"message":"JWT not in audience"}|] { matchStatus = 401 } context "when the audience claim is an array of strings" $ do it "succeeds when the audience claim has 1 element and it matches" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": ["youraudience"] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "succeeds when the audience claim has more than 1 element and one matches" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": ["notyouraudience", "youraudience", "anotheraudience"] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "fails when the audience claim has 1 element and it doesn't match" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": ["notyouraudience"] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` [json|{"code":"PGRST303","details":null,"hint":null,"message":"JWT not in audience"}|] { matchStatus = 401 } it "fails when the audience claim has more than 1 element and none matches" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": ["notyouraudience", "stillnotyouraudience", "anotheraudience"] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` [json|{"code":"PGRST303","details":null,"hint":null,"message":"JWT not in audience"}|] { matchStatus = 401 } it "ignores the audience claim and succeeds when it's empty" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": [] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "ignores the audience claim and succeeds when it's null" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": null }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 context "when the audience claim is not present" $ do it "succeeds with a JWT with no audience claim" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "succeeds without a JWT" $ get "/has_count_column" `shouldRespondWith` 200 disabledSpec :: SpecWith ((), Application) disabledSpec = describe "test handling of aud claims in JWT when the jwt-aud config is not set" $ do context "when the audience claim is a string" $ do it "ignores the audience claim and suceeds" $ do let jwtPayload = [json|{ "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": "youraudience" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "ignores the audience claim and suceeds when it's empty" $ do let jwtPayload = [json|{ "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": "" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 context "when the audience is an array of strings" $ do it "ignores the audience claim and suceeds when it has 1 element" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": ["youraudience"] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "ignores the audience claim and suceeds when it has more than 1 element" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": ["notyouraudience", "youraudience", "anotheraudience"] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "ignores the audience claim and suceeds when it's empty" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": [] }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "ignores the audience claim and succeeds when it's null" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe", "aud": null }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 context "when the audience claim is not present" $ do it "succeeds with a JWT with no audience claim" $ do let jwtPayload = [json| { "exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe" }|] auth = authHeaderJWT $ generateJWT jwtPayload request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 it "succeeds without a JWT" $ get "/has_count_column" `shouldRespondWith` 200