apiary-authenticate 0.8.0.0 → 0.9.0.0
raw patch · 4 files changed
+134/−52 lines, 4 filesdep +binarydep +taggeddep −waidep ~apiarydep ~apiary-clientsessionPVP ok
version bump matches the API change (PVP)
Dependencies added: binary, tagged
Dependencies removed: wai
Dependency ranges changed: apiary, apiary-clientsession
API changes (from Hackage documentation)
+ Web.Apiary.Authenticate: OpenId_ :: a -> [(a, a)] -> Maybe a -> OpenId_ a
+ Web.Apiary.Authenticate: claimed :: OpenId_ a -> Maybe a
+ Web.Apiary.Authenticate: data OpenId_ a
+ Web.Apiary.Authenticate: opLocal :: OpenId_ a -> a
+ Web.Apiary.Authenticate: params :: OpenId_ a -> [(a, a)]
+ Web.Apiary.Authenticate: type OpenId = OpenId_ Text
+ Web.Apiary.Authenticate.Explicit: AuthConfig :: ByteString -> ByteString -> Text -> [Text] -> [Text] -> [Text] -> [(Text, Provider)] -> AuthConfig
+ Web.Apiary.Authenticate.Explicit: OpenId_ :: a -> [(a, a)] -> Maybe a -> OpenId_ a
+ Web.Apiary.Authenticate.Explicit: Provider :: Text -> Maybe Text -> [(Text, Text)] -> Provider
+ Web.Apiary.Authenticate.Explicit: authConfig :: Auth -> AuthConfig
+ Web.Apiary.Authenticate.Explicit: authHandler :: (Functor n, MonadIO n) => Auth -> ApiaryT c n m ()
+ Web.Apiary.Authenticate.Explicit: authLogout :: Monad m => Auth -> ActionT m ()
+ Web.Apiary.Authenticate.Explicit: authLogoutPath :: AuthConfig -> [Text]
+ Web.Apiary.Authenticate.Explicit: authPrefix :: AuthConfig -> [Text]
+ Web.Apiary.Authenticate.Explicit: authProviders :: Auth -> [(Text, Provider)]
+ Web.Apiary.Authenticate.Explicit: authReturnToPath :: AuthConfig -> [Text]
+ Web.Apiary.Authenticate.Explicit: authRoutes :: Auth -> [(Text, ByteString)]
+ Web.Apiary.Authenticate.Explicit: authSessionName :: AuthConfig -> ByteString
+ Web.Apiary.Authenticate.Explicit: authSuccessPage :: AuthConfig -> ByteString
+ Web.Apiary.Authenticate.Explicit: authUrl :: AuthConfig -> Text
+ Web.Apiary.Authenticate.Explicit: authorized :: Auth -> Apiary (Snoc as OpenId) a -> Apiary as a
+ Web.Apiary.Authenticate.Explicit: claimed :: OpenId_ a -> Maybe a
+ Web.Apiary.Authenticate.Explicit: data Auth
+ Web.Apiary.Authenticate.Explicit: data AuthConfig
+ Web.Apiary.Authenticate.Explicit: data OpenId_ a
+ Web.Apiary.Authenticate.Explicit: data Provider
+ Web.Apiary.Authenticate.Explicit: opLocal :: OpenId_ a -> a
+ Web.Apiary.Authenticate.Explicit: parameters :: Provider -> [(Text, Text)]
+ Web.Apiary.Authenticate.Explicit: params :: OpenId_ a -> [(a, a)]
+ Web.Apiary.Authenticate.Explicit: providerUrl :: Provider -> Text
+ Web.Apiary.Authenticate.Explicit: providers :: AuthConfig -> [(Text, Provider)]
+ Web.Apiary.Authenticate.Explicit: realm :: Provider -> Maybe Text
+ Web.Apiary.Authenticate.Explicit: type OpenId = OpenId_ Text
+ Web.Apiary.Authenticate.Explicit: withAuth :: Session -> AuthConfig -> (Auth -> IO a) -> IO a
+ Web.Apiary.Authenticate.Explicit: withAuthWith :: Session -> ManagerSettings -> AuthConfig -> (Auth -> IO a) -> IO a
- Web.Apiary.Authenticate: authConfig :: (Monad m, HasAuth) => ActionT m AuthConfig
+ Web.Apiary.Authenticate: authConfig :: HasAuth => AuthConfig
- Web.Apiary.Authenticate: authProviders :: (Monad m, HasAuth) => ActionT m [(Text, Provider)]
+ Web.Apiary.Authenticate: authProviders :: HasAuth => [(Text, Provider)]
- Web.Apiary.Authenticate: authRoutes :: (Monad m, HasAuth) => ActionT m [(Text, ByteString)]
+ Web.Apiary.Authenticate: authRoutes :: HasAuth => [(Text, ByteString)]
- Web.Apiary.Authenticate: authorized :: HasAuth => Apiary (Snoc as ByteString) a -> Apiary as a
+ Web.Apiary.Authenticate: authorized :: HasAuth => Apiary (Snoc as OpenId) a -> Apiary as a
- Web.Apiary.Authenticate: type HasAuth = (Given Auth, HasSession)
+ Web.Apiary.Authenticate: type HasAuth = Given Auth
Files
- apiary-authenticate.cabal +6/−4
- src/Web/Apiary/Authenticate.hs +47/−2
- src/Web/Apiary/Authenticate/Explicit.hs +18/−0
- src/Web/Apiary/Authenticate/Internal.hs +63/−46
apiary-authenticate.cabal view
@@ -1,5 +1,5 @@ name: apiary-authenticate-version: 0.8.0.0+version: 0.9.0.0 synopsis: authenticate support for apiary web framework. description: example: <https://github.com/philopon/apiary/blob/master/examples/auth.hs>@@ -18,21 +18,23 @@ library exposed-modules: Web.Apiary.Authenticate+ Web.Apiary.Authenticate.Explicit other-modules: Web.Apiary.Authenticate.Internal build-depends: base >=4.6 && <4.8- , apiary >=0.8 && <0.9- , apiary-clientsession >=0.8 && <0.9+ , apiary >=0.9 && <0.10+ , apiary-clientsession >=0.9 && <0.10 , authenticate >=1.3 && <1.4 , http-client >=0.3 && <0.4 , http-client-tls >=0.2 && <0.3 , data-default-class >=0.0 && <0.1 , bytestring >=0.10 && <0.11 , text >=1.1 && <1.2- , wai >=2.1 && <2.2 , resourcet >=1.1 && <1.2 , http-types >=0.8 && <0.9 , blaze-builder >=0.3 && <0.4 , reflection >=1.4 && <1.5+ , binary >=0.7 && <0.8+ , tagged >=0.7 && <0.8 hs-source-dirs: src ghc-options: -O2 -Wall
src/Web/Apiary/Authenticate.hs view
@@ -1,5 +1,10 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE Rank2Types #-}+ module Web.Apiary.Authenticate (- AuthConfig(..), Provider(..)+ E.AuthConfig(..), E.Provider(..)+ , E.OpenId_(..), E.OpenId , HasAuth , withAuth, withAuthWith , authHandler@@ -13,5 +18,45 @@ , module Data.Default.Class ) where -import Web.Apiary.Authenticate.Internal+import Web.Apiary+import qualified Web.Apiary.Authenticate.Explicit as E+import qualified Network.HTTP.Client as Client+import Network.HTTP.Client.TLS(tlsManagerSettings)+import Web.Apiary.ClientSession++import Data.Reflection import Data.Default.Class+import Data.Apiary.SList+import qualified Data.Text as T+import qualified Data.ByteString as S++type HasAuth = Given E.Auth++withAuth :: HasSession => E.AuthConfig -> (HasAuth => IO a) -> IO a+withAuth = withAuthWith tlsManagerSettings++withAuthWith :: HasSession => Client.ManagerSettings+ -> E.AuthConfig -> (HasAuth => IO a) -> IO a+withAuthWith ms ac m = E.withAuthWith given ms ac (\a -> give a m)++-- | default auth handlers. since 0.8.0.0.+authHandler :: (Functor n, MonadIO n, HasAuth) => ApiaryT c n m ()+authHandler = E.authHandler given++-- | filter which check whether logged in or not, and get id. since 0.7.0.0.+authorized :: HasAuth => Apiary (Snoc as E.OpenId) a -> Apiary as a+authorized = E.authorized given++-- | delete session. since 0.7.0.0.+authLogout :: (Monad m, HasAuth) => ActionT m ()+authLogout = E.authLogout given++authConfig :: HasAuth => E.AuthConfig+authConfig = E.authConfig given++authProviders :: HasAuth => [(T.Text, E.Provider)]+authProviders = E.authProviders given++-- | get authenticate routes: (title, route). since 0.7.0.0.+authRoutes :: HasAuth => [(T.Text, S.ByteString)]+authRoutes = E.authRoutes given
+ src/Web/Apiary/Authenticate/Explicit.hs view
@@ -0,0 +1,18 @@+module Web.Apiary.Authenticate.Explicit (+ AuthConfig(..), Provider(..)+ , Auth+ , OpenId_(..), OpenId+ , withAuth, withAuthWith+ , authHandler+ -- * filter+ , authorized+ -- * action+ , authLogout+ -- ** getter+ , authConfig, authProviders, authRoutes+ -- * reexport+ , module Data.Default.Class+ ) where++import Web.Apiary.Authenticate.Internal+import Data.Default.Class
src/Web/Apiary/Authenticate/Internal.hs view
@@ -1,26 +1,29 @@-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ImplicitParams #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-} module Web.Apiary.Authenticate.Internal where import Control.Monad.Trans.Resource import Control.Applicative +import GHC.Generics(Generic)+import Data.Binary+import Data.Data import Data.Maybe import Data.List import Data.Default.Class-import Data.Reflection+import Data.Proxy -- for ghc-7.6 import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy as L import qualified Data.Text as T import qualified Data.Text.Encoding as T import Blaze.ByteString.Builder -import qualified Network.Wai as Wai+import qualified Web.Apiary.Wai as Wai import qualified Network.HTTP.Types as HTTP import qualified Network.HTTP.Client as Client import Network.HTTP.Client.TLS(tlsManagerSettings)@@ -29,7 +32,7 @@ import Web.Apiary hiding(Default(..)) import Data.Apiary.SList import Control.Monad.Apiary.Filter.Internal-import Web.Apiary.ClientSession+import Web.Apiary.ClientSession.Explicit data AuthConfig = AuthConfig { authSessionName :: S.ByteString@@ -56,29 +59,26 @@ ] data Auth = Auth- { manager :: Client.Manager- , config :: AuthConfig+ { manager :: Client.Manager+ , config :: AuthConfig+ , authSession :: Session } -type HasAuth = (Given Auth, HasSession)--withAuth :: HasSession => AuthConfig -> (HasAuth => IO a) -> IO a-withAuth = withAuthWith tlsManagerSettings+withAuth :: Session -> AuthConfig -> (Auth -> IO a) -> IO a+withAuth sess = withAuthWith sess tlsManagerSettings -withAuthWith :: HasSession => Client.ManagerSettings- -> AuthConfig -> (HasAuth => IO a) -> IO a-withAuthWith s conf m = Client.withManager s $ \mgr -> - give (Auth mgr conf) m+withAuthWith :: Session -> Client.ManagerSettings+ -> AuthConfig -> (Auth -> IO a) -> IO a+withAuthWith sess s conf m = Client.withManager s $ \mgr -> + m (Auth mgr conf sess) --- | default auth handlers. since 0.8.0.0.-authHandler :: (Functor n, MonadIO n, HasAuth) => ApiaryT c n m ()-authHandler = retH >> mapM_ (uncurry go) (providers config)+authHandler :: (Functor n, MonadIO n) => Auth -> ApiaryT c n m ()+authHandler Auth{..} = retH >> mapM_ (uncurry go) (providers config) where- Auth{..} = given pfxPath p = function (\_ r -> if p `isPrefixOf` Wai.pathInfo r then Just SNil else Nothing) retH = pfxPath (authPrefix config ++ authReturnToPath config) . stdMethod GET . action $- returnAction manager (authSessionName config) (authSuccessPage config)+ returnAction authSession manager (authSessionName config) (authSuccessPage config) go name Provider{..} = pfxPath (authPrefix config ++ [name]) . stdMethod GET . action $ authAction manager providerUrl returnTo realm parameters@@ -86,30 +86,22 @@ returnTo = T.decodeUtf8 $ T.encodeUtf8 (authUrl config) `S.append` toByteString (HTTP.encodePathSegments (authPrefix config ++ authReturnToPath config)) ---- | filter which check whether logged in or not, and get id. since 0.7.0.0.-authorized :: HasAuth => Apiary (Snoc as S.ByteString) a -> Apiary as a-authorized = session (authSessionName $ config given) (pOne pByteString)+authorized :: Auth -> Apiary (Snoc as OpenId) a -> Apiary as a+authorized Auth{..} = session authSession (authSessionName config) (pOne (Proxy :: Proxy OpenId)) --- | get auth config. since 0.7.0.0.-authConfig :: (Monad m, HasAuth) => ActionT m AuthConfig-authConfig = return (config given)+authConfig :: Auth -> AuthConfig+authConfig = config --- | get providers. since 0.7.0.0.-authProviders :: (Monad m, HasAuth) => ActionT m [(T.Text, Provider)]-authProviders = providers <$> authConfig+authProviders :: Auth -> [(T.Text, Provider)]+authProviders = providers . config --- | get authenticate routes: (title, route). since 0.7.0.0.-authRoutes :: (Monad m, HasAuth) => ActionT m [(T.Text, S.ByteString)]-authRoutes = do - conf <- authConfig- return . map (\(k,_) -> (k, toByteString . HTTP.encodePathSegments $ authPrefix conf ++ [k])) $ providers conf+authRoutes :: Auth -> [(T.Text, S.ByteString)]+authRoutes auth =+ map (\(k,_) -> (k, toByteString . HTTP.encodePathSegments $ authPrefix (config auth) ++ [k])) $+ providers (config auth) --- | delete session. since 0.7.0.0.-authLogout :: (Monad m, HasAuth) => ActionT m ()-authLogout = do- conf <- authConfig- deleteCookie (authSessionName conf)+authLogout :: Monad m => Auth -> ActionT m ()+authLogout auth = deleteCookie (authSessionName $ config auth) authAction :: MonadIO m => Client.Manager -> T.Text -> T.Text -> Maybe T.Text -> [(T.Text, T.Text)] -> ActionT m ()@@ -117,11 +109,36 @@ fw <- liftIO . runResourceT $ getForwardUrl uri returnTo realm param mgr redirect $ T.encodeUtf8 fw -returnAction :: (MonadIO m, HasSession) => Client.Manager -> S.ByteString -> S.ByteString -> ActionT m ()-returnAction mgr key to = do+data OpenId_ a = OpenId_+ { opLocal :: a+ , params :: [(a, a)]+ , claimed :: Maybe a+ } deriving (Show, Read, Eq, Ord, Data, Typeable, Generic, Functor)+instance Binary (OpenId_ S.ByteString)++instance Binary (OpenId_ T.Text) where+ get = fmap (fmap T.decodeUtf8) (get :: Get (OpenId_ S.ByteString))+ put g = put (fmap T.encodeUtf8 g)++instance Query (OpenId_ T.Text) where+ readQuery Nothing = Nothing+ readQuery (Just s) = case decodeOrFail (L.fromStrict s) of+ Right (s',_,a) | L.null s' -> Just a+ _ -> Nothing++type OpenId = OpenId_ T.Text++toOpenId :: OpenIdResponse -> OpenId+toOpenId r = OpenId_ + (identifier $ oirOpLocal r)+ (oirParams r)+ (identifier <$> oirClaimed r)++returnAction :: MonadIO m => Session -> Client.Manager -> S.ByteString -> S.ByteString -> ActionT m ()+returnAction sess mgr key to = do q <- Wai.queryString <$> getRequest r <- liftIO . runResourceT $ authenticateClaimed (mapMaybe queryElem q) mgr- setSession key (T.encodeUtf8 . identifier $ oirOpLocal r)+ setSession sess key . L.toStrict $ encode (toOpenId r) redirect to where queryElem (_, Nothing) = Nothing