Как получить доступ к Amazon AWS S3 с помощью GSOAP для C и C ++?
Шаг 1
Использовать инструмент gSOAP wsd2lh для конвертации AmazonS3 WSDL в файл заголовка интерфейса aws-s3.h :
wsdl2h -t typemap.dat -o aws-s3.h http://doc.s3.amazonaws.com/2006-03-01/AmazonS3.wsdl
Используйте параметр -c
для создания исходного кода C вместо исходного C ++ по умолчаниюкод.Файл typemap.dat
находится в каталоге gsoap дистрибутива gSOAP.
Шаг 2
Используйте инструмент soapcpp2 для файла заголовка, созданного из инструмента wsdl2h.
soapcpp2 -C -j aws-s3.h
Thisгенерирует код на стороне клиента (опция -C
) с прокси-серверами и объектами службы C ++ (опция -j
) из заголовка aws-s3.h.Пропустите -j
для кода C.
Шаг 3
Используйте автоматически сгенерированные прокси-методы AmazonS3SoapBindingProxy
для доступа к AWS S3 и создания HMAC в кодировке base64-SHA1 хэшированная подпись для AWS S3.Сигнатура представляет собой строку с версией хешированной строки HMAC-SHA1 в кодировке base64 "AmazonS3" + OPERATION_NAME + Timestamp
:
/*
createbucket.cpp
Example AWS S3 CreateBucket service invocation
*/
#include "soapAmazonS3SoapBindingProxy.h"
#include "AmazonS3SoapBinding.nsmap"
#include <fstream>
// Make allocation of primitive values quick and easy:
template<class T>
T * soap_make(struct soap *soap, T val) {
T *p = (T*)soap_malloc(soap, sizeof(T));
*p = val;
return p;
}
// Make base64-encoded, HMAC-SHA1 hashed signature for AWS S3
std::string soap_make_s3__signature(struct soap *soap, char const *operation, char const *key) {
std::string signature = "AmazonS3";
signature += operation;
char UTCstamp[40]; //to hold ISO 8601 time format
time_t now;
time(&now);
strftime(UTCstamp, sizeof UTCstamp, "%Y-%m-%dT%H:%M:%S.000Z", gmtime(&now));
signature += UTCstamp;
// Get the HMAC-SHA1 digest of the signature string
unsigned char * digest;
digest = HMAC(EVP_sha1(), key, strlen(key),
(unsigned char*)(signature.c_str()),
signature.length(), NULL, NULL);
char signatureBase64[20];
// Convert the digest to base64
soap_s2base64(soap, digest, signatureBase64, sizeof signatureBase64);
return std::string(signatureBase64);
}
// Read access keys from file generated by AWS CLI
bool getAWSKeys(std::string path, std::string user, std::string &accessKey, std::string &secretKey) {
std::ifstream credentialsFile(path.c_str());
if (!credentialsFile.is_open())
return false;
std::string line;
while (std::getline(credentialsFile, line)) {
// Keep going until we get to the desired user
if (line.find(user) == std::string::npos)
continue;
while (std::getline(credentialsFile, line)) {
// Keep going until we get to the access key lines
if (line.find("aws_access_key_id") == std::string::npos)
continue;
// Grab keys and trim whitespace
size_t first, last;
accessKey = line.substr(line.find_first_of('=')+1);
first = accessKey.find_first_not_of(' ');
if (first == std::string::npos)
return false;
last = accessKey.find_last_not_of(' ');
accessKey.substr(first, last-first+1).swap(accessKey);
std::getline(credentialsFile, line);
secretKey = line.substr(line.find_first_of('=')+1);
first = secretKey.find_first_not_of(' ');
if (first == std::string::npos)
return false;
last = secretKey.find_last_not_of(' ');
secretKey.substr(first, last-first+1).swap(secretKey);
return true;
}
}
return false;
}
int main(int argc, char **argv) {
// Load AWS keys from file
std::string accessKey, secretKey;
// Use the path to your AWS credentials file
std::string credentialsFile = (argc > 2 ? argv[2] : "path_to_aws_credentials_file");
std::string user = "default";
if (!getAWSKeys(credentialsFile, user, accessKey, secretKey)) {
std::cout << "Couldn't read AWS keys for user " << user
<< " from file " << credentialsFile << '\n';
return 0;
}
// Create a proxy to invoke AWS S3 services
AmazonS3SoapBindingProxy aws(SOAP_XML_INDENT);
// Create bucket
// Set the arguments of the CreateBucket service operation
_s3__CreateBucket createBucketReq;
std::string bucketName = (argc > 1 ? argv[1] : "BucketName");
createBucketReq.Bucket = bucketName;
createBucketReq.AWSAccessKeyId = soap_new_std__string(aws.soap);
*createBucketReq.AWSAccessKeyId = accessKey;
createBucketReq.Timestamp = soap_make(aws.soap, time(0));
createBucketReq.Signature = soap_new_std__string(aws.soap);
*createBucketReq.Signature = soap_make_s3__signature(aws.soap,
"CreateBucket",
secretKey.c_str());
// Store the result of the service
_s3__CreateBucketResponse createBucketRes;
// Create a bucket
if (aws.CreateBucket(&createBucketReq, createBucketRes)) {
aws.soap_stream_fault(std::cerr);
}
/*
NOTE: you must add the line:
_s3__CreateBucketResponse = $ s3__CreateBucketResult* CreateBucketResponse;
to the typemap.dat file because Amazon's response doesn't match
their promised schema. This adds the variable CreateBucketResponse
to the _s3__CreateBucketResponse class so we can access the response.
*/
else if (createBucketRes.CreateBucketResponse) {
s3__CreateBucketResult &result = *createBucketRes.CreateBucketResponse;
std::cout << "You are the owner of bucket '" << result.BucketName << "'." << std::endl;
}
// Delete all managed data
aws.destroy();
return 0;
}
Код C выглядит аналогично, основное отличие заключается в использовании вызовов функций вместо методоввызовы, то есть soap_call___s3__CreateBucket(&createBucketReq, &createBucketRes)
.Все это объясняется в сгенерированном файле aws-s4.h .
Скомпилируйте сгенерированные файлы с вашим исходным кодом:
c++ -DSOAP_MAXDIMESIZE=104857600 -DWITH_OPENSSL -o createbucket createbucket.cpp soapAmazonS3SoapBindingProxy.cpp soapC.cpp stdsoap2.cpp -lssl -lcrypto
SOAP_MAXDIMESIZE=104857600
гарантирует, чтоРазмеры вложений DIME могут быть достаточно большими, в то же время предотвращая атаки типа «отказ в обслуживании» с использованием DIME.Заголовок DIME имеет размер вложения, поэтому злоумышленник может установить этот произвольно большой размер для исчерпания ресурсов памяти.Другие посты не упоминали об этом.
Выполните createbucket
, и будет создано новое ведро.
В последнем файле .cpp обратите внимание, что мы проверяем аргументы командной строки (argv)при настройке credentialsFile и bucketName.Это позволяет программе вызываться с аргументами:
./createbucket BucketName path_to_credentials_file
Для более подробной информации обо всем этом, я предлагаю прочитать отличную статью CodeProject по Как использовать AWS S3 в C ++ с gSOAP Крисом Мутсосом, из которого происходят части этого объяснения.