admin管理员组文章数量:1122833
This is the final working token generator:
std::string crypto_GenerateSasToken(
const std::string& permissions,
const std::string& blobName,
const std::string& accessKey,
const std::string& containerName,
const std::string& accountName)
{
// Define SAS token parameters
auto currentTime = std::chrono::system_clock::now();
auto currentTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(currentTime.time_since_epoch());
auto expirationTime = currentTimeSeconds + std::chrono::minutes(120);
// Convert time to ISO 8601 format
std::string signedStart = TimePointToString(currentTimeSeconds);
std::string signedExpiry = TimePointToString(expirationTime);
// Define other SAS parameters
std::string signedPermissions = permissions;
std::string signedService = (blobName.empty()) ? "c" : "b"; // 'c' for container, 'b' for blob
std::string signedProtocol = "https";
std::string signedVersion = "2022-11-02";
std::string signedResourceType = ""; // Specifies the resource type (s, c, o for service, container, or object).
// Create canonicalized resource
std::string canonicalizedResource;
if (blobName.empty()) {
// Use container-level resource if blobName is empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName;
} else {
// Use blob-level resource if blobName is not empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName + "/" + blobName;
}
// Construct the string to sign
std::ostringstream stringToSign;
stringToSign << signedPermissions << "\n"
<< signedStart << "\n"
<< signedExpiry << "\n"
<< canonicalizedResource << "\n"
<< "\n" // signedIdentifier (empty)
<< "\n" // signedIP (empty)
<< signedProtocol << "\n"
<< signedVersion << "\n"
<< signedService << "\n"
<< signedResourceType << "\n" // signedResourceType (if not used, empty)
<< "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n";
// std::cout << "String to sign: '" << stringToSign.str() << "'" << std::endl;
// Generate the signature
std::string signature = GenerateSas(accessKey, stringToSign.str());
// URL encode the signature
std::string urlEncodedSignature = UrlEncode(signature);
// Construct the SAS token
std::ostringstream sasToken;
sasToken
<< "sp=" << signedPermissions
<< "&st=" << signedStart
<< "&se=" << signedExpiry
<< "&spr=" << signedProtocol
<< "&sv=" << signedVersion
<< "&sr=" << signedService
<< "&sig=" << urlEncodedSignature;
// std::cout << "Blob Service URL: https://" << accountName << ".blob.core.windows/"
// << containerName << "/" << blobName << "?" << sasToken.str() << std::endl;
return sasToken.str();
}
I am creating a new rather or follow-up question: "Unable to generate a valid Azure Storage SAS token in Cpp".
I have used the method shown by [Venkatesan]. I'm sure I had a working version at some point, but no more.
<Error>
AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:b56dca11-101e-0036-08f4-3c47cd000000 Time:2024-11-22T15:41:17.0196662Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rwl 2024-11-22T15:38:31Z 2024-11-22T17:38:31Z /blob/fotacontainer/fota/testfile.txt https 2022-11-02 b
</AuthenticationErrorDetail>
</Error>
The resulting URL is:
.txt?sv=2022-11-02&sr=b&sp=rwl&st=2024-11-22T15:38:31Z&se=2024-11-22T17:38:31Z&spr=https&sig=EMswjhCIzPCd8OBU48OV2suiJI4HNKl94rB5ctyaGGA%3d
Updated code:
std::string GenerateSas(const std::string& storageAccountKey, const std::string& input) {
std::string decodedKey;
StringSource(storageAccountKey, true, new Base64Decoder(new StringSink(decodedKey)));
// Create HMAC-SHA256 signature
std::string digest;
CryptoPP::HMAC<CryptoPP::SHA256> hmac((const byte*)decodedKey.data(), decodedKey.size());
StringSource(input, true,
new HashFilter(hmac, new StringSink(digest))); // Compute HMAC digest
// Encode the digest to Base64
std::string encodedDigest;
StringSource(digest, true, new Base64Encoder(new StringSink(encodedDigest), false));
encodedDigest.erase(std::remove(encodedDigest.begin(), encodedDigest.end(), '\n'), encodedDigest.end());
return encodedDigest;
}
std::string TimePointToString(const std::chrono::seconds& timePoint) {
std::time_t t = timePoint.count();
std::tm tm{};
gmtime_r(&t, &tm);
std::ostringstream oss;
oss << std::put_time(&tm, "%Y-%m-%dT%H:%M:%SZ");
return oss.str();
}
std::string crypto_GenerateSasToken(
const std::string& permissions,
const std::string& blobName,
const std::string& accessKey,
const std::string& containerName,
const std::string& accountName)
{
// Define SAS token parameters
auto currentTime = std::chrono::system_clock::now();
auto currentTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(currentTime.time_since_epoch());
auto expirationTime = currentTimeSeconds + std::chrono::minutes(120);
// Convert time to ISO 8601 format
std::string signedStart = TimePointToString(currentTimeSeconds);
std::string signedExpiry = TimePointToString(expirationTime);
// Define other SAS parameters
std::string signedPermissions = permissions; //"racwdxl";
std::string signedService = "b"; //(blobName.empty()) ? "c" : "b"; // 'c' for container, 'b' for blob
std::string signedProtocol = "https";
std::string signedVersion = "2022-11-02";
// Create canonicalized resource
std::string canonicalizedResource;
if (blobName.empty()) {
// Use container-level resource if blobName is empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName;
} else {
// Use blob-level resource if blobName is not empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName + "/" + blobName;
}
// Construct the string to sign
std::ostringstream stringToSign;
stringToSign << signedPermissions << "\n"
<< signedStart << "\n"
<< signedExpiry << "\n"
<< canonicalizedResource << "\n"
<< "\n"
<< "\n"
<< signedProtocol << "\n"
<< signedVersion << "\n"
<< signedService << "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n" ;
// Generate the signature
std::string signature = GenerateSas(accessKey, stringToSign.str());
// URL encode the signature
std::string urlEncodedSignature = UrlEncode(signature);
// Construct the SAS token
std::ostringstream sasToken;
sasToken
<< "sv=" << signedVersion
<< "&sr=" << signedService
<< "&sp=" << signedPermissions
<< "&st=" << signedStart
<< "&se=" << signedExpiry
<< "&spr=" << signedProtocol
<< "&sig=" << urlEncodedSignature;
std::cout << "Blob URL: https://" << accountName << ".blob.core.windows/"
<< containerName << "/" << blobName << "?" << sasToken.str() << std::endl;
return sasToken.str();
}
// URL encode function
std::string UrlEncode(const std::string& str) {
std::ostringstream escaped;
for (char c : str) {
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
}
else {
escaped << '%' << std::setw(2) << std::setfill('0') << std::hex << (int)(unsigned char)c;
}
}
return escaped.str();
};
I would really appreciate a second look at this version! Should the "&s__=" field order match the string-to-sign?
This is the final working token generator:
std::string crypto_GenerateSasToken(
const std::string& permissions,
const std::string& blobName,
const std::string& accessKey,
const std::string& containerName,
const std::string& accountName)
{
// Define SAS token parameters
auto currentTime = std::chrono::system_clock::now();
auto currentTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(currentTime.time_since_epoch());
auto expirationTime = currentTimeSeconds + std::chrono::minutes(120);
// Convert time to ISO 8601 format
std::string signedStart = TimePointToString(currentTimeSeconds);
std::string signedExpiry = TimePointToString(expirationTime);
// Define other SAS parameters
std::string signedPermissions = permissions;
std::string signedService = (blobName.empty()) ? "c" : "b"; // 'c' for container, 'b' for blob
std::string signedProtocol = "https";
std::string signedVersion = "2022-11-02";
std::string signedResourceType = ""; // Specifies the resource type (s, c, o for service, container, or object).
// Create canonicalized resource
std::string canonicalizedResource;
if (blobName.empty()) {
// Use container-level resource if blobName is empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName;
} else {
// Use blob-level resource if blobName is not empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName + "/" + blobName;
}
// Construct the string to sign
std::ostringstream stringToSign;
stringToSign << signedPermissions << "\n"
<< signedStart << "\n"
<< signedExpiry << "\n"
<< canonicalizedResource << "\n"
<< "\n" // signedIdentifier (empty)
<< "\n" // signedIP (empty)
<< signedProtocol << "\n"
<< signedVersion << "\n"
<< signedService << "\n"
<< signedResourceType << "\n" // signedResourceType (if not used, empty)
<< "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n";
// std::cout << "String to sign: '" << stringToSign.str() << "'" << std::endl;
// Generate the signature
std::string signature = GenerateSas(accessKey, stringToSign.str());
// URL encode the signature
std::string urlEncodedSignature = UrlEncode(signature);
// Construct the SAS token
std::ostringstream sasToken;
sasToken
<< "sp=" << signedPermissions
<< "&st=" << signedStart
<< "&se=" << signedExpiry
<< "&spr=" << signedProtocol
<< "&sv=" << signedVersion
<< "&sr=" << signedService
<< "&sig=" << urlEncodedSignature;
// std::cout << "Blob Service URL: https://" << accountName << ".blob.core.windows.net/"
// << containerName << "/" << blobName << "?" << sasToken.str() << std::endl;
return sasToken.str();
}
I am creating a new rather or follow-up question: "Unable to generate a valid Azure Storage SAS token in Cpp".
I have used the method shown by [Venkatesan]. I'm sure I had a working version at some point, but no more.
<Error>
AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:b56dca11-101e-0036-08f4-3c47cd000000 Time:2024-11-22T15:41:17.0196662Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rwl 2024-11-22T15:38:31Z 2024-11-22T17:38:31Z /blob/fotacontainer/fota/testfile.txt https 2022-11-02 b
</AuthenticationErrorDetail>
</Error>
The resulting URL is:
https://fotacontainer.blob.core.windows.net/fota/testfile.txt?sv=2022-11-02&sr=b&sp=rwl&st=2024-11-22T15:38:31Z&se=2024-11-22T17:38:31Z&spr=https&sig=EMswjhCIzPCd8OBU48OV2suiJI4HNKl94rB5ctyaGGA%3d
Updated code:
std::string GenerateSas(const std::string& storageAccountKey, const std::string& input) {
std::string decodedKey;
StringSource(storageAccountKey, true, new Base64Decoder(new StringSink(decodedKey)));
// Create HMAC-SHA256 signature
std::string digest;
CryptoPP::HMAC<CryptoPP::SHA256> hmac((const byte*)decodedKey.data(), decodedKey.size());
StringSource(input, true,
new HashFilter(hmac, new StringSink(digest))); // Compute HMAC digest
// Encode the digest to Base64
std::string encodedDigest;
StringSource(digest, true, new Base64Encoder(new StringSink(encodedDigest), false));
encodedDigest.erase(std::remove(encodedDigest.begin(), encodedDigest.end(), '\n'), encodedDigest.end());
return encodedDigest;
}
std::string TimePointToString(const std::chrono::seconds& timePoint) {
std::time_t t = timePoint.count();
std::tm tm{};
gmtime_r(&t, &tm);
std::ostringstream oss;
oss << std::put_time(&tm, "%Y-%m-%dT%H:%M:%SZ");
return oss.str();
}
std::string crypto_GenerateSasToken(
const std::string& permissions,
const std::string& blobName,
const std::string& accessKey,
const std::string& containerName,
const std::string& accountName)
{
// Define SAS token parameters
auto currentTime = std::chrono::system_clock::now();
auto currentTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(currentTime.time_since_epoch());
auto expirationTime = currentTimeSeconds + std::chrono::minutes(120);
// Convert time to ISO 8601 format
std::string signedStart = TimePointToString(currentTimeSeconds);
std::string signedExpiry = TimePointToString(expirationTime);
// Define other SAS parameters
std::string signedPermissions = permissions; //"racwdxl";
std::string signedService = "b"; //(blobName.empty()) ? "c" : "b"; // 'c' for container, 'b' for blob
std::string signedProtocol = "https";
std::string signedVersion = "2022-11-02";
// Create canonicalized resource
std::string canonicalizedResource;
if (blobName.empty()) {
// Use container-level resource if blobName is empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName;
} else {
// Use blob-level resource if blobName is not empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName + "/" + blobName;
}
// Construct the string to sign
std::ostringstream stringToSign;
stringToSign << signedPermissions << "\n"
<< signedStart << "\n"
<< signedExpiry << "\n"
<< canonicalizedResource << "\n"
<< "\n"
<< "\n"
<< signedProtocol << "\n"
<< signedVersion << "\n"
<< signedService << "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n" ;
// Generate the signature
std::string signature = GenerateSas(accessKey, stringToSign.str());
// URL encode the signature
std::string urlEncodedSignature = UrlEncode(signature);
// Construct the SAS token
std::ostringstream sasToken;
sasToken
<< "sv=" << signedVersion
<< "&sr=" << signedService
<< "&sp=" << signedPermissions
<< "&st=" << signedStart
<< "&se=" << signedExpiry
<< "&spr=" << signedProtocol
<< "&sig=" << urlEncodedSignature;
std::cout << "Blob URL: https://" << accountName << ".blob.core.windows.net/"
<< containerName << "/" << blobName << "?" << sasToken.str() << std::endl;
return sasToken.str();
}
// URL encode function
std::string UrlEncode(const std::string& str) {
std::ostringstream escaped;
for (char c : str) {
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
}
else {
escaped << '%' << std::setw(2) << std::setfill('0') << std::hex << (int)(unsigned char)c;
}
}
return escaped.str();
};
I would really appreciate a second look at this version! Should the "&s__=" field order match the string-to-sign?
Share Improve this question edited Nov 23, 2024 at 23:57 Tom 51.5k2 gold badges18 silver badges34 bronze badges asked Nov 22, 2024 at 16:07 Stefan GudmundssonStefan Gudmundsson 32 bronze badges 3- 1 Question: should the order of the "&s__=" tokens not match the order of the same items as in string-to-sign? – Stefan Gudmundsson Commented Nov 22, 2024 at 16:47
- Finally found the correct token format! – Stefan Gudmundsson Commented Nov 22, 2024 at 20:56
- It's great to hear that you were able to resolve your issue. Could you please document your solution in an answer? It would provide clarity for those encountering similar technical challenges within the community – Venkatesan Commented Nov 23, 2024 at 5:44
1 Answer
Reset to default 0Here is my solution:
std::string crypto_GenerateSasToken(
const std::string& permissions,
const std::string& blobName,
const std::string& accessKey,
const std::string& containerName,
const std::string& accountName)
{
// Define SAS token parameters
auto currentTime = std::chrono::system_clock::now();
auto currentTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(currentTime.time_since_epoch());
auto expirationTime = currentTimeSeconds + std::chrono::minutes(120);
// Convert time to ISO 8601 format
std::string signedStart = TimePointToString(currentTimeSeconds);
std::string signedExpiry = TimePointToString(expirationTime);
// Define other SAS parameters
std::string signedPermissions = permissions;
std::string signedService = (blobName.empty()) ? "c" : "b"; // 'c' for container, 'b' for blob
std::string signedProtocol = "https";
std::string signedVersion = "2022-11-02";
std::string signedResourceType = ""; // Specifies the resource type (s, c, o for service, container, or object).
// Create canonicalized resource
std::string canonicalizedResource;
if (blobName.empty()) {
// Use container-level resource if blobName is empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName;
} else {
// Use blob-level resource if blobName is not empty
canonicalizedResource = "/blob/" + accountName + "/" + containerName + "/" + blobName;
}
// Construct the string to sign
std::ostringstream stringToSign;
stringToSign << signedPermissions << "\n"
<< signedStart << "\n"
<< signedExpiry << "\n"
<< canonicalizedResource << "\n"
<< "\n" // signedIdentifier (empty)
<< "\n" // signedIP (empty)
<< signedProtocol << "\n"
<< signedVersion << "\n"
<< signedService << "\n"
<< signedResourceType << "\n" // signedResourceType (if not used, empty)
<< "\n"
<< "\n"
<< "\n"
<< "\n"
<< "\n";
// Generate the signature
std::string signature = GenerateSas(accessKey, stringToSign.str());
// URL encode the signature
std::string urlEncodedSignature = UrlEncode(signature);
// Construct the SAS token
std::ostringstream sasToken;
sasToken
<< "sp=" << signedPermissions
<< "&st=" << signedStart
<< "&se=" << signedExpiry
<< "&spr=" << signedProtocol
<< "&sv=" << signedVersion
<< "&sr=" << signedService
<< "&sig=" << urlEncodedSignature;
return sasToken.str();
}
本文标签: cUnable to generate a valid Azure Storage SAS token in CppUpdated codeStack Overflow
版权声明:本文标题:c++ - Unable to generate a valid Azure Storage SAS token in Cpp - Updated code - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736302423a1931528.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论