fix: Fix wrong CORS header Authentication -> Authorization

Also refactors defaultCorsPolicy and corsPolicy and cleans up CORS tests
This commit is contained in:
Wolfgang Walther
2022-06-03 22:19:16 -05:00
committed by Steve Chavez
parent 7db4a75146
commit 130dcc4f66
3 changed files with 55 additions and 74 deletions
+1
View File
@@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2058, Return 204 No Content without Content-Type for PUT - @wolfgangwalther - #2058, Return 204 No Content without Content-Type for PUT - @wolfgangwalther
- #2077, Fix `is` not working with upper or mixed case values like `NULL, TrUe, FaLsE` - @steve-chavez - #2077, Fix `is` not working with upper or mixed case values like `NULL, TrUe, FaLsE` - @steve-chavez
- #2024, Fix schema cache loading when views with XMLTABLE and DEFAULT are present - @wolfgangwalther - #2024, Fix schema cache loading when views with XMLTABLE and DEFAULT are present - @wolfgangwalther
- #1724, Fix wrong CORS header Authentication -> Authorization - @wolfgangwalther
## [9.0.0] - 2021-11-25 ## [9.0.0] - 2021-11-25
+12 -14
View File
@@ -8,8 +8,6 @@ module PostgREST.Middleware
( runPgLocals ( runPgLocals
, pgrstFormat , pgrstFormat
, pgrstMiddleware , pgrstMiddleware
, defaultCorsPolicy
, corsPolicy
, optionalRollback , optionalRollback
) where ) where
@@ -132,21 +130,21 @@ pgrstMiddleware logLevel =
LogWarn -> unsafePerformIO $ Wai.mkRequestLogger Wai.def { Wai.outputFormat = Wai.CustomOutputFormat $ pgrstFormat status400} LogWarn -> unsafePerformIO $ Wai.mkRequestLogger Wai.def { Wai.outputFormat = Wai.CustomOutputFormat $ pgrstFormat status400}
LogInfo -> Wai.logStdout LogInfo -> Wai.logStdout
defaultCorsPolicy :: Wai.CorsResourcePolicy
defaultCorsPolicy = Wai.CorsResourcePolicy Nothing
["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"] ["Authorization"] Nothing
(Just $ 60*60*24) False False True
-- | CORS policy to be used in by Wai Cors middleware -- | CORS policy to be used in by Wai Cors middleware
corsPolicy :: Wai.Request -> Maybe Wai.CorsResourcePolicy corsPolicy :: Wai.Request -> Maybe Wai.CorsResourcePolicy
corsPolicy req = case lookup "origin" headers of corsPolicy req = case lookup "origin" headers of
Just origin -> Just defaultCorsPolicy { Just origin ->
Wai.corsOrigins = Just ([origin], True) Just Wai.CorsResourcePolicy
, Wai.corsRequestHeaders = "Authentication" : accHeaders { Wai.corsOrigins = Just ([origin], True)
, Wai.corsExposedHeaders = Just [ , Wai.corsMethods = ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"]
"Content-Encoding", "Content-Location", "Content-Range", "Content-Type" , Wai.corsRequestHeaders = "Authorization" : accHeaders
, "Date", "Location", "Server", "Transfer-Encoding", "Range-Unit" , Wai.corsExposedHeaders = Just
] [ "Content-Encoding", "Content-Location", "Content-Range", "Content-Type"
, "Date", "Location", "Server", "Transfer-Encoding", "Range-Unit"]
, Wai.corsMaxAge = Just $ 60*60*24
, Wai.corsVaryOrigin = False
, Wai.corsRequireOrigin = False
, Wai.corsIgnoreFailures = True
} }
Nothing -> Nothing Nothing -> Nothing
where where
+42 -60
View File
@@ -1,74 +1,56 @@
module Feature.CorsSpec where module Feature.CorsSpec where
-- {{{ Imports import Network.Wai (Application)
import qualified Data.ByteString.Lazy as BL
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleBody, simpleHeaders))
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Protolude import Protolude
import SpecHelper
-- }}}
spec :: SpecWith ((), Application) spec :: SpecWith ((), Application)
spec = spec =
describe "CORS" $ do describe "CORS" $ do
let preflightHeaders = [ it "replies naively and permissively to preflight request" $
("Accept", "*/*"), request methodOptions "/"
("Origin", "http://example.com"), [ ("Accept", "*/*")
("Access-Control-Request-Method", "POST"), , ("Origin", "http://example.com")
("Access-Control-Request-Headers", "Foo,Bar") ] , ("Access-Control-Request-Method", "POST")
let normalCors = [ , ("Access-Control-Request-Headers", "Foo,Bar") ]
("Host", "localhost:3000"), ""
("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0"), `shouldRespondWith`
("Origin", "http://localhost:8000"), ""
("Accept", "text/csv, */*; q=0.01"), { matchHeaders = [ "Access-Control-Allow-Origin" <:> "http://example.com"
("Accept-Language", "en-US,en;q=0.5"), , "Access-Control-Allow-Credentials" <:> "true"
("Accept-Encoding", "gzip, deflate"), , "Access-Control-Allow-Methods" <:> "GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD"
("Referer", "http://localhost:8000/"), , "Access-Control-Allow-Headers" <:> "Authorization, Foo, Bar, Accept, Accept-Language, Content-Language"
("Connection", "keep-alive") ] , "Access-Control-Max-Age" <:> "86400" ]
}
describe "preflight request" $ do it "exposes necesssary response headers to regular request" $
it "replies naively and permissively to preflight request" $ do request methodGet "/items"
r <- request methodOptions "/items" preflightHeaders "" [("Origin", "http://example.com")]
liftIO $ do ""
let respHeaders = simpleHeaders r `shouldRespondWith`
respHeaders `shouldSatisfy` matchHeader ResponseMatcher
"Access-Control-Allow-Origin" { matchStatus = 200
"http://example.com" , matchBody = MatchBody (\_ _ -> Nothing) -- match any body
respHeaders `shouldSatisfy` matchHeader , matchHeaders = [ "Access-Control-Expose-Headers" <:>
"Access-Control-Allow-Credentials" "Content-Encoding, Content-Location, Content-Range, Content-Type, \
"true" \Date, Location, Server, Transfer-Encoding, Range-Unit"]
respHeaders `shouldSatisfy` matchHeader }
"Access-Control-Allow-Methods"
"GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD"
respHeaders `shouldSatisfy` matchHeader
"Access-Control-Allow-Headers"
"Authentication, Foo, Bar, Accept, Accept-Language, Content-Language"
respHeaders `shouldSatisfy` matchHeader
"Access-Control-Max-Age"
"86400"
it "suppresses body in response" $ do it "allows INFO body through even with CORS request headers present to postflight request" $
r <- request methodOptions "/" preflightHeaders "" request methodOptions "/items"
liftIO $ simpleBody r `shouldBe` "" [ ("Host", "localhost:3000")
, ("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0")
describe "regular request" $ , ("Origin", "http://localhost:8000")
it "exposes necesssary response headers" $ do , ("Accept", "text/csv, */*; q=0.01")
r <- request methodGet "/items" [("Origin", "http://example.com")] "" , ("Accept-Language", "en-US,en;q=0.5")
liftIO $ simpleHeaders r `shouldSatisfy` matchHeader , ("Accept-Encoding", "gzip, deflate")
"Access-Control-Expose-Headers" , ("Referer", "http://localhost:8000/")
"Content-Encoding, Content-Location, Content-Range, Content-Type, \ , ("Connection", "keep-alive") ]
\Date, Location, Server, Transfer-Encoding, Range-Unit" ""
`shouldRespondWith`
describe "postflight request" $ ""
it "allows INFO body through even with CORS request headers present" $ do { matchHeaders = [ "Access-Control-Allow-Origin" <:> "*" ] }
r <- request methodOptions "/items" normalCors ""
liftIO $ do
simpleHeaders r `shouldSatisfy` matchHeader
"Access-Control-Allow-Origin" "\\*"
simpleBody r `shouldSatisfy` BL.null