int RGWPostObj_ObjStore_S3::get_policy()
{
if (part_bl(parts, "policy", &s->auth.s3_postobj_creds.encoded_policy)) {
- // check that the signature matches the encoded policy
- if (!part_str(parts, "AWSAccessKeyId",
- &s->auth.s3_postobj_creds.access_key)) {
- ldout(s->cct, 0) << "No S3 access key found!" << dendl;
- err_msg = "Missing access key";
- return -EINVAL;
+ bool aws4_auth = false;
+
+ /* x-amz-algorithm handling */
+ string x_amz_algorithm;
+ if ((part_str(parts, "x-amz-algorithm", &x_amz_algorithm)) &&
+ (x_amz_algorithm.compare("AWS4-HMAC-SHA256") == 0)) {
+ ldout(s->cct, 0) << "Signature verification algorithm AWS v4 (AWS4-HMAC-SHA256)" << dendl;
+ aws4_auth = true;
+ } else {
+ ldout(s->cct, 0) << "Signature verification algorithm AWS v2" << dendl;
}
- if (!part_str(parts, "signature", &s->auth.s3_postobj_creds.signature)) {
- ldout(s->cct, 0) << "No signature found!" << dendl;
- err_msg = "Missing signature";
- return -EINVAL;
- }
+ // check that the signature matches the encoded policy
- /* FIXME: this is a makeshift solution. The browser upload authentication will be
- * handled by an instance of rgw::auth::Completer spawned in Handler's authorize()
- * method. */
- const auto& strategy = auth_registry_ptr->get_s3_post();
- try {
- auto result = strategy.authenticate(s);
- if (result.get_status() != decltype(result)::Status::GRANTED) {
+ if (aws4_auth) {
+
+ /* AWS4 */
+
+ string s3_access_key;
+
+ string received_credential_str;
+ string date_cs;
+ string region_cs;
+ string service_cs;
+
+ string received_signature_str;
+ string received_date_str;
+
+ /* x-amz-credential handling */
+ if (!part_str(parts, "x-amz-credential", &received_credential_str)) {
+ ldout(s->cct, 0) << "No S3 aws4 credential found!" << dendl;
+ err_msg = "Missing aws4 credential";
+ return -EINVAL;
+ }
+ size_t pos;
+ string cs_aux = received_credential_str;
+ /* s3_access_key */
+ s3_access_key = cs_aux;
+ pos = s3_access_key.find("/");
+ s3_access_key = s3_access_key.substr(0, pos);
+ cs_aux = cs_aux.substr(pos + 1, cs_aux.length());
+ /* date cred */
+ 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());
+ /* region cred */
+ 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());
+ /* service cred */
+ service_cs = cs_aux;
+ pos = service_cs.find("/");
+ service_cs = service_cs.substr(0, pos);
+ /* x-amz-signature handling */
+ if (!part_str(parts, "x-amz-signature", &received_signature_str)) {
+ ldout(s->cct, 0) << "No aws4 signature found!" << dendl;
+ err_msg = "Missing aws4 signature";
+ return -EINVAL;
+ }
+ /* x-amz-date handling */
+ if (!part_str(parts, "x-amz-date", &received_date_str)) {
+ ldout(s->cct, 0) << "No aws4 date found!" << dendl;
+ err_msg = "Missing aws4 date";
+ return -EINVAL;
+ }
+
+ RGWUserInfo user_info;
+ op_ret = rgw_get_user_info_by_access_key(store, s3_access_key, user_info);
+ if (op_ret < 0) {
return -EACCES;
+ } else {
+ map<string, RGWAccessKey> access_keys = user_info.access_keys;
+ map<string, RGWAccessKey>::const_iterator iter = access_keys.find(s3_access_key);
+ // We know the key must exist, since the user was returned by
+ // rgw_get_user_info_by_access_key, but it doesn't hurt to check!
+ if (iter == access_keys.end()) {
+ ldout(s->cct, 0) << "Secret key lookup failed!" << dendl;
+ err_msg = "No secret key for matching access key";
+ return -EACCES;
+ }
+ string s3_secret_key = (iter->second).key;
+
+ /* AWS4 */
+
+ try {
+ s->aws4_auth = std::unique_ptr<rgw_aws4_auth>(new rgw_aws4_auth);
+ } catch (std::bad_alloc&) {
+ return -ENOMEM;
+ }
+
+ std::string encoded_policy_str(s->auth.s3_postobj_creds.encoded_policy.c_str(),
+ s->auth.s3_postobj_creds.encoded_policy.length());
+ std::string new_signature_str;
+
+ int err = rgw_calculate_s3_v4_aws_signature(s, s3_access_key,
+ date_cs, region_cs, service_cs,
+ encoded_policy_str, new_signature_str,
+ s3_secret_key);
+ if (err) {
+ return err;
+ }
+
+ ldout(s->cct, 10) << "----------------------------- Verifying signatures" << dendl;
+ ldout(s->cct, 10) << "Signature = " << received_signature_str << dendl;
+ ldout(s->cct, 10) << "New Signature = " << new_signature_str << dendl;
+ ldout(s->cct, 10) << "-----------------------------" << dendl;
+
+ if (received_signature_str != new_signature_str) {
+ return -ERR_SIGNATURE_NO_MATCH;
+ }
+ }
+
+ /* Deep copy. */
+ *(s->user) = user_info;
+ s->owner.set_id(user_info.user_id);
+ s->owner.set_name(user_info.display_name);
+
+ /* FIXME: remove this after switching S3 to the new authentication
+ * infrastructure. */
+ s->auth.identity = rgw::auth::transform_old_authinfo(s);
+ } else {
+
+ /* AWS2 */
+
+ // check that the signature matches the encoded policy
+ if (!part_str(parts, "AWSAccessKeyId",
+ &s->auth.s3_postobj_creds.access_key)) {
+ ldout(s->cct, 0) << "No S3 aws2 access key found!" << dendl;
+ err_msg = "Missing aws2 access key";
+ return -EINVAL;
+ }
+
+ if (!part_str(parts, "signature", &s->auth.s3_postobj_creds.signature)) {
+ ldout(s->cct, 0) << "No aws2 signature found!" << dendl;
+ err_msg = "Missing aws2 signature";
+ return -EINVAL;
}
+ /* FIXME: this is a makeshift solution. The browser upload authentication will be
+ * handled by an instance of rgw::auth::Completer spawned in Handler's authorize()
+ * method. */
+ const auto& strategy = auth_registry_ptr->get_s3_post();
try {
- auto applier = result.get_applier();
+ auto result = strategy.authenticate(s);
+ if (result.get_status() != decltype(result)::Status::GRANTED) {
+ return -EACCES;
+ }
+
+ try {
+ auto applier = result.get_applier();
- applier->load_acct_info(*s->user);
- s->perm_mask = applier->get_perm_mask();
- applier->modify_request_state(s);
- s->auth.identity = std::move(applier);
+ applier->load_acct_info(*s->user);
+ s->perm_mask = applier->get_perm_mask();
+ applier->modify_request_state(s);
+ s->auth.identity = std::move(applier);
- s->owner.set_id(s->user->user_id);
- s->owner.set_name(s->user->display_name);
- /* OK, fall through. */
+ s->owner.set_id(s->user->user_id);
+ s->owner.set_name(s->user->display_name);
+ /* OK, fall through. */
+ } catch (int err) {
+ return -EACCES;
+ }
} catch (int err) {
return -EACCES;
}
- } catch (int err) {
- return -EACCES;
}
ldout(s->cct, 0) << "Successful Signature Verification!" << dendl;
return -EINVAL;
}
- post_policy.set_var_checked("AWSAccessKeyId");
+ if (aws4_auth) {
+ /* AWS4 */
+ post_policy.set_var_checked("x-amz-signature");
+ } else {
+ /* AWS2 */
+ post_policy.set_var_checked("AWSAccessKeyId");
+ post_policy.set_var_checked("signature");
+ }
post_policy.set_var_checked("policy");
- post_policy.set_var_checked("signature");
r = post_policy.check(&env, err_msg);
if (r < 0) {
if (s->info.args.exists("uploads"))
return new RGWInitMultipart_ObjStore_S3;
- return NULL;
+ return new RGWPostObj_ObjStore_S3;
}
RGWOp *RGWHandler_REST_Obj_S3::op_options()