packages feed

authenticate 0.6.5 → 0.6.6

raw patch · 8 files changed

+491/−151 lines, 8 filesdep +networkdep +xmlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: network, xml

API changes (from Hackage documentation)

- Web.Authenticate.OpenId: AuthenticateException :: String -> AuthenticateException
- Web.Authenticate.OpenId: MissingOpenIdParameter :: String -> AuthenticateException
- Web.Authenticate.OpenId: data AuthenticateException
- Web.Authenticate.OpenId: identifier :: Identifier -> String
- Web.Authenticate.OpenId: instance Eq Identifier
- Web.Authenticate.OpenId: instance Exception AuthenticateException
- Web.Authenticate.OpenId: instance Exception MissingVar
- Web.Authenticate.OpenId: instance Monad Error
- Web.Authenticate.OpenId: instance Show AuthenticateException
- Web.Authenticate.OpenId: instance Show Identifier
- Web.Authenticate.OpenId: instance Show MissingVar
- Web.Authenticate.OpenId: instance Typeable AuthenticateException
- Web.Authenticate.OpenId: instance Typeable MissingVar
+ Web.Authenticate.OpenId: AuthenticationException :: String -> OpenIdException
+ Web.Authenticate.OpenId: DiscoveryException :: String -> OpenIdException
+ Web.Authenticate.OpenId: NormalizationException :: String -> OpenIdException
+ Web.Authenticate.OpenId: data OpenIdException
+ Web.Authenticate.Rpxnow: RpxnowException :: String -> RpxnowException
+ Web.Authenticate.Rpxnow: data RpxnowException
+ Web.Authenticate.Rpxnow: instance Exception RpxnowException
+ Web.Authenticate.Rpxnow: instance Show RpxnowException
+ Web.Authenticate.Rpxnow: instance Typeable RpxnowException
- Web.Authenticate.OpenId: authenticate :: (MonadIO m, Failure AuthenticateException m, Failure InvalidUrlException m, Failure HttpException m, Failure MissingVar m) => [(String, String)] -> m Identifier
+ Web.Authenticate.OpenId: authenticate :: (MonadIO m, Failure OpenIdException m, Failure InvalidUrlException m, Failure HttpException m) => [(String, String)] -> m Identifier
- Web.Authenticate.OpenId: getForwardUrl :: (MonadIO m, Failure InvalidUrlException m, Failure HttpException m, Failure MissingVar m) => String -> String -> m String
+ Web.Authenticate.OpenId: getForwardUrl :: (MonadIO m, Failure OpenIdException m, Failure HttpException m, Failure InvalidUrlException m) => String -> String -> m String
- Web.Authenticate.Rpxnow: authenticate :: (MonadIO m, Failure HttpException m, Failure InvalidUrlException m, Failure AuthenticateException m, Failure ObjectExtractError m, Failure JsonDecodeError m) => String -> String -> m Identifier
+ Web.Authenticate.Rpxnow: authenticate :: (MonadIO m, Failure HttpException m, Failure InvalidUrlException m, Failure RpxnowException m, Failure ObjectExtractError m, Failure JsonDecodeError m) => String -> String -> m Identifier

Files

+ OpenId2/Discovery.hs view
@@ -0,0 +1,186 @@+{-# LANGUAGE FlexibleContexts #-}++--------------------------------------------------------------------------------+-- |+-- Module      : Network.OpenID.Discovery+-- Copyright   : (c) Trevor Elliott, 2008+-- License     : BSD3+--+-- Maintainer  : Trevor Elliott <trevor@geekgateway.com>+-- Stability   :+-- Portability :+--++module OpenId2.Discovery (+    -- * Discovery+    discover+  , Discovery (..)+  ) where++-- Friends+import OpenId2.Types+import OpenId2.XRDS++-- Libraries+import Data.Char+import Data.List+import Data.Maybe+import Network.HTTP.Enumerator+import qualified Data.ByteString.Lazy.UTF8 as BSLU+import qualified Data.ByteString.Char8 as S8+import Control.Arrow (first, (***))+import Control.Monad.IO.Class (MonadIO)+import Control.Failure (Failure (failure))+import Control.Monad (mplus, liftM)++data Discovery = Discovery1 String (Maybe String)+               | Discovery2 Provider Identifier+    deriving Show++-- | Attempt to resolve an OpenID endpoint, and user identifier.+discover :: ( MonadIO m+            , Failure OpenIdException m+            , Failure HttpException m+            , Failure InvalidUrlException m+            )+         => Identifier+         -> m Discovery+discover ident@(Identifier i) = do+    res1 <- discoverYADIS ident Nothing+    case res1 of+        Just (x, y) -> return $ Discovery2 x y+        Nothing -> do+            res2 <- discoverHTML ident+            case res2 of+                Just x -> return x+                Nothing -> failure $ DiscoveryException i++-- YADIS-Based Discovery -------------------------------------------------------++-- | Attempt a YADIS based discovery, given a valid identifier.  The result is+--   an OpenID endpoint, and the actual identifier for the user.+discoverYADIS :: ( MonadIO m+                 , Failure HttpException m+                 , Failure InvalidUrlException m+                 )+              => Identifier+              -> Maybe String+              -> m (Maybe (Provider,Identifier))+discoverYADIS ident mb_loc = do+    let uri = fromMaybe (identifier ident) mb_loc+    req <- parseUrl uri+    res <- httpLbs req+    let mloc = lookup "x-xrds-location"+             $ map (first $ map toLower . S8.unpack)+             $ responseHeaders res+    case statusCode res of+        200 ->+          case mloc of+            Just loc -> discoverYADIS ident (Just $ S8.unpack loc)+            Nothing  -> do+              let mdoc = parseXRDS $ BSLU.toString $ responseBody res+              case mdoc of+                  Just doc -> return $ parseYADIS ident doc+                  Nothing -> return Nothing+        _ -> return Nothing+++-- | Parse out an OpenID endpoint, and actual identifier from a YADIS xml+-- document.+parseYADIS :: Identifier -> XRDS -> Maybe (Provider,Identifier)+parseYADIS ident = listToMaybe . mapMaybe isOpenId . concat+  where+  isOpenId svc = do+    let tys = serviceTypes svc+        localId = maybe ident Identifier $ listToMaybe $ serviceLocalIDs svc+        f (x,y) | x `elem` tys = Just y+                | otherwise    = Nothing+    lid <- listToMaybe $ mapMaybe f+      [ ("http://specs.openid.net/auth/2.0/server", ident)+      -- claimed identifiers+      , ("http://specs.openid.net/auth/2.0/signon", localId)+      , ("http://openid.net/signon/1.0"           , localId)+      , ("http://openid.net/signon/1.1"           , localId)+      ]+    uri <- listToMaybe $ serviceURIs svc+    return (Provider uri, lid)+++-- HTML-Based Discovery --------------------------------------------------------++-- | Attempt to discover an OpenID endpoint, from an HTML document.  The result+-- will be an endpoint on success, and the actual identifier of the user.+discoverHTML :: ( MonadIO m+                , Failure HttpException m+                , Failure InvalidUrlException m+                )+             => Identifier+             -> m (Maybe Discovery)+discoverHTML ident'@(Identifier ident) =+    (parseHTML ident' . BSLU.toString) `liftM` simpleHttp ident++-- | Parse out an OpenID endpoint and an actual identifier from an HTML+-- document.+parseHTML :: Identifier -> String -> Maybe Discovery+parseHTML ident = resolve+                . filter isOpenId+                . map (dropQuotes *** dropQuotes)+                . linkTags+                . htmlTags+  where+    isOpenId (rel,_) = "openid" `isPrefixOf` rel+    resolve1 ls = do+      server <- lookup "openid.server" ls+      let delegate = lookup "openid.delegate" ls+      return $ Discovery1 server delegate+    resolve2 ls = do+      prov <- lookup "openid2.provider" ls+      let lid = maybe ident Identifier $ lookup "openid2.local_id" ls+      return $ Discovery2 (Provider prov) lid+    resolve ls = resolve2 ls `mplus` resolve1 ls+++-- FIXME this would all be a lot better if it used tagsoup+-- | Filter out link tags from a list of html tags.+linkTags :: [String] -> [(String,String)]+linkTags  = mapMaybe f . filter p+  where+    p = ("link " `isPrefixOf`)+    f xs = do+      let ys = unfoldr splitAttr (drop 5 xs)+      x <- lookup "rel"  ys+      y <- lookup "href" ys+      return (x,y)+++-- | Split a string into strings of html tags.+htmlTags :: String -> [String]+htmlTags [] = []+htmlTags xs = case break (== '<') xs of+  (as,_:bs) -> fmt as : htmlTags bs+  (as,[])   -> [as]+  where+    fmt as = case break (== '>') as of+      (bs,_) -> bs+++-- | Split out values from a key="value" like string, in a way that+-- is suitable for use with unfoldr.+splitAttr :: String -> Maybe ((String,String),String)+splitAttr xs = case break (== '=') xs of+  (_,[])         -> Nothing+  (key,_:'"':ys) -> f key (== '"') ys+  (key,_:ys)     -> f key isSpace  ys+  where+  f key p cs = case break p cs of+      (_,[])         -> Nothing+      (value,_:rest) -> Just ((key,value), dropWhile isSpace rest)++dropQuotes :: String -> String+dropQuotes s@('\'':x:y)+    | last y == '\'' = x : init y+    | otherwise = s+dropQuotes s@('"':x:y)+    | last y == '"' = x : init y+    | otherwise = s+dropQuotes s = s
+ OpenId2/Normalization.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE FlexibleContexts #-}+--------------------------------------------------------------------------------+-- |+-- Module      : Network.OpenID.Normalization+-- Copyright   : (c) Trevor Elliott, 2008+-- License     : BSD3+--+-- Maintainer  : Trevor Elliott <trevor@geekgateway.com>+-- Stability   : +-- Portability : +--++module OpenId2.Normalization+    ( normalize+    ) where++-- Friends+import OpenId2.Types++-- Libraries+import Control.Applicative+import Control.Monad+import Data.List+import Control.Failure (Failure (..))+import Network.URI++normalize :: Failure OpenIdException m => String -> m Identifier+normalize ident =+    case normalizeIdentifier $ Identifier ident of+        Just i -> return i+        Nothing -> failure $ NormalizationException ident++-- | Normalize an identifier, discarding XRIs.+normalizeIdentifier :: Identifier -> Maybe Identifier+normalizeIdentifier  = normalizeIdentifier' (const Nothing)+++-- | Normalize the user supplied identifier, using a supplied function to+-- normalize an XRI.+normalizeIdentifier' :: (String -> Maybe String) -> Identifier+                     -> Maybe Identifier+normalizeIdentifier' xri (Identifier str)+  | null str                  = Nothing+  | "xri://" `isPrefixOf` str = Identifier `fmap` xri str+  | head str `elem` "=@+$!"   = Identifier `fmap` xri str+  | otherwise = fmt `fmap` (url >>= norm)+  where+    url = parseURI str <|> parseURI ("http://" ++ str)++    norm uri = validScheme >> return u+      where+        scheme'     = uriScheme uri+        validScheme = guard (scheme' == "http:" || scheme' == "https:")+        u = uri { uriFragment = "", uriPath = path' }+        path' | null (uriPath uri) = "/"+              | otherwise          = uriPath uri++    fmt u = Identifier+          $ normalizePathSegments+          $ normalizeEscape+          $ normalizeCase+          $ uriToString (const "") u []
+ OpenId2/Types.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE DeriveDataTypeable #-}+--------------------------------------------------------------------------------+-- |+-- Module      : Network.OpenID.Types+-- Copyright   : (c) Trevor Elliott, 2008+-- License     : BSD3+--+-- Maintainer  : Trevor Elliott <trevor@geekgateway.com>+-- Stability   : +-- Portability : +--++module OpenId2.Types (+    Provider (..)+  , Identifier (..)+  , OpenIdException (..)+  ) where++-- Libraries+import Control.Exception (Exception)+import Data.Typeable (Typeable)++data OpenIdException =+      NormalizationException String+    | DiscoveryException String+    | AuthenticationException String+  deriving (Show, Typeable)+instance Exception OpenIdException++-- | An OpenID provider.+newtype Provider = Provider { providerURI :: String } deriving (Eq,Show)++-- | A valid OpenID identifier.+newtype Identifier = Identifier { identifier :: String }+  deriving (Eq, Show, Read)
+ OpenId2/XRDS.hs view
@@ -0,0 +1,101 @@++--------------------------------------------------------------------------------+-- |+-- Module      : Text.XRDS+-- Copyright   : (c) Trevor Elliott, 2008+-- License     : BSD3+--+-- Maintainer  : Trevor Elliott <trevor@geekgateway.com>+-- Stability   :+-- Portability :+--++module OpenId2.XRDS (+    -- * Types+    XRDS+  , Service(..)++    -- * Parsing+  , parseXRDS+  ) where++-- Libraries+import Control.Arrow+import Control.Monad+import Data.List+import Data.Maybe+import Text.XML.Light+++-- Types -----------------------------------------------------------------------++type XRDS = [XRD]++type XRD = [Service]++data Service = Service+  { serviceTypes      :: [String]+  , serviceMediaTypes :: [String]+  , serviceURIs       :: [String]+  , serviceLocalIDs   :: [String]+  , servicePriority   :: Maybe Int+  , serviceExtra      :: [Element]+  } deriving Show++-- Utilities -------------------------------------------------------------------++-- | Generate a tag name predicate, that ignores prefix and namespace.+tag :: String -> Element -> Bool+tag n el = qName (elName el) == n+++-- | Filter the attributes of an element by some predicate+findAttr' :: (QName -> Bool) -> Element -> Maybe String+findAttr' p el = attrVal `fmap` find (p . attrKey) (elAttribs el)+++-- | Read, maybe+readMaybe :: Read a => String -> Maybe a+readMaybe str = case reads str of+  [(x,"")] -> Just x+  _        -> Nothing+++-- | Get the text of an element+getText :: Element -> String+getText el = case elContent el of+  [Text cd] -> cdData cd+  _         -> []++-- Parsing ---------------------------------------------------------------------+++parseXRDS :: String -> Maybe XRDS+parseXRDS str = do+  doc <- parseXMLDoc str+  let xrds = filterChildren (tag "XRD") doc+  return $ map parseXRD xrds+++parseXRD :: Element -> XRD+parseXRD el =+  let svcs = filterChildren (tag "Service") el+   in mapMaybe parseService svcs+++parseService :: Element -> Maybe Service+parseService el = do+  let vals t x = first (map getText) $ partition (tag t) x+      (tys,tr)    = vals "Type"      (elChildren el)+      (mts,mr)    = vals "MediaType" tr+      (uris,ur)   = vals "URI"       mr+      (lids,rest) = vals "LocalID"   ur+      priority = readMaybe =<< findAttr' (("priority" ==) . qName) el+  guard $ not $ null tys+  return $ Service { serviceTypes      = tys+                   , serviceMediaTypes = mts+                   , serviceURIs       = uris+                   , serviceLocalIDs   = lids+                   , servicePriority   = priority+                   , serviceExtra      = rest+                   }
Web/Authenticate/Internal.hs view
@@ -1,9 +1,19 @@ module Web.Authenticate.Internal     ( qsEncode+    , qsUrl     ) where  import Codec.Binary.UTF8.String (encode) import Numeric (showHex)+import Data.List (intercalate)++qsUrl :: String -> [(String, String)] -> String+qsUrl s [] = s+qsUrl url pairs =+    url ++ delim : intercalate "&" (map qsPair pairs)+  where+    qsPair (x, y) = qsEncode x ++ '=' : qsEncode y +    delim = if '?' `elem` url then '&' else '?'  qsEncode :: String -> String qsEncode =
Web/Authenticate/OpenId.hs view
@@ -1,159 +1,93 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE PackageImports #-}------------------------------------------------------------- |--- Module        : Web.Authenticate.OpenId--- Copyright     : Michael Snoyman--- License       : BSD3------ Maintainer    : Michael Snoyman <michael@snoyman.com>--- Stability     : Unstable--- Portability   : portable------ Provides functionality for being an OpenId consumer.------------------------------------------------------------- module Web.Authenticate.OpenId-    ( Identifier (..)-    , getForwardUrl+    ( getForwardUrl     , authenticate-    , AuthenticateException (..)+    , OpenIdException (..)+    , Identifier (..)     ) where +import Control.Monad.IO.Class+import OpenId2.Normalization (normalize)+import OpenId2.Discovery (discover, Discovery (..))+import Control.Failure (Failure (failure))+import OpenId2.Types (OpenIdException (..), Identifier (Identifier),+                      Provider (Provider))+import Web.Authenticate.Internal (qsUrl)+import Control.Monad (unless)+import qualified Data.ByteString.UTF8 as BSU+import qualified Data.ByteString.Lazy.UTF8 as BSLU import Network.HTTP.Enumerator-import Text.HTML.TagSoup-import "transformers" Control.Monad.IO.Class-import Data.Data-import Control.Failure hiding (Error)-import Control.Exception-import Control.Monad (liftM, unless)-import qualified Data.ByteString.Lazy.Char8 as L8-import Web.Authenticate.Internal (qsEncode)-import Data.List (intercalate)---- | An openid identifier (ie, a URL).-newtype Identifier = Identifier { identifier :: String }-    deriving (Eq, Show)--data Error v = Error String | Ok v-instance Monad Error where-    return = Ok-    Error s >>= _ = Error s-    Ok v >>= f = f v-    fail s = Error s+    ( parseUrl, urlEncodedBody, responseBody, httpLbsRedirect+    , HttpException, InvalidUrlException+    )+import Control.Arrow ((***))+import Data.List (unfoldr)+import Data.Maybe (fromMaybe) --- | Returns a URL to forward the user to in order to login.-getForwardUrl :: (MonadIO m,-                  Failure InvalidUrlException m,-                  Failure HttpException m,-                  Failure MissingVar m-                  )+getForwardUrl :: ( MonadIO m+                 , Failure OpenIdException m+                 , Failure HttpException m+                 , Failure InvalidUrlException m+                 )               => String -- ^ The openid the user provided.               -> String -- ^ The URL for this application\'s complete page.               -> m String -- ^ URL to send the user to.-getForwardUrl openid complete = do-    bodyIdent' <- simpleHttp openid-    let bodyIdent = L8.unpack bodyIdent'-    server <- getOpenIdVar "server" bodyIdent-    let delegate = maybe openid id-                 $ getOpenIdVar "delegate" bodyIdent-    return $ constructUrl server-                        [ ("openid.mode", "checkid_setup")-                        , ("openid.identity", delegate)-                        , ("openid.return_to", complete)-                        ]--data MissingVar = MissingVar String-    deriving (Typeable, Show)-instance Exception MissingVar--getOpenIdVar :: Failure MissingVar m => String -> String -> m String-getOpenIdVar var content = do-    let tags = parseTags content-    let secs = sections (~== ("<link rel=openid." ++ var ++ ">")) tags-    secs' <- mhead secs-    secs'' <- mhead secs'-    return $ fromAttrib "href" secs''-    where-        mhead [] = failure $ MissingVar $ "openid." ++ var-        mhead (x:_) = return x--constructUrl :: String -> [(String, String)] -> String-constructUrl url [] = url-constructUrl url args =-    url ++ "?" ++ intercalate "&" (map qsPair args)-  where-    qsPair (x, y) = qsEncode x ++ '=' : qsEncode y +getForwardUrl openid' complete = do+    disc <- normalize openid' >>= discover+    case disc of+        Discovery1 server mdelegate ->+            return $ qsUrl server+                [ ("openid.mode", "checkid_setup")+                , ("openid.identity", fromMaybe openid' mdelegate)+                , ("openid.return_to", complete)+                ]+        Discovery2 (Provider p) (Identifier i) ->+            return $ qsUrl p+                [ ("openid.ns", "http://specs.openid.net/auth/2.0")+                , ("openid.mode", "checkid_setup")+                , ("openid.claimed_id", i)+                , ("openid.identity", i)+                , ("openid.return_to", complete)+                ] --- | Handle a redirect from an OpenID provider and check that the user--- logged in properly. If it was successfully, 'return's the openid.--- Otherwise, 'failure's an explanation.-authenticate :: (MonadIO m,-                 Failure AuthenticateException m,-                 Failure InvalidUrlException m,-                 Failure HttpException m,-                 Failure MissingVar m)+authenticate :: ( MonadIO m+                , Failure OpenIdException m+                , Failure InvalidUrlException m+                , Failure HttpException m+                )              => [(String, String)]              -> m Identifier-authenticate req = do-    unless (lookup "openid.mode" req == Just "id_res") $-        failure $ AuthenticateException "authenticate without openid.mode=id_res"-    authUrl <- getAuthUrl req-    content <- L8.unpack `liftM` simpleHttp authUrl-    if contains "is_valid:true" content-        then Identifier `liftM` alookup "openid.identity" req-        else failure $ AuthenticateException content--alookup :: (Failure AuthenticateException m, Monad m)-        => String-        -> [(String, String)]-        -> m String-alookup k x = case lookup k x of-                Just k' -> return k'-                Nothing -> failure $ MissingOpenIdParameter k--data AuthenticateException = AuthenticateException String-                           | MissingOpenIdParameter String-    deriving (Show, Typeable)-instance Exception AuthenticateException--getAuthUrl :: (MonadIO m, Failure AuthenticateException m,-               Failure InvalidUrlException m,-               Failure HttpException m,-               Failure MissingVar m)-           => [(String, String)] -> m String-getAuthUrl req = do-    identity <- alookup "openid.identity" req-    idContent <- simpleHttp identity-    helper $ L8.unpack idContent-    where-        helper idContent = do-            server <- getOpenIdVar "server" idContent-            dargs <- mapM makeArg [-                "assoc_handle",-                "sig",-                "signed",-                "identity",-                "return_to"-                ]-            let sargs = [("openid.mode", "check_authentication")]-            return $ constructUrl server $ dargs ++ sargs-        makeArg s = do-            let k = "openid." ++ s-            v <- alookup k req-            return (k, v)+authenticate params = do+    unless (lookup "openid.mode" params == Just "id_res")+        $ failure $ AuthenticationException "mode is not id_res"+    ident <- case lookup "openid.identity" params of+                Just i -> return i+                Nothing ->+                    failure $ AuthenticationException "Missing identity"+    disc <- normalize ident >>= discover+    let endpoint = case disc of+                    Discovery1 p _ -> p+                    Discovery2 (Provider p) _ -> p+    let params' = map (BSU.fromString *** BSU.fromString)+                $ ("openid.mode", "check_authentication")+                : filter (\(k, _) -> k /= "openid.mode") params+    req' <- parseUrl endpoint+    let req = urlEncodedBody params' req'+    rsp <- httpLbsRedirect req+    let rps = parseDirectResponse $ BSLU.toString $ responseBody rsp+    case lookup "is_valid" rps of+        Just "true" -> return $ Identifier ident+        _ -> failure $ AuthenticationException "OpenID provider did not validate" -contains :: String -> String -> Bool-contains [] _ = True-contains _ [] = False-contains needle haystack =-    begins needle haystack ||-    (contains needle $ tail haystack)+-- | Turn a response body into a list of parameters.+parseDirectResponse :: String -> [(String, String)]+parseDirectResponse  = unfoldr step+  where+    step []  = Nothing+    step str = case split (== '\n') str of+      (ps,rest) -> Just (split (== ':') ps,rest) -begins :: String -> String -> Bool-begins [] _ = True-begins _ [] = False-begins (x:xs) (y:ys) = x == y && begins xs ys+split :: (a -> Bool) -> [a] -> ([a],[a])+split p as = case break p as of+  (xs,_:ys) -> (xs,ys)+  pair      -> pair
Web/Authenticate/Rpxnow.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE PackageImports #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-} --------------------------------------------------------- -- -- Module        : Web.Authenticate.Rpxnow@@ -18,6 +19,7 @@ module Web.Authenticate.Rpxnow     ( Identifier (..)     , authenticate+    , RpxnowException (..)     ) where  import Data.Object@@ -26,11 +28,11 @@ import "transformers" Control.Monad.IO.Class import Control.Failure import Data.Maybe-import Web.Authenticate.OpenId (AuthenticateException (..)) import Control.Monad import qualified Data.ByteString.Char8 as S import qualified Data.ByteString.Lazy.Char8 as L-import Control.Exception (throwIO)+import Control.Exception (throwIO, Exception)+import Data.Typeable (Typeable)  -- | Information received from Rpxnow after a valid login. data Identifier = Identifier@@ -42,7 +44,7 @@ authenticate :: (MonadIO m,                  Failure HttpException m,                  Failure InvalidUrlException m,-                 Failure AuthenticateException m,+                 Failure RpxnowException m,                  Failure ObjectExtractError m,                  Failure JsonDecodeError m)              => String -- ^ API key given by RPXNOW.@@ -75,7 +77,7 @@     o <- decode $ S.concat $ L.toChunks b     m <- fromMapping o     stat <- lookupScalar "stat" m-    unless (stat == "ok") $ failure $ AuthenticateException $+    unless (stat == "ok") $ failure $ RpxnowException $         "Rpxnow login not accepted: " ++ stat ++ "\n" ++ L.unpack b     parseProfile m @@ -90,3 +92,7 @@     go ("identifier", _) = Nothing     go (k, Scalar v) = Just (k, v)     go _ = Nothing++data RpxnowException = RpxnowException String+    deriving (Show, Typeable)+instance Exception RpxnowException
authenticate.cabal view
@@ -1,5 +1,5 @@ name:            authenticate-version:         0.6.5+version:         0.6.6 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>@@ -22,9 +22,15 @@                      failure >= 0.0.0 && < 0.2,                      transformers >= 0.1 && < 0.3,                      bytestring >= 0.9 && < 0.10,-                     utf8-string >= 0.3 && < 0.4+                     utf8-string >= 0.3 && < 0.4,+                     network >= 2.2.1 && < 2.3,+                     xml >= 1.3.7 && < 1.4     exposed-modules: Web.Authenticate.Rpxnow,                      Web.Authenticate.OpenId,                      Web.Authenticate.Facebook-    other-modules:   Web.Authenticate.Internal+    other-modules:   Web.Authenticate.Internal,+                     OpenId2.Discovery,+                     OpenId2.Normalization,+                     OpenId2.Types,+                     OpenId2.XRDS     ghc-options:     -Wall