Hello community,
here is the log from the commit of package ghc-authenticate-oauth for
openSUSE:Factory checked in at 2017-03-03 17:48:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-authenticate-oauth (Old)
and /work/SRC/openSUSE:Factory/.ghc-authenticate-oauth.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-authenticate-oauth"
Fri Mar 3 17:48:01 2017 rev:4 rq:461603 version:1.6
Changes:
--------
---
/work/SRC/openSUSE:Factory/ghc-authenticate-oauth/ghc-authenticate-oauth.changes
2016-07-21 08:07:04.000000000 +0200
+++
/work/SRC/openSUSE:Factory/.ghc-authenticate-oauth.new/ghc-authenticate-oauth.changes
2017-03-03 17:48:09.818366684 +0100
@@ -1,0 +2,5 @@
+Sun Feb 12 14:19:10 UTC 2017 - [email protected]
+
+- Update to version 1.6 with cabal2obs.
+
+-------------------------------------------------------------------
Old:
----
authenticate-oauth-1.5.1.2.tar.gz
New:
----
authenticate-oauth-1.6.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-authenticate-oauth.spec ++++++
--- /var/tmp/diff_new_pack.1HyFni/_old 2017-03-03 17:48:10.510268969 +0100
+++ /var/tmp/diff_new_pack.1HyFni/_new 2017-03-03 17:48:10.514268404 +0100
@@ -1,7 +1,7 @@
#
# spec file for package ghc-authenticate-oauth
#
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,15 +18,14 @@
%global pkg_name authenticate-oauth
Name: ghc-%{pkg_name}
-Version: 1.5.1.2
+Version: 1.6
Release: 0
Summary: Library to authenticate with OAuth for Haskell web applications
License: BSD-2-Clause
-Group: System/Libraries
+Group: Development/Languages/Other
Url: https://hackage.haskell.org/package/%{pkg_name}
Source0:
https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
BuildRequires: ghc-Cabal-devel
-# Begin cabal-rpm deps:
BuildRequires: ghc-RSA-devel
BuildRequires: ghc-SHA-devel
BuildRequires: ghc-base64-bytestring-devel
@@ -39,9 +38,9 @@
BuildRequires: ghc-random-devel
BuildRequires: ghc-rpm-macros
BuildRequires: ghc-time-devel
+BuildRequires: ghc-transformers-compat-devel
BuildRequires: ghc-transformers-devel
BuildRoot: %{_tmppath}/%{name}-%{version}-build
-# End cabal-rpm deps
%description
API docs and the README are available at
@@ -62,15 +61,12 @@
%prep
%setup -q -n %{pkg_name}-%{version}
-
%build
%ghc_lib_build
-
%install
%ghc_lib_install
-
%post devel
%ghc_pkg_recache
++++++ authenticate-oauth-1.5.1.2.tar.gz -> authenticate-oauth-1.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/authenticate-oauth-1.5.1.2/ChangeLog.md
new/authenticate-oauth-1.6/ChangeLog.md
--- old/authenticate-oauth-1.5.1.2/ChangeLog.md 2016-05-24 09:55:05.000000000
+0200
+++ new/authenticate-oauth-1.6/ChangeLog.md 2016-06-04 12:34:32.000000000
+0200
@@ -1,3 +1,9 @@
+## 1.6
+
+* Add checkOAuth
+* Add support for [oauth_body_hash
extension](https://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html)
+ in `checkOAuth` and `signOAuth`; this might have slightly changed
`checkOAuth` behavior.
+
## 1.5.1.2
* Allow newest transformers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/authenticate-oauth-1.5.1.2/Web/Authenticate/OAuth.hs
new/authenticate-oauth-1.6/Web/Authenticate/OAuth.hs
--- old/authenticate-oauth-1.5.1.2/Web/Authenticate/OAuth.hs 2016-05-24
09:55:05.000000000 +0200
+++ new/authenticate-oauth-1.6/Web/Authenticate/OAuth.hs 2016-06-04
12:34:32.000000000 +0200
@@ -17,7 +17,7 @@
-- * Operations for credentials
newCredential, emptyCredential, insert, delete, inserts, injectVerifier,
-- * Signature
- signOAuth, genSign,
+ signOAuth, genSign, checkOAuth,
-- * Url & operation for authentication
-- ** Temporary credentials
getTemporaryCredential, getTemporaryCredentialWithScope,
@@ -39,9 +39,11 @@
import Blaze.ByteString.Builder (toByteString)
import Control.Exception
+import Control.Arrow (second)
import Control.Monad
import Control.Monad.IO.Class (MonadIO, liftIO)
-import Crypto.Types.PubKey.RSA (PrivateKey (..), PublicKey (..))
+import Control.Monad.Trans.Except
+import Crypto.Types.PubKey.RSA (PrivateKey (..)) -- , PublicKey
(..)
import Data.ByteString.Base64
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as BSL
@@ -49,7 +51,7 @@
import Data.Default
import Data.Digest.Pure.SHA
import qualified Data.IORef as I
-import Data.List (sort)
+import Data.List as List (sort, find)
import Data.Maybe
import Data.Time
import Network.HTTP.Client
@@ -135,7 +137,7 @@
deriving (Show, Eq, Read, Data, Typeable)
-data OAuthException = OAuthException String
+newtype OAuthException = OAuthException String
deriving (Show, Eq, Data, Typeable)
instance Exception OAuthException
@@ -193,8 +195,9 @@
-- | Data type for redential.
-data Credential = Credential { unCredential :: [(BS.ByteString,
BS.ByteString)] }
- deriving (Show, Eq, Ord, Read, Data, Typeable)
+newtype Credential = Credential -- we can easily change it back to "data"
later if needed, right?
+ { unCredential :: [(BS.ByteString, BS.ByteString)] }
+ deriving (Show, Eq, Ord, Read, Data, Typeable)
-- | Convenient function to create 'Credential' with OAuth Token and Token
Secret.
@@ -243,24 +246,40 @@
-> Credential -- ^ Credential
-> Request -- ^ Original Request
-> m Request -- ^ Signed OAuth Request
-signOAuth oa crd req = signOAuth' oa crd addAuthHeader req
+signOAuth oa crd req = signOAuth' oa crd True addAuthHeader req
-- | More flexible signOAuth
signOAuth' :: MonadIO m
=> OAuth -- ^ OAuth Application
-> Credential -- ^ Credential
+ -> Bool -- ^ whether to insert oauth_body_hash or not
-> (BS.ByteString -> Credential -> Request -> Request) -- ^
signature style
-> Request -- ^ Original Request
-> m Request -- ^ Signed OAuth Request
-signOAuth' oa crd add_auth req = do
+signOAuth' oa crd withHash add_auth req = do
crd' <- addTimeStamp =<< addNonce crd
- let tok = injectOAuthToCred oa crd'
+ mhash <- moauth_body_hash
+ let tok = addHashToCred mhash $ injectOAuthToCred oa crd'
sign <- genSign oa tok req
- return $ add_auth prefix (insert "oauth_signature" sign tok) req
- where
- prefix = case oauthRealm oa of
- Nothing -> "OAuth "
- Just v -> "OAuth realm=\"" `BS.append` v `BS.append` "\","
+ let prefix = case oauthRealm oa of
+ Nothing -> "OAuth "
+ Just v -> "OAuth realm=\"" `BS.append` v `BS.append` "\","
+ return $ add_auth prefix
+ (insert "oauth_signature" sign tok)
+ req
+ where -- adding extension
https://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
+ moauth_body_hash = if not withHash || isBodyFormEncoded (requestHeaders
req)
+ then return Nothing
+ else (Just
+ . encode
+ . BSL.toStrict
+ . bytestringDigest
+ . sha1
+ . BSL.fromStrict) `liftM` loadBodyBS req
+ -- encodeHash (Just h) = "oauth_body_hash=\"" `BS.append` paramEncode h
`BS.append` "\","
+ -- encodeHash Nothing = ""
+ addHashToCred (Just h) = insert "oauth_body_hash" h
+ addHashToCred Nothing = id
-- | Generate OAuth signature. Used by 'signOAuth'.
@@ -276,6 +295,70 @@
RSASHA1 pr ->
liftM (encode . toStrict . rsassa_pkcs1_v1_5_sign hashSHA1 pr)
(getBaseString tok req)
+-- | Test existing OAuth signature.
+-- Since 1.5.2
+checkOAuth :: MonadIO m
+ => OAuth -> Credential -> Request
+ -> ExceptT OAuthException m Request
+checkOAuth oa crd req = if isBodyFormEncoded origHeaders then checkOAuthB oa
crd req else do
+ case mosig of
+ Nothing -> throwE $ OAuthException "oauth_signature parameter not found"
+ Just osig -> do
+ mhash <- moauth_body_hash
+ case (\oh nh -> oh == paramEncode nh) `liftM` moauth_body_hash_orig `ap`
mhash of
+ Just False -> throwE $ OAuthException "Failed test of oauth_body_hash"
+ _ -> let tok = addHashToCred mhash . injectOAuthToCred oa $ inserts
(remParams authParams) crd
+ in genSign oa tok req
+ {requestHeaders = catMaybes [mtypeHeader]}
+ >>= \nsig -> if osig == paramEncode nsig
+ then return req
+ else throwE $ OAuthException "Failed test of
oauth_signature"
+ where
+ origHeaders = requestHeaders req
+ mauthHeader = List.find ( ("Authorization" ==) . fst) $ origHeaders
+ mtypeHeader = List.find ( ("Content-Type" ==) . fst) $ origHeaders
+ authParams = (map parseParam . BS.split ',' . BS.drop 6 . snd) `liftM`
mauthHeader
+ remParams Nothing = []
+ remParams (Just ms) = filter ( not . flip elem
+ ("realm" : "oauth_signature" : map
fst (unCredential crd))
+ . fst) ms
+ mosig = fmap snd . join $ List.find (("oauth_signature" ==) . fst) `liftM`
authParams
+ parseParam = second (BS.takeWhile ('"' /=) . BS.drop 1 . BS.dropWhile ('"'
/=))
+ . splitEq . BS.dropWhile (' ' ==)
+ splitEq s = case BS.elemIndex '=' s of
+ Nothing -> (s,"")
+ Just i -> BS.splitAt i s
+ moauth_body_hash_orig = join $ (fmap snd . List.find ( ("oauth_body_hash"
==) . fst)) `liftM` authParams
+ moauth_body_hash = if moauth_body_hash_orig == Nothing
+ then return Nothing
+ else (Just
+ . encode
+ . BSL.toStrict
+ . bytestringDigest
+ . sha1
+ . BSL.fromStrict) `liftM` loadBodyBS req
+ addHashToCred (Just h) = insert "oauth_body_hash" h
+ addHashToCred Nothing = id
+
+checkOAuthB :: MonadIO m
+ => OAuth -> Credential -> Request
+ -> ExceptT OAuthException m Request
+checkOAuthB oa crd req0 = do
+ (mosig, reqBody) <- getSig `liftM` loadBodyBS req0
+ let req = req0 {requestBody = RequestBodyBS reqBody}
+ case mosig of
+ "" -> throwE $ OAuthException "oauth_signature parameter not found"
+ osig -> do
+ nsig <- genSign oa crd req
+ if osig == paramEncode nsig
+ then return req0
+ else throwE $ OAuthException "Failed test of oauth_signature"
+ where
+ getSig b = let (h1 , r ) = BS.breakSubstring "&oauth_signature=" b
+ (sig, h2) = BS.breakSubstring "&" $ BS.drop 17 r
+ in (sig, h1 `BS.append` h2)
+
+
----------------------------------------------------------------------
-- Temporary credentails
@@ -315,13 +398,14 @@
getTemporaryCredential' hook oa manager = do
let req = fromJust $ parseUrl $ oauthRequestUri oa
crd = maybe id (insert "oauth_callback") (oauthCallback oa) $
emptyCredential
- req' <- signOAuth oa crd $ hook (req { method = "POST" })
+ req' <- signOAuth' oa crd False addAuthHeader $ hook (req { method = "POST"
})
rsp <- liftIO $ httpLbs req' manager
if responseStatus rsp == status200
then do
let dic = parseSimpleQuery . toStrict . responseBody $ rsp
return $ Credential dic
- else liftIO . throwIO . OAuthException $ "Gaining OAuth Temporary
Credential Failed: " ++ BSL.unpack (responseBody rsp)
+ else liftIO . throwIO . OAuthException
+ $ "Gaining OAuth Temporary Credential Failed: " ++ BSL.unpack
(responseBody rsp)
----------------------------------------------------------------------
@@ -381,17 +465,29 @@
-> Manager
-> m Credential -- ^ Token Credential (Access Token &
Secret)
getAccessToken' hook oauth cr manager = do
- maybe_access_token <- getAccessTokenWith AccessTokenRequest {
accessTokenAddAuth = addAuthHeader, accessTokenRequestHook = hook,
accessTokenOAuth = oauth, accessTokenTemporaryCredential = cr,
accessTokenManager = manager }
- case maybe_access_token of
- Left error_response -> liftIO . throwIO . OAuthException $ "Gaining
OAuth Token Credential Failed: " ++ BSL.unpack (responseBody error_response)
+ maybe_access_token <- getAccessTokenWith AccessTokenRequest
+ { accessTokenAddAuth = addAuthHeader
+ , accessTokenRequestHook = hook
+ , accessTokenOAuth = oauth
+ , accessTokenTemporaryCredential = cr
+ , accessTokenManager = manager
+ }
+ case maybe_access_token of
+ Left error_response -> liftIO . throwIO . OAuthException
+ $ "Gaining OAuth Token Credential Failed: "
+ ++ BSL.unpack (responseBody error_response)
Right access_token -> return access_token
getAccessTokenWith :: MonadIO m
=> AccessTokenRequest -- ^ extensible parameters
- -> m (Either (Response BSL.ByteString) Credential) -- ^
Token Credential (Access Token & Secret) or the conduit response on failures
+ -> m (Either (Response BSL.ByteString) Credential
+ ) -- ^ Token Credential (Access Token & Secret) or the
conduit response on failures
getAccessTokenWith params = do
let req = hook (fromJust $ parseUrl $ oauthAccessTokenUri oa) { method =
"POST" }
- rsp <- liftIO $ flip httpLbs manager =<< signOAuth' oa (if oauthVersion
oa == OAuth10 then delete "oauth_verifier" cr else cr) add_auth req
+ rsp <- liftIO $ flip httpLbs manager
+ =<< signOAuth' oa (if oauthVersion oa == OAuth10
+ then delete "oauth_verifier" cr
+ else cr) False add_auth req
if responseStatus rsp == status200
then do
let dic = parseSimpleQuery . toStrict . responseBody $ rsp
@@ -451,10 +547,28 @@
req { requestHeaders = insertMap "Authorization" (renderAuthHeader prefix
cred) $ requestHeaders req }
renderAuthHeader :: BS.ByteString -> [(BS.ByteString, BS.ByteString)] ->
BS.ByteString
-renderAuthHeader prefix = (prefix `BS.append`). BS.intercalate "," . map
(\(a,b) -> BS.concat [paramEncode a, "=\"", paramEncode b, "\""]) . filterCreds
+renderAuthHeader prefix = (prefix `BS.append`)
+ . BS.intercalate ","
+ . map (\(a,b) -> BS.concat [paramEncode a, "=\"",
paramEncode b, "\""])
+ . filterCreds
filterCreds :: [(BS.ByteString, BS.ByteString)] -> [(BS.ByteString,
BS.ByteString)]
-filterCreds = filter ((`elem` ["oauth_token", "oauth_verifier",
"oauth_consumer_key", "oauth_signature_method", "oauth_timestamp",
"oauth_nonce", "oauth_version", "oauth_callback", "oauth_signature"]) . fst)
+-- as per http://oauth.net/core/1.0a -- 9.1.1. Normalize Request Parameters
+-- everything except "realm" parameter should be encoded
+-- 6.1.1, 6.1.2, 6.2.1, 6.3.2 and 7 allow encoding anything in the
authorization parameters
+-- 6.2.3 is only limited to oauth_token and oauth_verifier (although query
params are allowed)
+-- 6.3.1 does not allow specifing other params, so no need to filter them (it
is an error anyway)
+filterCreds = filter (not . flip elem ["realm", "oauth_token_secret"] . fst )
+--filterCreds = filter ((`elem` [ "oauth_consumer_key"
+-- , "oauth_token"
+-- , "oauth_signature"
+-- , "oauth_signature_method"
+-- , "oauth_timestamp"
+-- , "oauth_nonce"
+-- , "oauth_verifier"
+-- , "oauth_version"
+-- , "oauth_callback"
+-- ] ) . fst )
getBaseString :: MonadIO m => Credential -> Request -> m BSL.ByteString
@@ -467,15 +581,15 @@
bsURI = BS.concat [scheme, "://", host req, bsPort, path req]
bsQuery = parseSimpleQuery $ queryString req
bsBodyQ <- if isBodyFormEncoded $ requestHeaders req
- then liftM parseSimpleQuery $ toBS (requestBody req)
+ then liftM parseSimpleQuery $ loadBodyBS req
else return []
- let bsAuthParams = filter ((`elem`["oauth_consumer_key","oauth_token",
"oauth_version","oauth_signature_method","oauth_timestamp", "oauth_nonce",
"oauth_verifier", "oauth_version","oauth_callback"]).fst) $ unCredential tok
+ let bsAuthParams = filterCreds $ unCredential tok
allParams = bsQuery++bsBodyQ++bsAuthParams
bsParams = BS.intercalate "&" $ map (\(a,b)->BS.concat[a,"=",b]) $ sort
$ map (\(a,b) -> (paramEncode a,paramEncode b)) allParams
-- parameter encoding method in OAuth is slight different from ordinary one.
-- So this is OK.
- return $ BSL.intercalate "&" $ map (fromStrict.paramEncode) [bsMtd, bsURI,
bsParams]
+ return . BSL.fromStrict $ BS.intercalate "&" $ map paramEncode [bsMtd,
bsURI, bsParams]
----------------------------------------------------------------------
@@ -519,12 +633,19 @@
fromStrict = BSL.fromChunks . return
+loadBodyBS :: MonadIO m => Request -> m BS.ByteString
+loadBodyBS = toBS . requestBody
+
toBS :: MonadIO m => RequestBody -> m BS.ByteString
toBS (RequestBodyLBS l) = return $ toStrict l
toBS (RequestBodyBS s) = return s
toBS (RequestBodyBuilder _ b) = return $ toByteString b
toBS (RequestBodyStream _ givesPopper) = toBS' givesPopper
toBS (RequestBodyStreamChunked givesPopper) = toBS' givesPopper
+#if MIN_VERSION_http_client(0, 4, 28)
+toBS (RequestBodyIO op) = liftIO op >>= toBS
+#else
+#endif
toBS' :: MonadIO m => GivesPopper () -> m BS.ByteString
toBS' gp = liftIO $ do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/authenticate-oauth-1.5.1.2/authenticate-oauth.cabal
new/authenticate-oauth-1.6/authenticate-oauth.cabal
--- old/authenticate-oauth-1.5.1.2/authenticate-oauth.cabal 2016-05-24
09:55:05.000000000 +0200
+++ new/authenticate-oauth-1.6/authenticate-oauth.cabal 2016-06-04
12:34:32.000000000 +0200
@@ -1,9 +1,9 @@
name: authenticate-oauth
-version: 1.5.1.2
+version: 1.6
license: BSD3
license-file: LICENSE
author: Hiromi Ishii
-maintainer: Hiromi Ishii
+maintainer: Hiromi Ishii, Artem Chirkin
synopsis: Library to authenticate with OAuth for Haskell web
applications.
description: API docs and the README are available at
<http://www.stackage.org/package/authenticate-oauth>.
category: Web
@@ -27,6 +27,7 @@
, random
, http-types >= 0.6
, blaze-builder
+ , transformers-compat >= 0.3
exposed-modules: Web.Authenticate.OAuth, Web.Authenticate.OAuth.IO
ghc-options: -Wall