2011-08-10 13 views
11

Tôi đã tìm kiếm ở khắp mọi nơi cho điều này và tôi không thể tìm thấy một mã phong nha duy nhất. Tôi làm cách nào để truy cập dịch vụ Amazon AWS S3 bằng cách sử dụng GSOAP?Tôi có thể truy cập Amazon AWS S3 bằng cách sử dụng GSOAP cho C và C++ như thế nào?

+0

Tôi biết điều này không thực sự là một câu hỏi, nhưng tôi cũng đã tự hỏi về gsoap + aws để tạo một ứng dụng c/C++ amazon. Cảm ơn điều này, ngay cả khi nó bị khóa/downvoted/tos'd: \ –

+2

bạn có thể vui lòng định dạng này thành một cặp câu hỏi/trả lời thích hợp? Xem http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ –

+0

Có một bài viết về chủ đề này được đăng tại [CodeProject về gSOAP và AWS S3 ] (https://www.codeproject.com/Articles/1108296/How-to-Use-Amazon-Simple-Storage-Service-S-in-Cplu) chi tiết hơn. Một bản sao của bài viết đó cũng xuất hiện trên trang web của nhà phát triển gSOAP. Bạn không chắc chắn lý do tại sao người kiểm duyệt đã xóa câu trả lời của tôi bằng các con trỏ này. –

Trả lời

3

Mã bên dưới là từ OP. Ban đầu, bài đăng chứa cả câu hỏi và câu trả lời và tôi chuyển nó thành định dạng Q &.

Chữ ký phải được định dạng

base64encode((HMAC-SHA1(ActionName+"AmazonS3"+XMLTimestamp))) 

Các HMAC, SHA1and B64 utils có sẵn trong openssl.

Định dạng cho các yêu cầu SOAP được cung cấp bởi wsdl.

Giao diện REST khác.

Sau wsdl2h để tạo ra các tiêu đề và soapcpp2 để tạo mã khách hàng GSOAP sau đây sẽ là mã để truy cập dịch vụ:

Yêu cầu: OpenSSL, GSOAP.

Tạo bằng chỉ thị tiền xử lý biên dịch WITH_OPENSSL. Liên kết với thư viện libeay32ssleay32.

#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; 
    } 

} 
0

Làm thế nào tôi có thể truy cập vào Amazon AWS S3 sử dụng GSOAP cho C và C++?

Bước 1

cụ wsd2lh Sử dụng gSOAP để chuyển đổi WSDL S3 của Amazon vào một tập tin tiêu đề giao diện aws-s3.h:

wsdl2h -t typemap.dat -o aws-s3.h http://doc.s3.amazonaws.com/2006-03-01/AmazonS3.wsdl

Sử dụng tùy chọn -c để tạo ra mã nguồn C thay vì mã nguồn C++ mặc định. Tệp typemap.dat nằm trong thư mục gsoap của bản phân phối gSOAP.

Bước 2

Sử dụng công cụ soapcpp2 vào file tiêu đề được tạo ra từ các công cụ wsdl2h.

soapcpp2 -C -j aws-s3.h

này tạo ra mã client-side (-C tùy chọn) với C++ proxy dịch vụ và các đối tượng (-j tùy chọn) từ tiêu đề AWS-s3.h. Bỏ qua -j cho mã C.

Bước 3

Sử dụng các phương pháp AmazonS3SoapBindingProxy proxy tự động được tạo ra để truy cập AWS S3 và tạo ra một chữ ký base64 mã hóa, HMAC-SHA1 băm cho AWS S3.Chữ ký là một chuỗi với phiên bản base64 mã hóa của HMAC-SHA1 băm chuỗi "AmazonS3" + OPERATION_NAME + Timestamp:

/* 
    createbucket.cpp 
    Example AWS S3 CreateBucket service invocation 
*/ 

#include "soapAmazonS3SoapBindingProxy.h" 
#include "AmazonS3SoapBinding.nsmap" 
#include &lt;fstream> 

// Make allocation of primitive values quick and easy: 
template&lt;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 &lt;&lt; "Couldn't read AWS keys for user " &lt;&lt; user  
                  &lt;&lt; " from file " &lt;&lt; credentialsFile &lt;&lt; '\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 &lt;&lt; "You are the owner of bucket '" &lt;&lt; result.BucketName &lt;&lt; "'." &lt;&lt; std::endl; 
    } 

    // Delete all managed data 
    aws.destroy(); 

    return 0; 
} 

Mã C trông tương tự, với sự khác biệt chính là việc sử dụng các chức năng cuộc gọi thay vì lời gọi phương pháp, tức là soap_call___s3__CreateBucket(&createBucketReq, &createBucketRes) . Tất cả điều này được giải thích trong tệp aws-s4.h được tạo.

Biên dịch các tập tin được tạo ra với mã nguồn của bạn:

c++ -DSOAP_MAXDIMESIZE=104857600 -DWITH_OPENSSL -o createbucket createbucket.cpp soapAmazonS3SoapBindingProxy.cpp soapC.cpp stdsoap2.cpp -lssl -lcrypto 

Các SOAP_MAXDIMESIZE=104857600 đảm bảo rằng DIME kích thước tập tin đính kèm có thể đủ lớn trong khi ngăn chặn tấn công từ chối dịch vụ sử dụng DIME. Tiêu đề DIME có kích thước tệp đính kèm, vì vậy kẻ tấn công có thể đặt mức lớn tùy ý đó để làm cạn kiệt tài nguyên bộ nhớ. Các bài đăng khác không đề cập đến điều này.

Chạy createbucket và một nhóm mới sẽ được tạo.

Trong tệp .cpp cuối cùng, lưu ý rằng chúng tôi kiểm tra các đối số dòng lệnh (argv) khi đặt credentialsFile và bucketName. Điều này cho phép chương trình được gọi với đối số:

./createbucket BucketName path_to_credentials_file 

Để biết thêm chi tiết về tất cả những điều này, tôi đề nghị để đọc các bài viết CodeProject tuyệt vời trên How to use AWS S3 in C++ with gSOAP Chris Moutsos từ phần nào của lời giải thích này bắt nguồn.