]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
Merge remote-tracking branch 'jmunhoz/wip-aws4' into wip-aws4 7720/head
authorYehuda Sadeh <yehuda@redhat.com>
Fri, 19 Feb 2016 22:34:13 +0000 (14:34 -0800)
committerYehuda Sadeh <yehuda@redhat.com>
Fri, 19 Feb 2016 22:34:13 +0000 (14:34 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
Conflicts:
src/rgw/rgw_auth_s3.h
src/rgw/rgw_client_io.cc
src/rgw/rgw_client_io.h
src/rgw/rgw_common.h
src/rgw/rgw_main.cc
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rest.cc
src/rgw/rgw_rest_metadata.cc
src/rgw/rgw_rest_s3.cc

16 files changed:
1  2 
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_client_io.cc
src/rgw/rgw_client_io.h
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_http_errors.h
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_process.cc
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_rest_metadata.cc
src/rgw/rgw_rest_metadata.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index b372630cb3e265b03e6bcf9225ac142f3625127b,82ea8763f2d95af47bb55be3304b7e75d5c842fc..9525a71d52a94ef91bb0802f7ae984bc01983af5
@@@ -2,7 -2,9 +2,10 @@@
  // vim: ts=8 sw=2 smarttab
  
  #include "common/armor.h"
+ #include "common/utf8.h"
  #include "rgw_common.h"
+ #include "rgw_client_io.h"
++#include "rgw_rest.h"
  
  #define dout_subsys ceph_subsys_rgw
  
@@@ -214,3 -221,193 +222,193 @@@ bool rgw_create_s3_canonical_header(req
  
    return true;
  }
 -      request_payload_hash = s->cio->grab_aws4_sha256_hash();
+ /*
+  * assemble canonical request for signature version 4
+  */
+ void rgw_assemble_s3_v4_canonical_request(const char *method, const char *canonical_uri, const char *canonical_qs,
+                                           const char *canonical_hdrs, const char *signed_hdrs, const char *request_payload_hash,
+                                           string& dest_str)
+ {
+   string dest;
+   if (method)
+     dest = method;
+   dest.append("\n");
+   if (canonical_uri) {
+     dest.append(canonical_uri);
+   }
+   dest.append("\n");
+   if (canonical_qs) {
+     dest.append(canonical_qs);
+   }
+   dest.append("\n");
+   if (canonical_hdrs)
+     dest.append(canonical_hdrs);
+   dest.append("\n");
+   if (signed_hdrs)
+     dest.append(signed_hdrs);
+   dest.append("\n");
+   if (request_payload_hash)
+     dest.append(request_payload_hash);
+   dest_str = dest;
+ }
+ /*
+  * create canonical request for signature version 4
+  */
+ void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri, const string& canonical_qs,
+                                         const string& canonical_hdrs, const string& signed_hdrs, const string& request_payload,
+                                         bool unsigned_payload, string& canonical_req, string& canonical_req_hash)
+ {
+   string request_payload_hash;
+   if (unsigned_payload) {
+     request_payload_hash = "UNSIGNED-PAYLOAD";
+   } else {
+     if (s->aws4_auth_needs_complete) {
 -  map<string, RGWAccessKey>::iterator iter = s->user.access_keys.find(access_key_id);
 -  if (iter == s->user.access_keys.end()) {
++      request_payload_hash = STREAM_IO(s)->grab_aws4_sha256_hash();
+     } else {
+       rgw_hash_s3_string_sha256(request_payload.c_str(), request_payload.size(), request_payload_hash);
+     }
+   }
+   s->aws4_auth->payload_hash = request_payload_hash;
+   ldout(s->cct, 10) << "payload request hash = " << request_payload_hash << dendl;
+   rgw_assemble_s3_v4_canonical_request(s->info.method, canonical_uri.c_str(),
+       canonical_qs.c_str(), canonical_hdrs.c_str(), signed_hdrs.c_str(),
+       request_payload_hash.c_str(), canonical_req);
+   rgw_hash_s3_string_sha256(canonical_req.c_str(), canonical_req.size(), canonical_req_hash);
+   ldout(s->cct, 10) << "canonical request = " << canonical_req << dendl;
+   ldout(s->cct, 10) << "canonical request hash = " << canonical_req_hash << dendl;
+ }
+ /*
+  * assemble string to sign for signature version 4
+  */
+ void rgw_assemble_s3_v4_string_to_sign(const char *algorithm, const char *request_date,
+                                        const char *credential_scope, const char *hashed_qr, string& dest_str)
+ {
+   string dest;
+   if (algorithm)
+     dest = algorithm;
+   dest.append("\n");
+   if (request_date)
+     dest.append(request_date);
+   dest.append("\n");
+   if (credential_scope)
+     dest.append(credential_scope);
+   dest.append("\n");
+   if (hashed_qr)
+     dest.append(hashed_qr);
+   dest_str = dest;
+ }
+ /*
+  * create string to sign for signature version 4
+  */
+ void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm, const string& request_date,
+                                      const string& credential_scope, const string& hashed_qr,
+                                      string& string_to_sign) {
+   rgw_assemble_s3_v4_string_to_sign(algorithm.c_str(), request_date.c_str(),
+       credential_scope.c_str(), hashed_qr.c_str(), string_to_sign);
+   ldout(cct, 10) << "string to sign = " << string_to_sign << dendl;
+ }
+ /*
+  * calculate the AWS signature version 4
+  */
+ int rgw_calculate_s3_v4_aws_signature(struct req_state *s,
+     const string& access_key_id, const string &date, const string& region,
+     const string& service, const string& string_to_sign, string& signature) {
++  map<string, RGWAccessKey>::iterator iter = s->user->access_keys.find(access_key_id);
++  if (iter == s->user->access_keys.end()) {
+     ldout(s->cct, 10) << "ERROR: access key not encoded in user info" << dendl;
+     return -EPERM;
+   }
+   RGWAccessKey& k = iter->second;
+   string secret_key = "AWS4" + k.key;
+   char secret_k[secret_key.size() * MAX_UTF8_SZ];
+   size_t n = 0;
+   for (size_t i = 0; i < secret_key.size(); i++) {
+     n += encode_utf8(secret_key[i], (unsigned char *) (secret_k + n));
+   }
+   string secret_key_utf8_k(secret_k, n);
+   /* date */
+   char date_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
+   calc_hmac_sha256(secret_key_utf8_k.c_str(), secret_key_utf8_k.size(),
+       date.c_str(), date.size(), date_k);
+   char aux[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE * 2 + 1];
+   buf_to_hex((unsigned char *) date_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);
+   ldout(s->cct, 10) << "date_k        = " << string(aux) << dendl;
+   /* region */
+   char region_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
+   calc_hmac_sha256(date_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, region.c_str(), region.size(), region_k);
+   buf_to_hex((unsigned char *) region_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);
+   ldout(s->cct, 10) << "region_k      = " << string(aux) << dendl;
+   /* service */
+   char service_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
+   calc_hmac_sha256(region_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, service.c_str(), service.size(), service_k);
+   buf_to_hex((unsigned char *) service_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);
+   ldout(s->cct, 10) << "service_k     = " << string(aux) << dendl;
+   /* aws4_request */
+   char signing_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
+   calc_hmac_sha256(service_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, "aws4_request", 12, signing_k);
+   buf_to_hex((unsigned char *) signing_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);
+   ldout(s->cct, 10) << "signing_k     = " << string(aux) << dendl;
+   /* new signature */
+   char signature_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
+   calc_hmac_sha256(signing_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, string_to_sign.c_str(), string_to_sign.size(), signature_k);
+   buf_to_hex((unsigned char *) signature_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);
+   ldout(s->cct, 10) << "signature_k   = " << string(aux) << dendl;
+   signature = string(aux);
+   ldout(s->cct, 10) << "new signature = " << signature << dendl;
+   return 0;
+ }
index 840b2697a353f33bfa0136ecfc64b68a239eb167,b5b49429475a803d4b604a4293dbdb06092aebe0..4e8dd1ca5c8b6fc4567d06ecf1b3b5ad8241ca9d
@@@ -7,16 -7,16 +7,31 @@@
  
  #include "rgw_common.h"
  
 -void rgw_create_s3_canonical_header(const char *method, const char *content_md5, const char *content_type, const char *date,
 -                            map<string, string>& meta_map, const char *request_uri, map<string, string>& sub_resources,
 -                            string& dest_str);
 -bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time, string& dest, bool qsr);
 +void rgw_create_s3_canonical_header(const char *method,
 +                                  const char *content_md5,
 +                                  const char *content_type, const char *date,
 +                                  map<string, string>& meta_map,
 +                                  const char *request_uri,
 +                                  map<string, string>& sub_resources,
 +                                  string& dest_str);
 +bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time,
 +                                  string& dest, bool qsr);
 +int rgw_get_s3_header_digest(const string& auth_hdr, const string& key,
 +                           string& dest);
+ int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& dest);
++
+ void rgw_hash_s3_string_sha256(const char *data, int len, string& dest);
 -void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri, const string& canonical_qs,
 -                                        const string& canonical_hdrs, const string& signed_hdrs, const string& request_payload,
 -                                        bool unsigned_payload, string& canonical_req, string& canonical_req_hash);
 -void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm, const string& request_date, const string& credential_scope, const string& hashed_qr, string& string_to_sign);
 -int rgw_calculate_s3_v4_aws_signature(struct req_state *s, const string& access_key_id, const string &date, const string& region, const string& service, const string& string_to_sign, string& signature);
++void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri,
++                                        const string& canonical_qs, const string& canonical_hdrs,
++                                        const string& signed_hdrs, const string& request_payload,
++                                        bool unsigned_payload,
++                                        string& canonical_req, string& canonical_req_hash);
++void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm,
++                                     const string& request_date, const string& credential_scope,
++                                     const string& hashed_qr, string& string_to_sign);
++int rgw_calculate_s3_v4_aws_signature(struct req_state *s, const string& access_key_id,
++                                      const string &date, const string& region,
++                                      const string& service, const string& string_to_sign,
++                                      string& signature);
  
  #endif
index 26d89259f0ba4e2f7b4f1aa19c5a3249e22516fa,d13dce877dcf6299383d8309b36e47035a4e38fd..b326a61b7faf0517ef7518ea7f310ad328f365bf
@@@ -69,7 -70,8 +69,7 @@@ int RGWStreamIO::write(const char *buf
    return 0;
  }
  
- int RGWStreamIO::read(char *buf, int max, int *actual)
 -
 -int RGWClientIO::read(char *buf, int max, int *actual, bool hash /* = false */)
++int RGWStreamIO::read(char *buf, int max, int *actual, bool hash /* = false */)
  {
    int ret = read_data(buf, max);
    if (ret < 0)
  
    bytes_received += *actual;
  
+   if (hash) {
+     if (!sha256_hash) {
+       sha256_hash = calc_hash_sha256_open_stream();
+     }
+     calc_hash_sha256_update_stream(sha256_hash, buf, *actual);
+   }
    return 0;
  }
 -
 -string RGWClientIO::grab_aws4_sha256_hash()
++string RGWStreamIO::grab_aws4_sha256_hash()
+ {
+   return calc_hash_sha256_close_stream(&sha256_hash);
+ }
index a25b193efa5a6b92e2ea2e9fa131e225a7f4b675,d8dc803a07527309646a3af6c9ee6a018a6a1f61..09cf332b1ecae46fbd24c1eb481f84f279517eb0
@@@ -20,38 -23,15 +20,40 @@@ protected
  
    virtual void init_env(CephContext *cct) = 0;
  
 +public:
 +  virtual ~RGWClientIO() {}
 +  RGWClientIO() : _account(false) {}
 +
 +  void init(CephContext *cct);
 +  RGWEnv& get_env() { return env; }
 +
 +  bool account() { return _account; }
 +  void set_account(bool _accnt) {
 +    _account = _accnt;
 +  }
 +
 +  virtual int complete_request() = 0; /* XXX signature likely changing */
 +
 +  virtual uint64_t get_bytes_sent() { return 0; }
 +  virtual uint64_t get_bytes_received() { return 0; }
 +}; /* RGWClient IO */
 +
 +/* HTTP IO */
 +class RGWStreamIO : public RGWClientIO {
 +
 +  size_t bytes_sent;
 +  size_t bytes_received;
 +
++  SHA256 *sha256_hash;
++
 +protected:
    virtual int write_data(const char *buf, int len) = 0;
    virtual int read_data(char *buf, int max) = 0;
  
  public:
 -  virtual ~RGWClientIO() {}
 -  RGWClientIO() : account(false), bytes_sent(0), bytes_received(0), sha256_hash(NULL) {}
 +  virtual ~RGWStreamIO() {}
-   RGWStreamIO() : bytes_sent(0), bytes_received(0) {}
++  RGWStreamIO() : bytes_sent(0), bytes_received(0), sha256_hash(nullptr) {}
  
 -  void init(CephContext *cct);
    int print(const char *format, ...);
    int write(const char *buf, int len);
    virtual void flush() = 0;
Simple merge
index 3cc3c4b64c979e4f3031cfc1fb8eddc375f7136e,f94c0a485ee2f0333b306125a7bb5ceda37333f6..2ea635a205e1f30938564713a1fd75218e26de4d
@@@ -378,6 -372,48 +379,49 @@@ enum http_op 
    OP_UNKNOWN,
  };
  
+ enum RGWOpType {
+   RGW_OP_UNKNOWN = 0,
+   RGW_OP_GET_OBJ,
+   RGW_OP_LIST_BUCKETS,
+   RGW_OP_STAT_ACCOUNT,
+   RGW_OP_LIST_BUCKET,
+   RGW_OP_GET_BUCKET_LOGGING,
+   RGW_OP_GET_BUCKET_VERSIONING,
+   RGW_OP_SET_BUCKET_VERSIONING,
+   RGW_OP_GET_BUCKET_WEBSITE,
+   RGW_OP_SET_BUCKET_WEBSITE,
+   RGW_OP_STAT_BUCKET,
+   RGW_OP_CREATE_BUCKET,
+   RGW_OP_DELETE_BUCKET,
+   RGW_OP_PUT_OBJ,
++  RGW_OP_STAT_OBJ,
+   RGW_OP_POST_OBJ,
+   RGW_OP_PUT_METADATA_ACCOUNT,
+   RGW_OP_PUT_METADATA_BUCKET,
+   RGW_OP_PUT_METADATA_OBJECT,
+   RGW_OP_SET_TEMPURL,
+   RGW_OP_DELETE_OBJ,
+   RGW_OP_COPY_OBJ,
+   RGW_OP_GET_ACLS,
+   RGW_OP_PUT_ACLS,
+   RGW_OP_GET_CORS,
+   RGW_OP_PUT_CORS,
+   RGW_OP_DELETE_CORS,
+   RGW_OP_OPTIONS_CORS,
+   RGW_OP_GET_REQUEST_PAYMENT,
+   RGW_OP_SET_REQUEST_PAYMENT,
+   RGW_OP_INIT_MULTIPART,
+   RGW_OP_COMPLETE_MULTIPART,
+   RGW_OP_ABORT_MULTIPART,
+   RGW_OP_LIST_MULTIPART,
+   RGW_OP_LIST_BUCKET_MULTIPARTS,
+   RGW_OP_DELETE_MULTI_OBJ,
+   RGW_OP_BULK_DELETE,
+   /* rgw specific */
+   RGW_OP_ADMIN_SET_METADATA
+ };
  class RGWAccessControlPolicy;
  class JSONObj;
  
@@@ -1087,89 -1127,92 +1147,94 @@@ struct req_init_state 
    string src_bucket;
  };
  
 +/* XXX why don't RGWRequest (or descendants) hold this state? */
 +class RGWRequest;
 +
  /** Store all the state necessary to complete and respond to an HTTP request*/
  struct req_state {
 -   CephContext *cct;
 -   RGWClientIO *cio;
 -   http_op op;
 -   RGWOpType op_type;
 -   bool content_started;
 -   int format;
 -   ceph::Formatter *formatter;
 -   string decoded_uri;
 -   string relative_uri;
 -   const char *length;
 -   int64_t content_length;
 -   map<string, string> generic_attrs;
 -   struct rgw_err err;
 -   bool expect_cont;
 -   bool header_ended;
 -   uint64_t obj_size;
 -   bool enable_ops_log;
 -   bool enable_usage_log;
 -   uint8_t defer_to_bucket_acls;
 -   uint32_t perm_mask;
 -   utime_t header_time;
 -
 -   /* Set once when url_bucket is parsed and not violated thereafter. */
 -   string bucket_tenant;
 -   string bucket_name;
 -
 -   rgw_bucket bucket;
 -   rgw_obj_key object;
 -   string src_tenant_name;
 -   string src_bucket_name;
 -   rgw_obj_key src_object;
 -   ACLOwner bucket_owner;
 -   ACLOwner owner;
 -
 -   string region_endpoint;
 -   string bucket_instance_id;
 -
 -   string redirect;
 +  CephContext *cct;
 +  RGWClientIO *cio;
 +  RGWRequest *req; /// XXX: re-remove??
 +  http_op op;
++  RGWOpType op_type;
 +  bool content_started;
 +  int format;
 +  ceph::Formatter *formatter;
 +  string decoded_uri;
 +  string relative_uri;
 +  const char *length;
 +  int64_t content_length;
 +  map<string, string> generic_attrs;
 +  struct rgw_err err;
 +  bool expect_cont;
 +  bool header_ended;
 +  uint64_t obj_size;
 +  bool enable_ops_log;
 +  bool enable_usage_log;
 +  uint8_t defer_to_bucket_acls;
 +  uint32_t perm_mask;
 +  utime_t header_time;
  
 -   RGWBucketInfo bucket_info;
 -   map<string, bufferlist> bucket_attrs;
 -   bool bucket_exists;
 +  /* Set once when url_bucket is parsed and not violated thereafter. */
 +  string bucket_tenant;
 +  string bucket_name;
  
 -   bool has_bad_meta;
 +  rgw_bucket bucket;
 +  rgw_obj_key object;
 +  string src_tenant_name;
 +  string src_bucket_name;
 +  rgw_obj_key src_object;
 +  ACLOwner bucket_owner;
 +  ACLOwner owner;
  
 -   RGWUserInfo user; 
 -   RGWAccessControlPolicy *bucket_acl;
 -   RGWAccessControlPolicy *object_acl;
 +  string zonegroup_name;
 +  string zonegroup_endpoint;
 +  string bucket_instance_id;
 +  int bucket_instance_shard_id;
  
 -   bool system_request;
 +  string redirect;
  
 -   string canned_acl;
 -   bool has_acl_header;
 -   const char *http_auth;
 -   bool local_source; /* source is local */
 +  RGWBucketInfo bucket_info;
 +  map<string, bufferlist> bucket_attrs;
 +  bool bucket_exists;
  
 -   int prot_flags;
 +  bool has_bad_meta;
  
 -   const char *os_auth_token;
 -   string swift_user;
 -   string swift_groups;
 +  RGWUserInfo *user;
  
 -   /* aws4 auth support */
 -   bool   aws4_auth_needs_complete;
 +  RGWAccessControlPolicy *bucket_acl;
 +  RGWAccessControlPolicy *object_acl;
  
 -   rgw_aws4_auth *aws4_auth;
 +  bool system_request;
  
 -   utime_t time;
++  /* aws4 auth support */
++  bool aws4_auth_needs_complete;
++  rgw_aws4_auth *aws4_auth;
 -   void *obj_ctx;
 +  string canned_acl;
 +  bool has_acl_header;
 +  const char *http_auth;
 +  bool local_source; /* source is local */
  
 -   string dialect;
 +  int prot_flags;
  
 -   string req_id;
 +  const char *os_auth_token;
 +  string swift_user;
 +  string swift_groups;
  
 -   string trans_id;
 +  string host_id;
  
 -   string host_id;
 +  req_info info;
 +  req_init_state init_state;
  
 -   req_info info;
 -   req_init_state init_state;
 +  utime_t time;
 +  void *obj_ctx;
 +  string dialect;
 +  string req_id;
 +  string trans_id;
  
 -   req_state(CephContext *_cct, class RGWEnv *e);
 -   ~req_state();
 +  req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u);
 +  ~req_state();
  };
  
  /** Store basic data on an object */
Simple merge
index f3c95ea976c9f3e8ca2f0b57c3ddd6fb34d24e19,4ff45120076c09ca8ca9a0a58db7b5ed22f12833..b4171217c887e29555d2c8fda16720a55f75806f
@@@ -25,7 -25,7 +25,8 @@@
  #include "rgw_multi_del.h"
  #include "rgw_cors.h"
  #include "rgw_cors_s3.h"
 +#include "rgw_rest_conn.h"
+ #include "rgw_rest_s3.h"
  
  #include "rgw_client_io.h"
  
index c977bf2e9673bb4a91703fa654694c59e99cb5b5,6b69c01ea39fd3289732ed7011da3fdf4c22a403..895c2b3991e4fa0694e35ee8d79df96818418bff
@@@ -93,11 -45,12 +53,13 @@@ protected
    RGWQuotaInfo user_quota;
    int op_ret;
  
+   int do_aws4_auth_completion();
    virtual int init_quota();
  public:
 -RGWOp() : s(NULL), dialect_handler(NULL), store(NULL), cors_exist(false),
 -    op_ret(0) {}
 +RGWOp() : s(nullptr), dialect_handler(nullptr), store(nullptr),
 +    cors_exist(false), op_ret(0) {}
 +
    virtual ~RGWOp() {}
  
    int get_ret() const { return op_ret; }
index 5095fe77846a79621d49159afdbeeb53a67bf12d,0000000000000000000000000000000000000000..6a92c49ce673cc9c55aabf1c32bc6c36a4972526
mode 100644,000000..100644
--- /dev/null
@@@ -1,204 -1,0 +1,206 @@@
 +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 +// vim: ts=8 sw=2 smarttab
 +
 +#include "common/errno.h"
 +#include "common/Throttle.h"
 +#include "common/WorkQueue.h"
 +
 +#include "rgw_rados.h"
 +#include "rgw_rest.h"
 +#include "rgw_frontend.h"
 +#include "rgw_request.h"
 +#include "rgw_process.h"
 +#include "rgw_loadgen.h"
 +#include "rgw_client_io.h"
 +
 +#define dout_subsys ceph_subsys_rgw
 +
 +void RGWProcess::RGWWQ::_dump_queue()
 +{
 +  if (!g_conf->subsys.should_gather(ceph_subsys_rgw, 20)) {
 +    return;
 +  }
 +  deque<RGWRequest *>::iterator iter;
 +  if (process->m_req_queue.empty()) {
 +    dout(20) << "RGWWQ: empty" << dendl;
 +    return;
 +  }
 +  dout(20) << "RGWWQ:" << dendl;
 +  for (iter = process->m_req_queue.begin();
 +       iter != process->m_req_queue.end(); ++iter) {
 +    dout(20) << "req: " << hex << *iter << dec << dendl;
 +  }
 +} /* RGWProcess::RGWWQ::_dump_queue */
 +
 +int process_request(RGWRados* store, RGWREST* rest, RGWRequest* req,
 +                  RGWStreamIO* client_io, OpsLogSocket* olog)
 +{
 +  int ret = 0;
 +
 +  client_io->init(g_ceph_context);
 +
 +  req->log_init();
 +
 +  dout(1) << "====== starting new request req=" << hex << req << dec
 +        << " =====" << dendl;
 +  perfcounter->inc(l_rgw_req);
 +
 +  RGWEnv& rgw_env = client_io->get_env();
 +
 +  RGWUserInfo userinfo;
 +
 +  struct req_state rstate(g_ceph_context, &rgw_env, &userinfo);
 +  struct req_state *s = &rstate;
 +
 +  RGWObjectCtx rados_ctx(store, s);
 +  s->obj_ctx = &rados_ctx;
 +
 +  s->req_id = store->unique_id(req->id);
 +  s->trans_id = store->unique_trans_id(req->id);
 +  s->host_id = store->host_id;
 +
 +  req->log_format(s, "initializing for trans_id = %s", s->trans_id.c_str());
 +
 +  RGWOp* op = NULL;
 +  int init_error = 0;
 +  bool should_log = false;
 +  RGWRESTMgr *mgr;
 +  RGWHandler_REST *handler = rest->get_handler(store, s, client_io, &mgr,
 +                                            &init_error);
 +  if (init_error != 0) {
 +    abort_early(s, NULL, init_error, NULL);
 +    goto done;
 +  }
 +  dout(10) << "handler=" << typeid(*handler).name() << dendl;
 +
 +  should_log = mgr->get_logging();
 +
 +  req->log_format(s, "getting op %d", s->op);
 +  op = handler->get_op(store);
 +  if (!op) {
 +    abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED, handler);
 +    goto done;
 +  }
 +  req->op = op;
 +  dout(10) << "op=" << typeid(*op).name() << dendl;
 +
++  s->op_type = op->get_type();
++
 +  req->log(s, "authorizing");
 +  ret = handler->authorize();
 +  if (ret < 0) {
 +    dout(10) << "failed to authorize request" << dendl;
 +    abort_early(s, NULL, ret, handler);
 +    goto done;
 +  }
 +
 +  req->log(s, "normalizing buckets and tenants");
 +  ret = handler->postauth_init();
 +  if (ret < 0) {
 +    dout(10) << "failed to run post-auth init" << dendl;
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +
 +  if (s->user->suspended) {
 +    dout(10) << "user is suspended, uid=" << s->user->user_id << dendl;
 +    abort_early(s, op, -ERR_USER_SUSPENDED, handler);
 +    goto done;
 +  }
 +
 +  req->log(s, "init permissions");
 +  ret = handler->init_permissions(op);
 +  if (ret < 0) {
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +
 +  /**
 +   * Only some accesses support website mode, and website mode does NOT apply
 +   * if you are using the REST endpoint either (ergo, no authenticated access)
 +   */
 +  req->log(s, "recalculating target");
 +  ret = handler->retarget(op, &op);
 +  if (ret < 0) {
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +  req->op = op;
 +
 +  req->log(s, "reading permissions");
 +  ret = handler->read_permissions(op);
 +  if (ret < 0) {
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +
 +  req->log(s, "init op");
 +  ret = op->init_processing();
 +  if (ret < 0) {
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +
 +  req->log(s, "verifying op mask");
 +  ret = op->verify_op_mask();
 +  if (ret < 0) {
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +
 +  req->log(s, "verifying op permissions");
 +  ret = op->verify_permission();
 +  if (ret < 0) {
 +    if (s->system_request) {
 +      dout(2) << "overriding permissions due to system operation" << dendl;
 +    } else {
 +      abort_early(s, op, ret, handler);
 +      goto done;
 +    }
 +  }
 +
 +  req->log(s, "verifying op params");
 +  ret = op->verify_params();
 +  if (ret < 0) {
 +    abort_early(s, op, ret, handler);
 +    goto done;
 +  }
 +
 +  req->log(s, "pre-executing");
 +  op->pre_exec();
 +
 +  req->log(s, "executing");
 +  op->execute();
 +
 +  req->log(s, "completing");
 +  op->complete();
 +done:
 +  int r = client_io->complete_request();
 +  if (r < 0) {
 +    dout(0) << "ERROR: client_io->complete_request() returned " << r << dendl;
 +  }
 +  if (should_log) {
 +    rgw_log_op(store, s, (op ? op->name() : "unknown"), olog);
 +  }
 +
 +  int http_ret = s->err.http_ret;
 +  int op_ret = 0;
 +  if (op) {
 +    op_ret = op->get_ret();
 +  }
 +
 +  req->log_format(s, "op status=%d", op_ret);
 +  req->log_format(s, "http status=%d", http_ret);
 +
 +  if (handler)
 +    handler->put_op(op);
 +  rest->put_handler(handler);
 +
 +  dout(1) << "====== req done req=" << hex << req << dec
 +        << " op status=" << op_ret
 +        << " http_status=" << http_ret
 +        << " ======"
 +        << dendl;
 +
 +  return (ret < 0 ? ret : s->err.ret);
 +} /* process_request */
index c418f358b9d5c2199e858151a1f93589e5404105,a7f306ee806bdc619239beebf44106bc124aaa23..fa119947c3a91cffb792c7e57c5f8bac0c499421
@@@ -1001,7 -970,7 +1001,7 @@@ int RGWPutObj_ObjStore::get_data(buffer
      bufferptr bp(cl);
  
      int read_len; /* cio->read() expects int * */
-     int r = STREAM_IO(s)->read(bp.c_str(), cl, &read_len);
 -    int r = s->cio->read(bp.c_str(), cl, &read_len, true);
++    int r = STREAM_IO(s)->read(bp.c_str(), cl, &read_len, true);
      len = read_len;
      if (r < 0)
        return r;
@@@ -1046,7 -1015,7 +1046,7 @@@ int RGWPutACLs_ObjStore::get_params(
         return op_ret;
      }
      int read_len;
-     int r = STREAM_IO(s)->read(data, cl, &read_len);
 -    int r = s->cio->read(data, cl, &read_len, s->aws4_auth_needs_complete);
++    int r = STREAM_IO(s)->read(data, cl, &read_len, s->aws4_auth_needs_complete);
      len = read_len;
      if (r < 0)
        return r;
@@@ -1071,7 -1039,7 +1071,7 @@@ static int read_all_chunked_input(req_s
  
    int read_len = 0, len = 0;
    do {
-     int r = STREAM_IO(s)->read(data + len, need_to_read, &read_len);
 -    int r = s->cio->read(data + len, need_to_read, &read_len, s->aws4_auth_needs_complete);
++    int r = STREAM_IO(s)->read(data + len, need_to_read, &read_len, s->aws4_auth_needs_complete);
      if (r < 0) {
        free(data);
        return r;
@@@ -1125,7 -1092,7 +1125,7 @@@ int rgw_rest_read_all_input(struct req_
      if (!data) {
         return -ENOMEM;
      }
-     int ret = STREAM_IO(s)->read(data, cl, &len);
 -    int ret = s->cio->read(data, cl, &len, s->aws4_auth_needs_complete);
++    int ret = STREAM_IO(s)->read(data, cl, &len, s->aws4_auth_needs_complete);
      if (ret < 0) {
        free(data);
        return ret;
@@@ -1230,7 -1198,7 +1230,7 @@@ int RGWDeleteMultiObj_ObjStore::get_par
        return op_ret;
      }
      int read_len;
-     op_ret = STREAM_IO(s)->read(data, cl, &read_len);
 -    op_ret = s->cio->read(data, cl, &read_len, s->aws4_auth_needs_complete);
++    op_ret = STREAM_IO(s)->read(data, cl, &read_len, s->aws4_auth_needs_complete);
      len = read_len;
      if (op_ret < 0)
        return op_ret;
Simple merge
index 13a9aba566e648c1cc94a2f455d29e6eb0cc32c2,3cbb7d77a6dc3a9ee49e21d2201719ee66378aa6..1794fbd7b3fd4517047f63b773320d08fd4e37b0
@@@ -160,8 -158,15 +160,15 @@@ void RGWOp_Metadata_Put::execute() 
      return;
    }
  
+   if (s->aws4_auth_needs_complete) {
+     http_ret = do_aws4_auth_completion();
+     if (http_ret < 0) {
+       return;
+     }
+   }
+   
    frame_metadata_key(s, metadata_key);
 -  
 +
    RGWMetadataHandler::sync_type_t sync_type = RGWMetadataHandler::APPLY_ALWAYS;
  
    bool mode_exists = false;
Simple merge
index 41118414c813e29d0a326e649f74c84adbcd07ae,72afee8800c1ca8656575d5e17da7c409ca83679..105ad8711b8ba829eb2d4148027f3c255d1a46df
@@@ -1836,12 -1725,24 +1864,26 @@@ void RGWGetACLs_ObjStore_S3::send_respo
    end_header(s, this, "application/xml");
    dump_start(s);
    rgw_flush_formatter(s, s->formatter);
 -  s->cio->write(acls.c_str(), acls.size());
 +  STREAM_IO(s)->write(acls.c_str(), acls.size());
  }
  
 -int RGWPutACLs_ObjStore_S3::get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss)
+ int RGWPutACLs_ObjStore_S3::get_params()
+ {
+   int ret =  RGWPutACLs_ObjStore::get_params();
+   if (ret < 0)
+     s->aws4_auth_needs_complete = false;
+   if (s->aws4_auth_needs_complete) {
+     int ret_auth = do_aws4_auth_completion();
+     if (ret_auth < 0) {
+       return ret_auth;
+     }
+   }
+   return ret;
+ }
 +int RGWPutACLs_ObjStore_S3::get_policy_from_state(RGWRados *store,
 +                                                struct req_state *s,
 +                                                stringstream& ss)
  {
    RGWAccessControlPolicy_S3 s3policy(s->cct);
  
@@@ -1910,7 -1810,7 +1952,7 @@@ int RGWPutCORS_ObjStore_S3::get_params(
         goto done_err;
      }
      int read_len;
-     r = STREAM_IO(s)->read(data, cl, &read_len);
 -    r = s->cio->read(data, cl, &read_len, s->aws4_auth_needs_complete);
++    r = STREAM_IO(s)->read(data, cl, &read_len, s->aws4_auth_needs_complete);
      len = read_len;
      if (r < 0)
        goto done_err;
@@@ -2780,24 -2737,601 +2857,601 @@@ int RGW_Auth_S3::authorize(RGWRados *st
    }
  
    if (!s->http_auth || !(*s->http_auth)) {
-     auth_id = s->info.args.get("AWSAccessKeyId");
+     /* AWS4 */
+     string algorithm = s->info.args.get("X-Amz-Algorithm");
+     if (algorithm.size()) {
+       if (algorithm != "AWS4-HMAC-SHA256") {
+         return -EPERM;
+       }
+       return authorize_v4(store, s);
+     }
+     /* AWS2 */
+     string auth_id = s->info.args.get("AWSAccessKeyId");
      if (auth_id.size()) {
-       auth_sign = s->info.args.get("Signature");
+       return authorize_v2(store, s);
+     }
  
-       string date = s->info.args.get("Expires");
-       time_t exp = atoll(date.c_str());
-       if (now >= exp)
-       return -EPERM;
+     /* anonymous access */
  
-       qsr = true;
-     } else {
-       /* anonymous access */
-       init_anon_user(s);
-       return 0;
+     init_anon_user(s);
+     return 0;
+   } else {
+     /* AWS4 */
+     if (!strncmp(s->http_auth, "AWS4-HMAC-SHA256", 16)) {
+       return authorize_v4(store, s);
+     }
+     /* AWS2 */
+     if (!strncmp(s->http_auth, "AWS ", 4)) {
+       return authorize_v2(store, s);
+     }
+   }
+   return -EINVAL;
+ }
+ int RGW_Auth_S3::authorize_aws4_auth_complete(RGWRados *store, struct req_state *s)
+ {
+   return authorize_v4_complete(store, s, "", false);
+ }
+ int RGW_Auth_S3::authorize_v4_complete(RGWRados *store, struct req_state *s, const string& request_payload, bool unsigned_payload)
+ {
+   size_t pos;
+   /* craft canonical request */
+   string canonical_req;
+   string canonical_req_hash;
+   rgw_create_s3_v4_canonical_request(s, s->aws4_auth->canonical_uri, s->aws4_auth->canonical_qs,
+       s->aws4_auth->canonical_hdrs, s->aws4_auth->signed_hdrs, request_payload, unsigned_payload,
+       canonical_req, canonical_req_hash);
+   /* Validate x-amz-sha256 */
+   if (s->aws4_auth_needs_complete) {
+     const char *expected_request_payload_hash = s->info.env->get("HTTP_X_AMZ_CONTENT_SHA256");
+     if (expected_request_payload_hash &&
+       s->aws4_auth->payload_hash.compare(expected_request_payload_hash) != 0) {
+       ldout(s->cct, 10) << "ERROR: x-amz-content-sha256 does not match" << dendl;
+       return -ERR_AMZ_CONTENT_SHA256_MISMATCH;
+     }
+   }
+   /*
+    * create a string to sign
+    *
+    * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
+    */
+   string string_to_sign;
+   rgw_create_s3_v4_string_to_sign(s->cct, "AWS4-HMAC-SHA256", s->aws4_auth->date, s->aws4_auth->credential_scope,
+       canonical_req_hash, string_to_sign);
+   /*
+    * calculate the AWS signature
+    *
+    * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
+    */
+   string cs_aux = s->aws4_auth->credential_scope;
+   string date_cs = cs_aux;
+   pos = date_cs.find("/");
+   date_cs = date_cs.substr(0, pos);
+   cs_aux = cs_aux.substr(pos + 1, cs_aux.length());
+   string region_cs = cs_aux;
+   pos = region_cs.find("/");
+   region_cs = region_cs.substr(0, pos);
+   cs_aux = cs_aux.substr(pos + 1, cs_aux.length());
+   string service_cs = cs_aux;
+   pos = service_cs.find("/");
+   service_cs = service_cs.substr(0, pos);
+   int err = rgw_calculate_s3_v4_aws_signature(s, s->aws4_auth->access_key_id, date_cs,
+       region_cs, service_cs, string_to_sign, s->aws4_auth->new_signature);
+   ldout(s->cct, 10) << "----------------------------- Verifying signatures" << dendl;
+   ldout(s->cct, 10) << "Signature     = " << s->aws4_auth->signature << dendl;
+   ldout(s->cct, 10) << "New Signature = " << s->aws4_auth->new_signature << dendl;
+   ldout(s->cct, 10) << "-----------------------------" << dendl;
+   if (err) {
+     return err;
+   }
+   return 0;
+ }
+ static inline bool is_base64_for_content_md5(unsigned char c) {
+   return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '='));
+ }
+ static bool char_needs_aws4_escaping(char c)
+ {
+   if ((c >= 'a' && c <= 'z') ||
+       (c >= 'A' && c <= 'Z') ||
+       (c >= '0' && c <= '9')) {
+     return false;
+   }
+   switch (c) {
+     case '-':
+     case '_':
+     case '.':
+     case '~':
+       return false;
+   }
+   return true;
+ }
+ static void aws4_uri_encode(const string& src, string& dst)
+ {
+   const char *p = src.c_str();
+   for (unsigned i = 0; i < src.size(); i++, p++) {
+     if (char_needs_aws4_escaping(*p)) {
+       rgw_uri_escape_char(*p, dst);
+       continue;
+     }
+     dst.append(p, 1);
+   }
+ }
+ /*
+  * handle v4 signatures (rados auth only)
+  */
+ int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s)
+ {
+   string::size_type pos;
+   bool using_qs;
+   time_t now, now_req=0;
+   time(&now);
+   /* v4 requires rados auth */
+   if (!store->ctx()->_conf->rgw_s3_auth_use_rados) {
+     return -EPERM;
+   }
+   string algorithm = "AWS4-HMAC-SHA256";
+   s->aws4_auth = new rgw_aws4_auth;
+   if ((!s->http_auth) || !(*s->http_auth)) {
+     /* auth ships with req params ... */
+     /* look for required params */
+     using_qs = true;
+     s->aws4_auth->credential = s->info.args.get("X-Amz-Credential");
+     if (s->aws4_auth->credential.size() == 0) {
+       return -EPERM;
+     }
+     s->aws4_auth->date = s->info.args.get("X-Amz-Date");
+     struct tm date_t;
+     if (!parse_iso8601(s->aws4_auth->date.c_str(), &date_t, false))
+       return -EPERM;
+     s->aws4_auth->expires = s->info.args.get("X-Amz-Expires");
+     if (s->aws4_auth->expires.size() != 0) {
+       /* X-Amz-Expires provides the time period, in seconds, for which
+          the generated presigned URL is valid. The minimum value
+          you can set is 1, and the maximum is 604800 (seven days) */
+       time_t exp = atoll(s->aws4_auth->expires.c_str());
+       if ((exp < 1) || (exp > 604800)) {
+         dout(10) << "NOTICE: exp out of range, exp = " << exp << dendl;
+         return -EPERM;
+       }
+       /* handle expiration in epoch time */
+       now_req = mktime(&date_t);
+       if (now >= now_req + exp) {
+         dout(10) << "NOTICE: now = " << now << ", now_req = " << now_req << ", exp = " << exp << dendl;
+         return -EPERM;
+       }
+     }
+     if ( (now_req < now - RGW_AUTH_GRACE_MINS * 60) ||
+          (now_req > now + RGW_AUTH_GRACE_MINS * 60) ) {
+       dout(10) << "NOTICE: request time skew too big." << dendl;
+       dout(10) << "now_req = " << now_req << " now = " << now << "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60 << "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60 << dendl;
+       return -ERR_REQUEST_TIME_SKEWED;
      }
+     s->aws4_auth->signedheaders = s->info.args.get("X-Amz-SignedHeaders");
+     if (s->aws4_auth->signedheaders.size() == 0) {
+       return -EPERM;
+     }
+     s->aws4_auth->signature = s->info.args.get("X-Amz-Signature");
+     if (s->aws4_auth->signature.size() == 0) {
+       return -EPERM;
+     }
    } else {
-     if (strncmp(s->http_auth, "AWS ", 4))
+     /* auth ships in headers ... */
+     /* ------------------------- handle Credential header */
+     using_qs = false;
+     s->aws4_auth->credential = s->http_auth;
+     s->aws4_auth->credential = s->aws4_auth->credential.substr(17, s->aws4_auth->credential.length());
+     pos = s->aws4_auth->credential.find("Credential");
+     if (pos == std::string::npos) {
+       return -EINVAL;
+     }
+     s->aws4_auth->credential = s->aws4_auth->credential.substr(pos, s->aws4_auth->credential.find(","));
+     s->aws4_auth->credential = s->aws4_auth->credential.substr(pos + 1, s->aws4_auth->credential.length());
+     pos = s->aws4_auth->credential.find("=");
+     s->aws4_auth->credential = s->aws4_auth->credential.substr(pos + 1, s->aws4_auth->credential.length());
+     /* ------------------------- handle SignedHeaders header */
+     s->aws4_auth->signedheaders = s->http_auth;
+     s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(17, s->aws4_auth->signedheaders.length());
+     pos = s->aws4_auth->signedheaders.find("SignedHeaders");
+     if (pos == std::string::npos) {
+       return -EINVAL;
+     }
+     s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(pos, s->aws4_auth->signedheaders.length());
+     pos = s->aws4_auth->signedheaders.find(",");
+     if (pos == std::string::npos) {
+       return -EINVAL;
+     }
+     s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(0, pos);
+     pos = s->aws4_auth->signedheaders.find("=");
+     if (pos == std::string::npos) {
        return -EINVAL;
 -  if (rgw_get_user_info_by_access_key(store, s->aws4_auth->access_key_id, s->user) < 0) {
+     }
+     s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(pos + 1, s->aws4_auth->signedheaders.length());
+     /* host;user-agent;x-amz-content-sha256;x-amz-date */
+     dout(10) << "v4 signedheaders format = " << s->aws4_auth->signedheaders << dendl;
+     /* ------------------------- handle Signature header */
+     s->aws4_auth->signature = s->http_auth;
+     s->aws4_auth->signature = s->aws4_auth->signature.substr(17, s->aws4_auth->signature.length());
+     pos = s->aws4_auth->signature.find("Signature");
+     if (pos == std::string::npos) {
+       return -EINVAL;
+     }
+     s->aws4_auth->signature = s->aws4_auth->signature.substr(pos, s->aws4_auth->signature.length());
+     pos = s->aws4_auth->signature.find("=");
+     if (pos == std::string::npos) {
+       return -EINVAL;
+     }
+     s->aws4_auth->signature = s->aws4_auth->signature.substr(pos + 1, s->aws4_auth->signature.length());
+     /* sig hex str */
+     dout(10) << "v4 signature format = " << s->aws4_auth->signature << dendl;
+     /* ------------------------- handle x-amz-date header */
+     /* grab date */
+     const char *d = s->info.env->get("HTTP_X_AMZ_DATE");
+     struct tm t;
+     if (!parse_iso8601(d, &t, false)) {
+       dout(10) << "error reading date via http_x_amz_date" << dendl;
+       return -EACCES;
+     }
+     s->aws4_auth->date = d;
+   }
+   /* AKIAIVKTAZLOCF43WNQD/AAAAMMDD/region/host/aws4_request */
+   dout(10) << "v4 credential format = " << s->aws4_auth->credential << dendl;
+   if (std::count(s->aws4_auth->credential.begin(), s->aws4_auth->credential.end(), '/') != 4) {
+     return -EINVAL;
+   }
+   /* credential must end with 'aws4_request' */
+   if (s->aws4_auth->credential.find("aws4_request") == std::string::npos) {
+     return -EINVAL;
+   }
+   /* grab access key id */
+   pos = s->aws4_auth->credential.find("/");
+   s->aws4_auth->access_key_id = s->aws4_auth->credential.substr(0, pos);
+   dout(10) << "access key id = " << s->aws4_auth->access_key_id << dendl;
+   /* grab credential scope */
+   s->aws4_auth->credential_scope = s->aws4_auth->credential.substr(pos + 1, s->aws4_auth->credential.length());
+   dout(10) << "credential scope = " << s->aws4_auth->credential_scope << dendl;
+   /* grab user information */
 -  map<string, RGWAccessKey>::iterator iter = s->user.access_keys.find(s->aws4_auth->access_key_id);
 -  if (iter == s->user.access_keys.end()) {
++  if (rgw_get_user_info_by_access_key(store, s->aws4_auth->access_key_id, *s->user) < 0) {
+     dout(10) << "error reading user info, uid=" << s->aws4_auth->access_key_id
+               << " can't authenticate" << dendl;
+     return -ERR_INVALID_ACCESS_KEY;
+   }
+   /*
+    * create a canonical request
+    *
+    * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
+    */
+   /* craft canonical uri */
+   /* here code should normalize via rfc3986 but S3 does **NOT** do path normalization
+    * that SigV4 typically does. this code follows the same approach that boto library
+    * see auth.py:canonical_uri(...) */
+   s->aws4_auth->canonical_uri = s->info.request_uri;
+   if (s->aws4_auth->canonical_uri.empty()) {
+     s->aws4_auth->canonical_uri = "/";
+   }
+   /* craft canonical query string */
+   s->aws4_auth->canonical_qs = s->info.request_params;
+   if (!s->aws4_auth->canonical_qs.empty()) {
+     /* handle case when query string exists. Step 3 in
+      * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html */
+     map<string, string> canonical_qs_map;
+     istringstream cqs(s->aws4_auth->canonical_qs);
+     string keyval;
+     while (getline(cqs, keyval, '&')) {
+       string key, val;
+       istringstream kv(keyval);
+       getline(kv, key, '=');
+       getline(kv, val, '=');
+       if (!using_qs || key != "X-Amz-Signature") {
+         string encoded_key;
+         string encoded_val;
+         if (key != "X-Amz-Credential") {
+           aws4_uri_encode(key, encoded_key);
+           aws4_uri_encode(val, encoded_val);
+         } else {
+           encoded_key = key;
+           encoded_val = val;
+         }
+         canonical_qs_map[encoded_key] = encoded_val;
+       }
+     }
+     s->aws4_auth->canonical_qs = "";
+     map<string, string>::iterator last = canonical_qs_map.end();
+     --last;
+     for (map<string, string>::iterator it = canonical_qs_map.begin();
+         it != canonical_qs_map.end(); ++it) {
+       s->aws4_auth->canonical_qs.append(it->first + "=" + it->second);
+       if (it != last) {
+         s->aws4_auth->canonical_qs.append("&");
+       }
+     }
+   }
+   /* craft canonical headers */
+   map<string, string> canonical_hdrs_map;
+   istringstream sh(s->aws4_auth->signedheaders);
+   string token;
+   string port = s->info.env->get("SERVER_PORT");
+   while (getline(sh, token, ';')) {
+     string token_env = "HTTP_" + token;
+     transform(token_env.begin(), token_env.end(), token_env.begin(), ::toupper);
+     replace(token_env.begin(), token_env.end(), '-', '_');
+     if (token_env == "HTTP_CONTENT_LENGTH") {
+       token_env = "CONTENT_LENGTH";
+     }
+     if (token_env == "HTTP_CONTENT_TYPE") {
+       token_env = "CONTENT_TYPE";
+     }
+     const char *t = s->info.env->get(token_env.c_str());
+     if (!t) {
+       dout(10) << "warning env var not available" << dendl;
+       continue;
+     }
+     if (token_env == "HTTP_CONTENT_MD5") {
+       for (const char *p = t; *p; p++) {
+       if (!is_base64_for_content_md5(*p)) {
+         dout(0) << "NOTICE: bad content-md5 provided (not base64), aborting request p=" << *p << " " << (int)*p << dendl;
+         return -EPERM;
+       }
+       }
+     }
+     string token_value = string(t);
+     if (using_qs && (token == "host"))
+       token_value = token_value + ":" + port;
+     canonical_hdrs_map[token] = rgw_trim_whitespace(token_value);
+   }
+   for (map<string, string>::iterator it = canonical_hdrs_map.begin();
+       it != canonical_hdrs_map.end(); ++it) {
+     s->aws4_auth->canonical_hdrs.append(it->first + ":" + it->second + "\n");
+   }
+   dout(10) << "canonical headers format = " << s->aws4_auth->canonical_hdrs << dendl;
+   /* craft signed headers */
+   s->aws4_auth->signed_hdrs = s->aws4_auth->signedheaders;
+   /* handle request payload */
+   /* from rfc2616 - 4.3 Message Body
+    *
+    * "The presence of a message-body in a request is signaled by the inclusion of a
+    *  Content-Length or Transfer-Encoding header field in the request's message-headers."
+    */
+   s->aws4_auth->payload_hash = "";
+   string request_payload;
+   bool unsigned_payload = false;
+   if (using_qs) {
+     unsigned_payload = true;
+   }
+   if (using_qs || ((s->content_length == 0) && s->info.env->get("HTTP_TRANSFER_ENCODING") == NULL)) {
+     /* requests lacking of body are authenticated now */
+     /* complete aws4 auth */
+     int err = authorize_v4_complete(store, s, request_payload, unsigned_payload);
+     if (err) {
+       return err;
+     }
+     /* verify signature */
+     if (s->aws4_auth->signature != s->aws4_auth->new_signature) {
+       return -ERR_SIGNATURE_NO_MATCH;
+     }
+     /* authorization ok */
+     dout(10) << "v4 auth ok" << dendl;
+     /* aws4 auth completed */
+     s->aws4_auth_needs_complete = false;
+   } else {
+     /* aws4 auth not completed... delay aws4 auth */
+     dout(10) << "body content detected... delaying v4 auth" << dendl;
+     switch (s->op_type)
+     {
+       case RGW_OP_CREATE_BUCKET:
+       case RGW_OP_PUT_OBJ:
+       case RGW_OP_PUT_ACLS:
+       case RGW_OP_PUT_CORS:
+       case RGW_OP_COMPLETE_MULTIPART:
+       case RGW_OP_SET_BUCKET_VERSIONING:
+       case RGW_OP_DELETE_MULTI_OBJ:
+       case RGW_OP_ADMIN_SET_METADATA:
+         break;
+       default:
+         dout(10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED" << dendl;
+         return -ERR_NOT_IMPLEMENTED;
+     }
+     s->aws4_auth_needs_complete = true;
+   }
 -    map<string, RGWSubUser>::iterator uiter = s->user.subusers.find(k.subuser);
 -    if (uiter == s->user.subusers.end()) {
++  map<string, RGWAccessKey>::iterator iter = s->user->access_keys.find(s->aws4_auth->access_key_id);
++  if (iter == s->user->access_keys.end()) {
+     dout(0) << "ERROR: access key not encoded in user info" << dendl;
+     return -EPERM;
+   }
+   RGWAccessKey& k = iter->second;
+   if (!k.subuser.empty()) {
 -  if (s->user.system) {
++    map<string, RGWSubUser>::iterator uiter = s->user->subusers.find(k.subuser);
++    if (uiter == s->user->subusers.end()) {
+       dout(0) << "NOTICE: could not find subuser: " << k.subuser << dendl;
+       return -EPERM;
+     }
+     RGWSubUser& subuser = uiter->second;
+     s->perm_mask = subuser.perm_mask;
+   } else {
+     s->perm_mask = RGW_PERM_FULL_CONTROL;
+   }
 -      s->user = effective_user;
++  if (s->user->system) {
+     s->system_request = true;
+     dout(20) << "system request" << dendl;
+     s->info.args.set_system();
+     string euid = s->info.args.get(RGW_SYS_PARAM_PREFIX "uid");
+     rgw_user effective_uid(euid);
+     RGWUserInfo effective_user;
+     if (!effective_uid.empty()) {
+       int ret = rgw_get_user_info_by_uid(store, effective_uid, effective_user);
+       if (ret < 0) {
+         ldout(s->cct, 0) << "User lookup failed!" << dendl;
+         return -ENOENT;
+       }
 -  s->owner.set_id(s->user.user_id);
 -  s->owner.set_name(s->user.display_name);
++      *(s->user) = effective_user;
+     }
+   }
+   // populate the owner info
++  s->owner.set_id(s->user->user_id);
++  s->owner.set_name(s->user->display_name);
+   return 0;
+ }
+ /*
+  * handle v2 signatures
+  */
+ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
+ {
+   bool qsr = false;
+   string auth_id;
+   string auth_sign;
+   time_t now;
+   time(&now);
+   if (!s->http_auth || !(*s->http_auth)) {
+     auth_id = s->info.args.get("AWSAccessKeyId");
+     auth_sign = s->info.args.get("Signature");
+     string date = s->info.args.get("Expires");
+     time_t exp = atoll(date.c_str());
+     if (now >= exp)
+       return -EPERM;
+     qsr = true;
+   } else {
      string auth_str(s->http_auth + 4);
      int pos = auth_str.rfind(':');
      if (pos < 0)
index a97b82fe1cddfd3403c9ff45d1161619a38f00d0,5417de8d7041ead7ec9e12b7da5a4bba45e63369..7c70ec1481a9b167ac3535c231fbde48ddef2cec
@@@ -390,12 -390,19 +394,19 @@@ public
  class RGW_Auth_S3 {
  public:
    static int authorize(RGWRados *store, struct req_state *s);
+   static int authorize_aws4_auth_complete(RGWRados *store, struct req_state *s);
+ private:
+   static int authorize_v2(RGWRados *store, struct req_state *s);
+   static int authorize_v4(RGWRados *store, struct req_state *s);
+   static int authorize_v4_complete(RGWRados *store, struct req_state *s,
+                                    const string& request_payload, bool unsigned_payload);
  };
  
 -class RGWHandler_Auth_S3 : public RGWHandler_ObjStore {
 +class RGWHandler_Auth_S3 : public RGWHandler_REST {
    friend class RGWRESTMgr_S3;
  public:
 -  RGWHandler_Auth_S3() : RGWHandler_ObjStore() {}
 +  RGWHandler_Auth_S3() : RGWHandler_REST() {}
    virtual ~RGWHandler_Auth_S3() {}
  
    virtual int validate_bucket_name(const string& bucket) {