Merge pull request #8 from Shimuuar/master
HashDB improvements and refactorings
This commit is contained in:
commit
bbdca8cb5d
@ -22,19 +22,27 @@ module Yesod.Auth
|
|||||||
, requireAuth
|
, requireAuth
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
|
import Control.Monad (when)
|
||||||
|
import Control.Monad.Trans.Class (lift)
|
||||||
|
import Control.Monad.Trans.Maybe
|
||||||
|
|
||||||
|
import Data.Aeson
|
||||||
|
import Data.Text.Encoding (decodeUtf8With)
|
||||||
|
import Data.Text.Encoding.Error (lenientDecode)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
import Language.Haskell.TH.Syntax hiding (lift)
|
||||||
|
|
||||||
|
import qualified Network.Wai as W
|
||||||
|
import Text.Hamlet (hamlet)
|
||||||
|
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.Persist
|
import Yesod.Persist
|
||||||
import Yesod.Json
|
import Yesod.Json
|
||||||
import Language.Haskell.TH.Syntax hiding (lift)
|
|
||||||
import qualified Network.Wai as W
|
|
||||||
import Text.Hamlet (hamlet)
|
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Control.Monad.Trans.Class (lift)
|
|
||||||
import Data.Aeson
|
|
||||||
import Data.Text (Text)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import Data.Text.Encoding (decodeUtf8With)
|
|
||||||
import Data.Text.Encoding.Error (lenientDecode)
|
|
||||||
import Yesod.Auth.Message (AuthMessage, defaultMessage)
|
import Yesod.Auth.Message (AuthMessage, defaultMessage)
|
||||||
import qualified Yesod.Auth.Message as Msg
|
import qualified Yesod.Auth.Message as Msg
|
||||||
import Yesod.Form (FormMessage)
|
import Yesod.Form (FormMessage)
|
||||||
@ -91,11 +99,7 @@ mkYesodSub "Auth"
|
|||||||
[ ClassP ''YesodAuth [VarT $ mkName "master"]
|
[ ClassP ''YesodAuth [VarT $ mkName "master"]
|
||||||
]
|
]
|
||||||
#define STRINGS *Texts
|
#define STRINGS *Texts
|
||||||
#if GHC7
|
[QQ(parseRoutes)|
|
||||||
[parseRoutes|
|
|
||||||
#else
|
|
||||||
[$parseRoutes|
|
|
||||||
#endif
|
|
||||||
/check CheckR GET
|
/check CheckR GET
|
||||||
/login LoginR GET
|
/login LoginR GET
|
||||||
/logout LogoutR GET POST
|
/logout LogoutR GET POST
|
||||||
@ -108,34 +112,21 @@ credsKey = "_ID"
|
|||||||
-- | FIXME: won't show up till redirect
|
-- | FIXME: won't show up till redirect
|
||||||
setCreds :: YesodAuth m => Bool -> Creds m -> GHandler s m ()
|
setCreds :: YesodAuth m => Bool -> Creds m -> GHandler s m ()
|
||||||
setCreds doRedirects creds = do
|
setCreds doRedirects creds = do
|
||||||
y <- getYesod
|
y <- getYesod
|
||||||
maid <- getAuthId creds
|
maid <- getAuthId creds
|
||||||
case maid of
|
case maid of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
if doRedirects
|
when doRedirects $ do
|
||||||
then do
|
case authRoute y of
|
||||||
case authRoute y of
|
Nothing -> do rh <- defaultLayout [QQ(hamlet)| <h1>Invalid login |]
|
||||||
Nothing -> do
|
|
||||||
rh <- defaultLayout
|
|
||||||
#if GHC7
|
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
<h1>Invalid login
|
|
||||||
|]
|
|
||||||
sendResponse rh
|
sendResponse rh
|
||||||
Just ar -> do
|
Just ar -> do setMessageI Msg.InvalidLogin
|
||||||
setMessageI Msg.InvalidLogin
|
|
||||||
redirect RedirectTemporary ar
|
redirect RedirectTemporary ar
|
||||||
else return ()
|
|
||||||
Just aid -> do
|
Just aid -> do
|
||||||
setSession credsKey $ toSinglePiece aid
|
setSession credsKey $ toSinglePiece aid
|
||||||
if doRedirects
|
when doRedirects $ do
|
||||||
then do
|
setMessageI Msg.NowLoggedIn
|
||||||
setMessageI Msg.NowLoggedIn
|
redirectUltDest RedirectTemporary $ loginDest y
|
||||||
redirectUltDest RedirectTemporary $ loginDest y
|
|
||||||
else return ()
|
|
||||||
|
|
||||||
getCheckR :: YesodAuth m => GHandler Auth m RepHtmlJson
|
getCheckR :: YesodAuth m => GHandler Auth m RepHtmlJson
|
||||||
getCheckR = do
|
getCheckR = do
|
||||||
@ -145,11 +136,7 @@ getCheckR = do
|
|||||||
addHtml $ html creds) (json' creds)
|
addHtml $ html creds) (json' creds)
|
||||||
where
|
where
|
||||||
html creds =
|
html creds =
|
||||||
#if GHC7
|
[QQ(hamlet)|
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
<h1>Authentication Status
|
<h1>Authentication Status
|
||||||
$maybe _ <- creds
|
$maybe _ <- creds
|
||||||
<p>Logged in.
|
<p>Logged in.
|
||||||
@ -195,15 +182,10 @@ maybeAuth :: ( YesodAuth m
|
|||||||
, PersistEntity val
|
, PersistEntity val
|
||||||
, YesodPersist m
|
, YesodPersist m
|
||||||
) => GHandler s m (Maybe (Key val, val))
|
) => GHandler s m (Maybe (Key val, val))
|
||||||
maybeAuth = do
|
maybeAuth = runMaybeT $ do
|
||||||
maid <- maybeAuthId
|
aid <- MaybeT $ maybeAuthId
|
||||||
case maid of
|
a <- MaybeT $ runDB $ get aid
|
||||||
Nothing -> return Nothing
|
return (aid, a)
|
||||||
Just aid -> do
|
|
||||||
ma <- runDB $ get aid
|
|
||||||
case ma of
|
|
||||||
Nothing -> return Nothing
|
|
||||||
Just a -> return $ Just (aid, a)
|
|
||||||
|
|
||||||
requireAuthId :: YesodAuth m => GHandler s m (AuthId m)
|
requireAuthId :: YesodAuth m => GHandler s m (AuthId m)
|
||||||
requireAuthId = maybeAuthId >>= maybe redirectLogin return
|
requireAuthId = maybeAuthId >>= maybe redirectLogin return
|
||||||
|
|||||||
@ -8,6 +8,8 @@ module Yesod.Auth.Dummy
|
|||||||
( authDummy
|
( authDummy
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import Yesod.Form (runInputPost, textField, ireq)
|
import Yesod.Form (runInputPost, textField, ireq)
|
||||||
import Yesod.Handler (notFound)
|
import Yesod.Handler (notFound)
|
||||||
@ -23,11 +25,7 @@ authDummy =
|
|||||||
dispatch _ _ = notFound
|
dispatch _ _ = notFound
|
||||||
url = PluginR "dummy" []
|
url = PluginR "dummy" []
|
||||||
login authToMaster =
|
login authToMaster =
|
||||||
#if GHC7
|
[QQ(hamlet)|
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
<form method="post" action="@{authToMaster url}">
|
<form method="post" action="@{authToMaster url}">
|
||||||
\Your new identifier is:
|
\Your new identifier is:
|
||||||
<input type="text" name="ident">
|
<input type="text" name="ident">
|
||||||
|
|||||||
@ -14,6 +14,8 @@ module Yesod.Auth.Email
|
|||||||
, setpassR
|
, setpassR
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Network.Mail.Mime (randomString)
|
import Network.Mail.Mime (randomString)
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import System.Random
|
import System.Random
|
||||||
@ -81,11 +83,7 @@ authEmail =
|
|||||||
AuthPlugin "email" dispatch $ \tm -> do
|
AuthPlugin "email" dispatch $ \tm -> do
|
||||||
y <- lift getYesod
|
y <- lift getYesod
|
||||||
l <- lift languages
|
l <- lift languages
|
||||||
#if GHC7
|
[QQ(whamlet)|
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<form method="post" action="@{tm loginR}">
|
<form method="post" action="@{tm loginR}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@ -119,11 +117,7 @@ getRegisterR = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI Msg.RegisterLong
|
setTitleI Msg.RegisterLong
|
||||||
addWidget
|
addWidget
|
||||||
#if GHC7
|
[QQ(whamlet)|
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<p>_{Msg.EnterEmail}
|
<p>_{Msg.EnterEmail}
|
||||||
<form method="post" action="@{toMaster registerR}">
|
<form method="post" action="@{toMaster registerR}">
|
||||||
<label for="email">_{Msg.Email}
|
<label for="email">_{Msg.Email}
|
||||||
@ -154,13 +148,7 @@ postRegisterR = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI Msg.ConfirmationEmailSentTitle
|
setTitleI Msg.ConfirmationEmailSentTitle
|
||||||
addWidget
|
addWidget
|
||||||
#if GHC7
|
[QQ(whamlet)| <p>_{Msg.ConfirmationEmailSent email} |]
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<p>_{Msg.ConfirmationEmailSent email}
|
|
||||||
|]
|
|
||||||
|
|
||||||
getVerifyR :: YesodAuthEmail m
|
getVerifyR :: YesodAuthEmail m
|
||||||
=> AuthEmailId m -> Text -> GHandler Auth m RepHtml
|
=> AuthEmailId m -> Text -> GHandler Auth m RepHtml
|
||||||
@ -181,13 +169,7 @@ getVerifyR lid key = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI Msg.InvalidKey
|
setTitleI Msg.InvalidKey
|
||||||
addWidget
|
addWidget
|
||||||
#if GHC7
|
[QQ(whamlet)| <p>_{Msg.InvalidKey} |]
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<p>_{Msg.InvalidKey}
|
|
||||||
|]
|
|
||||||
|
|
||||||
postLoginR :: YesodAuthEmail master => GHandler Auth master ()
|
postLoginR :: YesodAuthEmail master => GHandler Auth master ()
|
||||||
postLoginR = do
|
postLoginR = do
|
||||||
@ -226,11 +208,7 @@ getPasswordR = do
|
|||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitleI Msg.SetPassTitle
|
setTitleI Msg.SetPassTitle
|
||||||
addWidget
|
addWidget
|
||||||
#if GHC7
|
[QQ(whamlet)|
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<h3>_{Msg.SetPass}
|
<h3>_{Msg.SetPass}
|
||||||
<form method="post" action="@{toMaster setpassR}">
|
<form method="post" action="@{toMaster setpassR}">
|
||||||
<table>
|
<table>
|
||||||
|
|||||||
@ -6,6 +6,8 @@ module Yesod.Auth.Facebook
|
|||||||
, facebookUrl
|
, facebookUrl
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import qualified Web.Authenticate.Facebook as Facebook
|
import qualified Web.Authenticate.Facebook as Facebook
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
@ -56,11 +58,7 @@ authFacebook cid secret perms =
|
|||||||
render <- lift getUrlRender
|
render <- lift getUrlRender
|
||||||
let fb = Facebook.Facebook cid secret $ render $ tm url
|
let fb = Facebook.Facebook cid secret $ render $ tm url
|
||||||
let furl = Facebook.getForwardUrl fb $ perms
|
let furl = Facebook.getForwardUrl fb $ perms
|
||||||
#if GHC7
|
[QQ(whamlet)|
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<p>
|
<p>
|
||||||
<a href="#{furl}">_{Msg.Facebook}
|
<a href="#{furl}">_{Msg.Facebook}
|
||||||
|]
|
|]
|
||||||
|
|||||||
@ -16,8 +16,7 @@
|
|||||||
-- Portability : Portable
|
-- Portability : Portable
|
||||||
--
|
--
|
||||||
-- A yesod-auth AuthPlugin designed to look users up in Persist where
|
-- A yesod-auth AuthPlugin designed to look users up in Persist where
|
||||||
-- their user id's and a sha1 hash of their password will already be
|
-- their user id's and a salted SHA1 hash of their password is stored.
|
||||||
-- stored.
|
|
||||||
--
|
--
|
||||||
-- Example usage:
|
-- Example usage:
|
||||||
--
|
--
|
||||||
@ -37,10 +36,8 @@
|
|||||||
-- >
|
-- >
|
||||||
-- > loginDest _ = RootR
|
-- > loginDest _ = RootR
|
||||||
-- > logoutDest _ = RootR
|
-- > logoutDest _ = RootR
|
||||||
-- > getAuthId = getAuthIdHashDB AuthR
|
-- > getAuthId = getAuthIdHashDB AuthR (Just . UniqueUser)
|
||||||
-- > showAuthId _ = showIntegral
|
-- > authPlugins = [authHashDB (Just . UniqueUser)]
|
||||||
-- > readAuthId _ = readIntegral
|
|
||||||
-- > authPlugins = [authHashDB]
|
|
||||||
-- >
|
-- >
|
||||||
-- >
|
-- >
|
||||||
-- > -- include the migration function in site startup
|
-- > -- include the migration function in site startup
|
||||||
@ -49,21 +46,31 @@
|
|||||||
-- > runSqlPool (runMigration migrateUsers) p
|
-- > runSqlPool (runMigration migrateUsers) p
|
||||||
-- > let h = DevSite p
|
-- > let h = DevSite p
|
||||||
--
|
--
|
||||||
-- Your app must be an instance of YesodPersist and the username and
|
-- Note that function which converts username to unique identifier must be same.
|
||||||
-- hashed-passwords must be added manually to the database.
|
|
||||||
--
|
--
|
||||||
-- > echo -n 'MyPassword' | sha1sum
|
-- Your app must be an instance of YesodPersist. and the username,
|
||||||
|
-- salt and hashed-passwords should be added to the database.
|
||||||
|
--
|
||||||
|
-- > echo -n 'MySaltMyPassword' | sha1sum
|
||||||
--
|
--
|
||||||
-- can be used to get the hash from the commandline.
|
-- can be used to get the hash from the commandline.
|
||||||
--
|
--
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
module Yesod.Auth.HashDB
|
module Yesod.Auth.HashDB
|
||||||
( authHashDB
|
( HashDBUser(..)
|
||||||
|
, setPassword
|
||||||
|
-- * Authentification
|
||||||
|
, validateUser
|
||||||
|
, authHashDB
|
||||||
, getAuthIdHashDB
|
, getAuthIdHashDB
|
||||||
|
-- * Predefined data type
|
||||||
|
, User(..)
|
||||||
, UserId
|
, UserId
|
||||||
, migrateUsers
|
, migrateUsers
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Yesod.Persist
|
import Yesod.Persist
|
||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
import Yesod.Form
|
import Yesod.Form
|
||||||
@ -71,115 +78,130 @@ import Yesod.Auth
|
|||||||
import Text.Hamlet (hamlet)
|
import Text.Hamlet (hamlet)
|
||||||
|
|
||||||
import Control.Applicative ((<$>), (<*>))
|
import Control.Applicative ((<$>), (<*>))
|
||||||
import Data.ByteString.Lazy.Char8 (pack)
|
import Control.Monad (replicateM,liftM)
|
||||||
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
||||||
|
|
||||||
|
import qualified Data.ByteString.Lazy.Char8 as BS (pack)
|
||||||
import Data.Digest.Pure.SHA (sha1, showDigest)
|
import Data.Digest.Pure.SHA (sha1, showDigest)
|
||||||
import Data.Text (Text, unpack)
|
import Data.Text (Text, pack, unpack, append)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
|
import System.Random (randomRIO)
|
||||||
|
|
||||||
-- | Computer the sha1 of a string and return it as a string
|
|
||||||
sha1String :: String -> String
|
|
||||||
sha1String = showDigest . sha1 . pack
|
|
||||||
|
|
||||||
-- | Generate data base instances for a valid user
|
-- | Interface for data type which holds user info. It's just a
|
||||||
share2 mkPersist (mkMigrate "migrateUsers")
|
-- collection of getters and setters
|
||||||
#if GHC7
|
class HashDBUser user where
|
||||||
[persist|
|
-- | Retrieve password hash from user data
|
||||||
#else
|
userPasswordHash :: user -> Maybe Text
|
||||||
[$persist|
|
-- | Retrieve salt for password
|
||||||
#endif
|
userPasswordSalt :: user -> Maybe Text
|
||||||
User
|
-- | Set hash and password
|
||||||
username Text Eq
|
setUserHashAndSalt :: Text -- ^ Salt
|
||||||
password Text
|
-> Text -- ^ Password hash
|
||||||
UniqueUser username
|
-> user -> user
|
||||||
|]
|
|
||||||
|
-- | Generate random salt. Length of 8 is chosen arbitrarily
|
||||||
|
randomSalt :: MonadIO m => m Text
|
||||||
|
randomSalt = pack `liftM` liftIO (replicateM 8 (randomRIO ('0','z')))
|
||||||
|
|
||||||
|
-- | Calculate salted hash using SHA1.
|
||||||
|
saltedHash :: Text -- ^ Salt
|
||||||
|
-> Text -- ^ Password
|
||||||
|
-> Text
|
||||||
|
saltedHash salt =
|
||||||
|
pack . showDigest . sha1 . BS.pack . unpack . append salt
|
||||||
|
|
||||||
|
-- | Set password for user. This function should be used for setting
|
||||||
|
-- passwords. It generates random salt and calculates proper hashes.
|
||||||
|
setPassword :: (MonadIO m, HashDBUser user) => Text -> user -> m user
|
||||||
|
setPassword pwd u = do salt <- randomSalt
|
||||||
|
return $ setUserHashAndSalt salt (saltedHash salt pwd) u
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Authentification
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
-- | Given a user ID and password in plaintext, validate them against
|
||||||
|
-- the database values.
|
||||||
|
validateUser :: ( YesodPersist yesod
|
||||||
|
, PersistBackend (YesodDB yesod (GGHandler sub yesod IO))
|
||||||
|
, PersistEntity user
|
||||||
|
, HashDBUser user
|
||||||
|
) =>
|
||||||
|
Unique user -- ^ User unique identifier
|
||||||
|
-> Text -- ^ Password in plaint-text
|
||||||
|
-> GHandler sub yesod Bool
|
||||||
|
validateUser userID passwd = do
|
||||||
|
-- Checks that hash and password match
|
||||||
|
let validate u = do hash <- userPasswordHash u
|
||||||
|
salt <- userPasswordSalt u
|
||||||
|
return $ hash == saltedHash salt passwd
|
||||||
|
-- Get user data
|
||||||
|
user <- runDB $ getBy userID
|
||||||
|
return $ fromMaybe False $ validate . snd =<< user
|
||||||
|
|
||||||
-- | Given a (user,password) in plaintext, validate them against the
|
|
||||||
-- database values
|
|
||||||
validateUser :: (YesodPersist y,
|
|
||||||
PersistBackend (YesodDB y (GGHandler sub y IO)))
|
|
||||||
=> (Text, Text)
|
|
||||||
-> GHandler sub y Bool
|
|
||||||
validateUser (user,password) = runDB (getBy $ UniqueUser user) >>= \dbUser ->
|
|
||||||
case dbUser of
|
|
||||||
-- user not found
|
|
||||||
Nothing -> return False
|
|
||||||
-- validate password
|
|
||||||
Just (_, sqlUser) -> return $ sha1String (unpack password) == unpack (userPassword sqlUser)
|
|
||||||
|
|
||||||
login :: AuthRoute
|
login :: AuthRoute
|
||||||
login = PluginR "hashdb" ["login"]
|
login = PluginR "hashdb" ["login"]
|
||||||
|
|
||||||
-- | Handle the login form
|
|
||||||
postLoginR :: (YesodAuth y,
|
-- | Handle the login form. First parameter is function which maps
|
||||||
YesodPersist y,
|
-- username (whatever it might be) to unique user ID.
|
||||||
PersistBackend (YesodDB y (GGHandler Auth y IO)))
|
postLoginR :: ( YesodAuth y, YesodPersist y
|
||||||
=> GHandler Auth y ()
|
, HashDBUser user, PersistEntity user
|
||||||
postLoginR = do
|
, PersistBackend (YesodDB y (GGHandler Auth y IO)))
|
||||||
|
=> (Text -> Maybe (Unique user))
|
||||||
|
-> GHandler Auth y ()
|
||||||
|
postLoginR uniq = do
|
||||||
(mu,mp) <- runInputPost $ (,)
|
(mu,mp) <- runInputPost $ (,)
|
||||||
<$> iopt textField "username"
|
<$> iopt textField "username"
|
||||||
<*> iopt textField "password"
|
<*> iopt textField "password"
|
||||||
|
|
||||||
isValid <- case (mu,mp) of
|
isValid <- fromMaybe (return False)
|
||||||
(Nothing, _ ) -> return False
|
(validateUser <$> (uniq =<< mu) <*> mp)
|
||||||
(_ , Nothing) -> return False
|
|
||||||
(Just u , Just p ) -> validateUser (u,p)
|
|
||||||
|
|
||||||
if isValid
|
if isValid
|
||||||
then setCreds True $ Creds "hashdb" (fromMaybe "" mu) []
|
then setCreds True $ Creds "hashdb" (fromMaybe "" mu) []
|
||||||
else do
|
else do setMessage [QQ(hamlet)| Invalid username/password |]
|
||||||
setMessage
|
toMaster <- getRouteToMaster
|
||||||
#if GHC7
|
redirect RedirectTemporary $ toMaster LoginR
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
Invalid username/password
|
|
||||||
|]
|
|
||||||
toMaster <- getRouteToMaster
|
|
||||||
redirect RedirectTemporary $ toMaster LoginR
|
|
||||||
|
|
||||||
-- | A drop in for the getAuthId method of your YesodAuth instance which
|
-- | A drop in for the getAuthId method of your YesodAuth instance which
|
||||||
-- can be used if authHashDB is the only plugin in use.
|
-- can be used if authHashDB is the only plugin in use.
|
||||||
getAuthIdHashDB :: (Key User ~ AuthId master,
|
getAuthIdHashDB :: ( YesodAuth master, YesodPersist master
|
||||||
PersistBackend (YesodDB master (GGHandler sub master IO)),
|
, HashDBUser user, PersistEntity user
|
||||||
YesodPersist master,
|
, Key user ~ AuthId master
|
||||||
YesodAuth master)
|
, PersistBackend (YesodDB master (GGHandler sub master IO)))
|
||||||
=> (AuthRoute -> Route master) -- ^ your site's Auth Route
|
=> (AuthRoute -> Route master) -- ^ your site's Auth Route
|
||||||
-> Creds m -- ^ the creds argument
|
-> (Text -> Maybe (Unique user)) -- ^ gets user ID
|
||||||
-> GHandler sub master (Maybe UserId)
|
-> Creds master -- ^ the creds argument
|
||||||
getAuthIdHashDB authR creds = do
|
-> GHandler sub master (Maybe (AuthId master))
|
||||||
|
getAuthIdHashDB authR uniq creds = do
|
||||||
muid <- maybeAuth
|
muid <- maybeAuth
|
||||||
case muid of
|
case muid of
|
||||||
-- user already authenticated
|
-- user already authenticated
|
||||||
Just (uid, _) -> return $ Just uid
|
Just (uid, _) -> return $ Just uid
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
x <- runDB $ getBy $ UniqueUser (credsIdent creds)
|
x <- case uniq (credsIdent creds) of
|
||||||
|
Nothing -> return Nothing
|
||||||
|
Just u -> runDB (getBy u)
|
||||||
case x of
|
case x of
|
||||||
-- user exists
|
-- user exists
|
||||||
Just (uid, _) -> return $ Just uid
|
Just (uid, _) -> return $ Just uid
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
setMessage
|
setMessage [QQ(hamlet)| User not found |]
|
||||||
#if GHC7
|
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
User not found
|
|
||||||
|]
|
|
||||||
redirect RedirectTemporary $ authR LoginR
|
redirect RedirectTemporary $ authR LoginR
|
||||||
|
|
||||||
-- | Prompt for username and password, validate that against a database
|
-- | Prompt for username and password, validate that against a database
|
||||||
-- which holds the username and a hash of the password
|
-- which holds the username and a hash of the password
|
||||||
authHashDB :: (YesodAuth y,
|
authHashDB :: ( YesodAuth m, YesodPersist m
|
||||||
YesodPersist y,
|
, HashDBUser user
|
||||||
PersistBackend (YesodDB y (GGHandler Auth y IO)))
|
, PersistEntity user
|
||||||
=> AuthPlugin y
|
, PersistBackend (YesodDB m (GGHandler Auth m IO)))
|
||||||
authHashDB = AuthPlugin "hashdb" dispatch $ \tm ->
|
=> (Text -> Maybe (Unique user)) -> AuthPlugin m
|
||||||
#if GHC7
|
authHashDB uniq = AuthPlugin "hashdb" dispatch $ \tm ->
|
||||||
[hamlet|
|
[QQ(hamlet)|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<h1>Login
|
<h1>Login
|
||||||
|
|
||||||
@ -206,5 +228,27 @@ authHashDB = AuthPlugin "hashdb" dispatch $ \tm ->
|
|||||||
|
|
||||||
|]
|
|]
|
||||||
where
|
where
|
||||||
dispatch "POST" ["login"] = postLoginR >>= sendResponse
|
dispatch "POST" ["login"] = postLoginR uniq >>= sendResponse
|
||||||
dispatch _ _ = notFound
|
dispatch _ _ = notFound
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Predefined datatype
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
-- | Generate data base instances for a valid user
|
||||||
|
share2 mkPersist (mkMigrate "migrateUsers")
|
||||||
|
[QQ(persist)|
|
||||||
|
User
|
||||||
|
username Text Eq
|
||||||
|
password Text
|
||||||
|
salt Text
|
||||||
|
UniqueUser username
|
||||||
|
|]
|
||||||
|
|
||||||
|
instance HashDBUser User where
|
||||||
|
userPasswordHash = Just . userPassword
|
||||||
|
userPasswordSalt = Just . userSalt
|
||||||
|
setUserHashAndSalt s h u = u { userSalt = s
|
||||||
|
, userPassword = h
|
||||||
|
}
|
||||||
|
|||||||
@ -6,6 +6,9 @@ module Yesod.Auth.OAuth
|
|||||||
, authTwitter
|
, authTwitter
|
||||||
, twitterUrl
|
, twitterUrl
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import Yesod.Form
|
import Yesod.Form
|
||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
@ -66,13 +69,7 @@ authOAuth name ident reqUrl accUrl authUrl key sec = AuthPlugin name dispatch lo
|
|||||||
render <- lift getUrlRender
|
render <- lift getUrlRender
|
||||||
let oaUrl = render $ tm $ oauthUrl name
|
let oaUrl = render $ tm $ oauthUrl name
|
||||||
addHtml
|
addHtml
|
||||||
#if GHC7
|
[QQ(hamlet)| <a href=#{oaUrl}>Login with #{name} |]
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
<a href=#{oaUrl}>Login with #{name}
|
|
||||||
|]
|
|
||||||
|
|
||||||
authTwitter :: YesodAuth m =>
|
authTwitter :: YesodAuth m =>
|
||||||
String -- ^ Consumer Key
|
String -- ^ Consumer Key
|
||||||
|
|||||||
@ -6,6 +6,8 @@ module Yesod.Auth.OpenId
|
|||||||
, forwardUrl
|
, forwardUrl
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import qualified Web.Authenticate.OpenId as OpenId
|
import qualified Web.Authenticate.OpenId as OpenId
|
||||||
import Control.Monad.Attempt
|
import Control.Monad.Attempt
|
||||||
@ -34,20 +36,12 @@ authOpenId =
|
|||||||
ident <- lift newIdent
|
ident <- lift newIdent
|
||||||
y <- lift getYesod
|
y <- lift getYesod
|
||||||
addCassius
|
addCassius
|
||||||
#if GHC7
|
[QQ(cassius)|##{ident}
|
||||||
[cassius|##{ident}
|
|
||||||
#else
|
|
||||||
[$cassius|##{ident}
|
|
||||||
#endif
|
|
||||||
background: #fff url(http://www.myopenid.com/static/openid-icon-small.gif) no-repeat scroll 0pt 50%;
|
background: #fff url(http://www.myopenid.com/static/openid-icon-small.gif) no-repeat scroll 0pt 50%;
|
||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
|]
|
|]
|
||||||
l <- lift languages
|
l <- lift languages
|
||||||
#if GHC7
|
[QQ(whamlet)|
|
||||||
[whamlet|
|
|
||||||
#else
|
|
||||||
[$whamlet|
|
|
||||||
#endif
|
|
||||||
<form method="get" action="@{tm forwardUrl}">
|
<form method="get" action="@{tm forwardUrl}">
|
||||||
<label for="#{ident}">OpenID: #
|
<label for="#{ident}">OpenID: #
|
||||||
<input id="#{ident}" type="text" name="#{name}" value="http://">
|
<input id="#{ident}" type="text" name="#{name}" value="http://">
|
||||||
|
|||||||
@ -5,6 +5,8 @@ module Yesod.Auth.Rpxnow
|
|||||||
( authRpxnow
|
( authRpxnow
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
#include "qq.h"
|
||||||
|
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import qualified Web.Authenticate.Rpxnow as Rpxnow
|
import qualified Web.Authenticate.Rpxnow as Rpxnow
|
||||||
import Control.Monad (mplus)
|
import Control.Monad (mplus)
|
||||||
@ -27,11 +29,7 @@ authRpxnow app apiKey =
|
|||||||
login tm = do
|
login tm = do
|
||||||
let url = {- FIXME urlEncode $ -} tm $ PluginR "rpxnow" []
|
let url = {- FIXME urlEncode $ -} tm $ PluginR "rpxnow" []
|
||||||
addHamlet
|
addHamlet
|
||||||
#if GHC7
|
[QQ(hamlet)|
|
||||||
[hamlet|
|
|
||||||
#else
|
|
||||||
[$hamlet|
|
|
||||||
#endif
|
|
||||||
<iframe src="http://#{app}.rpxnow.com/openid/embed?token_url=@{url}" scrolling="no" frameBorder="no" allowtransparency="true" style="width:400px;height:240px">
|
<iframe src="http://#{app}.rpxnow.com/openid/embed?token_url=@{url}" scrolling="no" frameBorder="no" allowtransparency="true" style="width:400px;height:240px">
|
||||||
|]
|
|]
|
||||||
dispatch _ [] = do
|
dispatch _ [] = do
|
||||||
|
|||||||
10
include/qq.h
Normal file
10
include/qq.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- CPP macro which choses which quasyquotes syntax to use depending
|
||||||
|
-- on GHC version.
|
||||||
|
--
|
||||||
|
-- QQ stands for quasyquote.
|
||||||
|
#if GHC7
|
||||||
|
# define QQ(x) x
|
||||||
|
#else
|
||||||
|
# define QQ(x) $x
|
||||||
|
#endif
|
||||||
@ -53,6 +53,8 @@ library
|
|||||||
Yesod.Auth.HashDB
|
Yesod.Auth.HashDB
|
||||||
Yesod.Auth.Message
|
Yesod.Auth.Message
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
include-dirs:
|
||||||
|
include
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user