-
Notifications
You must be signed in to change notification settings - Fork 68
/
AuthManager.hs
103 lines (82 loc) · 3.55 KB
/
AuthManager.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
------------------------------------------------------------------------------
-- | Internal module exporting AuthManager implementation.
--
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Snap.Snaplet.Auth.AuthManager
( -- * AuthManager Datatype
AuthManager(..)
-- * Backend Typeclass
, IAuthBackend(..)
-- * Context-free Operations
, buildAuthUser
) where
------------------------------------------------------------------------------
import Data.ByteString (ByteString)
import Data.Text (Text)
import Data.Time
import Web.ClientSession
import Snap.Snaplet
import Snap.Snaplet.Session
import Snap.Snaplet.Auth.Types
------------------------------------------------------------------------------
-- | Creates a new user from a username and password.
--
buildAuthUser :: IAuthBackend r =>
r -- ^ An auth backend
-> Text -- ^ Username
-> ByteString -- ^ Password
-> IO (Either AuthFailure AuthUser)
buildAuthUser r unm pass = do
now <- getCurrentTime
let au = defAuthUser {
userLogin = unm
, userPassword = Nothing
, userCreatedAt = Just now
, userUpdatedAt = Just now
}
au' <- setPassword au pass
save r au'
------------------------------------------------------------------------------
-- | All storage backends need to implement this typeclass
--
class IAuthBackend r where
-- | Create or update the given 'AuthUser' record. A 'userId' of Nothing
-- indicates that a new user should be created, otherwise the user
-- information for that userId should be updated.
save :: r -> AuthUser -> IO (Either AuthFailure AuthUser)
lookupByUserId :: r -> UserId -> IO (Maybe AuthUser)
lookupByLogin :: r -> Text -> IO (Maybe AuthUser)
lookupByRememberToken :: r -> Text -> IO (Maybe AuthUser)
destroy :: r -> AuthUser -> IO ()
------------------------------------------------------------------------------
-- | Abstract data type holding all necessary information for auth operation
data AuthManager b = forall r. IAuthBackend r => AuthManager {
backend :: r
-- ^ Storage back-end
, session :: SnapletLens b SessionManager
-- ^ A lens pointer to a SessionManager
, activeUser :: Maybe AuthUser
-- ^ A per-request logged-in user cache
, minPasswdLen :: Int
-- ^ Password length range
, rememberCookieName :: ByteString
-- ^ Cookie name for the remember token
, rememberPeriod :: Maybe Int
-- ^ Remember period in seconds. Defaults to 2 weeks.
, siteKey :: Key
-- ^ A unique encryption key used to encrypt remember cookie
, lockout :: Maybe (Int, NominalDiffTime)
-- ^ Lockout after x tries, re-allow entry after y seconds
, randomNumberGenerator :: RNG
-- ^ Random number generator
}
instance IAuthBackend (AuthManager b) where
save AuthManager{..} u = save backend u
lookupByUserId AuthManager{..} u = lookupByUserId backend u
lookupByLogin AuthManager{..} u = lookupByLogin backend u
lookupByRememberToken AuthManager{..} u = lookupByRememberToken backend u
destroy AuthManager{..} u = destroy backend u