Changeset 2442


Ignore:
Timestamp:
06/01/2009 13:18:07 (3 years ago)
Author:
chris
Message:

Add Amazon S3 signature checking to simulator.

Location:
box/trunk
Files:
8 added
3 edited

Legend:

Unmodified
Added
Removed
  • box/trunk/lib/httpserver/HTTPRequest.cpp

    r2438 r2442  
    135135        else 
    136136        { 
    137                 std::string method = requestLine.substr(0, p); 
    138                 if (method == "GET") 
     137                mHttpVerb = requestLine.substr(0, p); 
     138                if (mHttpVerb == "GET") 
    139139                { 
    140140                        mMethod = Method_GET; 
    141141                } 
    142                 else if (method == "HEAD") 
     142                else if (mHttpVerb == "HEAD") 
    143143                { 
    144144                        mMethod = Method_HEAD; 
    145145                } 
    146                 else if (method == "POST") 
     146                else if (mHttpVerb == "POST") 
    147147                { 
    148148                        mMethod = Method_POST; 
    149149                } 
    150                 else if (method == "PUT") 
     150                else if (mHttpVerb == "PUT") 
    151151                { 
    152152                        mMethod = Method_PUT; 
  • box/trunk/lib/httpserver/HTTPRequest.h

    r2438 r2442  
    8787        } 
    8888 
    89         const int GetHostPort() const {return mHostPort;}  // into host name and port number 
     89        const int GetHostPort() const {return mHostPort;} 
    9090        const std::string &GetQueryString() const {return mQueryString;} 
    9191        int GetHTTPVersion() const {return mHTTPVersion;} 
     
    110110                return false; 
    111111        } 
     112        std::vector<Header> GetHeaders() { return mExtraHeaders; } 
    112113 
    113114        // -------------------------------------------------------------------------- 
     
    131132        } 
    132133        bool IsExpectingContinue() const { return mExpectContinue; } 
     134        const char* GetVerb() const 
     135        { 
     136                if (!mHttpVerb.empty()) 
     137                { 
     138                        return mHttpVerb.c_str(); 
     139                } 
     140                switch (mMethod) 
     141                { 
     142                        case Method_UNINITIALISED: return "Uninitialized"; 
     143                        case Method_UNKNOWN: return "Unknown"; 
     144                        case Method_GET: return "GET"; 
     145                        case Method_HEAD: return "HEAD"; 
     146                        case Method_POST: return "POST"; 
     147                        case Method_PUT: return "PUT"; 
     148                } 
     149                return "Bad"; 
     150        } 
    133151         
    134152private: 
     
    150168        bool mExpectContinue; 
    151169        IOStream* mpStreamToReadFrom; 
     170        std::string mHttpVerb; 
    152171}; 
    153172 
  • box/trunk/test/httpserver/testhttpserver.cpp

    r2441 r2442  
    1313#include <string.h> 
    1414 
    15 #include "Test.h" 
    16 #include "HTTPServer.h" 
     15#include <openssl/hmac.h> 
     16 
    1717#include "HTTPRequest.h" 
    1818#include "HTTPResponse.h" 
     19#include "HTTPServer.h" 
    1920#include "IOStreamGetLine.h" 
    2021#include "ServerControl.h" 
     22#include "Test.h" 
     23#include "decode.h" 
     24#include "encode.h" 
    2125 
    2226#include "MemLeakFindOn.h" 
     
    132136 
    133137        try 
    134         {                
    135                 if (rRequest.GetMethod() == HTTPRequest::Method_GET) 
     138        { 
     139                // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html 
     140                std::string access_key = "0PN5J17HBGZHT7JJ3X82"; 
     141                std::string secret_key = "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"; 
     142                 
     143                std::string md5, date, bucket; 
     144                rRequest.GetHeader("Content-MD5", &md5); 
     145                rRequest.GetHeader("Date", &date); 
     146                 
     147                std::string host = rRequest.GetHostName(); 
     148                std::string s3suffix = ".s3.amazonaws.com"; 
     149                if (host.size() > s3suffix.size()) 
     150                { 
     151                        std::string suffix = host.substr(host.size() - 
     152                                s3suffix.size(), s3suffix.size()); 
     153                        if (suffix == s3suffix) 
     154                        { 
     155                                bucket = host.substr(0, host.size() - 
     156                                        s3suffix.size()); 
     157                        } 
     158                } 
     159                 
     160                std::ostringstream data; 
     161                data << rRequest.GetVerb() << "\n"; 
     162                data << md5 << "\n"; 
     163                data << rRequest.GetContentType() << "\n"; 
     164                data << date << "\n"; 
     165                 
     166                std::vector<HTTPRequest::Header> headers = rRequest.GetHeaders(); 
     167                 
     168                for (std::vector<HTTPRequest::Header>::iterator 
     169                        i = headers.begin(); i != headers.end(); i++) 
     170                { 
     171                        std::string& rHeaderName = i->first; 
     172                         
     173                        for (std::string::iterator c = rHeaderName.begin(); 
     174                                c != rHeaderName.end() && *c != ':'; c++) 
     175                        { 
     176                                *c = tolower(*c); 
     177                        } 
     178                } 
     179                 
     180                sort(headers.begin(), headers.end()); 
     181                 
     182                for (std::vector<HTTPRequest::Header>::iterator 
     183                        i = headers.begin(); i != headers.end(); i++) 
     184                { 
     185                        if (i->first.substr(0, 5) == "x-amz") 
     186                        { 
     187                                data << i->first << ":" << i->second << "\n"; 
     188                        } 
     189                }                
     190                 
     191                if (! bucket.empty()) 
     192                { 
     193                        data << "/" << bucket; 
     194                } 
     195                 
     196                data << rRequest.GetRequestURI(); 
     197                std::string data_string = data.str(); 
     198 
     199                unsigned char digest_buffer[EVP_MAX_MD_SIZE]; 
     200                unsigned int digest_size = sizeof(digest_buffer); 
     201                unsigned char* mac = HMAC(EVP_sha1(), 
     202                        secret_key.c_str(), secret_key.size(), 
     203                        (const unsigned char*)data_string.c_str(), 
     204                        data_string.size(), digest_buffer, &digest_size); 
     205                std::string digest((const char *)digest_buffer, digest_size); 
     206                 
     207                base64::encoder encoder; 
     208                std::string expectedAuth = "AWS " + access_key + ":" + 
     209                        encoder.encode(digest); 
     210                 
     211                if (expectedAuth[expectedAuth.size() - 1] == '\n') 
     212                { 
     213                        expectedAuth = expectedAuth.substr(0, 
     214                                expectedAuth.size() - 1); 
     215                } 
     216                 
     217                std::string actualAuth; 
     218                if (!rRequest.GetHeader("Authorization", &actualAuth) || 
     219                        actualAuth != expectedAuth) 
     220                { 
     221                        rResponse.SetResponseCode(HTTPResponse::Code_Unauthorized); 
     222                }        
     223                else if (rRequest.GetMethod() == HTTPRequest::Method_GET) 
    136224                { 
    137225                        HandleGet(rRequest, rResponse); 
     
    349437        TestRemoteProcessMemLeaks("generic-httpserver.memleaks"); 
    350438 
     439        { 
     440                // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html 
     441                HTTPRequest request(HTTPRequest::Method_GET, "/photos/puppy.jpg"); 
     442                request.SetHostName("johnsmith.s3.amazonaws.com"); 
     443                request.AddHeader("Date", "Tue, 27 Mar 2007 19:36:42 +0000"); 
     444                request.AddHeader("Authorization", 
     445                        "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA="); 
     446                 
     447                S3Simulator simulator; 
     448                 
     449                CollectInBufferStream response_buffer; 
     450                HTTPResponse response(&response_buffer); 
     451                 
     452                simulator.Handle(request, response); 
     453                TEST_EQUAL(200, response.GetResponseCode()); 
     454                 
     455                std::string response_data((const char *)response.GetBuffer(), 
     456                        response.GetSize()); 
     457                TEST_EQUAL("omgpuppies!\n", response_data); 
     458        } 
     459 
     460        { 
     461                // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html 
     462                HTTPRequest request(HTTPRequest::Method_GET, "/photos/puppy.jpg"); 
     463                request.SetHostName("johnsmith.s3.amazonaws.com"); 
     464                request.AddHeader("Date", "Tue, 27 Mar 2007 19:36:42 +0000"); 
     465                request.AddHeader("Authorization", 
     466                        "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbB="); 
     467                 
     468                S3Simulator simulator; 
     469                 
     470                CollectInBufferStream response_buffer; 
     471                HTTPResponse response(&response_buffer); 
     472                 
     473                simulator.Handle(request, response); 
     474                TEST_EQUAL(401, response.GetResponseCode()); 
     475                 
     476                std::string response_data((const char *)response.GetBuffer(), 
     477                        response.GetSize()); 
     478                TEST_EQUAL("", response_data); 
     479        } 
     480 
     481        { 
     482                HTTPRequest request(HTTPRequest::Method_GET, "/nonexist"); 
     483                request.SetHostName("quotes.s3.amazonaws.com"); 
     484                request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
     485                request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:0cSX/YPdtXua1aFFpYmH1tc0ajA="); 
     486 
     487                S3Simulator simulator; 
     488                 
     489                CollectInBufferStream response_buffer; 
     490                HTTPResponse response(&response_buffer); 
     491                 
     492                simulator.Handle(request, response); 
     493                TEST_EQUAL(404, response.GetResponseCode()); 
     494        } 
     495 
     496        { 
     497                HTTPRequest request(HTTPRequest::Method_PUT, 
     498                        "/newfile"); 
     499                request.SetHostName("quotes.s3.amazonaws.com"); 
     500                request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
     501                request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:XtMYZf0hdOo4TdPYQknZk0Lz7rw="); 
     502                request.AddHeader("Content-Type", "text/plain"); 
     503                 
     504                FileStream fs("testfiles/testrequests.pl"); 
     505                fs.CopyStreamTo(request); 
     506                request.SetForReading(); 
     507 
     508                CollectInBufferStream response_buffer; 
     509                HTTPResponse response(&response_buffer); 
     510                 
     511                S3Simulator simulator; 
     512                simulator.Handle(request, response); 
     513                 
     514                TEST_EQUAL(200, response.GetResponseCode()); 
     515                TEST_EQUAL("LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7", response.GetHeaderValue("x-amz-id-2")); 
     516                TEST_EQUAL("F2A8CCCA26B4B26D", response.GetHeaderValue("x-amz-request-id")); 
     517                TEST_EQUAL("Wed, 01 Mar  2006 12:00:00 GMT", response.GetHeaderValue("Date")); 
     518                TEST_EQUAL("Sun, 1 Jan 2006 12:00:00 GMT", response.GetHeaderValue("Last-Modified")); 
     519                TEST_EQUAL("\"828ef3fdfa96f00ad9f27c383fc9ac7f\"", response.GetHeaderValue("ETag")); 
     520                TEST_EQUAL("", response.GetContentType()); 
     521                TEST_EQUAL("AmazonS3", response.GetHeaderValue("Server")); 
     522                TEST_EQUAL(0, response.GetSize()); 
     523 
     524                FileStream f1("testfiles/testrequests.pl"); 
     525                FileStream f2("testfiles/newfile"); 
     526                TEST_THAT(f1.CompareWith(f2)); 
     527                TEST_EQUAL(0, ::unlink("testfiles/newfile")); 
     528        } 
     529 
    351530        // Start the S3Simulator server 
    352531        pid = LaunchServer("./test s3server testfiles/httpserver.conf", 
     
    365544                request.SetHostName("quotes.s3.amazonaws.com"); 
    366545                request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
    367                 request.AddHeader("Authorization", "AWS 15B4D3461F177624206A:xQE0diMbLRepdf3YB+FIEXAMPLE="); 
     546                request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:0cSX/YPdtXua1aFFpYmH1tc0ajA="); 
    368547                request.SetClientKeepAliveRequested(true); 
    369548                request.Send(sock, IOStream::TimeOutInfinite); 
     
    381560                request.SetHostName("quotes.s3.amazonaws.com"); 
    382561                request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
    383                 request.AddHeader("Authorization", "AWS 15B4D3461F177624206A:xQE0diMbLRepdf3YB+FIEXAMPLE="); 
     562                request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:qc1e8u8TVl2BpIxwZwsursIb8U8="); 
    384563                request.SetClientKeepAliveRequested(true); 
    385564                request.Send(sock, IOStream::TimeOutInfinite); 
     
    397576                request.SetHostName("quotes.s3.amazonaws.com"); 
    398577                request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
    399                 request.AddHeader("Authorization", "AWS 15B4D3461F177624206A:xQE0diMbLRepdf3YB+FIEXAMPLE="); 
     578                request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:qc1e8u8TVl2BpIxwZwsursIb8U8="); 
    400579                request.SetClientKeepAliveRequested(true); 
    401580                request.Send(sock, IOStream::TimeOutInfinite); 
     
    422601                request.SetHostName("quotes.s3.amazonaws.com"); 
    423602                request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
    424                 request.AddHeader("Authorization", "AWS 15B4D3461F177624206A:xQE0diMbLRepdf3YB+FIEXAMPLE="); 
     603                request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:kfY1m6V3zTufRy2kj92FpQGKz4M="); 
    425604                request.AddHeader("Content-Type", "text/plain"); 
    426605                FileStream fs("testfiles/testrequests.pl"); 
Note: See TracChangeset for help on using the changeset viewer.