show logout success before redirecting
This commit is contained in:
parent
83d99e5530
commit
2a2813fef2
@ -38,6 +38,7 @@ library
|
|||||||
, bytestring
|
, bytestring
|
||||||
, containers
|
, containers
|
||||||
, cookie
|
, cookie
|
||||||
|
, ghc
|
||||||
, http-api-data
|
, http-api-data
|
||||||
, http-client
|
, http-client
|
||||||
, http-media
|
, http-media
|
||||||
@ -74,6 +75,7 @@ executable oauth2-mock-server-exe
|
|||||||
, conduit
|
, conduit
|
||||||
, containers
|
, containers
|
||||||
, cookie
|
, cookie
|
||||||
|
, ghc
|
||||||
, http-api-data
|
, http-api-data
|
||||||
, http-client
|
, http-client
|
||||||
, http-media
|
, http-media
|
||||||
@ -115,6 +117,7 @@ test-suite oauth2-mock-server-test
|
|||||||
, bytestring
|
, bytestring
|
||||||
, containers
|
, containers
|
||||||
, cookie
|
, cookie
|
||||||
|
, ghc
|
||||||
, http-api-data
|
, http-api-data
|
||||||
, http-client
|
, http-client
|
||||||
, http-media
|
, http-media
|
||||||
|
|||||||
@ -25,6 +25,7 @@ description: Please see the README # on GitHub at <https://github.com/gi
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
- base >= 4.7 && < 5
|
- base >= 4.7 && < 5
|
||||||
|
- ghc
|
||||||
- servant
|
- servant
|
||||||
- servant-server
|
- servant-server
|
||||||
- servant-client
|
- servant-client
|
||||||
|
|||||||
@ -14,11 +14,13 @@ module LoginForm
|
|||||||
|
|
||||||
import Prelude hiding (head)
|
import Prelude hiding (head)
|
||||||
|
|
||||||
import qualified Data.Map as M
|
|
||||||
import Data.Aeson (encode)
|
import Data.Aeson (encode)
|
||||||
import qualified Data.String.Interpolate as I
|
|
||||||
import Data.String (IsString(..))
|
import Data.String (IsString(..))
|
||||||
import Data.Text (Text)
|
import Data.Text (Text, unpack)
|
||||||
|
import qualified Data.Map as M
|
||||||
|
import qualified Data.String.Interpolate as I
|
||||||
|
|
||||||
|
import GHC.Data.Maybe (whenIsJust)
|
||||||
|
|
||||||
import Network.HTTP.Media ((//), (/:))
|
import Network.HTTP.Media ((//), (/:))
|
||||||
|
|
||||||
@ -74,8 +76,8 @@ loginPage uri headers = docTypeHtml $ head' >> body'
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
|
|
||||||
logoutPage :: Html
|
logoutPage :: Maybe Text -> Html
|
||||||
logoutPage = docTypeHtml $ head' >> body'
|
logoutPage mUri = docTypeHtml $ head' >> body'
|
||||||
where
|
where
|
||||||
head' = head $ do
|
head' = head $ do
|
||||||
meta ! A.charset "UTF-8"
|
meta ! A.charset "UTF-8"
|
||||||
@ -83,4 +85,10 @@ logoutPage = docTypeHtml $ head' >> body'
|
|||||||
title "UniWorX Oauth2 Mock Server"
|
title "UniWorX Oauth2 Mock Server"
|
||||||
body' = body $ do
|
body' = body $ do
|
||||||
h1 "UniWorX Oauth2 Mock Server"
|
h1 "UniWorX Oauth2 Mock Server"
|
||||||
p "Logout successful."
|
p "Logout successful."
|
||||||
|
whenIsJust mUri $ \uri -> do
|
||||||
|
a ! A.href (fromString $ unpack uri) $ "Continue"
|
||||||
|
script $
|
||||||
|
[I.i|
|
||||||
|
setTimeout(_ => window.location.replace('#{uri}'), 2000); |]
|
||||||
|
|
||||||
@ -13,6 +13,7 @@
|
|||||||
, AllowAmbiguousTypes
|
, AllowAmbiguousTypes
|
||||||
, LambdaCase
|
, LambdaCase
|
||||||
, FlexibleContexts
|
, FlexibleContexts
|
||||||
|
, KindSignatures
|
||||||
#-}
|
#-}
|
||||||
|
|
||||||
module Server
|
module Server
|
||||||
@ -35,19 +36,19 @@ import Control.Concurrent
|
|||||||
import Control.Concurrent.STM (atomically)
|
import Control.Concurrent.STM (atomically)
|
||||||
import Control.Concurrent.STM.TVar (newTVarIO, readTVar, modifyTVar)
|
import Control.Concurrent.STM.TVar (newTVarIO, readTVar, modifyTVar)
|
||||||
import Control.Exception (bracket)
|
import Control.Exception (bracket)
|
||||||
import Control.Monad (unless, (>=>), foldM)
|
import Control.Monad (unless, (>=>), foldM, void)
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Control.Monad.Trans.Error (Error(..))
|
import Control.Monad.Trans.Error (Error(..))
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.ByteString (fromStrict, ByteString)
|
import Data.ByteString (fromStrict, toStrict, ByteString)
|
||||||
import Data.List (find, elemIndex)
|
import Data.List (find, elemIndex)
|
||||||
import Data.Maybe (fromMaybe, fromJust, isJust, isNothing)
|
import Data.Maybe (fromMaybe, fromJust, isJust, isNothing)
|
||||||
import Data.String (IsString (..))
|
import Data.String (IsString (..))
|
||||||
import Data.Text hiding (elem, find, head, length, map, null, splitAt, tail, words)
|
import Data.Text hiding (elem, find, head, length, map, null, splitAt, tail, words)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Text.Encoding (encodeUtf8)
|
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
|
||||||
import Data.Text.Encoding.Base64
|
import Data.Text.Encoding.Base64
|
||||||
import Data.Time.Clock (NominalDiffTime (..), nominalDay, UTCTime(..), getCurrentTime, addUTCTime)
|
import Data.Time.Clock (NominalDiffTime (..), nominalDay, UTCTime(..), getCurrentTime, addUTCTime)
|
||||||
|
|
||||||
@ -58,20 +59,22 @@ import GHC.Read (readPrec, lexP)
|
|||||||
import Jose.Jwk (generateRsaKeyPair, KeyUse(..), KeyId)
|
import Jose.Jwk (generateRsaKeyPair, KeyUse(..), KeyId)
|
||||||
import Jose.Jwt hiding (decode, encode)
|
import Jose.Jwt hiding (decode, encode)
|
||||||
|
|
||||||
import Network.HTTP.Client (newManager, defaultManagerSettings)
|
import Network.HTTP.Client (newManager, defaultManagerSettings, httpLbs, parseRequest)
|
||||||
import Network.Wai.Handler.Warp
|
import Network.Wai.Handler.Warp
|
||||||
|
|
||||||
import Servant
|
import Servant
|
||||||
import Servant.Client hiding (client)
|
import Servant.Client hiding (client)
|
||||||
import Servant.API
|
import Servant.API
|
||||||
|
|
||||||
|
import System.Environment (getEnv)
|
||||||
|
|
||||||
import Text.ParserCombinators.ReadPrec (look, pfail)
|
import Text.ParserCombinators.ReadPrec (look, pfail)
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
|
|
||||||
import qualified Text.Read.Lex as Lex
|
import qualified Text.Read.Lex as Lex
|
||||||
|
|
||||||
import Web.Cookie (parseCookiesText)
|
import Web.Cookie (parseCookiesText)
|
||||||
import Web.Internal.FormUrlEncoded (FromForm(..), parseUnique, parseMaybe, Form(..))
|
import Web.Internal.FormUrlEncoded (FromForm(..), parseUnique, parseMaybe, Form(..), urlEncodeParams)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -364,23 +367,66 @@ userListEndpoint = handleUserData
|
|||||||
---- Logout ----
|
---- Logout ----
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
{-type Redirect (cs :: [*]) (hs :: [*]) a = Verb 'GET 303 cs (Headers (Header "Location" Text : hs) a)
|
||||||
|
|
||||||
|
type CookieLogout = "clogout"
|
||||||
|
:> QParam "redirect" QRedirect
|
||||||
|
:> Redirect '[HTML] '[] Text
|
||||||
|
clogoutEndpoint :: forall user userData . UserData user userData => AuthServer user CookieLogout
|
||||||
|
clogoutEndpoint uri = do
|
||||||
|
return $ addHeader uri ""-}
|
||||||
|
|
||||||
|
|
||||||
type Logout = "logout"
|
type Logout = "logout"
|
||||||
:> QueryParam "post_logout_redirect_uri" QRedirect
|
:> QueryParam "post_logout_redirect_uri" QRedirect
|
||||||
:> HeaderR "Cookie" QCookie
|
:> HeaderR "Cookie" QCookie
|
||||||
:> Get '[HTML] (Headers '[Header "Set-Cookie" Text] Html)
|
:> Get '[HTML] (Headers '[Header "Set-Cookie" Text] Html)
|
||||||
|
{- :> Redirect '[HTML] '[Header "Set-Cookie" Text] NoContent
|
||||||
|
:<|> "logout"
|
||||||
|
:> HeaderR "Cookie" QCookie
|
||||||
|
:> Get '[HTML] (Headers '[Header "Set-Cookie" Text] Html) -}
|
||||||
|
|
||||||
logoutEndpoint :: forall user userData . UserData user userData => AuthServer user Logout
|
logoutEndpoint :: forall user userData . UserData user userData => AuthServer user Logout
|
||||||
logoutEndpoint = logout
|
logoutEndpoint = logout -- rLogout :<|> logout
|
||||||
where
|
where
|
||||||
logout :: Maybe QRedirect
|
logout :: Maybe QRedirect
|
||||||
-> QCookie
|
-> QCookie
|
||||||
-> AuthHandler user (Headers '[Header "Set-Cookie" Text] Html)
|
-> AuthHandler user (Headers '[Header "Set-Cookie" Text] Html)
|
||||||
logout mUri cookie = do
|
logout mRedir cookie = do
|
||||||
let mCreds = lookup authCookie . parseCookiesText $ encodeUtf8 cookie
|
let mCreds = lookup authCookie . parseCookiesText $ encodeUtf8 cookie
|
||||||
unless (isJust mCreds) $ throwError err401 { errBody = "Missing auth cookie" }
|
unless (isJust mCreds) $ throwError err401 { errBody = "Missing auth cookie" }
|
||||||
addHeader (authCookie <> "=\"\"") <$> case mUri of
|
liftIO . putStrLn $ "\nLOGOUT\n "
|
||||||
Just uri -> throwError err303 { errHeaders = [("Location", encodeUtf8 uri)]}
|
return . addHeader (authCookie <> "=\"\"") $ logoutPage mRedir
|
||||||
Nothing -> return logoutPage
|
|
||||||
|
{- checkCookie :: QCookie -> AuthHandler user ()
|
||||||
|
checkCookie cookie = do
|
||||||
|
let mCreds = lookup authCookie . parseCookiesText $ encodeUtf8 cookie
|
||||||
|
unless (isJust mCreds) $ throwError err401 { errBody = "Missing auth cookie" }
|
||||||
|
return ()
|
||||||
|
|
||||||
|
rLogout :: QRedirect
|
||||||
|
-> QCookie
|
||||||
|
-> AuthHandler user (Headers '[ Header "Location" Text
|
||||||
|
, Header "Set-Cookie" Text
|
||||||
|
] NoContent)
|
||||||
|
rLogout uri cookie = do
|
||||||
|
liftIO . putStrLn $ "\nLOGOUT with uri " <> show uri <> "\n"
|
||||||
|
checkCookie cookie
|
||||||
|
let param = decodeUtf8 . toStrict $ urlEncodeParams [("redirect", uri)]
|
||||||
|
uri' = "../clogout?" <> param
|
||||||
|
addHeader uri' . addHeader (authCookie <> "=\"\"") <$> return NoContent
|
||||||
|
|
||||||
|
logout :: QCookie
|
||||||
|
-> AuthHandler user (Headers '[Header "Set-Cookie" Text] Html)
|
||||||
|
logout cookie = do
|
||||||
|
liftIO . putStrLn $ "\nLOGOUT\n "
|
||||||
|
checkCookie cookie
|
||||||
|
return . addHeader (authCookie <> "=\"\"")$ logoutPage Nothing
|
||||||
|
-- liftIO $ do
|
||||||
|
-- port <- getEnv "OAUTH2_SERVER_PORT"
|
||||||
|
-- manager <- newManager defaultManagerSettings
|
||||||
|
-- req <- parseRequest $ "GET http://localhost:" ++ port ++ "/clogout" -- TODO get root
|
||||||
|
-- void $ httpLbs req manager -}
|
||||||
|
|
||||||
|
|
||||||
-------------------
|
-------------------
|
||||||
@ -392,6 +438,7 @@ type Routing user userData = Auth
|
|||||||
:<|> Token
|
:<|> Token
|
||||||
:<|> Me userData
|
:<|> Me userData
|
||||||
:<|> UserList userData
|
:<|> UserList userData
|
||||||
|
-- :<|> CookieLogout
|
||||||
:<|> Logout
|
:<|> Logout
|
||||||
|
|
||||||
routing :: forall user userData . UserData user userData => AuthServer user (Routing user userData)
|
routing :: forall user userData . UserData user userData => AuthServer user (Routing user userData)
|
||||||
@ -400,6 +447,7 @@ routing = loginServer @user @userData
|
|||||||
:<|> tokenEndpoint @user @userData
|
:<|> tokenEndpoint @user @userData
|
||||||
:<|> userEndpoint @user @userData
|
:<|> userEndpoint @user @userData
|
||||||
:<|> userListEndpoint @user @userData
|
:<|> userListEndpoint @user @userData
|
||||||
|
-- :<|> clogoutEndpoint @user @userData
|
||||||
:<|> logoutEndpoint @user @userData
|
:<|> logoutEndpoint @user @userData
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user