libqtaws  0.1.0
UnofficialAWSlibraryforQt-InternalDocumentation
Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Friends | List of all members
AwsSignatureV3Private Class Reference

Private implementation for AwsSignatureV3. More...

Inheritance diagram for AwsSignatureV3Private:
Inheritance graph
[legend]
Collaboration diagram for AwsSignatureV3Private:
Collaboration graph
[legend]

Public Member Functions

 AwsSignatureV3Private (const QCryptographicHash::Algorithm hashAlgorithm, AwsSignatureV3 *const q)
 Constructs a new AwsSignatureV3Private object. More...
 
void setAuthorizationHeader (const AwsAbstractCredentials &credentials, const QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QByteArray &payload) const
 Set authorization header on a network request. More...
 
void setDateHeader (QNetworkRequest &request, const QDateTime &dateTime=QDateTime::currentDateTimeUtc()) const
 Set the AWS custom date header. More...
 
- Public Member Functions inherited from AwsAbstractSignaturePrivate
virtual ~AwsAbstractSignaturePrivate ()
 AwsAbstractSignaturePrivate destructor. More...
 
 AwsAbstractSignaturePrivate (AwsAbstractSignature *const q)
 Constructs a new AwsAbstractSignaturePrivate object. More...
 
QString canonicalPath (const QUrl &url) const
 Create an AWS Signature canonical path. More...
 
QByteArray canonicalQuery (const QUrlQuery &query) const
 Create an AWS Signature canonical query. More...
 
QString httpMethod (const QNetworkAccessManager::Operation operation) const
 Create an AWS Signature request method string. More...
 
bool setQueryItem (QUrlQuery &query, const QString &key, const QString &value, const bool warnOnNonIdenticalDuplicate=true) const
 Set a query item, checking for existing values first. More...
 

Protected Member Functions

QByteArray algorithmDesignation (const QCryptographicHash::Algorithm algorithm) const
 Create an AWS V3 Signature algorithm designation. More...
 
QByteArray authorizationHeaderValue (const AwsAbstractCredentials &credentials, const QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QByteArray &payload) const
 Create an AWS V3 Signature authorization header value. More...
 
QByteArray canonicalHeader (const QByteArray &headerName, const QByteArray &headerValue) const
 Create an AWS V3 Signature canonical header string. More...
 
QByteArray canonicalHeaders (const QNetworkRequest &request, QByteArray *const signedHeaders) const
 Create an AWS V3 Signature canonical headers string. More...
 
QByteArray canonicalRequest (const QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload, QByteArray *const signedHeaders) const
 Create an AWS V3 Signature canonical request. More...
 

Static Protected Member Functions

static bool isHttps (const QNetworkRequest &request)
 Does a request use the HTTPS scheme? More...
 

Protected Attributes

const QCryptographicHash::Algorithm hashAlgorithm
 Hash algorithm to use when signing.
 
- Protected Attributes inherited from AwsAbstractSignaturePrivate
AwsAbstractSignature *const q_ptr
 Internal q-pointer.
 

Friends

class TestAwsSignatureV3
 

Detailed Description

Private implementation for AwsSignatureV3.

See also
http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

Definition at line 36 of file awssignaturev3_p.h.

Constructor & Destructor Documentation

AwsSignatureV3Private::AwsSignatureV3Private ( const QCryptographicHash::Algorithm  hashAlgorithm,
AwsSignatureV3 *const  q 
)

Constructs a new AwsSignatureV3Private object.

Parameters
hashAlgorithmThe algorithm to use during various stages of signing.
qPointer to this object's public AwsSignatureV3 instance.

Definition at line 98 of file awssignaturev3.cpp.

101 {
102 
103 }
const QCryptographicHash::Algorithm hashAlgorithm
Hash algorithm to use when signing.
AwsAbstractSignaturePrivate(AwsAbstractSignature *const q)
Constructs a new AwsAbstractSignaturePrivate object.

Member Function Documentation

QByteArray AwsSignatureV3Private::algorithmDesignation ( const QCryptographicHash::Algorithm  algorithm) const
protected

Create an AWS V3 Signature algorithm designation.

This function returns an algorithm designation, as defined by Amazon, for use with V3 signatures.

For example, if the algorith is QCryptographicHash::Sha256, this function will return HmacSHA256.

Parameters
algorithmThe hash algorithm to get the canonical designation for.
Returns
An AWS V3 Signature algorithm designation.
See also
http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/RESTAuthentication.html

Definition at line 120 of file awssignaturev3.cpp.

Referenced by authorizationHeaderValue().

121 {
122  switch (algorithm) {
123  case QCryptographicHash::Sha1: return "HmacSHA1";
124  case QCryptographicHash::Sha256: return "HmacSHA256";
125  default:
126  Q_ASSERT_X(false, Q_FUNC_INFO, "invalid algorithm");
127  return "invalid-algorithm";
128  }
129 }
QByteArray AwsSignatureV3Private::authorizationHeaderValue ( const AwsAbstractCredentials credentials,
const QNetworkAccessManager::Operation  operation,
QNetworkRequest &  request,
const QByteArray &  payload 
) const
protected

Create an AWS V3 Signature authorization header value.

This function builds a V3 signature, and returns it to the caller. The returned header value is then suitable for adding as an Authorization header in the HTTP request, to be accepted by Amazon.

Parameters
credentialsThe AWS credentials to use to sign the request.
operationThe HTTP method being used for the request.
requestThe network request to generate a signature for.
payloadOptional data being submitted in the request (eg for PUT and POST operations).
Returns
An AWS V3 Signature authorization header value.
See also
http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/RESTAuthentication.html
setAuthorizationHeader

Definition at line 148 of file awssignaturev3.cpp.

References AwsAbstractCredentials::accessKeyId(), algorithmDesignation(), canonicalRequest(), hashAlgorithm, isHttps(), and AwsAbstractCredentials::secretKey().

Referenced by setAuthorizationHeader().

151 {
152  // Calculate the signature.
153  QByteArray signedHeaders;
154  QByteArray stringToSign = canonicalRequest(operation, request, payload, &signedHeaders);
155  if (!isHttps(request)) {
156  stringToSign = QCryptographicHash::hash(stringToSign, hashAlgorithm);
157  }
158  const QByteArray signature = QMessageAuthenticationCode::hash(
159  stringToSign, credentials.secretKey().toUtf8(), hashAlgorithm);
160 
161  // Build and return the authorization header value.
162  return
163  QByteArray((isHttps(request)) ? "AWS3-HTTPS " : "AWS3 ") +
164  "AWSAccessKeyId=" + credentials.accessKeyId().toUtf8() + ","
165  "Algorithm=" + algorithmDesignation(hashAlgorithm) + "," +
166  ((!isHttps(request)) ? "SignedHeaders=" + signedHeaders + ',' : "") +
167  "Signature=" + signature.toBase64();
168 }
virtual QString secretKey() const =0
AWS secret access key for this credentials object.
QByteArray algorithmDesignation(const QCryptographicHash::Algorithm algorithm) const
Create an AWS V3 Signature algorithm designation.
virtual QString accessKeyId() const =0
AWS access key ID for this credentials object.
QByteArray canonicalRequest(const QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload, QByteArray *const signedHeaders) const
Create an AWS V3 Signature canonical request.
static bool isHttps(const QNetworkRequest &request)
Does a request use the HTTPS scheme?
const QCryptographicHash::Algorithm hashAlgorithm
Hash algorithm to use when signing.
QByteArray AwsSignatureV3Private::canonicalHeader ( const QByteArray &  headerName,
const QByteArray &  headerValue 
) const
protected

Create an AWS V3 Signature canonical header string.

Note
Amazon documentation does not specify how to handle whitespace within quotes for V3 signatures, so here we use the same approach as V3 signatures. That is:

In canonical form, header name and value are combined with a single semi-colon separator, with all whitespace removed from both, except for whitespace within double-quotes.

Note
This function is only applicable to the AWS3 format, not AWS3-HTTPS.
Parameters
headerNameName of the HTTP header to convert to canonical form.
headerValueValue of the HTTP header to convert to canonical form.
Returns
An AWS V3 Signature canonical header string.
See also
http://docs.aws.amazon.com/amazonswf/latest/developerguide/HMACAuth-swf.html
http://docs.aws.amazon.com/general/latest/gr/sigV4-create-canonical-request.html
canonicalHeaders

Definition at line 192 of file awssignaturev3.cpp.

Referenced by canonicalHeaders().

193 {
194  QByteArray header = headerName.toLower() + ':';
195  const QByteArray trimmedHeaderValue = headerValue.trimmed();
196  bool isInQuotes = false;
197  char previousChar = '\0';
198  for (int index = 0; index < trimmedHeaderValue.size(); ++index) {
199  char thisChar = trimmedHeaderValue.at(index);
200  header += thisChar;
201  if (isInQuotes) {
202  if ((thisChar == '"') && (previousChar != '\\'))
203  isInQuotes = false;
204  } else {
205  if ((thisChar == '"') && (previousChar != '\\')) {
206  isInQuotes = true;
207  } else if (isspace(thisChar)) {
208  while ((index < trimmedHeaderValue.size()-1) &&
209  (isspace(trimmedHeaderValue.at(index+1))))
210  ++index;
211  }
212  }
213  previousChar = thisChar;
214  }
215  return header;
216 }
QByteArray AwsSignatureV3Private::canonicalHeaders ( const QNetworkRequest &  request,
QByteArray *const  signedHeaders 
) const
protected

Create an AWS V3 Signature canonical headers string.

This function constructs a canonical string containing all of the headers in the given request.

Note
request will typically not include a Host header at this stage, however Qt will add an appropriate Host header when the request is performed. So, if request does not include a Host header yet, this function will include a derived Host header in the canonical headers to allow for it.
This function is only applicable to the AWS3 format, not AWS3-HTTPS.
Parameters
[in]requestThe network request to fetch the canonical headers from.
[out]signedHeadersA semi-colon separated list of the names of all headers included in the result.
Returns
An AWS V3 Signature canonical headers string.
See also
http://docs.aws.amazon.com/general/latest/gr/sigV3-create-canonical-request.html
canonicalHeader

Definition at line 241 of file awssignaturev3.cpp.

References canonicalHeader().

Referenced by canonicalRequest().

242 {
243  Q_CHECK_PTR(signedHeaders);
244  signedHeaders->clear();
245 
246  /* Note, Amazon says we should combine duplicate headers with comma separators...
247  * conveniently for us, QNetworkRequest requires that to have been done already.
248  * See note in QNetworkRequest::setRawHeader.
249  */
250 
251  // Convert the raw headers list to a map to sort on (lowercased) header names only.
252  QMap<QByteArray,QByteArray> headers;
253  foreach (const QByteArray &rawHeader, request.rawHeaderList()) {
254  headers.insert(rawHeader.toLower(), request.rawHeader(rawHeader));
255  }
256  // The "host" header is not included in QNetworkRequest::rawHeaderList, but will be sent by Qt.
257  headers.insert("host", request.url().host().toUtf8());
258 
259  // Convert the headers map to a canonical string, keeping track of which headers we've included too.
260  QByteArray canonicalHeaders;
261  for (QMap<QByteArray,QByteArray>::const_iterator iter = headers.constBegin(); iter != headers.constEnd(); ++iter) {
262  // Only include "host" and "x-amz-*" headers. Note, Amazon documentation states that latter as
263  // "x-amz-" (ie with the trailing '-'), yet the official Amazon Java SDK tests for a "x-amz"
264  // prefix. Thus the Java SDK would include headers with keys like "x-amzfoo", but here we do not
265  // since that would disagree with the official documentation.
266  if ((iter.key() == "host") || (iter.key().startsWith("x-amz-"))) {
267  canonicalHeaders += canonicalHeader(iter.key(), iter.value()) + '\n';
268  if (!signedHeaders->isEmpty()) *signedHeaders += ';';
269  *signedHeaders += iter.key();
270  }
271  }
272  return canonicalHeaders;
273 }
QByteArray canonicalHeader(const QByteArray &headerName, const QByteArray &headerValue) const
Create an AWS V3 Signature canonical header string.
QByteArray canonicalHeaders(const QNetworkRequest &request, QByteArray *const signedHeaders) const
Create an AWS V3 Signature canonical headers string.
QByteArray AwsSignatureV3Private::canonicalRequest ( const QNetworkAccessManager::Operation  operation,
const QNetworkRequest &  request,
const QByteArray &  payload,
QByteArray *const  signedHeaders 
) const
protected

Create an AWS V3 Signature canonical request.

Note, this function implments both AWS3 and AWS3-HTTPS variants of the AWS Signature version 3 - which are quite different.

Parameters
[in]operationThe HTTP method being used for the request.
[in]requestThe network request to generate a canonical request for.
[in]payloadOptional data being submitted in the request (eg for PUT and POST operations).
[out]signedHeadersA semi-colon separated list of the names of all headers included in the result.
Returns
An AWS V3 Signature canonical request.
See also
http://docs.aws.amazon.com/amazonswf/latest/developerguide/HMACAuth-swf.html (AWS3)
http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/RESTAuthentication.html (AWS3-HTTPS)

Definition at line 292 of file awssignaturev3.cpp.

References canonicalHeaders(), AwsAbstractSignaturePrivate::canonicalPath(), AwsAbstractSignaturePrivate::canonicalQuery(), AwsAbstractSignaturePrivate::httpMethod(), and isHttps().

Referenced by authorizationHeaderValue().

295 {
296  // AWS3-HTTPS
297  if (isHttps(request)) {
298  Q_ASSERT((request.hasRawHeader("x-amz-date")) || (request.hasRawHeader("Date")));
299  QByteArray canonicalRequest = request.rawHeader(request.hasRawHeader("x-amz-date") ? "x-amz-date" : "Date");
300  if (request.hasRawHeader("x-amz-nonce")) {
301  canonicalRequest += request.rawHeader("x-amz-nonce");
302  }
303  return canonicalRequest;
304  }
305 
306  // AWS3
307  return httpMethod(operation).toUtf8() + '\n' +
308  canonicalPath(request.url()).toUtf8() + '\n' +
309  canonicalQuery(QUrlQuery(request.url())) + '\n' +
310  canonicalHeaders(request, signedHeaders) + '\n' +
311  payload;
312 }
QByteArray canonicalQuery(const QUrlQuery &query) const
Create an AWS Signature canonical query.
QByteArray canonicalHeaders(const QNetworkRequest &request, QByteArray *const signedHeaders) const
Create an AWS V3 Signature canonical headers string.
QByteArray canonicalRequest(const QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload, QByteArray *const signedHeaders) const
Create an AWS V3 Signature canonical request.
static bool isHttps(const QNetworkRequest &request)
Does a request use the HTTPS scheme?
QString httpMethod(const QNetworkAccessManager::Operation operation) const
Create an AWS Signature request method string.
QString canonicalPath(const QUrl &url) const
Create an AWS Signature canonical path.
bool AwsSignatureV3Private::isHttps ( const QNetworkRequest &  request)
inlinestaticprotected

Does a request use the HTTPS scheme?

Parameters
requestThe network request to evaluate.
Returns
true if request uses the HTTPS scheme, false otherwise.

Definition at line 321 of file awssignaturev3.cpp.

Referenced by authorizationHeaderValue(), and canonicalRequest().

322 {
323  return (request.url().scheme() == QLatin1String("https"));
324 }
void AwsSignatureV3Private::setAuthorizationHeader ( const AwsAbstractCredentials credentials,
const QNetworkAccessManager::Operation  operation,
QNetworkRequest &  request,
const QByteArray &  payload 
) const

Set authorization header on a network request.

This function will calculate the authorization header value and set it as the Authorization HTTP header on request.

Parameters
[in]credentialsThe AWS credentials to use to sign the request.
[in]operationThe HTTP method being used for the request.
[in,out]requestThe network request to add the authorization header to.
[in]payloadOptional data being submitted in the request (eg for PUT and POST operations).
See also
http://docs.aws.amazon.com/general/latest/gr/sigV3-signed-request-examples.html
authorizationHeaderValue

Definition at line 340 of file awssignaturev3.cpp.

References authorizationHeaderValue().

343 {
344  Q_ASSERT(!request.hasRawHeader("Authorization"));
345  request.setRawHeader("Authorization", authorizationHeaderValue(credentials, operation, request, payload));
346 }
QByteArray authorizationHeaderValue(const AwsAbstractCredentials &credentials, const QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QByteArray &payload) const
Create an AWS V3 Signature authorization header value.
void AwsSignatureV3Private::setDateHeader ( QNetworkRequest &  request,
const QDateTime &  dateTime = QDateTime::currentDateTimeUtc() 
) const

Set the AWS custom date header.

If request does not already contain an x-amz-date header, then this function will set a custom x-amz-date header to the value of dateTime formatted like "Fri, 09 Sep 2011 23:36:00 GMT".

Parameters
requestThe network request to add the date header to.
dateTimeThe timestamp (in UTC) to set the date header's value to.

Definition at line 358 of file awssignaturev3.cpp.

359 {
360  Q_ASSERT(dateTime.timeSpec() == Qt::UTC);
361  if (!request.hasRawHeader("x-amz-date")) {
362  request.setRawHeader("x-amz-date", dateTime.toString(QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toUtf8());
363  }
364 }

The documentation for this class was generated from the following files: