Open schnecki opened 5 years ago
This is also a problem for me, and I do not know how to fix it either.
I've had several users report S3 compatible services that seem to not work with V2 authorization and so I tried switching my program to use V4. GetObject from aws with V4 works for me. I wonder what I'm doing differently?
I tried both path-style and request-style, to us-eastern.
i got same problem
some body help?
this work
`s3SignQuery S3Query{..} S3Configuration{ s3SignVersion = S3SignV4 signpayload,s3UseUri = True, .. } sd@SignatureData{..} = SignedQuery { sqMethod = s3QMethod , sqProtocol = s3Protocol , sqHost = B.intercalate "." $ catMaybes host , sqPort = s3Port , sqPath = mconcat $ catMaybes path , sqQuery = queryString ++ signatureQuery :: HTTP.Query , sqDate = Just signatureTime , sqAuthorization = authorization , sqContentType = s3QContentType , sqContentMd5 = s3QContentMd5 , sqAmzHeaders = Map.toList amzHeaders , sqOtherHeaders = s3QOtherHeaders , sqBody = s3QRequestBody , sqStringToSign = stringToSign } where -- V4 signing -- http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html -- http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html -- * http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
iamTok = maybe [] (\x -> [(hAmzSecurityToken, x)]) $ iamToken signatureCredentials
amzHeaders = Map.fromList $ (hAmzDate, sigTime):(hAmzContentSha256, payloadHash):iamTok ++ s3QAmzHeaders
where
-- needs to match the one produces in the @authorizationV4@
sigTime = fmtTime "%Y%m%dT%H%M%SZ" $ signatureTime
payloadHash = case (signpayload, s3QRequestBody) of
(AlwaysUnsigned, _) -> "UNSIGNED-PAYLOAD"
(_, Nothing) -> emptyBodyHash
(_, Just (HTTP.RequestBodyLBS lbs)) -> Base16.encode $ ByteArray.convert (CH.hashlazy lbs :: CH.Digest CH.SHA256)
(_, Just (HTTP.RequestBodyBS bs)) -> Base16.encode $ ByteArray.convert (CH.hash bs :: CH.Digest CH.SHA256)
(SignWithEffort, _) -> "UNSIGNED-PAYLOAD"
(AlwaysSigned, _) -> error "aws: RequestBody must be a on-memory one when AlwaysSigned mode."
emptyBodyHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
(host, path) = case s3RequestStyle of
PathStyle -> ([Just s3Endpoint], [Just "/", fmap (`B8.snoc` '/') s3QBucket, urlEncodedS3QObject])
BucketStyle -> ([s3QBucket, Just s3Endpoint], [Just "/", urlEncodedS3QObject])
VHostStyle -> ([Just $ fromMaybe s3Endpoint s3QBucket], [Just "/", urlEncodedS3QObject])
where
urlEncodedS3QObject = s3UriEncode False <$> s3QObject
-- must provide host in the canonical headers.
-- Map.union amzHeaders .
canonicalHeaders = Map.fromList $ catMaybes
[ Just ("host", B.intercalate "." $ catMaybes host)
, ("content-type",) <$> s3QContentType
]
signedHeaders = "host";-- B8.intercalate ";" (map CI.foldedCase $ Map.keys canonicalHeaders)
stringToSign = B.intercalate "\n" $
[ httpMethod s3QMethod -- method
, mconcat . catMaybes $ path -- path
, s3RenderQuery False $ sort queryString -- query string
] ++
Map.foldMapWithKey (\a b -> [CI.foldedCase a Sem.<> ":" Sem.<> b]) canonicalHeaders ++
[ "" -- end headers
, signedHeaders
, amzHeaders Map.! hAmzContentSha256
]
(authorization, signatureQuery, queryString) = case ti of
AbsoluteTimestamp _ -> (Just auth, [], allQueries)
AbsoluteExpires time ->
( Nothing
, [(CI.original hAmzSignature, Just sig)]
, (allQueries ++) . HTTP.toQuery . map (first CI.original) $
[ (hAmzAlgorithm, "AWS4-HMAC-SHA256")
, (hAmzCredential, cred)
, (hAmzDate, amzHeaders Map.! hAmzDate)
, (hAmzContentSha256, amzHeaders Map.! hAmzContentSha256)
, (hAmzExpires, B8.pack . (show :: Integer -> String) . floor $ diffUTCTime time signatureTime)
, (hAmzSignedHeaders, signedHeaders)
] ++ iamTok
)
where
allQueries = s3QSubresources ++ s3QQuery
region = s3ExtractRegion s3Endpoint
auth = authorizationV4 sd HmacSHA256 region "s3" signedHeaders stringToSign
sig = signatureV4 sd HmacSHA256 region "s3" stringToSign
cred = credentialV4 sd region "s3"
ti = case ( signatureTimeInfo) of
( AbsoluteTimestamp time) -> AbsoluteExpires $ s3DefaultExpiry `addUTCTime` time
( AbsoluteExpires time) -> AbsoluteExpires time
`
The headers that are used to sign the
GetObject
do not work. See https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html and https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.htmlThe requests fails with (note the StringToSign section):
While the Debug mode gives:
Obviously this results in a missmatch and the reported
SignatureDoesNotMatch
error. I tried to build the headers myself, but couldn't get it to work, as I am not familiar with the library.My test code gets the first 3 parameters correctly (see function
stringToSign
), but I couldn't get the hash to work. Can someone help me here?