Migration to control-monad-failure

This commit is contained in:
Michael Snoyman 2009-11-13 15:13:36 +02:00
parent e60354ebe1
commit 83d2d25d34
3 changed files with 29 additions and 20 deletions

View File

@ -1,5 +1,6 @@
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
--------------------------------------------------------- ---------------------------------------------------------
-- | -- |
-- Module : Web.Authenticate.OpenId -- Module : Web.Authenticate.OpenId
@ -23,9 +24,9 @@ import Network.HTTP.Wget
import Text.HTML.TagSoup import Text.HTML.TagSoup
import Numeric (showHex) import Numeric (showHex)
import Control.Monad.Trans import Control.Monad.Trans
import qualified Data.Attempt.Helper as A import qualified Safe.Failure as A
import Data.Generics import Data.Generics
import Data.Attempt import Control.Monad.Failure
import Control.Exception import Control.Exception
-- | An openid identifier (ie, a URL). -- | An openid identifier (ie, a URL).
@ -40,14 +41,14 @@ instance Monad Error where
fail s = Error s fail s = Error s
-- | Returns a URL to forward the user to in order to login. -- | Returns a URL to forward the user to in order to login.
getForwardUrl :: (MonadIO m, MonadAttempt m) getForwardUrl :: (MonadIO m, MonadFailure WgetException m)
=> String -- ^ The openid the user provided. => String -- ^ The openid the user provided.
-> String -- ^ The URL for this application\'s complete page. -> String -- ^ The URL for this application\'s complete page.
-> m String -- ^ URL to send the user to. -> m String -- ^ URL to send the user to.
getForwardUrl openid complete = do getForwardUrl openid complete = do
bodyIdent <- wget openid [] [] bodyIdent <- wget openid [] []
server <- getOpenIdVar "server" bodyIdent server <- getOpenIdVar "server" bodyIdent
let delegate = attempt (const openid) id let delegate = maybe openid id
$ getOpenIdVar "delegate" bodyIdent $ getOpenIdVar "delegate" bodyIdent
return $ constructUrl server return $ constructUrl server
[ ("openid.mode", "checkid_setup") [ ("openid.mode", "checkid_setup")
@ -55,7 +56,7 @@ getForwardUrl openid complete = do
, ("openid.return_to", complete) , ("openid.return_to", complete)
] ]
getOpenIdVar :: MonadAttempt m => String -> String -> m String getOpenIdVar :: Monad m => String -> String -> m String
getOpenIdVar var content = do getOpenIdVar var content = do
let tags = parseTags content let tags = parseTags content
let secs = sections (~== ("<link rel=openid." ++ var ++ ">")) tags let secs = sections (~== ("<link rel=openid." ++ var ++ ">")) tags
@ -63,7 +64,7 @@ getOpenIdVar var content = do
secs'' <- mhead secs' secs'' <- mhead secs'
return $ fromAttrib "href" secs'' return $ fromAttrib "href" secs''
where where
mhead [] = fail $ "Variable not found: openid." ++ var mhead [] = fail $ "Variable not found: openid." ++ var -- FIXME
mhead (x:_) = return x mhead (x:_) = return x
constructUrl :: String -> [(String, String)] -> String constructUrl :: String -> [(String, String)] -> String
@ -78,7 +79,9 @@ constructUrl url args = url ++ "?" ++ queryString args
-- | Handle a redirect from an OpenID provider and check that the user -- | Handle a redirect from an OpenID provider and check that the user
-- logged in properly. If it was successfully, 'return's the openid. -- logged in properly. If it was successfully, 'return's the openid.
-- Otherwise, 'failure's an explanation. -- Otherwise, 'failure's an explanation.
authenticate :: (MonadIO m, MonadAttempt m) authenticate :: (MonadIO m, MonadFailure WgetException m,
MonadFailure (A.LookupFailure String) m,
MonadFailure AuthenticateException m)
=> [(String, String)] => [(String, String)]
-> m Identifier -> m Identifier
authenticate req = do -- FIXME check openid.mode == id_res (not cancel) authenticate req = do -- FIXME check openid.mode == id_res (not cancel)
@ -87,19 +90,22 @@ authenticate req = do -- FIXME check openid.mode == id_res (not cancel)
let isValid = contains "is_valid:true" content let isValid = contains "is_valid:true" content
if isValid if isValid
then A.lookup "openid.identity" req >>= return . Identifier then A.lookup "openid.identity" req >>= return . Identifier
else failure $ AuthenticateError content else failure $ AuthenticateException content
newtype AuthenticateError = AuthenticateError String newtype AuthenticateException = AuthenticateException String
deriving (Show, Typeable) deriving (Show, Typeable)
instance Exception AuthenticateError instance Exception AuthenticateException
getAuthUrl :: (MonadIO m, MonadAttempt m) => [(String, String)] -> m String getAuthUrl :: (MonadIO m, MonadFailure (A.LookupFailure String) m,
MonadFailure WgetException m)
=> [(String, String)] -> m String
getAuthUrl req = do getAuthUrl req = do
identity <- A.lookup "openid.identity" req identity <- A.lookup "openid.identity" req
idContent <- wget identity [] [] idContent <- wget identity [] []
helper idContent helper idContent
where where
helper :: MonadAttempt m => String -> m String helper :: MonadFailure (A.LookupFailure String) m
=> String -> m String
helper idContent = do helper idContent = do
server <- getOpenIdVar "server" idContent server <- getOpenIdVar "server" idContent
dargs <- mapM makeArg [ dargs <- mapM makeArg [
@ -111,7 +117,8 @@ getAuthUrl req = do
] ]
let sargs = [("openid.mode", "check_authentication")] let sargs = [("openid.mode", "check_authentication")]
return $ constructUrl server $ dargs ++ sargs return $ constructUrl server $ dargs ++ sargs
makeArg :: MonadAttempt m => String -> m (String, String) makeArg :: MonadFailure (A.LookupFailure String) m
=> String -> m (String, String)
makeArg s = do makeArg s = do
let k = "openid." ++ s let k = "openid." ++ s
v <- A.lookup k req v <- A.lookup k req

View File

@ -1,3 +1,4 @@
{-# LANGUAGE FlexibleContexts #-}
--------------------------------------------------------- ---------------------------------------------------------
-- --
-- Module : Web.Authenticate.Rpxnow -- Module : Web.Authenticate.Rpxnow
@ -20,7 +21,7 @@ import Text.JSON -- FIXME use Data.Object.JSON
import Network.HTTP.Wget import Network.HTTP.Wget
import Data.Maybe (isJust, fromJust) import Data.Maybe (isJust, fromJust)
import Control.Monad.Trans import Control.Monad.Trans
import Control.Monad.Attempt.Class import Control.Monad.Failure
-- | Information received from Rpxnow after a valid login. -- | Information received from Rpxnow after a valid login.
data Identifier = Identifier data Identifier = Identifier
@ -29,7 +30,7 @@ data Identifier = Identifier
} }
-- | Attempt to log a user in. -- | Attempt to log a user in.
authenticate :: (MonadIO m, MonadAttempt m) authenticate :: (MonadIO m, MonadFailure WgetException m, MonadFailure StringException m)
=> String -- ^ API key given by RPXNOW. => String -- ^ API key given by RPXNOW.
-> String -- ^ Token passed by client. -> String -- ^ Token passed by client.
-> m Identifier -> m Identifier
@ -41,7 +42,7 @@ authenticate apiKey token = do
, ("token", token) , ("token", token)
] ]
case decode b >>= getObject of case decode b >>= getObject of
Error s -> failureString $ "Not a valid JSON response: " ++ s Error s -> failureString $ "Not a valid JSON response: " ++ s -- FIXME
Ok o -> Ok o ->
case valFromObj "stat" o of case valFromObj "stat" o of
Error _ -> failureString "Missing 'stat' field" Error _ -> failureString "Missing 'stat' field"
@ -49,7 +50,7 @@ authenticate apiKey token = do
Ok stat -> failureString $ "Login not accepted: " ++ stat Ok stat -> failureString $ "Login not accepted: " ++ stat
++ "\n" ++ b ++ "\n" ++ b
parseProfile :: MonadAttempt m => JSObject JSValue -> m Identifier parseProfile :: Monad m => JSObject JSValue -> m Identifier
parseProfile v = do parseProfile v = do
profile <- resultToMonad $ valFromObj "profile" v >>= getObject profile <- resultToMonad $ valFromObj "profile" v >>= getObject
ident <- resultToMonad $ valFromObj "identifier" profile ident <- resultToMonad $ valFromObj "identifier" profile

View File

@ -1,5 +1,5 @@
name: authenticate name: authenticate
version: 0.2.0 version: 0.2.1
license: BSD3 license: BSD3
license-file: LICENSE license-file: LICENSE
author: Michael Snoyman <michael@snoyman.com> author: Michael Snoyman <michael@snoyman.com>
@ -16,9 +16,10 @@ homepage: http://github.com/snoyberg/authenticate/tree/master
library library
build-depends: base >= 4 && < 5, build-depends: base >= 4 && < 5,
json, json,
http-wget >= 0.2.0, http-wget >= 0.2.1,
tagsoup, tagsoup,
attempt, control-monad-failure,
safe-failure,
transformers >= 0.1.4.0, transformers >= 0.1.4.0,
syb syb
exposed-modules: Web.Authenticate.Rpxnow, exposed-modules: Web.Authenticate.Rpxnow,