From 400bd564dc5ac3c36a032b443d954d071a06cd1e Mon Sep 17 00:00:00 2001 From: Joe Shanahan Date: Mon, 17 Jul 2017 09:18:34 +0100 Subject: [PATCH 1/6] Look inside cookies instead of just the header --- doc/tutorial/Authentication.lhs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/tutorial/Authentication.lhs b/doc/tutorial/Authentication.lhs index a097464f..2b6ce60a 100644 --- a/doc/tutorial/Authentication.lhs +++ b/doc/tutorial/Authentication.lhs @@ -284,14 +284,16 @@ create a value of type `AuthHandler Request Account` using the above `lookupAcco method: ```haskell --- | The auth handler wraps a function from Request -> Handler Account --- we look for a Cookie and pass the value of the cookie to `lookupAccount`. +import Web.Cookie (parseCookies) + authHandler :: AuthHandler Request Account -authHandler = - let handler req = case lookup "servant-auth-cookie" (requestHeaders req) of - Nothing -> throwError (err401 { errBody = "Missing auth header" }) - Just authCookieKey -> lookupAccount authCookieKey - in mkAuthHandler handler +authHandler = mkAuthHandler handler + where + maybeToEither e = maybe (Left e) Right + throw401 msg = throwError $ err401 { errBody = msg } + handler req = either throw401 lookupAccount $ do + cookie <- maybeToEither "Missing cookie header" $ lookup "cookie" $ requestHeaders req + maybeToEither "Missing token in cookie" $ lookup "servant-auth-cookie" $ parseCookies cookie ``` Let's now protect our API with our new, bespoke authentication scheme. We'll From c24096be168ce702d0410e9b253066b4b4f75d08 Mon Sep 17 00:00:00 2001 From: JoeMShanahan Date: Mon, 17 Jul 2017 10:09:51 +0100 Subject: [PATCH 2/6] Bring back the comment --- doc/tutorial/Authentication.lhs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/tutorial/Authentication.lhs b/doc/tutorial/Authentication.lhs index 2b6ce60a..9b3fa07b 100644 --- a/doc/tutorial/Authentication.lhs +++ b/doc/tutorial/Authentication.lhs @@ -286,6 +286,9 @@ method: ```haskell import Web.Cookie (parseCookies) +--- | The auth handler wraps a function from Request -> Handler Account +--- we look for a Cookie in the header and the perform a token look up +--- on the cookie, passing it to `lookupAccount`. authHandler :: AuthHandler Request Account authHandler = mkAuthHandler handler where From 160cda260282fda00ac98afa435d5b64171f098e Mon Sep 17 00:00:00 2001 From: JoeMShanahan Date: Mon, 17 Jul 2017 10:14:42 +0100 Subject: [PATCH 3/6] Explicitly state that we're adding a dependency here --- doc/tutorial/Authentication.lhs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial/Authentication.lhs b/doc/tutorial/Authentication.lhs index 9b3fa07b..25b87bd1 100644 --- a/doc/tutorial/Authentication.lhs +++ b/doc/tutorial/Authentication.lhs @@ -281,7 +281,7 @@ lookupAccount key = case Map.lookup key database of For generalized authentication, servant exposes the `AuthHandler` type, which is used to wrap the `Request -> Handler user` logic. Let's create a value of type `AuthHandler Request Account` using the above `lookupAccount` -method: +method (note: we depend upon `cookie`'s `parseCookies` for this): ```haskell import Web.Cookie (parseCookies) From 2c0aa36ae9bc628efbba045c31d7531d6dd11866 Mon Sep 17 00:00:00 2001 From: JoeMShanahan Date: Mon, 17 Jul 2017 10:51:08 +0100 Subject: [PATCH 4/6] Reword comment so that it actually makes sense! --- doc/tutorial/Authentication.lhs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/tutorial/Authentication.lhs b/doc/tutorial/Authentication.lhs index 25b87bd1..61eaea88 100644 --- a/doc/tutorial/Authentication.lhs +++ b/doc/tutorial/Authentication.lhs @@ -286,9 +286,9 @@ method (note: we depend upon `cookie`'s `parseCookies` for this): ```haskell import Web.Cookie (parseCookies) ---- | The auth handler wraps a function from Request -> Handler Account ---- we look for a Cookie in the header and the perform a token look up ---- on the cookie, passing it to `lookupAccount`. +--- | The auth handler wraps a function from Request -> Handler Account. +--- We look for a token in the request headers that we expect to be in the cookie. +--- The token is then passed to our `lookupAccount` function. authHandler :: AuthHandler Request Account authHandler = mkAuthHandler handler where From e6c492ab2ce07d26057634e575e08bdc64519b9d Mon Sep 17 00:00:00 2001 From: JoeMShanahan Date: Mon, 17 Jul 2017 11:18:13 +0100 Subject: [PATCH 5/6] Add hackage link to the cookie package --- doc/tutorial/Authentication.lhs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/tutorial/Authentication.lhs b/doc/tutorial/Authentication.lhs index 61eaea88..591bc595 100644 --- a/doc/tutorial/Authentication.lhs +++ b/doc/tutorial/Authentication.lhs @@ -281,7 +281,8 @@ lookupAccount key = case Map.lookup key database of For generalized authentication, servant exposes the `AuthHandler` type, which is used to wrap the `Request -> Handler user` logic. Let's create a value of type `AuthHandler Request Account` using the above `lookupAccount` -method (note: we depend upon `cookie`'s `parseCookies` for this): +method (note: we depend upon [`cookie`](https://hackage.haskell.org/package/cookie)'s +`parseCookies` for this): ```haskell import Web.Cookie (parseCookies) From 4b9d60ca8dc72d666a5d1e2327f4b72506288a25 Mon Sep 17 00:00:00 2001 From: Kazuki Okamoto Date: Wed, 13 Dec 2017 16:52:44 +0900 Subject: [PATCH 6/6] fix compilation error: move import declaration and add cookie to dependencies --- doc/tutorial/Authentication.lhs | 2 +- doc/tutorial/tutorial.cabal | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/tutorial/Authentication.lhs b/doc/tutorial/Authentication.lhs index 591bc595..b68e0300 100644 --- a/doc/tutorial/Authentication.lhs +++ b/doc/tutorial/Authentication.lhs @@ -69,6 +69,7 @@ import Servant.Server (BasicAuthCheck (BasicAuthCheck), import Servant.Server.Experimental.Auth (AuthHandler, AuthServerData, mkAuthHandler) import Servant.Server.Experimental.Auth() +import Web.Cookie (parseCookies) -- | private data that needs protection newtype PrivateData = PrivateData { ssshhh :: Text } @@ -285,7 +286,6 @@ method (note: we depend upon [`cookie`](https://hackage.haskell.org/package/cook `parseCookies` for this): ```haskell -import Web.Cookie (parseCookies) --- | The auth handler wraps a function from Request -> Handler Account. --- We look for a token in the request headers that we expect to be in the cookie. diff --git a/doc/tutorial/tutorial.cabal b/doc/tutorial/tutorial.cabal index 7b854f2f..c7e5ac7a 100644 --- a/doc/tutorial/tutorial.cabal +++ b/doc/tutorial/tutorial.cabal @@ -45,6 +45,7 @@ library , transformers , markdown-unlit >= 0.4 , http-client + , cookie default-language: Haskell2010 ghc-options: -Wall -pgmL markdown-unlit build-tool-depends: markdown-unlit:markdown-unlit