in src/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp [352:460]
bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const Aws::Auth::AWSCredentials& credentials, const char* region, const char* serviceName, long long expirationTimeInSeconds ) const
{
Aws::String signingRegion = region ? region : m_region;
Aws::String signingServiceName = serviceName ? serviceName : m_serviceName;
//don't sign anonymous requests
if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty())
{
return true;
}
if (m_signingAlgorithm == AWSSigningAlgorithm::ASYMMETRIC_SIGV4)
{
return SignRequestWithSigV4a(request, signingRegion.c_str(), signingServiceName.c_str(), false /* signBody doesn't matter for HttpRequestViaHeaders */,
expirationTimeInSeconds, Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams);
}
Aws::StringStream intConversionStream;
intConversionStream << expirationTimeInSeconds;
request.AddQueryStringParameter(Http::X_AMZ_EXPIRES_HEADER, intConversionStream.str());
if (!credentials.GetSessionToken().empty())
{
request.AddQueryStringParameter(Http::AWS_SECURITY_TOKEN, credentials.GetSessionToken());
}
//calculate date header to use in internal signature (this also goes into date header).
DateTime now = GetSigningTimestamp();
Aws::String dateQueryValue = now.ToGmtString(DateFormat::ISO_8601_BASIC);
request.AddQueryStringParameter(Http::AWS_DATE_HEADER, dateQueryValue);
Aws::StringStream headersStream;
Aws::StringStream signedHeadersStream;
for (const auto& header : Aws::Auth::AWSAuthHelper::CanonicalizeHeaders(request.GetHeaders()))
{
if(ShouldSignHeader(header.first))
{
headersStream << header.first.c_str() << ":" << header.second.c_str() << Aws::Auth::AWSAuthHelper::NEWLINE;
signedHeadersStream << header.first.c_str() << ";";
}
}
Aws::String canonicalHeadersString = headersStream.str();
AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString);
//calculate signed headers parameter
Aws::String signedHeadersValue(signedHeadersStream.str());
//remove that last semi-colon
if (!signedHeadersValue.empty())
{
signedHeadersValue.pop_back();
}
request.AddQueryStringParameter(X_AMZ_SIGNED_HEADERS, signedHeadersValue);
AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value: " << signedHeadersValue);
Aws::StringStream ss;
Aws::String simpleDate = now.ToGmtString(Aws::Auth::AWSAuthHelper::SIMPLE_DATE_FORMAT_STR);
ss << credentials.GetAWSAccessKeyId() << "/" << simpleDate
<< "/" << signingRegion << "/" << signingServiceName << "/" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST;
request.AddQueryStringParameter(X_AMZ_ALGORITHM, Aws::Auth::AWSAuthHelper::AWS_HMAC_SHA256);
request.AddQueryStringParameter(X_AMZ_CREDENTIAL, ss.str());
ss.str("");
request.SetSigningAccessKey(credentials.GetAWSAccessKeyId());
request.SetSigningRegion(signingRegion);
//generate generalized canonicalized request string.
Aws::String canonicalRequestString = Aws::Auth::AWSAuthHelper::CanonicalizeRequestSigningString(request, m_urlEscapePath);
//append v4 stuff to the canonical request string.
canonicalRequestString.append(canonicalHeadersString);
canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE);
canonicalRequestString.append(signedHeadersValue);
canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE);
if (ServiceRequireUnsignedPayload(signingServiceName))
{
canonicalRequestString.append(UNSIGNED_PAYLOAD);
}
else
{
canonicalRequestString.append(EMPTY_STRING_SHA256);
}
AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString);
//now compute sha256 on that request string
auto sha256Digest = HashingUtils::CalculateSHA256(canonicalRequestString);
if (sha256Digest.GetLength() == 0)
{
AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string");
AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\"");
return false;
}
auto canonicalRequestHash = HashingUtils::HexEncode(sha256Digest);
auto stringToSign = GenerateStringToSign(dateQueryValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName);
auto finalSigningHash = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName);
if (finalSigningHash.empty())
{
return false;
}
//add that the signature to the query string
request.AddQueryStringParameter(X_AMZ_SIGNATURE, finalSigningHash);
return true;
}