Logo ROOT  
Reference Guide
TS3HTTPRequest.cxx
Go to the documentation of this file.
1// @(#)root/net:$Id$
2// Author: Fabio Hernandez 30/01/2013
3// based on an initial version by Marcelo Sousa (class THTTPMessage)
4
5/*************************************************************************
6 * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13//////////////////////////////////////////////////////////////////////////
14// //
15// TS3HTTPRequest //
16// //
17// An object of this class represents an HTTP request extended to be //
18// compatible with Amazon's S3 protocol. //
19// Specifically, such a request contains an 'Authorization' header with //
20// information used by the S3 server for authenticating this request. //
21// The authentication information is computed based on a pair of access //
22// key and secret key which are both provided to the user by the S3 //
23// service provider (e.g. Amazon, Google, etc.). //
24// The secret key is used to compute a signature of selected fields in //
25// the request. The algorithm for computing the signature is documented //
26// in: //
27// //
28// Google storage: //
29// http://code.google.com/apis/storage/docs/reference/v1/developer-guidev1.html#authentication
30// //
31// Amazon: //
32// http://docs.aws.amazon.com/AmazonS3/latest/dev/S3_Authentication2.html
33// //
34//////////////////////////////////////////////////////////////////////////
35
36#include "TS3HTTPRequest.h"
37#include "TBase64.h"
38#if defined(MAC_OS_X_VERSION_10_7)
39#include <CommonCrypto/CommonHMAC.h>
40#define SHA_DIGEST_LENGTH 20
41#else
42#include <openssl/sha.h>
43#include <openssl/hmac.h>
44#include <openssl/evp.h>
45#include <openssl/bio.h>
46#include <openssl/buffer.h>
47#endif
48
49#include <stdio.h>
50#include <time.h>
51#include <string.h>
52
54
55////////////////////////////////////////////////////////////////////////////////
56
58 : fAuthType(kNoAuth), fHost("NoHost")
59{
60}
61
62////////////////////////////////////////////////////////////////////////////////
63/// Default constructor
64
66 const TString& bucket, const TString& objectKey, EAuthType authType,
67 const TString& accessKey, const TString& secretKey)
68{
69 fVerb = httpVerb;
70 fHost = host;
71 fBucket = bucket;
72 fObjectKey = objectKey;
73 fAuthType = authType;
74 fAccessKey = accessKey;
75 fSecretKey = secretKey;
76}
77
78////////////////////////////////////////////////////////////////////////////////
79/// Copy constructor
80
82 : TObject(r)
83{
84 fVerb = r.fVerb;
85 fHost = r.fHost;
86 fBucket = r.fBucket;
87 fObjectKey = r.fObjectKey;
88 fAuthType = r.fAuthType;
89 fAccessKey = r.fAccessKey;
90 fSecretKey = r.fSecretKey;
91 fTimeStamp = r.fTimeStamp;
92}
93
94////////////////////////////////////////////////////////////////////////////////
95/// Returns this request's signature
96
98{
99 // Please note, the order of the fields used for computing
100 // the signature is important. Make sure that the changes you
101 // make are compatible with the reference documentation.
102 //
103 // Refs:
104 // AMAZON http://awsdocs.s3.amazonaws.com/S3/latest/s3-qrc.pdf
105 // GOOGLE: http://code.google.com/apis/storage/docs/reference/v1/developer-guidev1.html#authentication
106
107 TString toSign = TString::Format("%s\n\n\n%s\n", // empty Content-MD5 and Content-Type
108 (const char*)HTTPVerbToTString(httpVerb),
109 (const char*)fTimeStamp);
110 if (fAuthType == kGoogle) {
111 // Must use API version 1. Google Storage API v2 only
112 // accepts OAuth authentication.
113 // This header is not strictly needed but if used for computing
114 // the signature, the request must contain it as a header
115 // (see method MakeAuthHeader)
116 // Ref: https://developers.google.com/storage/docs/reference/v1/apiversion1
117 toSign += "x-goog-api-version:1\n"; // Lowercase, no spaces around ':'
118 }
119
120 if (fAuthType == kAmazon) {
121 if (!fSessionToken.IsNull()) {
122 toSign += "x-amz-security-token:" + fSessionToken + "\n";
123 }
124 }
125
126 toSign += "/" + fBucket + fObjectKey;
127
128 unsigned char digest[SHA_DIGEST_LENGTH] = {0};
129#if defined(MAC_OS_X_VERSION_10_7)
130 CCHmac(kCCHmacAlgSHA1, fSecretKey.Data(), fSecretKey.Length() , (unsigned char *)toSign.Data(), toSign.Length(), digest);
131#else
132 unsigned int *sd = NULL;
133 HMAC(EVP_sha1(), fSecretKey.Data(), fSecretKey.Length() , (unsigned char *)toSign.Data(), toSign.Length(), digest, sd);
134#endif
135
136 return TBase64::Encode((const char *)digest, SHA_DIGEST_LENGTH);
137}
138
139////////////////////////////////////////////////////////////////////////////////
140
142{
143 switch (httpVerb) {
144 case kGET: return TString("GET");
145 case kPOST: return TString("POST");
146 case kPUT: return TString("PUT");
147 case kDELETE: return TString("DELETE");
148 case kHEAD: return TString("HEAD");
149 case kCOPY: return TString("COPY");
150 default: return TString("");
151 }
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// Sets this request's time stamp according to:
156/// http://code.google.com/apis/storage/docs/reference-headers.html#date
157
159{
160 time_t now = time(NULL);
161 char result[128];
162#ifdef _REENTRANT
163 struct tm dateFormat;
164 strftime(result, sizeof(result), "%a, %d %b %Y %H:%M:%S GMT",
165 gmtime_r(&now, &dateFormat));
166#else
167 strftime(result, sizeof(result), "%a, %d %b %Y %H:%M:%S GMT",
168 gmtime(&now));
169#endif
170 fTimeStamp = result;
171 return *this;
172}
173
174////////////////////////////////////////////////////////////////////////////////
175/// Returns the first line of a HTTP request for this object. Note that since
176/// we don't use the virtual host syntax which is supported by Amazon, we
177/// must include the bucket name in thr resource. For example, we don't use
178/// http://mybucket.s3.amazonaws.com/path/to/my/file but instead
179/// http://s3.amazonaws.com/mybucket/path/to/my/file so the HTTP request
180/// will be of the form "GET /mybucket/path/to/my/file HTTP/1.1"
181/// Also note that the path must include the leading '/'.
182
184{
185 return TString::Format("%s /%s%s HTTP/1.1",
186 (const char*)HTTPVerbToTString(httpVerb),
187 (const char*)fBucket,
188 (const char*)fObjectKey);
189}
190
191////////////////////////////////////////////////////////////////////////////////
192/// Returns the 'Host' header to include in the HTTP request.
193
195{
196 return "Host: " + fHost;
197}
198
199////////////////////////////////////////////////////////////////////////////////
200/// Returns the date header for this HTTP request
201
203{
204 return "Date: " + fTimeStamp;
205}
206
207////////////////////////////////////////////////////////////////////////////////
208/// Returns the session security token header for this HTTP request
209
211{
212 if (fAuthType != kAmazon)
213 return "";
214
215 if (fSessionToken.IsNull())
216 return "";
217
218 return TString::Format("x-amz-security-token: %s",
219 (const char*) fSessionToken.Data());
220}
221
222////////////////////////////////////////////////////////////////////////////////
223/// Returns the authentication prefix
224
226{
227 switch (fAuthType) {
228 case kNoAuth: return "";
229 case kGoogle: return "GOOG1";
230 case kAmazon:
231 default: return "AWS";
232 }
233}
234
235////////////////////////////////////////////////////////////////////////////////
236/// Returns the authentication header for this HTTP request
237
239{
240 if (fAuthType == kNoAuth)
241 return "";
242
243 return TString::Format("Authorization: %s %s:%s%s",
244 (const char*)MakeAuthPrefix(),
245 (const char*)fAccessKey,
246 (const char*)ComputeSignature(httpVerb),
247 (fAuthType == kGoogle) ? "\r\nx-goog-api-version: 1" : "");
248}
249
250////////////////////////////////////////////////////////////////////////////////
251/// Returns the HTTP request ready to be sent to the server
252
254{
255 // Set time stamp before computing this request's signature. The signature
256 // includes the date.
257 SetTimeStamp();
258 TString request = TString::Format("%s\r\n%s\r\n%s\r\n",
259 (const char*)MakeRequestLine(httpVerb),
260 (const char*)MakeHostHeader(),
261 (const char*)MakeDateHeader());
262 TString tokenHeader = MakeTokenHeader();
263 if (!tokenHeader.IsNull())
264 request += tokenHeader + "\r\n";
265 TString authHeader = MakeAuthHeader(httpVerb);
266 if (!authHeader.IsNull())
267 request += authHeader + "\r\n";
268 if (appendCRLF)
269 request += "\r\n";
270 return request;
271}
ROOT::R::TRInterface & r
Definition: Object.C:4
#define ClassImp(name)
Definition: Rtypes.h:361
static TString Encode(const char *data)
Transform data into a null terminated base64 string.
Definition: TBase64.cxx:107
Mother of all ROOT objects.
Definition: TObject.h:37
TString fSessionToken
TString GetRequest(TS3HTTPRequest::EHTTPVerb httpVerb, Bool_t appendCRLF=kTRUE)
Returns the HTTP request ready to be sent to the server.
TString HTTPVerbToTString(EHTTPVerb httpVerb) const
TString MakeAuthPrefix() const
Returns the authentication prefix.
TString fAccessKey
TString fTimeStamp
EAuthType fAuthType
TString MakeTokenHeader() const
Returns the session security token header for this HTTP request.
TS3HTTPRequest & SetTimeStamp()
Sets this request's time stamp according to: http://code.google.com/apis/storage/docs/reference-heade...
TString ComputeSignature(TS3HTTPRequest::EHTTPVerb httpVerb) const
Returns this request's signature.
TString fSecretKey
TString MakeRequestLine(TS3HTTPRequest::EHTTPVerb httpVerb) const
Returns the first line of a HTTP request for this object.
TString MakeAuthHeader(TS3HTTPRequest::EHTTPVerb httpVerb) const
Returns the authentication header for this HTTP request.
TString MakeHostHeader() const
Returns the 'Host' header to include in the HTTP request.
TString MakeDateHeader() const
Returns the date header for this HTTP request.
TString fObjectKey
EHTTPVerb fVerb
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
const char * Data() const
Definition: TString.h:364
Bool_t IsNull() const
Definition: TString.h:402
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition: TString.cxx:2311