Guest User

Untitled

a guest
Oct 3rd, 2018
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.48 KB | None | 0 0
  1. {-# LANGUAGE BangPatterns #-}
  2. {-# LANGUAGE OverloadedStrings #-}
  3. {-# LANGUAGE RecordWildCards #-}
  4.  
  5. module Snap.Snaplet.Auth.Backends.MongoDB
  6. ( initMongoAuth
  7. ) where
  8.  
  9. ------------------------------------------------------------------------------
  10. import Control.Arrow
  11. import qualified Data.Bson as BS
  12. import qualified Data.Configurator as C
  13. import qualified Data.Text as T
  14. import Data.Maybe
  15. import qualified Data.UString as US
  16. import Database.MongoDB (Document, Val(..), u, Field((:=)))
  17. import Database.MongoDB as M
  18. import Snap
  19. import Snap.Snaplet.Auth
  20. import Snap.Snaplet.MongoDB
  21. import Snap.Snaplet.Session
  22. import System.IO.Pool (Pool, Factory (Factory), aResource)
  23. import Web.ClientSession
  24. import Snap.Snaplet.MongoDB
  25. import Snap.Snaplet
  26.  
  27. data MongoAuthManager = MongoAuthManager
  28. { mongodbName :: String
  29. , mongoTable :: String
  30. , mongoConnPool :: MongoDB
  31. }
  32.  
  33.  
  34. ------------------------------------------------------------------------------
  35. -- | Simple function to get auth settings from a config file. All options
  36. -- are optional and default to what's in defAuthSettings if not supplied.
  37. settingsFromConfig :: Initializer b (AuthManager b) AuthSettings
  38. settingsFromConfig = do
  39. config <- getSnapletUserConfig
  40. minPasswordLen <- liftIO $ C.lookup config "minPasswordLen"
  41. let pw = maybe id (\x s -> s { asMinPasswdLen = x }) minPasswordLen
  42. rememberCookie <- liftIO $ C.lookup config "rememberCookie"
  43. let rc = maybe id (\x s -> s { asRememberCookieName = x }) rememberCookie
  44. rememberPeriod <- liftIO $ C.lookup config "rememberPeriod"
  45. let rp = maybe id (\x s -> s { asRememberPeriod = Just x }) rememberPeriod
  46. lockout <- liftIO $ C.lookup config "lockout"
  47. let lo = maybe id (\x s -> s { asLockout = Just (second fromInteger x) })
  48. lockout
  49. siteKey <- liftIO $ C.lookup config "siteKey"
  50. let sk = maybe id (\x s -> s { asSiteKey = x }) siteKey
  51. return $ (pw . rc . rp . lo . sk) defAuthSettings
  52.  
  53.  
  54. ------------------------------------------------------------------------------
  55. -- | Initializer for the MongoDB backend to the auth snaplet.
  56. --
  57. initMongoAuth
  58. :: Lens b (Snaplet SessionManager) -- ^ Lens to the session snaplet
  59. -> Snaplet MongoDB -- ^ The mongodb snaplet
  60. -> SnapletInit b (AuthManager b)
  61. initMongoAuth sess db = makeSnaplet "mongodb-auth" desc datadir $ do
  62. config <- getSnapletUserConfig
  63. dbName <- liftIO $ C.lookupDefault "local" config "authTable"
  64. authTable <- liftIO $ C.lookupDefault "snap_auth_user" config "authTable"
  65. authSettings <- settingsFromConfig
  66. key <- liftIO $ getKey (asSiteKey authSettings)
  67. let manager = MongoAuthManager dbName authTable $ getL snapletValue db
  68. rng <- liftIO mkRNG
  69. return $ AuthManager
  70. { backend = manager
  71. , session = sess
  72. , activeUser = Nothing
  73. , minPasswdLen = asMinPasswdLen authSettings
  74. , rememberCookieName = asRememberCookieName authSettings
  75. , rememberPeriod = asRememberPeriod authSettings
  76. , siteKey = key
  77. , lockout = asLockout authSettings
  78. , randomNumberGenerator = rng
  79. }
  80. where
  81. desc = "A MongoDB backend for user authentication"
  82. datadir = Nothing
  83.  
  84. withDB :: MonadIO m => MongoAuthManager -> Pipe -> Action m a -> m (Either Failure a)
  85. withDB manager conn action = access conn master (US.u $ mongodbName manager) action
  86.  
  87. instance IAuthBackend MongoAuthManager where
  88. save manager user = do
  89. let uid = userId user
  90. conn <- runIOE $ aResource $ mongoPool $ mongoConnPool manager
  91. withDB manager conn $ M.save (US.u $ mongoTable manager) (authUserToDocument user)
  92. return user
  93.  
  94. lookupByUserId manager uid = do
  95. conn <- runIOE $ aResource $ mongoPool $ mongoConnPool manager
  96. doc <- withDB manager conn $ findOne (select ["_id" =: (uidToOid uid)] (US.u $ mongoTable manager))
  97. return $ convertDocToUser doc
  98. where
  99. uidToOid uid = read (T.unpack $ unUid uid) :: ObjectId
  100.  
  101. lookupByLogin manager login = do
  102. conn <- runIOE $ aResource $ mongoPool $ mongoConnPool manager
  103. doc <- withDB manager conn $ findOne (select ["userLogin" =: (T.unpack login)] (US.u $ mongoTable manager))
  104. return $ convertDocToUser doc
  105.  
  106. lookupByRememberToken manager token = do
  107. conn <- runIOE $ aResource $ mongoPool $ mongoConnPool manager
  108. doc <- withDB manager conn $ findOne (select ["userRememberToken" =: (T.unpack token)] (US.u $ mongoTable manager))
  109. return $ convertDocToUser doc
  110.  
  111. destroy manager u = do
  112. conn <- runIOE $ aResource $ mongoPool $ mongoConnPool manager
  113. return ()
  114.  
  115. convertDocToUser :: Either e (Maybe Document) -> Maybe AuthUser
  116. convertDocToUser (Left _) = Nothing
  117. convertDocToUser (Right (Nothing)) = Nothing
  118. convertDocToUser (Right (Just doc)) = Just $ documentToAuthUser doc
  119.  
  120. authUserToDocument :: AuthUser -> Document
  121. authUserToDocument u = ("_id" =? (userIdString $ userId u))
  122. `merge` ["userLogin" =: (T.unpack $ userLogin u )]
  123. `merge` ("userPassword" =? (passwordText $ userPassword u) )
  124. `merge` ("userActivatedAt" =? userActivatedAt u )
  125. `merge` ("userSuspendedAt" =? userSuspendedAt u)
  126. `merge` ("userRememberToken" =? (userTokenText $ userRememberToken u) )
  127. `merge` ["userLoginCount" =: userLoginCount u]
  128. `merge` ["userFailedLoginCount" =: userFailedLoginCount u]
  129. `merge` ("userLockedOutUntil" =? userLockedOutUntil u)
  130. `merge` ("userCurrentLoginAt" =? userCurrentLoginAt u)
  131. `merge` ("userLastLoginAt" =? userLastLoginAt u)
  132. `merge` ("userCurrentLoginIp" =? (constructBin $ userCurrentLoginIp u) )
  133. `merge` ("userLastLoginIp" =? (constructBin $ userLastLoginIp u) )
  134. `merge` ("userCreatedAt" =? userCreatedAt u)
  135. `merge` ("userUpdatedAt" =? userUpdatedAt u)
  136. `merge` ["userRoles" =: (userRolesText $ userRoles u)]
  137. -- `merge` ("userMeta" =? userMeta u)
  138. where
  139. userIdString (Just _id) = Just (read (T.unpack $ unUid _id)::ObjectId)
  140. userIdString Nothing = Nothing
  141. passwordText (Just (Encrypted p)) = Just $ Binary p
  142. passwordText Nothing = Nothing
  143. userTokenText (Just a) = Just $ T.unpack a
  144. userTokenText Nothing = Nothing
  145. userRolesText xs = map stripRole xs
  146. stripRole (Role s) = Binary s
  147. constructBin (Just s) = Just $ Binary s
  148. constructBin Nothing = Nothing
  149.  
  150. documentToAuthUser :: Document -> AuthUser
  151. documentToAuthUser doc = AuthUser {
  152. userId = getOid (BS.look "_id" doc)
  153. , userLogin = (T.pack $ fromMaybe "" $ cast $ BS.valueAt "userLogin" doc)
  154. , userPassword = getPassword $ BS.look "userPassword" doc
  155. , userActivatedAt = getUTCTime $ BS.look "userActivatedAt" doc
  156. , userSuspendedAt = getUTCTime $ BS.look "userSuspendedAt" doc
  157. , userRememberToken = getText $ BS.look "userRememberToken" doc
  158. , userLoginCount = getInt $ valueAt "userLoginCount" doc
  159. , userFailedLoginCount = getInt $ BS.valueAt "userFailedLoginCount" doc
  160. , userLockedOutUntil = getUTCTime $ BS.look "userLockedOutUntil" doc
  161. , userCurrentLoginAt = getUTCTime $ BS.look "userCurrentLoginAt" doc
  162. , userLastLoginAt = getUTCTime $ BS.look "userLastLoginAt" doc
  163. , userCurrentLoginIp = getByteString $ BS.look "userCurrentLoginIp" doc
  164. , userLastLoginIp = getByteString $ BS.look "userLastLoginIp" doc
  165. , userCreatedAt = getUTCTime $ BS.look "userCreatedAt" doc
  166. , userUpdatedAt = getUTCTime $ BS.look "userUpdatedAt" doc
  167. , userRoles = getRoles $ BS.look "userRoles" doc
  168. }
  169. where
  170. getOid Nothing = Nothing
  171. getOid (Just (ObjId v)) = Just $ UserId $ T.pack $ show v
  172. getPassword Nothing = Nothing
  173. getPassword (Just (Bin (Binary p))) = Just $ Encrypted p
  174. getUTCTime Nothing = Nothing
  175. getUTCTime (Just (UTC t)) = Just t
  176. getText Nothing = Nothing
  177. getText (Just (String s)) = Just $ T.pack $ US.unpack s
  178. getInt v = fromMaybe 0 $ cast v
  179. getByteString Nothing = Nothing
  180. getByteString (Just (Bin (Binary s))) = Just s
  181. getRoles Nothing = []
  182. getRoles (Just (Array xs)) = map (\(Bin (Binary s)) -> Role s) xs
Add Comment
Please, Sign In to add comment