I have searched everywhere for this and I could not find a single decent code. How can I access Amazon AWS S3 service using GSOAP?
The code below is from the OP. Originally, the post contained both the question and the answer and I am turning it into a Q&A format.
The signature has to be of the format
base64encode((HMAC-SHA1(ActionName+"AmazonS3"+XMLTimestamp)))
The HMAC, SHA1and B64 utils are available in openssl.
The format for SOAP requests is given by the wsdl.
The REST interface is different.
After wsdl2h
to generate the header and soapcpp2 to generate the GSOAP
client code the following will be the code to access the service:
Requirements : OpenSSL, GSOAP.
Build with the compiler preprocessor directive WITH_OPENSSL
. Link with
libraries libeay32
and ssleay32
.
#include "AmazonS3SoapBinding.nsmap" //generated from soapcpp2
#include "soapAmazonS3SoapBindingProxy.h" //generated from soapcpp2
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
/* convert to base64 */
std::string base64_encodestring(char* text, int len) {
EVP_ENCODE_CTX ectx;
int size = len*2;
size = size > 64 ? size : 64;
unsigned char* out = (unsigned char*)malloc( size );
int outlen = 0;
int tlen = 0;
EVP_EncodeInit(&ectx);
EVP_EncodeUpdate(&ectx,
out,
&outlen,
(const unsigned char*)text,
len
);
tlen += outlen;
EVP_EncodeFinal( &ectx, out+tlen, &outlen );
tlen += outlen;
std::string str((char*)out, tlen );
free( out );
return str;
}
/* return the utc date+time in xml format */
const char* xml_datetime() {
/*"YYYY-mm-ddTHH:MM:SS.000Z\"*/
const int MAX=25;
static char output[MAX+1];
time_t now = time(NULL);
strftime( output, MAX+1, "%Y-%m-%dT%H:%M:%S.000Z", gmtime( &now ) );
std::cout <<output<<std::endl;
return output;
}
/* first argument is the signing key */
/* all subsequent argumets are concatenated */
/* must end list with NULL */
char* aws_signature(char* key, ...) {
unsigned int i, len;
char *data, **list = &key;
static char hmac[EVP_MAX_MD_SIZE];
for (i = 1, len = 0; *(list+i) != NULL; ++i) {
len += strlen( *(list+i) );
}
data = (char*)malloc(sizeof(char) * (len+1));
if (data) {
for ( i = 1, len = 0 ; *(list+i) != NULL ; ++i ) {
strncpy( data+len, *(list+i), strlen(*(list+i)) );
len += strlen(*(list+i));
}
data[len]='\0';
std::cout<<data<<std::endl;
HMAC( EVP_sha1(),
key, strlen(key),
(unsigned char*)data, strlen(data),
(unsigned char*) hmac, &len
);
free(data);
}
std::string b64data=base64_encodestring(hmac, len);
strcpy(hmac,b64data.c_str());
return hmac;
};
int main(void) {
AmazonS3SoapBindingProxy client;
soap_ssl_client_context(&client,
/* for encryption w/o authentication */
SOAP_SSL_NO_AUTHENTICATION,
/* SOAP_SSL_DEFAULT | SOAP_SSL_SKIP_HOST_CHECK, */
/* if we don't want the host name checks since
* these will change from machine to machine */
/*SOAP_SSL_DEFAULT,*/
/* use SOAP_SSL_DEFAULT in production code */
NULL, /* keyfile (cert+key): required only when
client must authenticate to server
(see SSL docs to create this file) */
NULL, /* password to read the keyfile */
NULL, /* optional cacert file to store trusted
certificates, use cacerts.pem for all
public certificates issued by common CAs */
NULL, /* optional capath to directory with trusted
certificates */
NULL /* if randfile!=NULL: use a file with random
data to seed randomness */
);
/* use this if you are behind a proxy server.....
client.proxy_host="proxyserver"; // proxy hostname
client.proxy_port=4250;
client.proxy_userid="username"; // user pass if proxy
client.proxy_passwd="password"; // requires authentication
client.proxy_http_version="1.1"; // http version
*/
_ns1__ListAllMyBuckets buk_req;
_ns1__ListAllMyBucketsResponse buk_resp;
ns1__ListAllMyBucketsResult buk_res;
buk_res.soap=&client;
buk_req.AWSAccessKeyId=new std::string("ACCESSKEY");
buk_req.soap=&client;
/* ListAllMyBuckets is the method I want to call here.
* change it for other S3 services that you wish to call.*/
char *sig=aws_signature(
"SECRETKEY",
"AmazonS3",
"ListAllMyBuckets",
xml_datetime(),
NULL
);
buk_req.Signature=new std::string(sig);
buk_req.Timestamp=new time_t(time(NULL));
buk_resp.soap=&client;
buk_resp.ListAllMyBucketsResponse=&buk_res;
client.ListAllMyBuckets(&buk_req,&buk_resp);
client.soap_stream_fault(std::cout);
std::vector<ns1__ListAllMyBucketsEntry * >::iterator itr;
for(itr=buk_resp.ListAllMyBucketsResponse->Buckets->Bucket.begin();
itr!=buk_resp.ListAllMyBucketsResponse->Buckets->Bucket.end();
itr++
) {
std::cout<<(*itr)->Name<<std::endl;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With