241 lines
8.4 KiB
Haskell
241 lines
8.4 KiB
Haskell
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
|