diff --git a/yesod-auth-oauth/Yesod/Auth/OAuth.hs b/yesod-auth-oauth/Yesod/Auth/OAuth.hs index 7efd9dfe..8d2598de 100644 --- a/yesod-auth-oauth/Yesod/Auth/OAuth.hs +++ b/yesod-auth-oauth/Yesod/Auth/OAuth.hs @@ -5,6 +5,7 @@ module Yesod.Auth.OAuth , oauthUrl , authTwitter , twitterUrl + , module Web.Authenticate.OAuth ) where #include "qq.h" @@ -16,71 +17,75 @@ import Yesod.Widget import Text.Hamlet (shamlet) import Web.Authenticate.OAuth import Data.Maybe -import Data.String -import Data.ByteString.Char8 (pack) import Control.Arrow ((***)) -import Data.Text (Text, unpack) +import Data.Text (Text) +import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8, decodeUtf8With) import Data.Text.Encoding.Error (lenientDecode) import Data.ByteString (ByteString) import Control.Applicative ((<$>), (<*>)) +import Data.Conduit oauthUrl :: Text -> AuthRoute oauthUrl name = PluginR name ["forward"] -authOAuth :: YesodAuth m => - Text -- ^ Service Name - -> String -- ^ OAuth Parameter Name to use for identify - -> String -- ^ Request URL - -> String -- ^ Access Token URL - -> String -- ^ Authorize URL - -> String -- ^ Consumer Key - -> String -- ^ Consumer Secret +authOAuth :: YesodAuth m + => OAuth -- ^ 'OAuth' data-type for signing. + -> (Credential -> IO (Creds m)) -- ^ How to extract ident. -> AuthPlugin m -authOAuth name ident reqUrl accUrl authUrl key sec = AuthPlugin name dispatch login +authOAuth oauth mkCreds = AuthPlugin name dispatch login where + name = T.pack $ oauthServerName oauth url = PluginR name [] - oauth = OAuth { oauthServerName = unpack name, oauthRequestUri = reqUrl - , oauthAccessTokenUri = accUrl, oauthAuthorizeUri = authUrl - , oauthSignatureMethod = HMACSHA1 - , oauthConsumerKey = fromString key, oauthConsumerSecret = fromString sec - , oauthCallback = Nothing - , oauthRealm = Nothing - } + lookupTokenSecret = bsToText . fromMaybe "" . lookup "oauth_token_secret" . unCredential + oauthSessionName = "__oauth_token_secret" dispatch "GET" ["forward"] = do render <- getUrlRender tm <- getRouteToMaster let oauth' = oauth { oauthCallback = Just $ encodeUtf8 $ render $ tm url } master <- getYesod tok <- lift $ getTemporaryCredential oauth' (authHttpManager master) + setSession oauthSessionName $ lookupTokenSecret tok redirect $ authorizeUrl oauth' tok dispatch "GET" [] = do (verifier, oaTok) <- runInputGet $ (,) <$> ireq textField "oauth_verifier" <*> ireq textField "oauth_token" - let reqTok = Credential [ ("oauth_verifier", encodeUtf8 verifier), ("oauth_token", encodeUtf8 oaTok) + tokSec <- fromJust <$> lookupSession oauthSessionName + deleteSession oauthSessionName + let reqTok = Credential [ ("oauth_verifier", encodeUtf8 verifier) + , ("oauth_token", encodeUtf8 oaTok) + , ("oauth_token_secret", encodeUtf8 tokSec) ] master <- getYesod accTok <- lift $ getAccessToken oauth reqTok (authHttpManager master) - let crId = decodeUtf8With lenientDecode $ fromJust $ lookup (pack ident) $ unCredential accTok - creds = Creds name crId $ map (bsToText *** bsToText ) $ unCredential accTok + creds <- resourceLiftBase $ mkCreds accTok setCreds True creds dispatch _ _ = notFound login tm = do render <- lift getUrlRender let oaUrl = render $ tm $ oauthUrl name addHtml - [QQ(shamlet)| Login with #{name} |] + [QQ(shamlet)| Login via #{name} |] -authTwitter :: YesodAuth m => - String -- ^ Consumer Key - -> String -- ^ Consumer Secret +authTwitter :: YesodAuth m + => ByteString -- ^ Consumer Key + -> ByteString -- ^ Consumer Secret -> AuthPlugin m -authTwitter = authOAuth "twitter" - "screen_name" - "http://twitter.com/oauth/request_token" - "http://twitter.com/oauth/access_token" - "http://twitter.com/oauth/authorize" +authTwitter key secret = authOAuth + (newOAuth { oauthServerName = "twitter" + , oauthRequestUri = "https://api.twitter.com/oauth/request_token" + , oauthAccessTokenUri = "https://api.twitter.com/oauth/access_token" + , oauthAuthorizeUri = "https://api.twitter.com/oauth/authorize" + , oauthSignatureMethod = HMACSHA1 + , oauthConsumerKey = key + , oauthConsumerSecret = secret + }) + extractCreds + where + extractCreds (Credential dic) = do + let crId = decodeUtf8With lenientDecode $ fromJust $ lookup "screen_name" dic + return $ Creds "twitter" crId $ map (bsToText *** bsToText ) dic twitterUrl :: AuthRoute twitterUrl = oauthUrl "twitter" diff --git a/yesod-auth-oauth/yesod-auth-oauth.cabal b/yesod-auth-oauth/yesod-auth-oauth.cabal index 171f7dcd..f86efd85 100644 --- a/yesod-auth-oauth/yesod-auth-oauth.cabal +++ b/yesod-auth-oauth/yesod-auth-oauth.cabal @@ -27,6 +27,7 @@ library , yesod-auth >= 0.8 && < 0.9 , text >= 0.7 && < 0.12 , hamlet >= 0.10 && < 0.11 + , conduit >= 0.2 && < 0.3 , yesod-form >= 0.4 && < 0.5 exposed-modules: Yesod.Auth.OAuth