Signing works! But includes lots of debug stmts.

This commit is contained in:
Aditya Manthramurthy 2016-10-22 19:28:49 -07:00
parent 5ce595bc6f
commit 4569348dc2
5 changed files with 88 additions and 23 deletions

View File

@ -32,11 +32,13 @@ library
, http-client , http-client
, http-conduit , http-conduit
, http-types , http-types
, memory
, text , text
, time , time
default-language: Haskell2010 default-language: Haskell2010
default-extensions: OverloadedStrings default-extensions: OverloadedStrings
, NoImplicitPrelude , NoImplicitPrelude
, MultiWayIf
executable minio-hs-exe executable minio-hs-exe
hs-source-dirs: app hs-source-dirs: app

View File

@ -14,11 +14,23 @@ import Network.Minio.Data
import Network.Minio.Data.Crypto import Network.Minio.Data.Crypto
import Network.Minio.Sign.V4 import Network.Minio.Sign.V4
runRequestDebug r mgr = do
print $ "runRequestDebug"
print $ NC.method r
print $ NC.secure r
print $ NC.host r
print $ NC.port r
print $ NC.path r
print $ NC.queryString r
print $ NC.requestHeaders r
-- print $ NC.requestBody r
NC.httpLbs r mgr
minioExecute :: MinioClient -> RequestInfo -> IO (Response LByteString) minioExecute :: MinioClient -> RequestInfo -> IO (Response LByteString)
minioExecute mc ri = do minioExecute mc ri = do
mgr <- NC.newManager defaultManagerSettings mgr <- NC.newManager defaultManagerSettings
finalHeaders <- signV4 mc updatedRI finalHeaders <- signV4 mc updatedRI
NC.httpLbs (req finalHeaders) mgr runRequestDebug (req finalHeaders) mgr
where where
req h = NC.defaultRequest { req h = NC.defaultRequest {
NC.method = method ri NC.method = method ri

View File

@ -2,16 +2,29 @@ module Network.Minio.Data.Crypto
( (
hashSHA256 hashSHA256
, hmacSHA256 , hmacSHA256
, hmacSHA256RawBS
, digestToBS
, digestToBase16
) where ) where
import Crypto.Hash (SHA256(..), hashWith, Digest) import Crypto.Hash (SHA256(..), hashWith, Digest)
import Crypto.MAC.HMAC (hmac, HMAC(hmacGetDigest)) import Crypto.MAC.HMAC (hmac, HMAC(hmacGetDigest))
import Data.ByteArray (ByteArrayAccess, convert)
import Data.ByteArray.Encoding (convertToBase, Base(Base16))
import Lib.Prelude import Lib.Prelude
hashSHA256 :: ByteString -> ByteString hashSHA256 :: ByteString -> ByteString
hashSHA256 = show . hashWith SHA256 hashSHA256 = convertToBase Base16 . hashWith SHA256
hmacSHA256 :: ByteString -> ByteString -> ByteString hmacSHA256 :: ByteString -> ByteString -> HMAC SHA256
hmacSHA256 message key = hmacSHA256 message key = hmac key message
show (hmacGetDigest (hmac key message) :: Digest SHA256)
hmacSHA256RawBS :: ByteString -> ByteString -> ByteString
hmacSHA256RawBS message key = convert $ hmacSHA256 message key
digestToBS :: ByteArrayAccess a => a -> ByteString
digestToBS = convert
digestToBase16 :: ByteArrayAccess a => a -> ByteString
digestToBase16 = convertToBase Base16

View File

@ -4,6 +4,7 @@ module Network.Minio.Data.Time
, awsTimeFormatBS , awsTimeFormatBS
, awsDateFormat , awsDateFormat
, awsDateFormatBS , awsDateFormatBS
, awsParseTime
) where ) where
@ -23,3 +24,6 @@ awsDateFormat = Time.formatTime Time.defaultTimeLocale "%Y%m%d"
awsDateFormatBS :: UTCTime -> ByteString awsDateFormatBS :: UTCTime -> ByteString
awsDateFormatBS = pack . awsDateFormat awsDateFormatBS = pack . awsDateFormat
awsParseTime :: [Char] -> Maybe UTCTime
awsParseTime = Time.parseTimeM False Time.defaultTimeLocale "%Y%m%dT%H%M%SZ"

View File

@ -1,9 +1,15 @@
module Network.Minio.Sign.V4 module Network.Minio.Sign.V4
( (
signV4 signV4
, signV4AtTime
, getScope
, getHeadersToSign
, getCanonicalRequest
, SignV4Data(..)
) where ) where
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import Data.ByteString.Char8 (pack) import Data.ByteString.Char8 (pack)
import Data.CaseInsensitive (mk) import Data.CaseInsensitive (mk)
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
@ -25,6 +31,35 @@ ignoredHeaders = Set.fromList $ map CI.foldedCase [
mk "User-Agent" mk "User-Agent"
] ]
data SignV4Data = SignV4Data {
sv4SignTime :: UTCTime
, sv4Scope :: ByteString
, sv4CanonicalRequest :: ByteString
, sv4HeadersToSign :: [(ByteString, ByteString)]
, sv4InputHeaders :: [Header]
, sv4OutputHeaders :: [Header]
, sv4StringToSign :: ByteString
, sv4SigningKey :: ByteString
} deriving (Show)
debugPrintSignV4Data :: SignV4Data -> IO ()
debugPrintSignV4Data (SignV4Data t s cr h2s ih oh sts sk) = do
B8.putStrLn "SignV4Data:"
B8.putStr "Timestamp: " >> print t
B8.putStr "Scope: " >> B8.putStrLn s
B8.putStrLn "Canonical Request:"
B8.putStrLn cr
B8.putStr "Headers to Sign: " >> print h2s
B8.putStr "Input headers: " >> print ih
B8.putStr "Output headers: " >> print oh
B8.putStr "StringToSign: " >> B8.putStrLn sts
B8.putStr "SigningKey: " >> printBytes sk
B8.putStrLn "END of SignV4Data ========="
where
printBytes b = do
mapM_ (\x -> B.putStr $ B.concat [show x, " "]) $ B.unpack b
B8.putStrLn ""
-- | Given MinioClient and request details, including request method, -- | Given MinioClient and request details, including request method,
-- request path, headers, query params and payload hash, generates an -- request path, headers, query params and payload hash, generates an
-- updated set of headers, including the x-amz-date header and the -- updated set of headers, including the x-amz-date header and the
@ -33,17 +68,22 @@ signV4 :: MinioClient -> RequestInfo
-> IO [Header] -> IO [Header]
signV4 mc ri = do signV4 mc ri = do
timestamp <- Time.getCurrentTime timestamp <- Time.getCurrentTime
return $ signV4AtTime timestamp mc ri let signData = signV4AtTime timestamp mc ri
debugPrintSignV4Data signData
return $ sv4OutputHeaders signData
-- | Takes a timestamp, server params and request params and generates -- | Takes a timestamp, server params and request params and generates
-- an updated list of headers. -- an updated list of headers.
signV4AtTime :: UTCTime -> MinioClient -> RequestInfo -> [Header] signV4AtTime :: UTCTime -> MinioClient -> RequestInfo -> SignV4Data
signV4AtTime ts mc ri = authHeader : headersWithDate signV4AtTime ts mc ri =
SignV4Data ts scope canonicalRequest headersToSign (headers ri) outHeaders stringToSign signingKey
where where
outHeaders = authHeader : headersWithDate
timeBS = awsTimeFormatBS ts timeBS = awsTimeFormatBS ts
dateHeader = (mk "X-Amz-Date", timeBS) dateHeader = (mk "X-Amz-Date", timeBS)
hostHeader = (mk "host", encodeUtf8 $ mcEndPointHost mc)
headersWithDate = dateHeader : (headers ri) headersWithDate = dateHeader : hostHeader : (headers ri)
authHeader = (mk "Authorization", authHeaderValue) authHeader = (mk "Authorization", authHeaderValue)
@ -51,7 +91,7 @@ signV4AtTime ts mc ri = authHeader : headersWithDate
authHeaderValue = B.concat [ authHeaderValue = B.concat [
"AWS4-HMAC-SHA256 Credential=", "AWS4-HMAC-SHA256 Credential=",
scope, encodeUtf8 (mcAccessKey mc), "/", scope,
", SignedHeaders=", signedHeaders, ", SignedHeaders=", signedHeaders,
", Signature=", signature ", Signature=", signature
] ]
@ -60,12 +100,12 @@ signV4AtTime ts mc ri = authHeader : headersWithDate
signedHeaders = B.intercalate ";" $ map fst headersToSign signedHeaders = B.intercalate ";" $ map fst headersToSign
signature = hmacSHA256 stringToSign signingKey signature = digestToBase16 $ hmacSHA256 stringToSign signingKey
signingKey = hmacSHA256 "aws4_request" signingKey = hmacSHA256RawBS "aws4_request"
. hmacSHA256 "s3" . hmacSHA256RawBS "s3"
. hmacSHA256 (encodeUtf8 $ mcRegion mc) . hmacSHA256RawBS (encodeUtf8 $ mcRegion mc)
. hmacSHA256 timeBS . hmacSHA256RawBS (awsDateFormatBS ts)
$ (B.concat ["AWS4", encodeUtf8 $ mcSecretKey mc]) $ (B.concat ["AWS4", encodeUtf8 $ mcSecretKey mc])
stringToSign = B.intercalate "\n" $ stringToSign = B.intercalate "\n" $
@ -80,7 +120,6 @@ signV4AtTime ts mc ri = authHeader : headersWithDate
getScope :: UTCTime -> MinioClient -> ByteString getScope :: UTCTime -> MinioClient -> ByteString
getScope ts mc = B.intercalate "/" $ [ getScope ts mc = B.intercalate "/" $ [
encodeUtf8 (mcAccessKey mc),
pack $ Time.formatTime Time.defaultTimeLocale "%Y%m%d" ts, pack $ Time.formatTime Time.defaultTimeLocale "%Y%m%d" ts,
"us-east-1", "s3", "aws4_request" "us-east-1", "s3", "aws4_request"
] ]
@ -99,15 +138,10 @@ getCanonicalRequest ri headersForSign = B.intercalate "\n" $ [
canonicalQueryString, canonicalQueryString,
canonicalHeaders, canonicalHeaders,
signedHeaders, signedHeaders,
payloadHash ri, payloadHash ri
""
] ]
where where
path = B.concat $ path = getPathFromRI ri
maybe [] (\bkt -> bkt : (
maybe [] (\obj ->
["/", encodeUtf8 $ obj]) $ object ri)) $
bucket ri
canonicalQueryString = B.intercalate "&" $ canonicalQueryString = B.intercalate "&" $
map (\(x, y) -> B.concat [x, "=", y]) $ map (\(x, y) -> B.concat [x, "=", y]) $