@@ -14,9 +14,10 @@ module Server.Auth (
14 cookieTokenKey,
14 cookieTokenKey,
15 genAuthServerContext,
15 genAuthServerContext,
16 AuthenticationHandler,
16 AuthenticationHandler,
17− authenticate,
17+ logIn,
18 contextProxy,
18 contextProxy,
19− AuthenticationCredits(..)
19+ AuthenticationCredits(..),
22import Server.App
23import Server.App
@@ -35,6 +36,7 @@ import Network.Wai (Request, requestHeaders)
35import Servant.Server
36import Servant.Server
36import Web.Cookie
37import Web.Cookie
37import Data.Time.Clock
38import Data.Time.Clock
39+import Data.Time.Calendar
38import Data.Proxy
40import Data.Proxy
39import qualified GHC.Generics as GHC
41import qualified GHC.Generics as GHC
40import Data.Aeson
42import Data.Aeson
@@ -48,27 +50,41 @@ instance ToSample AuthenticationCredits where
49-- MARK: Implementation
51-- MARK: Implementation
53+type AuthenticationHandler =
55+ ReqBody '[JSON] AuthenticationCredits :>
56+ Post '[JSON] (Headers '[Header "Set-Cookie" String] UserId) :<|>
51−type AuthenticationHandler = ReqBody '[JSON] AuthenticationCredits :> PostNoContent '[JSON, PlainText, FormUrlEncoded] (Headers '[Header "Set-Cookie" String] NoContent)
58+ PostNoContent '[JSON, PlainText, FormUrlEncoded] (Headers '[Header "Set-Cookie" String] NoContent)
53−data AuthenticationCredits = AuthenticationCredits {authenticationId :: UserId}
60+newtype AuthenticationCredits = AuthenticationCredits {authenticationId :: UserId}
54 deriving GHC.Generic
61 deriving GHC.Generic
56instance ToJSON AuthenticationCredits
63instance ToJSON AuthenticationCredits
57instance FromJSON AuthenticationCredits
64instance FromJSON AuthenticationCredits
59−authenticate :: ServerT AuthenticationHandler App
66+authenticationAPI :: ServerT AuthenticationHandler App
67+authenticationAPI = logIn :<|> logOut
69+logIn :: AuthenticationCredits -> App (Headers '[Header "Set-Cookie" String] UserId)
60−authenticate (AuthenticationCredits uId) = do
70+logIn (AuthenticationCredits uId) = do
61 expire <- liftIO $ fmap (addUTCTime (1 * 24 * 60 * 60)) getCurrentTime -- one days
71 expire <- liftIO $ fmap (addUTCTime (1 * 24 * 60 * 60)) getCurrentTime -- one days
62− tId <- fmap userId . runQ invalidToken . getUser $ uId
72+ tId <- fmap userId . runQ err404 . getUser $ uId
63 let cookie = defaultSetCookie {
73 let cookie = defaultSetCookie {
64 setCookieName = cookieTokenKey,
74 setCookieName = cookieTokenKey,
65 setCookieValue = C.pack $ show tId,
75 setCookieValue = C.pack $ show tId,
66 setCookieExpires = Just expire,
76 setCookieExpires = Just expire,
67− -- setCookieDomain = Just "127.0.0.1",
68 setCookiePath = Just "/" }
77 setCookiePath = Just "/" }
69− -- let token = cookieTokenKeyString <> "=" <> show tId <> "; Expires=" <> show expire <> "; Domain=127.0.0.1:2000; Path=/" -- ; Secure" --; HttpOnly"
70− return $ addHeader (L.unpack . toLazyByteString . renderSetCookie $ cookie) NoContent
78+ return $ addHeader (L.unpack . toLazyByteString . renderSetCookie $ cookie) tId
80+logOut :: App (Headers '[Header "Set-Cookie" String] NoContent)
82+ let cookie = defaultSetCookie {
83+ setCookieName = cookieTokenKey,
84+ setCookieValue = "invalid",
85+ setCookieExpires = Just (UTCTime (ModifiedJulianDay 0) 0),
86+ setCookiePath = Just "/" }
87+ in return $ addHeader (L.unpack . toLazyByteString . renderSetCookie $ cookie) NoContent
73checkToken :: DBConnection -> BS.ByteString -> Handler UserId
89checkToken :: DBConnection -> BS.ByteString -> Handler UserId
74checkToken conn token = do
90checkToken conn token = do
@@ -80,11 +96,11 @@ checkToken conn token = do
80authHandler :: DBConnection -> AuthHandler Request UserId
96authHandler :: DBConnection -> AuthHandler Request UserId
81authHandler conn = mkAuthHandler handler
97authHandler conn = mkAuthHandler handler
83− maybeToEither e = maybe (Left e) Right
99+ maybeToEither = maybe (Left ()) Right
84− throw401 msg = throwError $ err401 { errBody = msg }
100+ throw = const $ throwError invalidToken
85− handler req = either throw401 (checkToken conn) $ do
101+ handler req = either throw (checkToken conn) $ do
86− cookie <- maybeToEither "Missing cookie header" $ lookup "cookie" $ requestHeaders req
102+ cookie <- maybeToEither $ lookup "cookie" $ requestHeaders req
87− maybeToEither "Missing token in cookie" $ lookup cookieTokenKey $ parseCookies cookie
103+ maybeToEither $ lookup cookieTokenKey $ parseCookies cookie
89cookieTokenKey :: BS.ByteString
105cookieTokenKey :: BS.ByteString
90cookieTokenKey = "servant-auth-cookie"
106cookieTokenKey = "servant-auth-cookie"