packages feed

Spock-auth (empty) → 0.1.0.0

raw patch · 3 files changed

+172/−0 lines, 3 filesdep +Spockdep +basedep +http-typessetup-changed

Dependencies added: Spock, base, http-types, text, time

Files

+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Spock-auth.cabal view
@@ -0,0 +1,26 @@+name:                Spock-auth+version:             0.1.0.0+synopsis:            Provides authentification helpers for Spock+Homepage:            https://github.com/agrafix/Spock-auth+Bug-reports:         https://github.com/agrafix/Spock-auth/issues+license:             BSD3+author:              Alexander Thiemann <mail@agrafix.net>+maintainer:          mail@agrafix.net+copyright:           (c) 2014 Alexander Thiemann+category:            Web+build-type:          Simple+cabal-version:       >=1.8++library+  hs-source-dirs:   src+  exposed-modules:  Web.Spock.Auth+  build-depends:    base >= 4 && < 5,+                    Spock >=0.4.3.0,+                    text,+                    http-types,+                    time+  ghc-options: -Wall -fno-warn-orphans++source-repository head+  type:     git+  location: git://github.com/agrafix/Spock-auth.git
+ src/Web/Spock/Auth.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE OverloadedStrings #-}+module Web.Spock.Auth+    ( -- * Initialisation helpers+      authSessCfg, AuthCfg (..)+      -- * Handeling custom session data+    , writeSessionData, readSessionData, modifySessionData+      -- * Access control+    , VisitorSession, NoAccessReason (..)+    , NoAccessHandler, LoadUserFun, CheckRightsFun, UserRights+    , markAsLoggedIn+    , markAsGuest+    , userRoute+    )+where++import Web.Spock++import Control.Applicative+import Data.Time.Clock+import qualified Network.HTTP.Types as Http+import qualified Data.Text as T++-- | Configuration+data AuthCfg sess+   = AuthCfg+   { ac_sessionTTL :: NominalDiffTime+   , ac_emptySession :: sess+   }++-- | Assign the current session roles/permission, eg. admin or user+type UserRights = T.Text++-- | Describes why access was denied to a user+data NoAccessReason+   = NotEnoughRights+   | NotLoggedIn+   | NotValidUser+   deriving (Show, Eq, Read, Enum)++-- | Define what happens to non-authorized requests+type NoAccessHandler conn sess userId st =+    NoAccessReason -> SpockAction conn (VisitorSession sess userId) st ()++-- | How should a session be transformed into a user? Can access the database using 'runQuery'+type LoadUserFun conn sess userId st user =+    userId -> SpockAction conn (VisitorSession sess userId) st (Maybe user)++-- | What rights does the current user have? Can access the database using 'runQuery'+type CheckRightsFun conn sess userId st user =+    user -> [UserRights] -> SpockAction conn (VisitorSession sess userId) st Bool++data SessionType userId+   = GuestSession+   | UserSession userId+   deriving (Show, Eq)++data VisitorSession sess userId+   = VisitorSession+   { vs_type :: SessionType userId+   , vs_data :: sess+   }+   deriving (Show, Eq)++-- | Plug this into the 'spock' function to create SessionCfg+authSessCfg :: AuthCfg sess -> SessionCfg (VisitorSession sess userId)+authSessCfg authCfg =+    SessionCfg+    { sc_cookieName = "spocksession"+    , sc_sessionTTL = ac_sessionTTL authCfg+    , sc_sessionIdEntropy = 42+    , sc_emptySession = VisitorSession GuestSession (ac_emptySession authCfg)+    }++-- | Mark current visitor as logged in+markAsLoggedIn :: userId -> SpockAction conn (VisitorSession sess userId) st ()+markAsLoggedIn userId =+    modifySession (\oldData -> oldData { vs_type = (UserSession userId) })++-- | Mark current visitor as guest+markAsGuest :: SpockAction conn (VisitorSession sess userId) st ()+markAsGuest =+    modifySession (\oldData -> oldData { vs_type = GuestSession })++-- | Replacement for 'readSession'+readSessionData :: SpockAction conn (VisitorSession sess userId) st sess+readSessionData =+    vs_data <$> readSession++-- | Replacement for 'modifySession'+modifySessionData :: (sess -> sess) -> SpockAction conn (VisitorSession sess userId) st ()+modifySessionData f =+    modifySession (\oldData -> oldData { vs_data = f (vs_data oldData) })++-- | Replacement for 'writeSession'+writeSessionData :: sess -> SpockAction conn (VisitorSession sess userId) st ()+writeSessionData v =+    modifySessionData (const v)++-- | Before the request is performed, you can check if the signed in user has permissions to+-- view the contents of the request. You may want to define a helper function that+-- proxies this function to not pass around 'NoAccessHandler', 'LoadUserFun' and 'CheckRightsFun'+-- all the time.+-- Example:+--+-- > type MyWebMonad a = SpockAction Connection (VisitorSession () UserId) () a+-- > newtype MyUser = MyUser { unMyUser :: T.Text }+-- >+-- > http403 msg =+-- >    do status Http.status403+-- >       text (show msg)+-- >+-- > login :: Http.StdMethod+-- >       -> [UserRights]+-- >       -> RoutePattern+-- >       -> (MyUser -> MyWebMonad ())+-- >       -> MyWebMonad ()+-- > login =+-- >     userRoute http403 myLoadUser myCheckRights+--+userRoute :: NoAccessHandler conn sess userId st+          -> LoadUserFun conn sess userId st user+          -> CheckRightsFun conn sess userId st user+          -> Http.StdMethod+          -> [UserRights]+          -> RoutePattern+          -> (user -> SpockAction conn (VisitorSession sess userId) st ())+          -> SpockM conn (VisitorSession sess userId) st ()+userRoute noAccessHandler loadUser checkRights reqTy requiredRights route action =+    addroute reqTy route $+    do sessData <- readSession+       case vs_type sessData of+         GuestSession ->+             noAccessHandler NotLoggedIn+         UserSession userId ->+             do mUser <- loadUser userId+                case mUser of+                  Nothing ->+                      noAccessHandler NotValidUser+                  Just user ->+                      do isOk <- checkRights user requiredRights+                         if isOk+                         then action user+                         else noAccessHandler NotEnoughRights