#include <errno.h>
#include <array>
#include <string.h>
+#include <string_view>
#include "common/ceph_crypto.h"
+#include "common/split.h"
#include "common/Formatter.h"
#include "common/utf8.h"
#include "common/ceph_json.h"
#include "auth/Crypto.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
-#include <boost/utility/string_view.hpp>
#include <boost/tokenizer.hpp>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#ifdef HAVE_WARN_IMPLICIT_CONST_INT_FLOAT_CONVERSION
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wimplicit-const-int-float-conversion"
+#endif
+#ifdef HAVE_WARN_IMPLICIT_CONST_INT_FLOAT_CONVERSION
+#pragma clang diagnostic pop
+#endif
+#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <liboath/oath.h>
#include "rgw_rest_sts.h"
#include "rgw_rest_iam.h"
#include "rgw_sts.h"
+#include "rgw_sal_rados.h"
+
+#include "rgw_s3select.h"
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_rgw
+using namespace std;
using namespace rgw;
using namespace ceph::crypto;
-using std::get;
-
void list_all_buckets_start(struct req_state *s)
{
s->formatter->open_array_section_in_ns("ListAllMyBucketsResult", XMLNS_AWS_S3);
s->formatter->close_section();
}
-void dump_bucket(struct req_state *s, rgw::sal::RGWBucket& obj)
+void dump_bucket(struct req_state *s, rgw::sal::Bucket& obj)
{
s->formatter->open_object_section("Bucket");
s->formatter->dump_string("Name", obj.get_name());
- dump_time(s, "CreationDate", &obj.get_creation_time());
+ dump_time(s, "CreationDate", obj.get_creation_time());
s->formatter->close_section();
}
const ceph::real_time& mtime)
{
return rgw::lc::s3_expiration_header(
- s, s->object, s->tagset, mtime, s->bucket_attrs);
+ s, s->object->get_key(), s->tagset, mtime, s->bucket_attrs);
+}
+
+static inline bool get_s3_multipart_abort_header(
+ struct req_state* s, const ceph::real_time& mtime,
+ ceph::real_time& date, std::string& rule_id)
+{
+ return rgw::lc::s3_multipart_abort_header(
+ s, s->object->get_key(), mtime, s->bucket_attrs, date, rule_id);
}
struct response_attr_param {
}
}
-int RGWGetObj_ObjStore_S3Website::send_response_data_error()
+int RGWGetObj_ObjStore_S3Website::send_response_data_error(optional_yield y)
{
- return RGWGetObj_ObjStore_S3::send_response_data_error();
+ return RGWGetObj_ObjStore_S3::send_response_data_error(y);
}
-int RGWGetObj_ObjStore_S3::get_params()
+int RGWGetObj_ObjStore_S3::get_params(optional_yield y)
{
// for multisite sync requests, only read the slo manifest itself, rather than
// all of the data from its parts. the parts will sync as separate objects
skip_decrypt = s->info.args.exists(RGW_SYS_PARAM_PREFIX "skip-decrypt");
}
- return RGWGetObj_ObjStore::get_params();
+ return RGWGetObj_ObjStore::get_params(y);
}
-int RGWGetObj_ObjStore_S3::send_response_data_error()
+int RGWGetObj_ObjStore_S3::send_response_data_error(optional_yield y)
{
bufferlist bl;
return send_response_data(bl, 0 , 0);
return 0;
}
+inline bool str_has_cntrl(const std::string s) {
+ return std::any_of(s.begin(), s.end(), ::iscntrl);
+}
+
+inline bool str_has_cntrl(const char* s) {
+ std::string _s(s);
+ return str_has_cntrl(_s);
+}
+
int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs,
off_t bl_len)
{
bool exists;
string val = s->info.args.get(p->param, &exists);
if (exists) {
+ /* reject unauthenticated response header manipulation, see
+ * https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html */
+ if (s->auth.identity->is_anonymous()) {
+ return -ERR_INVALID_REQUEST;
+ }
+ /* HTTP specification says no control characters should be present in
+ * header values: https://tools.ietf.org/html/rfc7230#section-3.2
+ * field-vchar = VCHAR / obs-text
+ *
+ * Failure to validate this permits a CRLF injection in HTTP headers,
+ * whereas S3 GetObject only permits specific headers.
+ */
+ if(str_has_cntrl(val)) {
+ /* TODO: return a more distinct error in future;
+ * stating what the problem is */
+ return -ERR_INVALID_REQUEST;
+ }
+
if (strcmp(p->param, "response-content-type") != 0) {
response_attrs[p->http_attr] = val;
} else {
try {
decode(retention, iter->second);
dump_header(s, "x-amz-object-lock-mode", retention.get_mode());
- dump_time_header(s, "x-amz-object-lock-retain-until-date", retention.get_retain_until_date());
+ string date = ceph::to_iso_8601(retention.get_retain_until_date());
+ dump_header(s, "x-amz-object-lock-retain-until-date", date.c_str());
} catch (buffer::error& err) {
ldpp_dout(this, 0) << "ERROR: failed to decode RGWObjectRetention" << dendl;
}
res = rgw_s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses);
if (res == 0) {
if (block_crypt != nullptr) {
- auto f = std::make_unique<RGWGetObj_BlockDecrypt>(s->cct, cb, std::move(block_crypt));
+ auto f = std::make_unique<RGWGetObj_BlockDecrypt>(s, s->cct, cb, std::move(block_crypt));
if (manifest_bl != nullptr) {
- res = f->read_manifest(*manifest_bl);
+ res = f->read_manifest(this, *manifest_bl);
if (res == 0) {
*filter = std::move(f);
}
}
return res;
}
+int RGWGetObj_ObjStore_S3::verify_requester(const rgw::auth::StrategyRegistry& auth_registry, optional_yield y)
+{
+ int ret = -EINVAL;
+ ret = RGWOp::verify_requester(auth_registry, y);
+ if(!s->user->get_caps().check_cap("amz-cache", RGW_CAP_READ) && !ret && s->info.env->exists("HTTP_X_AMZ_CACHE"))
+ ret = override_range_hdr(auth_registry, y);
+ return ret;
+}
+
+int RGWGetObj_ObjStore_S3::override_range_hdr(const rgw::auth::StrategyRegistry& auth_registry, optional_yield y)
+{
+ int ret = -EINVAL;
+ ldpp_dout(this, 10) << "cache override headers" << dendl;
+ RGWEnv* rgw_env = const_cast<RGWEnv *>(s->info.env);
+ const char* backup_range = rgw_env->get("HTTP_RANGE");
+ const char hdrs_split[2] = {(char)178,'\0'};
+ const char kv_split[2] = {(char)177,'\0'};
+ const char* cache_hdr = rgw_env->get("HTTP_X_AMZ_CACHE");
+ for (std::string_view hdr : ceph::split(cache_hdr, hdrs_split)) {
+ auto kv = ceph::split(hdr, kv_split);
+ auto k = kv.begin();
+ if (std::distance(k, kv.end()) != 2) {
+ return -EINVAL;
+ }
+ auto v = std::next(k);
+ std::string key = "HTTP_";
+ key.append(*k);
+ boost::replace_all(key, "-", "_");
+ rgw_env->set(std::move(key), std::string(*v));
+ ldpp_dout(this, 10) << "after splitting cache kv key: " << key << " " << rgw_env->get(key.c_str()) << dendl;
+ }
+ ret = RGWOp::verify_requester(auth_registry, y);
+ if(!ret && backup_range) {
+ rgw_env->set("HTTP_RANGE",backup_range);
+ } else {
+ rgw_env->remove("HTTP_RANGE");
+ }
+ return ret;
+}
+
void RGWGetObjTags_ObjStore_S3::send_response_data(bufferlist& bl)
{
}
-int RGWPutObjTags_ObjStore_S3::get_params()
+int RGWPutObjTags_ObjStore_S3::get_params(optional_yield y)
{
RGWXMLParser parser;
int r = 0;
bufferlist data;
- std::tie(r, data) = rgw_rest_read_all_input(s, max_size, false);
+ std::tie(r, data) = read_all_input(s, max_size, false);
if (r < 0)
return r;
try {
tagset.decode(iter);
} catch (buffer::error& err) {
- ldout(s->cct,0) << "ERROR: caught buffer::error, couldn't decode TagSet" << dendl;
+ ldpp_dout(this,0) << "ERROR: caught buffer::error, couldn't decode TagSet" << dendl;
op_ret= -EIO;
return;
}
}
}
-int RGWPutBucketTags_ObjStore_S3::get_params()
+int RGWPutBucketTags_ObjStore_S3::get_params(const DoutPrefixProvider *dpp, optional_yield y)
{
RGWXMLParser parser;
int r = 0;
bufferlist data;
- std::tie(r, data) = rgw_rest_read_all_input(s, max_size, false);
+ std::tie(r, data) = read_all_input(s, max_size, false);
if (r < 0)
return r;
try {
RGWXMLDecoder::decode_xml("Tagging", tagging, &parser);
} catch (RGWXMLDecoder::err& err) {
-
- ldout(s->cct, 5) << "Malformed tagging request: " << err << dendl;
+
+ ldpp_dout(dpp, 5) << "Malformed tagging request: " << err << dendl;
return -ERR_MALFORMED_XML;
}
return r;
obj_tags.encode(tags_bl);
- ldout(s->cct, 20) << "Read " << obj_tags.count() << "tags" << dendl;
+ ldpp_dout(dpp, 20) << "Read " << obj_tags.count() << "tags" << dendl;
// forward bucket tags requests to meta master zone
- if (!store->svc()->zone->is_meta_master()) {
+ if (!store->is_meta_master()) {
/* only need to keep this data around if we're not meta master */
in_data = std::move(data);
}
dump_start(s);
}
-void RGWDeleteBucketTags_ObjStore_S3::send_response()
+void RGWDeleteBucketTags_ObjStore_S3::send_response()
{
if (op_ret)
set_req_state_err(s, op_ret);
}
};
- set<rgw_zone_id> get_zone_ids_from_names(rgw::sal::RGWRadosStore *store,
+ set<rgw_zone_id> get_zone_ids_from_names(rgw::sal::Store* store,
const vector<string>& zone_names) const {
set<rgw_zone_id> ids;
for (auto& name : zone_names) {
rgw_zone_id id;
- if (store->svc()->zone->find_zone_id_by_name(name, &id)) {
+ if (static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone_id_by_name(name, &id)) {
ids.insert(std::move(id));
}
}
return ids;
}
- vector<string> get_zone_names_from_ids(rgw::sal::RGWRadosStore *store,
+ vector<string> get_zone_names_from_ids(rgw::sal::Store* store,
const set<rgw_zone_id>& zone_ids) const {
vector<string> names;
for (auto& id : zone_ids) {
RGWZone *zone;
- if (store->svc()->zone->find_zone(id, &zone)) {
+ if (static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone(id, &zone)) {
names.emplace_back(zone->name);
}
}
return true;
}
- int to_sync_policy_pipe(req_state *s, rgw::sal::RGWRadosStore *store,
+ int to_sync_policy_pipe(req_state *s, rgw::sal::Store* store,
rgw_sync_bucket_pipes *pipe,
bool *enabled) const {
if (!is_valid(s->cct)) {
return 0;
}
- void from_sync_policy_pipe(rgw::sal::RGWRadosStore *store,
+ void from_sync_policy_pipe(rgw::sal::Store* store,
const rgw_sync_bucket_pipes& pipe,
bool enabled) {
id = pipe.id;
encode_xml("Rule", rules, f);
}
- int to_sync_policy_groups(req_state *s, rgw::sal::RGWRadosStore *store,
+ int to_sync_policy_groups(req_state *s, rgw::sal::Store* store,
vector<rgw_sync_policy_group> *result) const {
result->resize(2);
bool enabled;
int r = rule.to_sync_policy_pipe(s, store, &pipe, &enabled);
if (r < 0) {
- ldout(s->cct, 5) << "NOTICE: failed to convert replication configuration into sync policy pipe (rule.id=" << rule.id << "): " << cpp_strerror(-r) << dendl;
+ ldpp_dout(s, 5) << "NOTICE: failed to convert replication configuration into sync policy pipe (rule.id=" << rule.id << "): " << cpp_strerror(-r) << dendl;
return r;
}
return 0;
}
- void from_sync_policy_group(rgw::sal::RGWRadosStore *store,
+ void from_sync_policy_group(rgw::sal::Store* store,
const rgw_sync_policy_group& group) {
bool enabled = (group.status == rgw_sync_policy_group::Status::ENABLED);
ReplicationConfiguration conf;
- if (s->bucket_info.sync_policy) {
- auto policy = s->bucket_info.sync_policy;
+ if (s->bucket->get_info().sync_policy) {
+ auto policy = s->bucket->get_info().sync_policy;
auto iter = policy->groups.find(enabled_group_id);
if (iter != policy->groups.end()) {
}
}
-int RGWPutBucketReplication_ObjStore_S3::get_params()
+int RGWPutBucketReplication_ObjStore_S3::get_params(optional_yield y)
{
RGWXMLParser parser;
int r = 0;
bufferlist data;
- std::tie(r, data) = rgw_rest_read_all_input(s, max_size, false);
+ std::tie(r, data) = read_all_input(s, max_size, false);
if (r < 0)
return r;
try {
RGWXMLDecoder::decode_xml("ReplicationConfiguration", conf, &parser);
} catch (RGWXMLDecoder::err& err) {
-
- ldout(s->cct, 5) << "Malformed tagging request: " << err << dendl;
+
+ ldpp_dout(this, 5) << "Malformed tagging request: " << err << dendl;
return -ERR_MALFORMED_XML;
}
}
// forward requests to meta master zone
- if (!store->svc()->zone->is_meta_master()) {
+ if (!store->is_meta_master()) {
/* only need to keep this data around if we're not meta master */
in_data = std::move(data);
}
policy->groups.erase(disabled_group_id);
}
-void RGWDeleteBucketReplication_ObjStore_S3::send_response()
+void RGWDeleteBucketReplication_ObjStore_S3::send_response()
{
if (op_ret)
set_req_state_err(s, op_ret);
}
}
-void RGWListBuckets_ObjStore_S3::send_response_data(rgw::sal::RGWBucketList& buckets)
+void RGWListBuckets_ObjStore_S3::send_response_data(rgw::sal::BucketList& buckets)
{
if (!sent_data)
return;
- map<string, rgw::sal::RGWBucket*>& m = buckets.get_buckets();
- map<string, rgw::sal::RGWBucket*>::iterator iter;
+ auto& m = buckets.get_buckets();
- for (iter = m.begin(); iter != m.end(); ++iter) {
- rgw::sal::RGWBucket* obj = iter->second;
- dump_bucket(s, *obj);
+ for (auto iter = m.begin(); iter != m.end(); ++iter) {
+ auto& bucket = iter->second;
+ dump_bucket(s, *bucket);
}
rgw_flush_formatter(s, s->formatter);
}
}
}
-int RGWGetUsage_ObjStore_S3::get_params()
+int RGWGetUsage_ObjStore_S3::get_params(optional_yield y)
{
start_date = s->info.args.get("start-date");
- end_date = s->info.args.get("end-date");
+ end_date = s->info.args.get("end-date");
return 0;
}
formatter->close_section(); // Category
}
-static void dump_usage_bucket_info(Formatter *formatter, const std::string& name, const cls_user_bucket_entry& entry)
+static void dump_usage_bucket_info(Formatter *formatter, const std::string& name, const bucket_meta_entry& entry)
{
formatter->open_object_section("Entry");
encode_json("Bucket", name, formatter);
Formatter *formatter = s->formatter;
string last_owner;
bool user_section_open = false;
-
+
formatter->open_object_section("Usage");
if (show_log_entries) {
formatter->open_array_section("Entries");
formatter->open_object_section("Stats");
}
+ // send info about quota config
+ auto user_info = s->user->get_info();
+ encode_json("QuotaMaxBytes", user_info.user_quota.max_size, formatter);
+ encode_json("QuotaMaxBuckets", user_info.max_buckets, formatter);
+ encode_json("QuotaMaxObjCount", user_info.user_quota.max_objects, formatter);
+ encode_json("QuotaMaxBytesPerBucket", user_info.bucket_quota.max_objects, formatter);
+ encode_json("QuotaMaxObjCountPerBucket", user_info.bucket_quota.max_size, formatter);
+ // send info about user's capacity utilization
encode_json("TotalBytes", stats.size, formatter);
encode_json("TotalBytesRounded", stats.size_rounded, formatter);
encode_json("TotalEntries", stats.num_objects, formatter);
formatter->open_object_section("User");
formatter->open_array_section("Buckets");
for (const auto& biter : buckets_usage) {
- const cls_user_bucket_entry& entry = biter.second;
+ const bucket_meta_entry& entry = biter.second;
dump_usage_bucket_info(formatter, biter.first, entry);
}
formatter->close_section(); // Buckets
if (s->system_request) {
s->info.args.get_bool("objs-container", &objs_container, false);
const char *shard_id_str = s->info.env->get("HTTP_RGWX_SHARD_ID");
- if (shard_id_str) {
+ if (shard_id_str) {
string err;
shard_id = strict_strtol(shard_id_str, 10, &err);
if (!err.empty()) {
- ldout(s->cct, 5) << "bad shard id specified: " << shard_id_str << dendl;
+ ldpp_dout(this, 5) << "bad shard id specified: " << shard_id_str << dendl;
return -EINVAL;
}
} else {
return 0;
}
-int RGWListBucket_ObjStore_S3::get_params()
+int RGWListBucket_ObjStore_S3::get_params(optional_yield y)
{
int ret = get_common_params();
if (ret < 0) {
return 0;
}
-int RGWListBucket_ObjStore_S3v2::get_params()
+int RGWListBucket_ObjStore_S3v2::get_params(optional_yield y)
{
int ret = get_common_params();
if (ret < 0) {
}
}
}
-
+
void RGWListBucket_ObjStore_S3::send_versioned_response()
{
s->formatter->open_object_section_in_ns("ListVersionsResult", XMLNS_AWS_S3);
if (is_truncated && !next_marker.empty()) {
s->formatter->dump_string("NextKeyMarker", next_marker.name);
if (next_marker.instance.empty()) {
- s->formatter->dump_string("NextVersionIdMarker", "null");
+ s->formatter->dump_string("NextVersionIdMarker", "null");
}
else {
s->formatter->dump_string("NextVersionIdMarker", next_marker.instance);
if (objs_container) {
s->formatter->open_array_section("Entries");
}
-
+
vector<rgw_bucket_dir_entry>::iterator iter;
for (iter = objs.begin(); iter != objs.end(); ++iter) {
const char *section_name = (iter->is_delete_marker() ? "DeleteMarker"
string key_name;
url_encode(key.name, key_name);
s->formatter->dump_string("Key", key_name);
- }
+ }
else {
s->formatter->dump_string("Key", key.name);
}
}
s->formatter->dump_string("VersionId", version_id);
s->formatter->dump_bool("IsLatest", iter->is_current());
- dump_time(s, "LastModified", &iter->meta.mtime);
+ dump_time(s, "LastModified", iter->meta.mtime);
if (!iter->is_delete_marker()) {
s->formatter->dump_format("ETag", "\"%s\"", iter->meta.etag.c_str());
s->formatter->dump_int("Size", iter->meta.accounted_size);
}
}
}
-
+
void RGWListBucket_ObjStore_S3::send_response()
{
if (op_ret < 0) {
} else {
s->formatter->dump_string("Key", key.name);
}
- dump_time(s, "LastModified", &iter->meta.mtime);
+ dump_time(s, "LastModified", iter->meta.mtime);
s->formatter->dump_format("ETag", "\"%s\"", iter->meta.etag.c_str());
s->formatter->dump_int("Size", iter->meta.accounted_size);
auto& storage_class = rgw_placement_rule::get_canonical_storage_class(iter->meta.storage_class);
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
}
-
+
void RGWListBucket_ObjStore_S3v2::send_versioned_response()
{
s->formatter->open_object_section_in_ns("ListVersionsResult", XMLNS_AWS_S3);
if (objs_container) {
s->formatter->open_array_section("Entries");
}
-
+
vector<rgw_bucket_dir_entry>::iterator iter;
for (iter = objs.begin(); iter != objs.end(); ++iter) {
const char *section_name = (iter->is_delete_marker() ? "DeleteContinuationToken"
string key_name;
url_encode(key.name, key_name);
s->formatter->dump_string("Key", key_name);
- }
+ }
else {
s->formatter->dump_string("Key", key.name);
}
}
s->formatter->dump_string("VersionId", version_id);
s->formatter->dump_bool("IsLatest", iter->is_current());
- dump_time(s, "LastModified", &iter->meta.mtime);
+ dump_time(s, "LastModified", iter->meta.mtime);
if (!iter->is_delete_marker()) {
s->formatter->dump_format("ETag", "\"%s\"", iter->meta.etag.c_str());
s->formatter->dump_int("Size", iter->meta.accounted_size);
s->formatter->close_section();
}
}
-
+
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
}
else {
s->formatter->dump_string("Key", key.name);
}
- dump_time(s, "LastModified", &iter->meta.mtime);
+ dump_time(s, "LastModified", iter->meta.mtime);
s->formatter->dump_format("ETag", "\"%s\"", iter->meta.etag.c_str());
s->formatter->dump_int("Size", iter->meta.accounted_size);
auto& storage_class = rgw_placement_rule::get_canonical_storage_class(iter->meta.storage_class);
if (is_truncated && !next_marker.empty()) {
s->formatter->dump_string("NextContinuationToken", next_marker.name);
}
- s->formatter->dump_int("KeyCount",objs.size());
+ s->formatter->dump_int("KeyCount", objs.size() + common_prefixes.size());
if (start_after_exist) {
s->formatter->dump_string("StartAfter", startAfter);
}
RGWZoneGroup zonegroup;
string api_name;
- int ret = store->svc()->zone->get_zonegroup(s->bucket_info.zonegroup, zonegroup);
+ int ret = store->get_zone()->get_zonegroup(s->bucket->get_info().zonegroup, zonegroup);
if (ret >= 0) {
api_name = zonegroup.api_name;
} else {
- if (s->bucket_info.zonegroup != "default") {
- api_name = s->bucket_info.zonegroup;
+ if (s->bucket->get_info().zonegroup != "default") {
+ api_name = s->bucket->get_info().zonegroup;
}
}
void RGWGetBucketVersioning_ObjStore_S3::send_response()
{
+ if (op_ret)
+ set_req_state_err(s, op_ret);
dump_errno(s);
end_header(s, this, "application/xml");
dump_start(s);
}
};
-int RGWSetBucketVersioning_ObjStore_S3::get_params()
+int RGWSetBucketVersioning_ObjStore_S3::get_params(optional_yield y)
{
int r = 0;
bufferlist data;
std::tie(r, data) =
- rgw_rest_read_all_input(s, s->cct->_conf->rgw_max_put_param_size, false);
- if (r < 0) {
- return r;
- }
-
- r = do_aws4_auth_completion();
+ read_all_input(s, s->cct->_conf->rgw_max_put_param_size, false);
if (r < 0) {
return r;
}
return -EINVAL;
}
- if (!store->svc()->zone->is_meta_master()) {
+ if (!store->is_meta_master()) {
/* only need to keep this data around if we're not meta master */
in_data.append(data);
}
mfa_status = true;
break;
default:
- ldpp_dout(this, 0) << "ERROR: RGWSetBucketVersioning_ObjStore_S3::get_params(): unexpected switch case mfa_status=" << status_conf.mfa_status << dendl;
+ ldpp_dout(this, 0) << "ERROR: RGWSetBucketVersioning_ObjStore_S3::get_params(optional_yield y): unexpected switch case mfa_status=" << status_conf.mfa_status << dendl;
r = -EIO;
}
} else if (status_conf.retcode < 0) {
end_header(s, this, "application/xml");
}
-int RGWSetBucketWebsite_ObjStore_S3::get_params()
+int RGWSetBucketWebsite_ObjStore_S3::get_params(optional_yield y)
{
const auto max_size = s->cct->_conf->rgw_max_put_param_size;
int r = 0;
bufferlist data;
- std::tie(r, data) = rgw_rest_read_all_input(s, max_size, false);
-
- if (r < 0) {
- return r;
- }
+ std::tie(r, data) = read_all_input(s, max_size, false);
- r = do_aws4_auth_completion();
if (r < 0) {
return r;
}
if (website_conf.is_redirect_all && website_conf.redirect_all.hostname.empty()) {
s->err.message = "A host name must be provided to redirect all requests (e.g. \"example.com\").";
- ldout(s->cct, 5) << s->err.message << dendl;
+ ldpp_dout(this, 5) << s->err.message << dendl;
return -EINVAL;
} else if (!website_conf.is_redirect_all && !website_conf.is_set_index_doc) {
s->err.message = "A value for IndexDocument Suffix must be provided if RedirectAllRequestsTo is empty";
- ldout(s->cct, 5) << s->err.message << dendl;
+ ldpp_dout(this, 5) << s->err.message << dendl;
return -EINVAL;
} else if (!website_conf.is_redirect_all && website_conf.is_set_index_doc &&
website_conf.index_doc_suffix.empty()) {
s->err.message = "The IndexDocument Suffix is not well formed";
- ldout(s->cct, 5) << s->err.message << dendl;
+ ldpp_dout(this, 5) << s->err.message << dendl;
return -EINVAL;
}
return;
}
- RGWBucketWebsiteConf& conf = s->bucket_info.website_conf;
+ RGWBucketWebsiteConf& conf = s->bucket->get_info().website_conf;
s->formatter->open_object_section_in_ns("WebsiteConfiguration", XMLNS_AWS_S3);
conf.dump_xml(s->formatter);
rgw_flush_formatter_and_reset(s, s->formatter);
}
-static void dump_bucket_metadata(struct req_state *s, rgw::sal::RGWBucket* bucket)
+static void dump_bucket_metadata(struct req_state *s, rgw::sal::Bucket* bucket)
{
dump_header(s, "X-RGW-Object-Count", static_cast<long long>(bucket->get_count()));
dump_header(s, "X-RGW-Bytes-Used", static_cast<long long>(bucket->get_size()));
+ // only bucket's owner is allowed to get the quota settings of the account
+ if (bucket->is_owner(s->user.get())) {
+ auto user_info = s->user->get_info();
+ dump_header(s, "X-RGW-Quota-User-Size", static_cast<long long>(user_info.user_quota.max_size));
+ dump_header(s, "X-RGW-Quota-User-Objects", static_cast<long long>(user_info.user_quota.max_objects));
+ dump_header(s, "X-RGW-Quota-Max-Buckets", static_cast<long long>(user_info.max_buckets));
+ dump_header(s, "X-RGW-Quota-Bucket-Size", static_cast<long long>(user_info.bucket_quota.max_size));
+ dump_header(s, "X-RGW-Quota-Bucket-Objects", static_cast<long long>(user_info.bucket_quota.max_objects));
+ }
}
void RGWStatBucket_ObjStore_S3::send_response()
{
if (op_ret >= 0) {
- dump_bucket_metadata(s, bucket);
+ dump_bucket_metadata(s, bucket.get());
}
set_req_state_err(s, op_ret);
dump_start(s);
}
-static int create_s3_policy(struct req_state *s, rgw::sal::RGWRadosStore *store,
+static int create_s3_policy(struct req_state *s, rgw::sal::Store* store,
RGWAccessControlPolicy_S3& s3policy,
ACLOwner& owner)
{
if (!s->canned_acl.empty())
return -ERR_INVALID_REQUEST;
- return s3policy.create_from_headers(store->ctl()->user, s->info.env, owner);
+ return s3policy.create_from_headers(s, store, s->info.env, owner);
}
return s3policy.create_canned(owner, s->bucket_owner, s->canned_acl);
}
};
-int RGWCreateBucket_ObjStore_S3::get_params()
+int RGWCreateBucket_ObjStore_S3::get_params(optional_yield y)
{
RGWAccessControlPolicy_S3 s3policy(s->cct);
bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names;
-
- int r = valid_s3_bucket_name(s->bucket_name, relaxed_names);
- if (r)
- return r;
+
+ int r;
+ if (!s->system_request) {
+ r = valid_s3_bucket_name(s->bucket_name, relaxed_names);
+ if (r) return r;
+ }
r = create_s3_policy(s, store, s3policy, s->owner);
if (r < 0)
int op_ret = 0;
bufferlist data;
- std::tie(op_ret, data) = rgw_rest_read_all_input(s, max_size, false);
+ std::tie(op_ret, data) = read_all_input(s, max_size, false);
if ((op_ret < 0) && (op_ret != -ERR_LENGTH_REQUIRED))
return op_ret;
- const int auth_ret = do_aws4_auth_completion();
- if (auth_ret < 0) {
- return auth_ret;
- }
-
in_data.append(data);
if (data.length()) {
}
}
-int RGWPutObj_ObjStore_S3::get_params()
+int RGWPutObj_ObjStore_S3::get_params(optional_yield y)
{
if (!s->length)
return -ERR_LENGTH_REQUIRED;
- map<string, bufferlist> src_attrs;
- size_t pos;
int ret;
map_qs_metadata(s);
if_match = s->info.env->get("HTTP_IF_MATCH");
if_nomatch = s->info.env->get("HTTP_IF_NONE_MATCH");
- copy_source = url_decode(s->info.env->get("HTTP_X_AMZ_COPY_SOURCE", ""));
- copy_source_range = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE_RANGE");
-
- /* handle x-amz-copy-source */
- boost::string_view cs_view(copy_source);
- if (! cs_view.empty()) {
- if (cs_view[0] == '/')
- cs_view.remove_prefix(1);
- copy_source_bucket_name = cs_view.to_string();
- pos = copy_source_bucket_name.find("/");
- if (pos == std::string::npos) {
- ret = -EINVAL;
- ldpp_dout(this, 5) << "x-amz-copy-source bad format" << dendl;
- return ret;
- }
- copy_source_object_name =
- copy_source_bucket_name.substr(pos + 1, copy_source_bucket_name.size());
- copy_source_bucket_name = copy_source_bucket_name.substr(0, pos);
-#define VERSION_ID_STR "?versionId="
- pos = copy_source_object_name.find(VERSION_ID_STR);
- if (pos == std::string::npos) {
- copy_source_object_name = url_decode(copy_source_object_name);
- } else {
- copy_source_version_id =
- copy_source_object_name.substr(pos + sizeof(VERSION_ID_STR) - 1);
- copy_source_object_name =
- url_decode(copy_source_object_name.substr(0, pos));
- }
- pos = copy_source_bucket_name.find(":");
- if (pos == std::string::npos) {
- copy_source_tenant_name = s->src_tenant_name;
- } else {
- copy_source_tenant_name = copy_source_bucket_name.substr(0, pos);
- copy_source_bucket_name = copy_source_bucket_name.substr(pos + 1, copy_source_bucket_name.size());
- if (copy_source_bucket_name.empty()) {
- ret = -EINVAL;
- ldpp_dout(this, 5) << "source bucket name is empty" << dendl;
- return ret;
- }
- }
- ret = store->getRados()->get_bucket_info(store->svc(),
- copy_source_tenant_name,
- copy_source_bucket_name,
- copy_source_bucket_info,
- NULL, s->yield, &src_attrs);
- if (ret < 0) {
- ldpp_dout(this, 5) << __func__ << "(): get_bucket_info() returned ret=" << ret << dendl;
- return ret;
- }
-
- /* handle x-amz-copy-source-range */
-
- if (copy_source_range) {
- string range = copy_source_range;
- pos = range.find("bytes=");
- if (pos == std::string::npos || pos != 0) {
- ret = -EINVAL;
- ldpp_dout(this, 5) << "x-amz-copy-source-range bad format" << dendl;
- return ret;
- }
- /* 6 is the length of "bytes=" */
- range = range.substr(pos + 6);
- pos = range.find("-");
- if (pos == std::string::npos) {
- ret = -EINVAL;
- ldpp_dout(this, 5) << "x-amz-copy-source-range bad format" << dendl;
- return ret;
- }
- string first = range.substr(0, pos);
- string last = range.substr(pos + 1);
- if (first.find_first_not_of("0123456789") != std::string::npos || last.find_first_not_of("0123456789") != std::string::npos)
- {
- ldpp_dout(this, 5) << "x-amz-copy-source-range bad format not an integer" << dendl;
- ret = -EINVAL;
- return ret;
- }
- copy_source_range_fst = strtoull(first.c_str(), NULL, 10);
- copy_source_range_lst = strtoull(last.c_str(), NULL, 10);
- if (copy_source_range_fst > copy_source_range_lst)
- {
- ret = -ERANGE;
- ldpp_dout(this, 5) << "x-amz-copy-source-range bad format first number bigger than second" << dendl;
- return ret;
- }
- }
-
- } /* copy_source */
/* handle object tagging */
auto tag_str = s->info.env->get("HTTP_X_AMZ_TAGGING");
}
obj_legal_hold = new RGWObjectLegalHold(obj_legal_hold_str);
}
- if (!s->bucket_info.obj_lock_enabled() && (obj_retention || obj_legal_hold)) {
+ if (!s->bucket->get_info().obj_lock_enabled() && (obj_retention || obj_legal_hold)) {
ldpp_dout(this, 0) << "ERROR: object retention or legal hold can't be set if bucket object lock not configured" << dendl;
ret = -ERR_INVALID_REQUEST;
return ret;
append = s->info.args.exists("append");
if (append) {
string pos_str = s->info.args.get("position");
- if (pos_str.empty()) {
+ string err;
+ long long pos_tmp = strict_strtoll(pos_str.c_str(), 10, &err);
+ if (!err.empty()) {
+ ldpp_dout(s, 10) << "bad position: " << pos_str << ": " << err << dendl;
+ return -EINVAL;
+ } else if (pos_tmp < 0) {
+ ldpp_dout(s, 10) << "bad position: " << pos_str << ": " << "position shouldn't be negative" << dendl;
return -EINVAL;
- } else {
- position = strtoull(pos_str.c_str(), NULL, 10);
}
+ position = uint64_t(pos_tmp);
}
-
- return RGWPutObj_ObjStore::get_params();
+
+ return RGWPutObj_ObjStore::get_params(y);
}
int RGWPutObj_ObjStore_S3::get_data(bufferlist& bl)
end_header(s, this);
}
-static inline int get_obj_attrs(rgw::sal::RGWRadosStore *store, struct req_state *s, rgw_obj& obj, map<string, bufferlist>& attrs)
-{
- RGWRados::Object op_target(store->getRados(), s->bucket_info, *static_cast<RGWObjectCtx *>(s->obj_ctx), obj);
- RGWRados::Object::Read read_op(&op_target);
-
- read_op.params.attrs = &attrs;
-
- return read_op.prepare(s->yield);
-}
-
static inline void set_attr(map<string, bufferlist>& attrs, const char* key, const std::string& value)
{
bufferlist bl;
res = rgw_s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses_unused);
if (res == 0) {
if (block_crypt != nullptr) {
- auto f = std::unique_ptr<RGWGetObj_BlockDecrypt>(new RGWGetObj_BlockDecrypt(s->cct, cb, std::move(block_crypt)));
+ auto f = std::unique_ptr<RGWGetObj_BlockDecrypt>(new RGWGetObj_BlockDecrypt(s, s->cct, cb, std::move(block_crypt)));
//RGWGetObj_BlockDecrypt* f = new RGWGetObj_BlockDecrypt(s->cct, cb, std::move(block_crypt));
if (f != nullptr) {
if (manifest_bl != nullptr) {
- res = f->read_manifest(*manifest_bl);
+ res = f->read_manifest(this, *manifest_bl);
if (res == 0) {
*filter = std::move(f);
}
}
int RGWPutObj_ObjStore_S3::get_encrypt_filter(
- std::unique_ptr<rgw::putobj::DataProcessor> *filter,
- rgw::putobj::DataProcessor *cb)
+ std::unique_ptr<rgw::sal::DataProcessor> *filter,
+ rgw::sal::DataProcessor *cb)
{
int res = 0;
if (!multipart_upload_id.empty()) {
- RGWMPObj mp(s->object.name, multipart_upload_id);
- rgw_obj obj;
- obj.init_ns(s->bucket, mp.get_meta(), RGW_OBJ_NS_MULTIPART);
- obj.set_in_extra_data(true);
- map<string, bufferlist> xattrs;
- res = get_obj_attrs(store, s, obj, xattrs);
+ std::unique_ptr<rgw::sal::MultipartUpload> upload =
+ s->bucket->get_multipart_upload(s->object->get_name(),
+ multipart_upload_id);
+ std::unique_ptr<rgw::sal::Object> obj = upload->get_meta_obj();
+ obj->set_in_extra_data(true);
+ res = obj->get_obj_attrs(s->obj_ctx, s->yield, this);
if (res == 0) {
std::unique_ptr<BlockCrypt> block_crypt;
/* We are adding to existing object.
* We use crypto mode that configured as if we were decrypting. */
- res = rgw_s3_prepare_decrypt(s, xattrs, &block_crypt, crypt_http_responses);
+ res = rgw_s3_prepare_decrypt(s, obj->get_attrs(), &block_crypt, crypt_http_responses);
if (res == 0 && block_crypt != nullptr)
- filter->reset(new RGWPutObj_BlockEncrypt(s->cct, cb, std::move(block_crypt)));
+ filter->reset(new RGWPutObj_BlockEncrypt(s, s->cct, cb, std::move(block_crypt)));
}
/* it is ok, to not have encryption at all */
}
std::unique_ptr<BlockCrypt> block_crypt;
res = rgw_s3_prepare_encrypt(s, attrs, nullptr, &block_crypt, crypt_http_responses);
if (res == 0 && block_crypt != nullptr) {
- filter->reset(new RGWPutObj_BlockEncrypt(s->cct, cb, std::move(block_crypt)));
+ filter->reset(new RGWPutObj_BlockEncrypt(s, s->cct, cb, std::move(block_crypt)));
}
}
return res;
}
-void RGWPostObj_ObjStore_S3::rebuild_key(string& key)
+void RGWPostObj_ObjStore_S3::rebuild_key(rgw::sal::Object* obj)
{
+ string key = obj->get_name();
static string var = "${filename}";
int pos = key.find(var);
if (pos < 0)
new_key.append(filename);
new_key.append(key.substr(pos + var.size()));
- key = new_key;
+ obj->set_key(new_key);
}
std::string RGWPostObj_ObjStore_S3::get_current_filename() const
{
- return s->object.name;
+ return s->object->get_name();
}
std::string RGWPostObj_ObjStore_S3::get_current_content_type() const
return content_type;
}
-int RGWPostObj_ObjStore_S3::get_params()
+int RGWPostObj_ObjStore_S3::get_params(optional_yield y)
{
- op_ret = RGWPostObj_ObjStore::get_params();
+ op_ret = RGWPostObj_ObjStore::get_params(y);
if (op_ret < 0) {
return op_ret;
}
map_qs_metadata(s);
- ldpp_dout(this, 20) << "adding bucket to policy env: " << s->bucket.name
+ ldpp_dout(this, 20) << "adding bucket to policy env: " << s->bucket->get_name()
<< dendl;
- env.add_var("bucket", s->bucket.name);
+ env.add_var("bucket", s->bucket->get_name());
bool done;
do {
return -EINVAL;
}
- s->object = rgw_obj_key(object_str);
+ s->object = store->get_object(rgw_obj_key(object_str));
- rebuild_key(s->object.name);
+ rebuild_key(s->object.get());
- if (s->object.empty()) {
+ if (rgw::sal::Object::empty(s->object.get())) {
err_msg = "Empty object name";
return -EINVAL;
}
- env.add_var("key", s->object.name);
+ env.add_var("key", s->object->get_name());
part_str(parts, "Content-Type", &content_type);
if (! storage_class.empty()) {
s->dest_placement.storage_class = storage_class;
- if (!store->svc()->zone->get_zone_params().valid_placement(s->dest_placement)) {
+ if (!store->get_zone()->get_params().valid_placement(s->dest_placement)) {
ldpp_dout(this, 0) << "NOTICE: invalid dest placement: " << s->dest_placement.to_str() << dendl;
err_msg = "The storage class you specified is not valid";
return -EINVAL;
attrs[attr_name] = attr_bl;
}
- int r = get_policy();
+ int r = get_policy(y);
if (r < 0)
return r;
return 0;
}
-int RGWPostObj_ObjStore_S3::get_policy()
+int RGWPostObj_ObjStore_S3::get_policy(optional_yield y)
{
if (part_bl(parts, "policy", &s->auth.s3_postobj_creds.encoded_policy)) {
bool aws4_auth = false;
/* 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 int ret = rgw::auth::Strategy::apply(this, auth_registry_ptr->get_s3_post(), s);
+ const int ret = rgw::auth::Strategy::apply(this, auth_registry_ptr->get_s3_post(), s, y);
if (ret != 0) {
return -EACCES;
} else {
url_encode(s->bucket_tenant, tenant); /* surely overkill, but cheap */
url_encode(s->bucket_name, bucket);
- url_encode(s->object.name, key);
+ url_encode(s->object->get_name(), key);
url_encode(etag_str, etag_url);
if (!s->bucket_tenant.empty()) {
base_uri.c_str(),
url_encode(s->bucket_tenant).c_str(),
url_encode(s->bucket_name).c_str(),
- url_encode(s->object.name).c_str());
+ url_encode(s->object->get_name()).c_str());
s->formatter->dump_string("Tenant", s->bucket_tenant);
} else {
s->formatter->dump_format("Location", "%s/%s/%s",
base_uri.c_str(),
url_encode(s->bucket_name).c_str(),
- url_encode(s->object.name).c_str());
+ url_encode(s->object->get_name()).c_str());
}
s->formatter->dump_string("Bucket", s->bucket_name);
- s->formatter->dump_string("Key", s->object.name);
+ s->formatter->dump_string("Key", s->object->get_name());
s->formatter->dump_string("ETag", etag);
s->formatter->close_section();
}
}
int RGWPostObj_ObjStore_S3::get_encrypt_filter(
- std::unique_ptr<rgw::putobj::DataProcessor> *filter,
- rgw::putobj::DataProcessor *cb)
+ std::unique_ptr<rgw::sal::DataProcessor> *filter,
+ rgw::sal::DataProcessor *cb)
{
std::unique_ptr<BlockCrypt> block_crypt;
int res = rgw_s3_prepare_encrypt(s, attrs, &parts, &block_crypt,
crypt_http_responses);
if (res == 0 && block_crypt != nullptr) {
- filter->reset(new RGWPutObj_BlockEncrypt(s->cct, cb, std::move(block_crypt)));
+ filter->reset(new RGWPutObj_BlockEncrypt(s, s->cct, cb, std::move(block_crypt)));
}
return res;
}
-int RGWDeleteObj_ObjStore_S3::get_params()
+int RGWDeleteObj_ObjStore_S3::get_params(optional_yield y)
{
const char *if_unmod = s->info.env->get("HTTP_X_AMZ_DELETE_IF_UNMODIFIED_SINCE");
return 0;
}
-int RGWCopyObj_ObjStore_S3::get_params()
+int RGWCopyObj_ObjStore_S3::get_params(optional_yield y)
{
+ //handle object lock
+ auto obj_lock_mode_str = s->info.env->get("HTTP_X_AMZ_OBJECT_LOCK_MODE");
+ auto obj_lock_date_str = s->info.env->get("HTTP_X_AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE");
+ auto obj_legal_hold_str = s->info.env->get("HTTP_X_AMZ_OBJECT_LOCK_LEGAL_HOLD");
+ if (obj_lock_mode_str && obj_lock_date_str) {
+ boost::optional<ceph::real_time> date = ceph::from_iso_8601(obj_lock_date_str);
+ if (boost::none == date || ceph::real_clock::to_time_t(*date) <= ceph_clock_now()) {
+ s->err.message = "invalid x-amz-object-lock-retain-until-date value";
+ ldpp_dout(this,0) << s->err.message << dendl;
+ return -EINVAL;
+ }
+ if (strcmp(obj_lock_mode_str, "GOVERNANCE") != 0 && strcmp(obj_lock_mode_str, "COMPLIANCE") != 0) {
+ s->err.message = "invalid x-amz-object-lock-mode value";
+ ldpp_dout(this,0) << s->err.message << dendl;
+ return -EINVAL;
+ }
+ obj_retention = new RGWObjectRetention(obj_lock_mode_str, *date);
+ } else if (obj_lock_mode_str || obj_lock_date_str) {
+ s->err.message = "need both x-amz-object-lock-mode and x-amz-object-lock-retain-until-date ";
+ ldpp_dout(this,0) << s->err.message << dendl;
+ return -EINVAL;
+ }
+ if (obj_legal_hold_str) {
+ if (strcmp(obj_legal_hold_str, "ON") != 0 && strcmp(obj_legal_hold_str, "OFF") != 0) {
+ s->err.message = "invalid x-amz-object-lock-legal-hold value";
+ ldpp_dout(this,0) << s->err.message << dendl;
+ return -EINVAL;
+ }
+ obj_legal_hold = new RGWObjectLegalHold(obj_legal_hold_str);
+ }
+
if_mod = s->info.env->get("HTTP_X_AMZ_COPY_IF_MODIFIED_SINCE");
if_unmod = s->info.env->get("HTTP_X_AMZ_COPY_IF_UNMODIFIED_SINCE");
if_match = s->info.env->get("HTTP_X_AMZ_COPY_IF_MATCH");
src_tenant_name = s->src_tenant_name;
src_bucket_name = s->src_bucket_name;
- src_object = s->src_object;
- dest_tenant_name = s->bucket.tenant;
- dest_bucket_name = s->bucket.name;
- dest_object = s->object.name;
+ dest_tenant_name = s->bucket->get_tenant();
+ dest_bucket_name = s->bucket->get_name();
+ dest_obj_name = s->object->get_name();
if (s->system_request) {
source_zone = s->info.args.get(RGW_SYS_PARAM_PREFIX "source-zone");
auto tmp_md_d = s->info.env->get("HTTP_X_AMZ_METADATA_DIRECTIVE");
if (tmp_md_d) {
if (strcasecmp(tmp_md_d, "COPY") == 0) {
- attrs_mod = RGWRados::ATTRSMOD_NONE;
+ attrs_mod = rgw::sal::ATTRSMOD_NONE;
} else if (strcasecmp(tmp_md_d, "REPLACE") == 0) {
- attrs_mod = RGWRados::ATTRSMOD_REPLACE;
+ attrs_mod = rgw::sal::ATTRSMOD_REPLACE;
} else if (!source_zone.empty()) {
- attrs_mod = RGWRados::ATTRSMOD_NONE; // default for intra-zone_group copy
+ attrs_mod = rgw::sal::ATTRSMOD_NONE; // default for intra-zone_group copy
} else {
s->err.message = "Unknown metadata directive.";
ldpp_dout(this, 0) << s->err.message << dendl;
if (source_zone.empty() &&
(dest_tenant_name.compare(src_tenant_name) == 0) &&
(dest_bucket_name.compare(src_bucket_name) == 0) &&
- (dest_object.compare(src_object.name) == 0) &&
- src_object.instance.empty() &&
- (attrs_mod != RGWRados::ATTRSMOD_REPLACE)) {
+ (dest_obj_name.compare(s->src_object->get_name()) == 0) &&
+ s->src_object->get_instance().empty() &&
+ (attrs_mod != rgw::sal::ATTRSMOD_REPLACE)) {
need_to_check_storage_class = true;
}
send_partial_response(0);
if (op_ret == 0) {
- dump_time(s, "LastModified", &mtime);
+ dump_time(s, "LastModified", mtime);
if (!etag.empty()) {
s->formatter->dump_string("ETag", std::move(etag));
}
dump_body(s, acls);
}
-int RGWPutACLs_ObjStore_S3::get_params()
+int RGWPutACLs_ObjStore_S3::get_params(optional_yield y)
{
- int ret = RGWPutACLs_ObjStore::get_params();
+ int ret = RGWPutACLs_ObjStore::get_params(y);
if (ret >= 0) {
const int ret_auth = do_aws4_auth_completion();
if (ret_auth < 0) {
return ret;
}
-int RGWPutACLs_ObjStore_S3::get_policy_from_state(rgw::sal::RGWRadosStore *store,
+int RGWPutACLs_ObjStore_S3::get_policy_from_state(rgw::sal::Store* store,
struct req_state *s,
stringstream& ss)
{
RGWAccessControlPolicy_S3 s3policy(s->cct);
// bucket-* canned acls do not apply to bucket
- if (s->object.empty()) {
+ if (rgw::sal::Object::empty(s->object.get())) {
if (s->canned_acl.find("bucket") != string::npos)
s->canned_acl.clear();
}
dump_start(s);
}
-void RGWGetLC_ObjStore_S3::execute()
+void RGWGetLC_ObjStore_S3::execute(optional_yield y)
{
config.set_ctx(s->cct);
void RGWGetLC_ObjStore_S3::send_response()
{
if (op_ret) {
- if (op_ret == -ENOENT) {
+ if (op_ret == -ENOENT) {
set_req_state_err(s, ERR_NO_SUCH_LC);
} else {
set_req_state_err(s, op_ret);
{
if (op_ret == 0)
op_ret = STATUS_NO_CONTENT;
- if (op_ret) {
+ if (op_ret) {
set_req_state_err(s, op_ret);
}
dump_errno(s);
}
}
-int RGWPutCORS_ObjStore_S3::get_params()
+int RGWPutCORS_ObjStore_S3::get_params(optional_yield y)
{
- RGWCORSXMLParser_S3 parser(s->cct);
+ RGWCORSXMLParser_S3 parser(this, s->cct);
RGWCORSConfiguration_S3 *cors_config;
const auto max_size = s->cct->_conf->rgw_max_put_param_size;
int r = 0;
bufferlist data;
- std::tie(r, data) = rgw_rest_read_all_input(s, max_size, false);
- if (r < 0) {
- return r;
- }
-
- r = do_aws4_auth_completion();
+ std::tie(r, data) = read_all_input(s, max_size, false);
if (r < 0) {
return r;
}
}
// forward bucket cors requests to meta master zone
- if (!store->svc()->zone->is_meta_master()) {
+ if (!store->is_meta_master()) {
/* only need to keep this data around if we're not meta master */
in_data.append(data);
}
end_header(s, NULL);
}
+void RGWPutBucketEncryption_ObjStore_S3::send_response()
+{
+ if (op_ret) {
+ set_req_state_err(s, op_ret);
+ }
+ dump_errno(s);
+ end_header(s);
+}
+
+void RGWGetBucketEncryption_ObjStore_S3::send_response()
+{
+ if (op_ret) {
+ if (op_ret == -ENOENT)
+ set_req_state_err(s, ERR_NO_SUCH_BUCKET_ENCRYPTION_CONFIGURATION);
+ else
+ set_req_state_err(s, op_ret);
+ }
+
+ dump_errno(s);
+ end_header(s, this, "application/xml");
+ dump_start(s);
+
+ if (!op_ret) {
+ encode_xml("ServerSideEncryptionConfiguration", bucket_encryption_conf, s->formatter);
+ rgw_flush_formatter_and_reset(s, s->formatter);
+ }
+}
+
+void RGWDeleteBucketEncryption_ObjStore_S3::send_response()
+{
+ if (op_ret == 0) {
+ op_ret = STATUS_NO_CONTENT;
+ }
+
+ set_req_state_err(s, op_ret);
+ dump_errno(s);
+ end_header(s);
+}
+
void RGWGetRequestPayment_ObjStore_S3::send_response()
{
dump_errno(s);
}
};
-int RGWSetRequestPayment_ObjStore_S3::get_params()
+int RGWSetRequestPayment_ObjStore_S3::get_params(optional_yield y)
{
const auto max_size = s->cct->_conf->rgw_max_put_param_size;
int r = 0;
- std::tie(r, in_data) = rgw_rest_read_all_input(s, max_size, false);
+ std::tie(r, in_data) = read_all_input(s, max_size, false);
if (r < 0) {
return r;
end_header(s);
}
-int RGWInitMultipart_ObjStore_S3::get_params()
+int RGWInitMultipart_ObjStore_S3::get_params(optional_yield y)
{
RGWAccessControlPolicy_S3 s3policy(s->cct);
op_ret = create_s3_policy(s, store, s3policy, s->owner);
dump_errno(s);
for (auto &it : crypt_http_responses)
dump_header(s, it.first, it.second);
+ ceph::real_time abort_date;
+ string rule_id;
+ bool exist_multipart_abort = get_s3_multipart_abort_header(s, mtime, abort_date, rule_id);
+ if (exist_multipart_abort) {
+ dump_time_header(s, "x-amz-abort-date", abort_date);
+ dump_header_if_nonempty(s, "x-amz-abort-rule-id", rule_id);
+ }
end_header(s, this, "application/xml");
if (op_ret == 0) {
dump_start(s);
if (!s->bucket_tenant.empty())
s->formatter->dump_string("Tenant", s->bucket_tenant);
s->formatter->dump_string("Bucket", s->bucket_name);
- s->formatter->dump_string("Key", s->object.name);
+ s->formatter->dump_string("Key", s->object->get_name());
s->formatter->dump_string("UploadId", upload_id);
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
return res;
}
-int RGWCompleteMultipart_ObjStore_S3::get_params()
+int RGWCompleteMultipart_ObjStore_S3::get_params(optional_yield y)
{
- int ret = RGWCompleteMultipart_ObjStore::get_params();
+ int ret = RGWCompleteMultipart_ObjStore::get_params(y);
if (ret < 0) {
return ret;
}
base_uri.c_str(),
s->bucket_tenant.c_str(),
s->bucket_name.c_str(),
- s->object.name.c_str()
+ s->object->get_name().c_str()
);
s->formatter->dump_string("Tenant", s->bucket_tenant);
} else {
s->formatter->dump_format("Location", "%s/%s/%s",
base_uri.c_str(),
s->bucket_name.c_str(),
- s->object.name.c_str()
+ s->object->get_name().c_str()
);
}
s->formatter->dump_string("Bucket", s->bucket_name);
- s->formatter->dump_string("Key", s->object.name);
+ s->formatter->dump_string("Key", s->object->get_name());
s->formatter->dump_string("ETag", etag);
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
if (op_ret == 0) {
dump_start(s);
s->formatter->open_object_section_in_ns("ListPartsResult", XMLNS_AWS_S3);
- map<uint32_t, RGWUploadPartInfo>::iterator iter;
- map<uint32_t, RGWUploadPartInfo>::reverse_iterator test_iter;
+ map<uint32_t, std::unique_ptr<rgw::sal::MultipartPart>>::iterator iter;
+ map<uint32_t, std::unique_ptr<rgw::sal::MultipartPart>>::reverse_iterator test_iter;
int cur_max = 0;
- iter = parts.begin();
- test_iter = parts.rbegin();
- if (test_iter != parts.rend()) {
+ iter = upload->get_parts().begin();
+ test_iter = upload->get_parts().rbegin();
+ if (test_iter != upload->get_parts().rend()) {
cur_max = test_iter->first;
}
if (!s->bucket_tenant.empty())
s->formatter->dump_string("Tenant", s->bucket_tenant);
s->formatter->dump_string("Bucket", s->bucket_name);
- s->formatter->dump_string("Key", s->object.name);
+ s->formatter->dump_string("Key", s->object->get_name());
s->formatter->dump_string("UploadId", upload_id);
- s->formatter->dump_string("StorageClass", "STANDARD");
+ s->formatter->dump_string("StorageClass", placement->get_storage_class());
s->formatter->dump_int("PartNumberMarker", marker);
s->formatter->dump_int("NextPartNumberMarker", cur_max);
s->formatter->dump_int("MaxParts", max_parts);
ACLOwner& owner = policy.get_owner();
dump_owner(s, owner.get_id(), owner.get_display_name());
- for (; iter != parts.end(); ++iter) {
- RGWUploadPartInfo& info = iter->second;
+ for (; iter != upload->get_parts().end(); ++iter) {
+ rgw::sal::MultipartPart* part = iter->second.get();
s->formatter->open_object_section("Part");
- dump_time(s, "LastModified", &info.modified);
+ dump_time(s, "LastModified", part->get_mtime());
- s->formatter->dump_unsigned("PartNumber", info.num);
- s->formatter->dump_format("ETag", "\"%s\"", info.etag.c_str());
- s->formatter->dump_unsigned("Size", info.accounted_size);
+ s->formatter->dump_unsigned("PartNumber", part->get_num());
+ s->formatter->dump_format("ETag", "\"%s\"", part->get_etag().c_str());
+ s->formatter->dump_unsigned("Size", part->get_size());
s->formatter->close_section();
}
s->formatter->close_section();
s->formatter->dump_string("Tenant", s->bucket_tenant);
s->formatter->dump_string("Bucket", s->bucket_name);
if (!prefix.empty())
- s->formatter->dump_string("ListMultipartUploadsResult.Prefix", prefix);
- const string& key_marker = marker.get_key();
- if (!key_marker.empty())
- s->formatter->dump_string("KeyMarker", key_marker);
- const string& upload_id_marker = marker.get_upload_id();
- if (!upload_id_marker.empty())
- s->formatter->dump_string("UploadIdMarker", upload_id_marker);
- string next_key = next_marker.mp.get_key();
- if (!next_key.empty())
- s->formatter->dump_string("NextKeyMarker", next_key);
- string next_upload_id = next_marker.mp.get_upload_id();
- if (!next_upload_id.empty())
- s->formatter->dump_string("NextUploadIdMarker", next_upload_id);
+ s->formatter->dump_string("Prefix", prefix);
+ if (!marker_key.empty())
+ s->formatter->dump_string("KeyMarker", marker_key);
+ if (!marker_upload_id.empty())
+ s->formatter->dump_string("UploadIdMarker", marker_upload_id);
+ if (!next_marker_key.empty())
+ s->formatter->dump_string("NextKeyMarker", next_marker_key);
+ if (!next_marker_upload_id.empty())
+ s->formatter->dump_string("NextUploadIdMarker", next_marker_upload_id);
s->formatter->dump_int("MaxUploads", max_uploads);
if (!delimiter.empty())
s->formatter->dump_string("Delimiter", delimiter);
s->formatter->dump_string("IsTruncated", (is_truncated ? "true" : "false"));
if (op_ret >= 0) {
- vector<RGWMultipartUploadEntry>::iterator iter;
+ vector<std::unique_ptr<rgw::sal::MultipartUpload>>::iterator iter;
for (iter = uploads.begin(); iter != uploads.end(); ++iter) {
- RGWMPObj& mp = iter->mp;
+ rgw::sal::MultipartUpload* upload = iter->get();
s->formatter->open_array_section("Upload");
if (encode_url) {
- s->formatter->dump_string("Key", url_encode(mp.get_key(), false));
+ s->formatter->dump_string("Key", url_encode(upload->get_key(), false));
} else {
- s->formatter->dump_string("Key", mp.get_key());
+ s->formatter->dump_string("Key", upload->get_key());
}
- s->formatter->dump_string("UploadId", mp.get_upload_id());
- dump_owner(s, s->user->get_id(), s->user->get_display_name(), "Initiator");
- dump_owner(s, s->user->get_id(), s->user->get_display_name());
+ s->formatter->dump_string("UploadId", upload->get_upload_id());
+ const ACLOwner& owner = upload->get_owner();
+ dump_owner(s, owner.get_id(), owner.get_display_name(), "Initiator");
+ dump_owner(s, owner.get_id(), owner.get_display_name()); // Owner
s->formatter->dump_string("StorageClass", "STANDARD");
- dump_time(s, "Initiated", &iter->obj.meta.mtime);
+ dump_time(s, "Initiated", upload->get_mtime());
s->formatter->close_section();
}
if (!common_prefixes.empty()) {
s->formatter->open_array_section("CommonPrefixes");
for (const auto& kv : common_prefixes) {
if (encode_url) {
- s->formatter->dump_string("CommonPrefixes.Prefix",
- url_encode(kv.first, false));
+ s->formatter->dump_string("Prefix", url_encode(kv.first, false));
} else {
- s->formatter->dump_string("CommonPrefixes.Prefix", kv.first);
+ s->formatter->dump_string("Prefix", kv.first);
}
}
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
}
-int RGWDeleteMultiObj_ObjStore_S3::get_params()
+int RGWDeleteMultiObj_ObjStore_S3::get_params(optional_yield y)
{
- int ret = RGWDeleteMultiObj_ObjStore::get_params();
+ int ret = RGWDeleteMultiObj_ObjStore::get_params(y);
if (ret < 0) {
return ret;
}
+ const char *bypass_gov_header = s->info.env->get("HTTP_X_AMZ_BYPASS_GOVERNANCE_RETENTION");
+ if (bypass_gov_header) {
+ std::string bypass_gov_decoded = url_decode(bypass_gov_header);
+ bypass_governance_mode = boost::algorithm::iequals(bypass_gov_decoded, "true");
+ }
+
return do_aws4_auth_completion();
}
}
f.open_object_section("result");
- ::encode_json("head", head_obj, &f);
- ::encode_json("manifest", *manifest, &f);
- f.open_array_section("data_location");
- for (auto miter = manifest->obj_begin(); miter != manifest->obj_end(); ++miter) {
- f.open_object_section("obj");
- rgw_raw_obj raw_loc = miter.get_location().get_raw_obj(store->getRados());
- uint64_t ofs = miter.get_ofs();
- uint64_t left = manifest->get_obj_size() - ofs;
- ::encode_json("ofs", miter.get_ofs(), &f);
- ::encode_json("loc", raw_loc, &f);
- ::encode_json("loc_ofs", miter.location_ofs(), &f);
- uint64_t loc_size = miter.get_stripe_size();
- if (loc_size > left) {
- loc_size = left;
- }
- ::encode_json("loc_size", loc_size, &f);
- f.close_section();
- rgw_flush_formatter(s, &f);
- }
- f.close_section();
+ s->object->dump_obj_layout(this, s->yield, &f, s->obj_ctx);
f.close_section();
rgw_flush_formatter(s, &f);
}
-int RGWConfigBucketMetaSearch_ObjStore_S3::get_params()
+int RGWConfigBucketMetaSearch_ObjStore_S3::get_params(optional_yield y)
{
auto iter = s->info.x_meta_map.find("x-amz-meta-search");
if (iter == s->info.x_meta_map.end()) {
Formatter *f = s->formatter;
f->open_array_section("GetBucketMetaSearchResult");
- for (auto& e : s->bucket_info.mdsearch_config) {
+ for (auto& e : s->bucket->get_info().mdsearch_config) {
f->open_object_section("Entry");
string k = string("x-amz-meta-") + e.first;
f->dump_string("Key", k.c_str());
if (op_ret) {
return;
}
- encode_xml("ObjectLockConfiguration", s->bucket_info.obj_lock, s->formatter);
+ encode_xml("ObjectLockConfiguration", s->bucket->get_info().obj_lock, s->formatter);
rgw_flush_formatter_and_reset(s, s->formatter);
}
-int RGWPutObjRetention_ObjStore_S3::get_params()
+int RGWPutObjRetention_ObjStore_S3::get_params(optional_yield y)
{
const char *bypass_gov_header = s->info.env->get("HTTP_X_AMZ_BYPASS_GOVERNANCE_RETENTION");
if (bypass_gov_header) {
}
const auto max_size = s->cct->_conf->rgw_max_put_param_size;
- std::tie(op_ret, data) = rgw_rest_read_all_input(s, max_size, false);
+ std::tie(op_ret, data) = read_all_input(s, max_size, false);
return op_ret;
}
RGWOp *RGWHandler_REST_Bucket_S3::get_obj_op(bool get_data) const
{
// Non-website mode
- if (get_data) {
+ if (get_data) {
int list_type = 1;
s->info.args.get_int("list-type", &list_type, 1);
switch (list_type) {
RGWOp *RGWHandler_REST_Bucket_S3::op_get()
{
+ if (s->info.args.sub_resource_exists("encryption"))
+ return nullptr;
+
if (s->info.args.sub_resource_exists("logging"))
return new RGWGetBucketLogging_ObjStore_S3;
return new RGWGetBucketPolicyStatus_ObjStore_S3;
} else if (is_block_public_access_op()) {
return new RGWGetBucketPublicAccessBlock_ObjStore_S3;
+ } else if (is_bucket_encryption_op()) {
+ return new RGWGetBucketEncryption_ObjStore_S3;
}
return get_obj_op(true);
}
RGWOp *RGWHandler_REST_Bucket_S3::op_put()
{
- if (s->info.args.sub_resource_exists("logging"))
- return NULL;
+ if (s->info.args.sub_resource_exists("logging") ||
+ s->info.args.sub_resource_exists("encryption"))
+ return nullptr;
if (s->info.args.sub_resource_exists("versioning"))
return new RGWSetBucketVersioning_ObjStore_S3;
if (s->info.args.sub_resource_exists("website")) {
} else if (is_notification_op()) {
return RGWHandler_REST_PSNotifs_S3::create_put_op();
} else if (is_replication_op()) {
- auto sync_policy_handler = store->svc()->zone->get_sync_policy_handler(nullopt);
+ auto sync_policy_handler = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_sync_policy_handler(nullopt);
if (!sync_policy_handler ||
sync_policy_handler->is_legacy_config()) {
return nullptr;
return new RGWPutBucketReplication_ObjStore_S3;
} else if (is_block_public_access_op()) {
return new RGWPutBucketPublicAccessBlock_ObjStore_S3;
+ } else if (is_bucket_encryption_op()) {
+ return new RGWPutBucketEncryption_ObjStore_S3;
}
return new RGWCreateBucket_ObjStore_S3;
}
RGWOp *RGWHandler_REST_Bucket_S3::op_delete()
{
+ if (s->info.args.sub_resource_exists("logging") ||
+ s->info.args.sub_resource_exists("encryption"))
+ return nullptr;
+
if (is_tagging_op()) {
return new RGWDeleteBucketTags_ObjStore_S3;
} else if (is_cors_op()) {
return new RGWDeleteBucketReplication_ObjStore_S3;
} else if (is_block_public_access_op()) {
return new RGWDeleteBucketPublicAccessBlock;
+ } else if (is_bucket_encryption_op()) {
+ return new RGWDeleteBucketEncryption_ObjStore_S3;
}
if (s->info.args.sub_resource_exists("website")) {
if (s->info.args.exists("uploads"))
return new RGWInitMultipart_ObjStore_S3;
+
+ if (is_select_op())
+ return rgw::s3select::create_s3select_op();
return new RGWPostObj_ObjStore_S3;
}
return new RGWOptionsCORS_ObjStore_S3;
}
-int RGWHandler_REST_S3::init_from_header(struct req_state* s,
- int default_formatter,
- bool configurable_format)
+int RGWHandler_REST_S3::init_from_header(rgw::sal::Store* store,
+ struct req_state* s,
+ int default_formatter,
+ bool configurable_format)
{
string req;
string first;
}
s->info.args.set(p);
- s->info.args.parse();
+ s->info.args.parse(s);
/* must be called after the args parsing */
int ret = allocate_formatter(s, default_formatter, configurable_format);
if (s->init_state.url_bucket.empty()) {
// Save bucket to tide us over until token is parsed.
s->init_state.url_bucket = first;
+ string encoded_obj_str;
if (pos >= 0) {
- string encoded_obj_str = req.substr(pos+1);
- s->object = rgw_obj_key(encoded_obj_str, s->info.args.get("versionId"));
+ encoded_obj_str = req.substr(pos+1);
+ }
+
+ /* dang: s->bucket is never set here, since it's created with permissions.
+ * These calls will always create an object with no bucket. */
+ if (!encoded_obj_str.empty()) {
+ if (s->bucket) {
+ s->object = s->bucket->get_object(rgw_obj_key(encoded_obj_str, s->info.args.get("versionId")));
+ } else {
+ s->object = store->get_object(rgw_obj_key(encoded_obj_str, s->info.args.get("versionId")));
+ }
}
} else {
- s->object = rgw_obj_key(req_name, s->info.args.get("versionId"));
+ if (s->bucket) {
+ s->object = s->bucket->get_object(rgw_obj_key(req_name, s->info.args.get("versionId")));
+ } else {
+ s->object = store->get_object(rgw_obj_key(req_name, s->info.args.get("versionId")));
+ }
}
return 0;
}
-static int verify_mfa(rgw::sal::RGWRadosStore *store, RGWUserInfo *user, const string& mfa_str, bool *verified, const DoutPrefixProvider *dpp)
+static int verify_mfa(rgw::sal::Store* store, RGWUserInfo *user,
+ const string& mfa_str, bool *verified, const DoutPrefixProvider *dpp, optional_yield y)
{
vector<string> params;
get_str_vec(mfa_str, " ", params);
return -EACCES;
}
- int ret = store->svc()->cls->mfa.check_mfa(user->user_id, serial, pin, null_yield);
+ int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.check_mfa(dpp, user->user_id, serial, pin, y);
if (ret < 0) {
ldpp_dout(dpp, 20) << "NOTICE: failed to check MFA, serial=" << serial << dendl;
return -EACCES;
return 0;
}
-int RGWHandler_REST_S3::postauth_init()
+int RGWHandler_REST_S3::postauth_init(optional_yield y)
{
struct req_init_state *t = &s->init_state;
rgw_parse_url_bucket(t->url_bucket, s->user->get_tenant(),
s->bucket_tenant, s->bucket_name);
- dout(10) << "s->object=" << (!s->object.empty() ? s->object : rgw_obj_key("<NULL>"))
+ if (s->auth.identity->get_identity_type() == TYPE_ROLE) {
+ s->bucket_tenant = s->auth.identity->get_role_tenant();
+ }
+
+ ldpp_dout(s, 10) << "s->object=" << s->object
<< " s->bucket=" << rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name) << dendl;
int ret;
ret = rgw_validate_tenant_name(s->bucket_tenant);
if (ret)
return ret;
- if (!s->bucket_name.empty()) {
- ret = validate_object_name(s->object.name);
+ if (!s->bucket_name.empty() && !rgw::sal::Object::empty(s->object.get())) {
+ ret = validate_object_name(s->object->get_name());
if (ret)
return ret;
}
if (!t->src_bucket.empty()) {
- rgw_parse_url_bucket(t->src_bucket, s->user->get_tenant(),
+ string auth_tenant;
+ if (s->auth.identity->get_identity_type() == TYPE_ROLE) {
+ auth_tenant = s->auth.identity->get_role_tenant();
+ } else {
+ auth_tenant = s->user->get_tenant();
+ }
+ rgw_parse_url_bucket(t->src_bucket, auth_tenant,
s->src_tenant_name, s->src_bucket_name);
ret = rgw_validate_tenant_name(s->src_tenant_name);
if (ret)
const char *mfa = s->info.env->get("HTTP_X_AMZ_MFA");
if (mfa) {
- ret = verify_mfa(store, &s->user->get_info(), string(mfa), &s->mfa_verified, s);
+ ret = verify_mfa(store, &s->user->get_info(), string(mfa), &s->mfa_verified, s, y);
}
return 0;
}
-int RGWHandler_REST_S3::init(rgw::sal::RGWRadosStore *store, struct req_state *s,
+int RGWHandler_REST_S3::init(rgw::sal::Store* store, struct req_state *s,
rgw::io::BasicClient *cio)
{
int ret;
if (ret)
return ret;
if (!s->bucket_name.empty()) {
- ret = validate_object_name(s->object.name);
+ ret = validate_object_name(s->object->get_name());
if (ret)
return ret;
}
if (copy_source &&
(! s->info.env->get("HTTP_X_AMZ_COPY_SOURCE_RANGE")) &&
(! s->info.args.exists("uploadId"))) {
+ rgw_obj_key key;
ret = RGWCopyObj::parse_copy_location(copy_source,
s->init_state.src_bucket,
- s->src_object);
+ key,
+ s);
if (!ret) {
ldpp_dout(s, 0) << "failed to parse copy location" << dendl;
return -EINVAL; // XXX why not -ERR_INVALID_BUCKET_NAME or -ERR_BAD_URL?
}
+ s->src_object = store->get_object(key);
}
const char *sc = s->info.env->get("HTTP_X_AMZ_STORAGE_CLASS");
return RGWHandler_REST::init(store, s, cio);
}
-int RGWHandler_REST_S3::authorize(const DoutPrefixProvider *dpp)
+int RGWHandler_REST_S3::authorize(const DoutPrefixProvider *dpp, optional_yield y)
{
if (s->info.args.exists("Action") && s->info.args.get("Action") == "AssumeRoleWithWebIdentity") {
- return RGW_Auth_STS::authorize(dpp, store, auth_registry, s);
+ return RGW_Auth_STS::authorize(dpp, store, auth_registry, s, y);
}
- return RGW_Auth_S3::authorize(dpp, store, auth_registry, s);
+ return RGW_Auth_S3::authorize(dpp, store, auth_registry, s, y);
}
enum class AwsVersion {
} else {
route = AwsRoute::QUERY_STRING;
- if (info.args.get("X-Amz-Algorithm") == AWS4_HMAC_SHA256_STR) {
+ if (info.args.get("x-amz-algorithm") == AWS4_HMAC_SHA256_STR) {
/* AWS v4 */
version = AwsVersion::V4;
} else if (!info.args.get("AWSAccessKeyId").empty()) {
* it tries AWS v4 before AWS v2
*/
int RGW_Auth_S3::authorize(const DoutPrefixProvider *dpp,
- rgw::sal::RGWRadosStore* const store,
+ rgw::sal::Store* const store,
const rgw::auth::StrategyRegistry& auth_registry,
- struct req_state* const s)
+ struct req_state* const s, optional_yield y)
{
/* neither keystone and rados enabled; warn and exit! */
return -EPERM;
}
- const auto ret = rgw::auth::Strategy::apply(dpp, auth_registry.get_s3_main(), s);
+ const auto ret = rgw::auth::Strategy::apply(dpp, auth_registry.get_s3_main(), s, y);
if (ret == 0) {
/* Populate the owner info. */
s->owner.set_id(s->user->get_id());
return ret;
}
-int RGWHandler_Auth_S3::init(rgw::sal::RGWRadosStore *store, struct req_state *state,
+int RGWHandler_Auth_S3::init(rgw::sal::Store* store, struct req_state *state,
rgw::io::BasicClient *cio)
{
- int ret = RGWHandler_REST_S3::init_from_header(state, RGW_FORMAT_JSON,
- true);
+ int ret = RGWHandler_REST_S3::init_from_header(store, state, RGW_FORMAT_JSON, true);
if (ret < 0)
return ret;
return RGWHandler_REST::init(store, state, cio);
}
-RGWHandler_REST* RGWRESTMgr_S3::get_handler(struct req_state* const s,
+RGWHandler_REST* RGWRESTMgr_S3::get_handler(rgw::sal::Store* store,
+ struct req_state* const s,
const rgw::auth::StrategyRegistry& auth_registry,
const std::string& frontend_prefix)
{
bool is_s3website = enable_s3website && (s->prot_flags & RGW_REST_WEBSITE);
int ret =
- RGWHandler_REST_S3::init_from_header(s,
+ RGWHandler_REST_S3::init_from_header(store, s,
is_s3website ? RGW_FORMAT_HTML :
RGW_FORMAT_XML, true);
if (ret < 0)
if (is_s3website) {
if (s->init_state.url_bucket.empty()) {
handler = new RGWHandler_REST_Service_S3Website(auth_registry);
- } else if (s->object.empty()) {
+ } else if (rgw::sal::Object::empty(s->object.get())) {
handler = new RGWHandler_REST_Bucket_S3Website(auth_registry);
} else {
handler = new RGWHandler_REST_Obj_S3Website(auth_registry);
} else {
if (s->init_state.url_bucket.empty()) {
handler = new RGWHandler_REST_Service_S3(auth_registry, enable_sts, enable_iam, enable_pubsub);
- } else if (s->object.empty()) {
- handler = new RGWHandler_REST_Bucket_S3(auth_registry, enable_pubsub);
- } else {
+ } else if (!rgw::sal::Object::empty(s->object.get())) {
handler = new RGWHandler_REST_Obj_S3(auth_registry);
+ } else if (s->info.args.exist_obj_excl_sub_resource()) {
+ return NULL;
+ } else {
+ handler = new RGWHandler_REST_Bucket_S3(auth_registry, enable_pubsub);
}
}
}
bool RGWHandler_REST_S3Website::web_dir() const {
- std::string subdir_name = url_decode(s->object.name);
+ std::string subdir_name;
+ if (!rgw::sal::Object::empty(s->object.get())) {
+ subdir_name = url_decode(s->object->get_name());
+ }
if (subdir_name.empty()) {
return false;
- } else if (subdir_name.back() == '/') {
+ } else if (subdir_name.back() == '/' && subdir_name.size() > 1) {
subdir_name.pop_back();
}
- rgw_obj obj(s->bucket, subdir_name);
+ std::unique_ptr<rgw::sal::Object> obj = s->bucket->get_object(rgw_obj_key(subdir_name));
RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);
- obj_ctx.set_atomic(obj);
- obj_ctx.set_prefetch_data(obj);
+ obj->set_atomic(&obj_ctx);
+ obj->set_prefetch_data(&obj_ctx);
RGWObjState* state = nullptr;
- if (store->getRados()->get_obj_state(&obj_ctx, s->bucket_info, obj, &state, false, s->yield) < 0) {
+ if (obj->get_obj_state(s, &obj_ctx, &state, s->yield) < 0) {
return false;
}
if (! state->exists) {
return state->exists;
}
-int RGWHandler_REST_S3Website::init(rgw::sal::RGWRadosStore *store, req_state *s,
+int RGWHandler_REST_S3Website::init(rgw::sal::Store* store, req_state *s,
rgw::io::BasicClient* cio)
{
// save the original object name before retarget() replaces it with the
// result of get_effective_key(). the error_handler() needs the original
// object name for redirect handling
- original_object_name = s->object.name;
+ if (!rgw::sal::Object::empty(s->object.get())) {
+ original_object_name = s->object->get_name();
+ } else {
+ original_object_name = "";
+ }
return RGWHandler_REST_S3::init(store, s, cio);
}
-int RGWHandler_REST_S3Website::retarget(RGWOp* op, RGWOp** new_op) {
+int RGWHandler_REST_S3Website::retarget(RGWOp* op, RGWOp** new_op, optional_yield y) {
*new_op = op;
ldpp_dout(s, 10) << __func__ << " Starting retarget" << dendl;
if (!(s->prot_flags & RGW_REST_WEBSITE))
return 0;
- int ret = store->getRados()->get_bucket_info(store->svc(), s->bucket_tenant,
- s->bucket_name, s->bucket_info, NULL,
- s->yield, &s->bucket_attrs);
- if (ret < 0) {
- // TODO-FUTURE: if the bucket does not exist, maybe expose it here?
- return -ERR_NO_SUCH_BUCKET;
- }
- if (!s->bucket_info.has_website) {
+ if (!s->bucket->get_info().has_website) {
// TODO-FUTURE: if the bucket has no WebsiteConfig, expose it here
return -ERR_NO_SUCH_WEBSITE_CONFIGURATION;
}
rgw_obj_key new_obj;
- bool get_res = s->bucket_info.website_conf.get_effective_key(s->object.name, &new_obj.name, web_dir());
+ string key_name;
+ if (!rgw::sal::Object::empty(s->object.get())) {
+ key_name = s->object->get_name();
+ }
+ bool get_res = s->bucket->get_info().website_conf.get_effective_key(key_name, &new_obj.name, web_dir());
if (!get_res) {
s->err.message = "The IndexDocument Suffix is not configurated or not well formed!";
ldpp_dout(s, 5) << s->err.message << dendl;
RGWBWRoutingRule rrule;
bool should_redirect =
- s->bucket_info.website_conf.should_redirect(new_obj.name, 0, &rrule);
+ s->bucket->get_info().website_conf.should_redirect(new_obj.name, 0, &rrule);
if (should_redirect) {
const string& hostname = s->info.env->get("HTTP_HOST", "");
const string& protocol =
(s->info.env->get("SERVER_PORT_SECURE") ? "https" : "http");
int redirect_code = 0;
- rrule.apply_rule(protocol, hostname, s->object.name, &s->redirect,
+ rrule.apply_rule(protocol, hostname, key_name, &s->redirect,
&redirect_code);
// APply a custom HTTP response code
if (redirect_code > 0)
/*
* FIXME: if s->object != new_obj, drop op and create a new op to handle
* operation. Or remove this comment if it's not applicable anymore
+ * dang: This could be problematic, since we're not actually replacing op, but
+ * we are replacing s->object. Something might have a pointer to it.
*/
-
- s->object = new_obj;
+ s->object = s->bucket->get_object(new_obj);
return 0;
}
return get_obj_op(false);
}
-int RGWHandler_REST_S3Website::serve_errordoc(int http_ret, const string& errordoc_key) {
+int RGWHandler_REST_S3Website::serve_errordoc(const DoutPrefixProvider *dpp, int http_ret, const string& errordoc_key, optional_yield y) {
int ret = 0;
s->formatter->reset(); /* Try to throw it all away */
getop->if_unmod = NULL;
getop->if_match = NULL;
getop->if_nomatch = NULL;
- s->object = errordoc_key;
+ /* This is okay. It's an error, so nothing will run after this, and it can be
+ * called by abort_early(), which can be called before s->object or s->bucket
+ * are set up. Note, it won't have bucket. */
+ s->object = store->get_object(errordoc_key);
- ret = init_permissions(getop.get());
+ ret = init_permissions(getop.get(), y);
if (ret < 0) {
ldpp_dout(s, 20) << "serve_errordoc failed, init_permissions ret=" << ret << dendl;
return -1; // Trigger double error handler
}
- ret = read_permissions(getop.get());
+ ret = read_permissions(getop.get(), y);
if (ret < 0) {
ldpp_dout(s, 20) << "serve_errordoc failed, read_permissions ret=" << ret << dendl;
return -1; // Trigger double error handler
getop->set_custom_http_response(http_ret);
}
- ret = getop->init_processing();
+ ret = getop->init_processing(y);
if (ret < 0) {
ldpp_dout(s, 20) << "serve_errordoc failed, init_processing ret=" << ret << dendl;
return -1; // Trigger double error handler
return -1; // Trigger double error handler
}
- ret = getop->verify_permission();
+ ret = getop->verify_permission(y);
if (ret < 0) {
ldpp_dout(s, 20) << "serve_errordoc failed, verify_permission ret=" << ret << dendl;
return -1; // Trigger double error handler
* x-amz-error-message: The specified key does not exist.
* x-amz-error-detail-Key: foo
*/
- getop->execute();
+ getop->execute(y);
getop->complete();
return 0;
-
}
int RGWHandler_REST_S3Website::error_handler(int err_no,
- string* error_content) {
+ string* error_content,
+ optional_yield y) {
int new_err_no = -1;
rgw_http_errors::const_iterator r = rgw_http_s3_errors.find(err_no > 0 ? err_no : -err_no);
int http_error_code = -1;
ldpp_dout(s, 10) << "RGWHandler_REST_S3Website::error_handler err_no=" << err_no << " http_ret=" << http_error_code << dendl;
RGWBWRoutingRule rrule;
- bool should_redirect =
- s->bucket_info.website_conf.should_redirect(original_object_name,
- http_error_code, &rrule);
+ bool have_bucket = !rgw::sal::Bucket::empty(s->bucket.get());
+ bool should_redirect = false;
+ if (have_bucket) {
+ should_redirect =
+ s->bucket->get_info().website_conf.should_redirect(original_object_name,
+ http_error_code, &rrule);
+ }
if (should_redirect) {
const string& hostname = s->info.env->get("HTTP_HOST", "");
} else if (err_no == -ERR_WEBSITE_REDIRECT) {
// Do nothing here, this redirect will be handled in abort_early's ERR_WEBSITE_REDIRECT block
// Do NOT fire the ErrorDoc handler
- } else if (!s->bucket_info.website_conf.error_doc.empty()) {
+ } else if (have_bucket && !s->bucket->get_info().website_conf.error_doc.empty()) {
/* This serves an entire page!
On success, it will return zero, and no further content should be sent to the socket
On failure, we need the double-error handler
*/
- new_err_no = RGWHandler_REST_S3Website::serve_errordoc(http_error_code, s->bucket_info.website_conf.error_doc);
- if (new_err_no && new_err_no != -1) {
+ new_err_no = RGWHandler_REST_S3Website::serve_errordoc(s, http_error_code, s->bucket->get_info().website_conf.error_doc, y);
+ if (new_err_no != -1) {
err_no = new_err_no;
}
} else {
boost::optional<std::string>
AWSGeneralAbstractor::get_v4_canonical_headers(
const req_info& info,
- const boost::string_view& signedheaders,
+ const std::string_view& signedheaders,
const bool using_qs) const
{
return rgw::auth::s3::get_v4_canonical_headers(info, signedheaders,
using_qs, false);
}
+AWSSignerV4::prepare_result_t
+AWSSignerV4::prepare(const DoutPrefixProvider *dpp,
+ const std::string& access_key_id,
+ const string& region,
+ const string& service,
+ const req_info& info,
+ const bufferlist *opt_content,
+ bool s3_op)
+{
+ std::string signed_hdrs;
+
+ ceph::real_time timestamp = ceph::real_clock::now();
+
+ map<string, string> extra_headers;
+
+ std::string date = ceph::to_iso_8601_no_separators(timestamp, ceph::iso_8601_format::YMDhms);
+
+ std::string credential_scope = gen_v4_scope(timestamp, region, service);
+
+ extra_headers["x-amz-date"] = date;
+
+ string content_hash;
+
+ if (opt_content) {
+ content_hash = rgw::auth::s3::calc_v4_payload_hash(opt_content->to_str());
+ extra_headers["x-amz-content-sha256"] = content_hash;
+
+ }
+
+ /* craft canonical headers */
+ std::string canonical_headers = \
+ gen_v4_canonical_headers(info, extra_headers, &signed_hdrs);
+
+ using sanitize = rgw::crypt_sanitize::log_content;
+ ldpp_dout(dpp, 10) << "canonical headers format = "
+ << sanitize{canonical_headers} << dendl;
+
+ bool is_non_s3_op = !s3_op;
+
+ const char* exp_payload_hash = nullptr;
+ string payload_hash;
+ if (is_non_s3_op) {
+ //For non s3 ops, we need to calculate the payload hash
+ payload_hash = info.args.get("PayloadHash");
+ exp_payload_hash = payload_hash.c_str();
+ } else {
+ /* Get the expected hash. */
+ if (content_hash.empty()) {
+ exp_payload_hash = rgw::auth::s3::get_v4_exp_payload_hash(info);
+ } else {
+ exp_payload_hash = content_hash.c_str();
+ }
+ }
+
+ /* Craft canonical URI. Using std::move later so let it be non-const. */
+ auto canonical_uri = rgw::auth::s3::gen_v4_canonical_uri(info);
+
+
+ /* Craft canonical query string. std::moving later so non-const here. */
+ auto canonical_qs = rgw::auth::s3::gen_v4_canonical_qs(info);
+
+ auto cct = dpp->get_cct();
+
+ /* Craft canonical request. */
+ auto canonical_req_hash = \
+ rgw::auth::s3::get_v4_canon_req_hash(cct,
+ info.method,
+ std::move(canonical_uri),
+ std::move(canonical_qs),
+ std::move(canonical_headers),
+ signed_hdrs,
+ exp_payload_hash,
+ dpp);
+
+ auto string_to_sign = \
+ rgw::auth::s3::get_v4_string_to_sign(cct,
+ AWS4_HMAC_SHA256_STR,
+ date,
+ credential_scope,
+ std::move(canonical_req_hash),
+ dpp);
+
+ const auto sig_factory = gen_v4_signature;
+
+ /* Requests authenticated with the Query Parameters are treated as unsigned.
+ * From "Authenticating Requests: Using Query Parameters (AWS Signature
+ * Version 4)":
+ *
+ * You don't include a payload hash in the Canonical Request, because
+ * when you create a presigned URL, you don't know the payload content
+ * because the URL is used to upload an arbitrary payload. Instead, you
+ * use a constant string UNSIGNED-PAYLOAD.
+ *
+ * This means we have absolutely no business in spawning completer. Both
+ * aws4_auth_needs_complete and aws4_auth_streaming_mode are set to false
+ * by default. We don't need to change that. */
+ return {
+ access_key_id,
+ date,
+ credential_scope,
+ std::move(signed_hdrs),
+ std::move(string_to_sign),
+ std::move(extra_headers),
+ sig_factory,
+ };
+}
+
+AWSSignerV4::signature_headers_t
+gen_v4_signature(const DoutPrefixProvider *dpp,
+ const std::string_view& secret_key,
+ const AWSSignerV4::prepare_result_t& sig_info)
+{
+ auto signature = rgw::auth::s3::get_v4_signature(sig_info.scope,
+ dpp->get_cct(),
+ secret_key,
+ sig_info.string_to_sign,
+ dpp);
+ AWSSignerV4::signature_headers_t result;
+
+ for (auto& entry : sig_info.extra_headers) {
+ result[entry.first] = entry.second;
+ }
+ auto& payload_hash = result["x-amz-content-sha256"];
+ if (payload_hash.empty()) {
+ payload_hash = AWS4_UNSIGNED_PAYLOAD_HASH;
+ }
+ string auth_header = string("AWS4-HMAC-SHA256 Credential=").append(sig_info.access_key_id) + "/";
+ auth_header.append(sig_info.scope + ",SignedHeaders=")
+ .append(sig_info.signed_headers + ",Signature=")
+ .append(signature);
+ result["Authorization"] = auth_header;
+
+ return result;
+}
+
+
AWSEngine::VersionAbstractor::auth_data_t
AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
const bool using_qs) const
{
- boost::string_view access_key_id;
- boost::string_view signed_hdrs;
+ std::string_view access_key_id;
+ std::string_view signed_hdrs;
- boost::string_view date;
- boost::string_view credential_scope;
- boost::string_view client_signature;
- boost::string_view session_token;
+ std::string_view date;
+ std::string_view credential_scope;
+ std::string_view client_signature;
+ std::string_view session_token;
int ret = rgw::auth::s3::parse_v4_credentials(s->info,
access_key_id,
client_signature,
date,
session_token,
- using_qs);
+ using_qs,
+ s);
if (ret < 0) {
throw ret;
}
throw -EPERM;
}
- bool is_non_s3_op = false;
- if (s->op_type == RGW_STS_GET_SESSION_TOKEN ||
- s->op_type == RGW_STS_ASSUME_ROLE ||
- s->op_type == RGW_STS_ASSUME_ROLE_WEB_IDENTITY ||
- s->op_type == RGW_OP_CREATE_ROLE ||
- s->op_type == RGW_OP_DELETE_ROLE ||
- s->op_type == RGW_OP_GET_ROLE ||
- s->op_type == RGW_OP_MODIFY_ROLE ||
- s->op_type == RGW_OP_LIST_ROLES ||
- s->op_type == RGW_OP_PUT_ROLE_POLICY ||
- s->op_type == RGW_OP_GET_ROLE_POLICY ||
- s->op_type == RGW_OP_LIST_ROLE_POLICIES ||
- s->op_type == RGW_OP_DELETE_ROLE_POLICY ||
- s->op_type == RGW_OP_PUT_USER_POLICY ||
- s->op_type == RGW_OP_GET_USER_POLICY ||
- s->op_type == RGW_OP_LIST_USER_POLICIES ||
- s->op_type == RGW_OP_DELETE_USER_POLICY) {
- is_non_s3_op = true;
- }
+ bool is_non_s3_op = rgw::auth::s3::is_non_s3_op(s->op_type);
const char* exp_payload_hash = nullptr;
string payload_hash;
std::move(canonical_qs),
std::move(*canonical_headers),
signed_hdrs,
- exp_payload_hash);
+ exp_payload_hash,
+ s);
auto string_to_sign = \
rgw::auth::s3::get_v4_string_to_sign(s->cct,
AWS4_HMAC_SHA256_STR,
date,
credential_scope,
- std::move(canonical_req_hash));
+ std::move(canonical_req_hash),
+ s);
const auto sig_factory = std::bind(rgw::auth::s3::get_v4_signature,
credential_scope,
std::placeholders::_1,
std::placeholders::_2,
- std::placeholders::_3);
+ std::placeholders::_3,
+ s);
/* Requests authenticated with the Query Parameters are treated as unsigned.
* From "Authenticating Requests: Using Query Parameters (AWS Signature
case RGW_OP_PUT_OBJ:
case RGW_OP_PUT_ACLS:
case RGW_OP_PUT_CORS:
+ case RGW_OP_PUT_BUCKET_ENCRYPTION:
+ case RGW_OP_GET_BUCKET_ENCRYPTION:
+ case RGW_OP_DELETE_BUCKET_ENCRYPTION:
case RGW_OP_INIT_MULTIPART: // in case that Init Multipart uses CHUNK encoding
case RGW_OP_COMPLETE_MULTIPART:
case RGW_OP_SET_BUCKET_VERSIONING:
case RGW_OP_DELETE_MULTI_OBJ:
case RGW_OP_ADMIN_SET_METADATA:
+ case RGW_OP_SYNC_DATALOG_NOTIFY:
+ case RGW_OP_SYNC_MDLOG_NOTIFY:
+ case RGW_OP_PERIOD_POST:
case RGW_OP_SET_BUCKET_WEBSITE:
case RGW_OP_PUT_BUCKET_POLICY:
case RGW_OP_PUT_OBJ_TAGGING:
case RGW_OP_PUT_LC:
case RGW_OP_SET_REQUEST_PAYMENT:
case RGW_OP_PUBSUB_NOTIF_CREATE:
+ case RGW_OP_PUBSUB_NOTIF_DELETE:
+ case RGW_OP_PUBSUB_NOTIF_LIST:
case RGW_OP_PUT_BUCKET_OBJ_LOCK:
case RGW_OP_PUT_OBJ_RETENTION:
case RGW_OP_PUT_OBJ_LEGAL_HOLD:
case RGW_OP_PUT_BUCKET_PUBLIC_ACCESS_BLOCK:
case RGW_OP_GET_BUCKET_PUBLIC_ACCESS_BLOCK:
case RGW_OP_DELETE_BUCKET_PUBLIC_ACCESS_BLOCK:
+ case RGW_OP_GET_OBJ://s3select its post-method(payload contain the query) , the request is get-object
break;
default:
- dout(10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED" << dendl;
+ ldpp_dout(s, 10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED" << dendl;
throw -ERR_NOT_IMPLEMENTED;
}
/* IMHO "streamed" doesn't fit too good here. I would prefer to call
* it "chunked" but let's be coherent with Amazon's terminology. */
- dout(10) << "body content detected in multiple chunks" << dendl;
+ ldpp_dout(s, 10) << "body content detected in multiple chunks" << dendl;
/* payload in multiple chunks */
case RGW_OP_PUT_OBJ:
break;
default:
- dout(10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED (streaming mode)" << dendl;
+ ldpp_dout(s, 10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED (streaming mode)" << dendl;
throw -ERR_NOT_IMPLEMENTED;
}
- dout(10) << "aws4 seed signature ok... delaying v4 auth" << dendl;
+ ldpp_dout(s, 10) << "aws4 seed signature ok... delaying v4 auth" << dendl;
/* In the case of streamed payload client sets the x-amz-content-sha256
* to "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" but uses "UNSIGNED-PAYLOAD"
boost::optional<std::string>
AWSGeneralBoto2Abstractor::get_v4_canonical_headers(
const req_info& info,
- const boost::string_view& signedheaders,
+ const std::string_view& signedheaders,
const bool using_qs) const
{
return rgw::auth::s3::get_v4_canonical_headers(info, signedheaders,
AWSEngine::VersionAbstractor::auth_data_t
AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
{
- boost::string_view access_key_id;
- boost::string_view signature;
- boost::string_view session_token;
+ std::string_view access_key_id;
+ std::string_view signature;
+ std::string_view session_token;
bool qsr = false;
const char* http_auth = s->info.env->get("HTTP_AUTHORIZATION");
signature = s->info.args.get("Signature");
qsr = true;
- boost::string_view expires = s->info.args.get("Expires");
+ std::string_view expires = s->info.args.get("Expires");
if (expires.empty()) {
throw -EPERM;
}
if (now >= exp) {
throw -EPERM;
}
- if (s->info.args.exists("X-Amz-Security-Token")) {
- session_token = s->info.args.get("X-Amz-Security-Token");
+ if (s->info.args.exists("x-amz-security-token")) {
+ session_token = s->info.args.get("x-amz-security-token");
if (session_token.size() == 0) {
throw -EPERM;
}
} else {
/* The "Authorization" HTTP header is being used. */
- const boost::string_view auth_str(http_auth + strlen("AWS "));
+ const std::string_view auth_str(http_auth + strlen("AWS "));
const size_t pos = auth_str.rfind(':');
- if (pos != boost::string_view::npos) {
+ if (pos != std::string_view::npos) {
access_key_id = auth_str.substr(0, pos);
signature = auth_str.substr(pos + 1);
}
/* Let's canonize the HTTP headers that are covered by the AWS auth v2. */
std::string string_to_sign;
utime_t header_time;
- if (! rgw_create_s3_canonical_header(s->info, &header_time, string_to_sign,
+ if (! rgw_create_s3_canonical_header(s, s->info, &header_time, string_to_sign,
qsr)) {
ldpp_dout(s, 10) << "failed to create the canonized auth header\n"
<< rgw::crypt_sanitize::auth{s,string_to_sign} << dendl;
AWSEngine::VersionAbstractor::auth_data_t
AWSBrowserUploadAbstractor::get_auth_data_v4(const req_state* const s) const
{
- const boost::string_view credential = s->auth.s3_postobj_creds.x_amz_credential;
+ const std::string_view credential = s->auth.s3_postobj_creds.x_amz_credential;
/* grab access key id */
const size_t pos = credential.find("/");
- const boost::string_view access_key_id = credential.substr(0, pos);
- dout(10) << "access key id = " << access_key_id << dendl;
+ const std::string_view access_key_id = credential.substr(0, pos);
+ ldpp_dout(s, 10) << "access key id = " << access_key_id << dendl;
/* grab credential scope */
- const boost::string_view credential_scope = credential.substr(pos + 1);
- dout(10) << "credential scope = " << credential_scope << dendl;
+ const std::string_view credential_scope = credential.substr(pos + 1);
+ ldpp_dout(s, 10) << "credential scope = " << credential_scope << dendl;
const auto sig_factory = std::bind(rgw::auth::s3::get_v4_signature,
credential_scope,
std::placeholders::_1,
std::placeholders::_2,
- std::placeholders::_3);
+ std::placeholders::_3,
+ s);
return {
access_key_id,
}
AWSEngine::result_t
-AWSEngine::authenticate(const DoutPrefixProvider* dpp, const req_state* const s) const
+AWSEngine::authenticate(const DoutPrefixProvider* dpp, const req_state* const s, optional_yield y) const
{
/* Small reminder: an ver_abstractor is allowed to throw! */
const auto auth_data = ver_abstractor.get_auth_data(s);
return authenticate(dpp,
auth_data.access_key_id,
auth_data.client_signature,
- auth_data.session_token,
+ auth_data.session_token,
auth_data.string_to_sign,
auth_data.signature_factory,
auth_data.completer_factory,
- s);
+ s, y);
}
}
rgw::auth::Engine::result_t
rgw::auth::s3::LDAPEngine::authenticate(
const DoutPrefixProvider* dpp,
- const boost::string_view& access_key_id,
- const boost::string_view& signature,
- const boost::string_view& session_token,
+ const std::string_view& access_key_id,
+ const std::string_view& signature,
+ const std::string_view& session_token,
const string_to_sign_t& string_to_sign,
const signature_factory_t&,
const completer_factory_t& completer_factory,
- const req_state* const s) const
+ const req_state* const s,
+ optional_yield y) const
{
/* boost filters and/or string_ref may throw on invalid input */
rgw::RGWToken base64_token;
rgw::auth::Engine::result_t
rgw::auth::s3::LocalEngine::authenticate(
const DoutPrefixProvider* dpp,
- const boost::string_view& _access_key_id,
- const boost::string_view& signature,
- const boost::string_view& session_token,
+ const std::string_view& _access_key_id,
+ const std::string_view& signature,
+ const std::string_view& session_token,
const string_to_sign_t& string_to_sign,
const signature_factory_t& signature_factory,
const completer_factory_t& completer_factory,
- const req_state* const s) const
+ const req_state* const s,
+ optional_yield y) const
{
/* get the user info */
- RGWUserInfo user_info;
+ std::unique_ptr<rgw::sal::User> user;
+ const std::string access_key_id(_access_key_id);
/* TODO(rzarzynski): we need to have string-view taking variant. */
- const std::string access_key_id = _access_key_id.to_string();
- if (rgw_get_user_info_by_access_key(ctl->user, access_key_id, user_info) < 0) {
+ if (store->get_user_by_access_key(dpp, access_key_id, y, &user) < 0) {
ldpp_dout(dpp, 5) << "error reading user info, uid=" << access_key_id
<< " can't authenticate" << dendl;
return result_t::deny(-ERR_INVALID_ACCESS_KEY);
}
}*/
- const auto iter = user_info.access_keys.find(access_key_id);
- if (iter == std::end(user_info.access_keys)) {
+ const auto iter = user->get_info().access_keys.find(access_key_id);
+ if (iter == std::end(user->get_info().access_keys)) {
ldpp_dout(dpp, 0) << "ERROR: access key not encoded in user info" << dendl;
return result_t::deny(-EPERM);
}
return result_t::deny(-ERR_SIGNATURE_NO_MATCH);
}
- auto apl = apl_factory->create_apl_local(cct, s, user_info, k.subuser, boost::none);
+ auto apl = apl_factory->create_apl_local(cct, s, user->get_info(),
+ k.subuser, std::nullopt);
return result_t::grant(std::move(apl), completer_factory(k.key));
}
}
int
-rgw::auth::s3::STSEngine::get_session_token(const DoutPrefixProvider* dpp, const boost::string_view& session_token,
+rgw::auth::s3::STSEngine::get_session_token(const DoutPrefixProvider* dpp, const std::string_view& session_token,
STS::SessionToken& token) const
{
string decodedSessionToken;
return -EINVAL;
}
string error;
- auto* keyhandler = cryptohandler->get_key_handler(secret, error);
+ std::unique_ptr<CryptoKeyHandler> keyhandler(cryptohandler->get_key_handler(secret, error));
if (! keyhandler) {
return -EINVAL;
}
auto iter = dec_output.cbegin();
decode(token, iter);
} catch (const buffer::error& e) {
- ldout(cct, 0) << "ERROR: decode SessionToken failed: " << error << dendl;
+ ldpp_dout(dpp, 0) << "ERROR: decode SessionToken failed: " << error << dendl;
return -EINVAL;
}
}
rgw::auth::Engine::result_t
rgw::auth::s3::STSEngine::authenticate(
const DoutPrefixProvider* dpp,
- const boost::string_view& _access_key_id,
- const boost::string_view& signature,
- const boost::string_view& session_token,
+ const std::string_view& _access_key_id,
+ const std::string_view& signature,
+ const std::string_view& session_token,
const string_to_sign_t& string_to_sign,
const signature_factory_t& signature_factory,
const completer_factory_t& completer_factory,
- const req_state* const s) const
+ const req_state* const s,
+ optional_yield y) const
{
- if (! s->info.args.exists("X-Amz-Security-Token") &&
+ if (! s->info.args.exists("x-amz-security-token") &&
! s->info.env->exists("HTTP_X_AMZ_SECURITY_TOKEN") &&
s->auth.s3_postobj_creds.x_amz_security_token.empty()) {
return result_t::deny();
}
// Get all the authorization info
- RGWUserInfo user_info;
+ std::unique_ptr<rgw::sal::User> user;
rgw_user user_id;
- vector<string> role_policies;
- string role_name;
+ string role_id;
+ rgw::auth::RoleApplier::Role r;
+ rgw::auth::RoleApplier::TokenAttrs t_attrs;
if (! token.roleId.empty()) {
- RGWRole role(s->cct, ctl, token.roleId);
- if (role.get_by_id() < 0) {
+ std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(token.roleId);
+ if (role->get_by_id(dpp, y) < 0) {
return result_t::deny(-EPERM);
}
- vector<string> role_policy_names = role.get_role_policy_names();
+ r.id = token.roleId;
+ r.name = role->get_name();
+ r.tenant = role->get_tenant();
+
+ vector<string> role_policy_names = role->get_role_policy_names();
for (auto& policy_name : role_policy_names) {
string perm_policy;
- if (int ret = role.get_role_policy(policy_name, perm_policy); ret == 0) {
- role_policies.push_back(std::move(perm_policy));
+ if (int ret = role->get_role_policy(dpp, policy_name, perm_policy); ret == 0) {
+ r.role_policies.push_back(std::move(perm_policy));
}
}
- if (! token.policy.empty()) {
- role_policies.push_back(std::move(token.policy));
- }
- // This is mostly needed to assign the owner of a bucket during its creation
- user_id = token.user;
- role_name = role.get_name();
}
+ user = store->get_user(token.user);
if (! token.user.empty() && token.acct_type != TYPE_ROLE) {
// get user info
- int ret = rgw_get_user_info_by_uid(ctl->user, token.user, user_info, NULL);
+ int ret = user->load_user(dpp, y);
if (ret < 0) {
ldpp_dout(dpp, 5) << "ERROR: failed reading user info: uid=" << token.user << dendl;
return result_t::reject(-EPERM);
if (token.acct_type == TYPE_KEYSTONE || token.acct_type == TYPE_LDAP) {
auto apl = remote_apl_factory->create_apl_remote(cct, s, get_acl_strategy(),
get_creds_info(token));
- return result_t::grant(std::move(apl), completer_factory(boost::none));
+ return result_t::grant(std::move(apl), completer_factory(token.secret_access_key));
} else if (token.acct_type == TYPE_ROLE) {
- auto apl = role_apl_factory->create_apl_role(cct, s, role_name, user_id, role_policies);
+ t_attrs.user_id = std::move(token.user); // This is mostly needed to assign the owner of a bucket during its creation
+ t_attrs.token_policy = std::move(token.policy);
+ t_attrs.role_session_name = std::move(token.role_session);
+ t_attrs.token_claims = std::move(token.token_claims);
+ t_attrs.token_issued_at = std::move(token.issued_at);
+ t_attrs.principal_tags = std::move(token.principal_tags);
+ auto apl = role_apl_factory->create_apl_role(cct, s, r, t_attrs);
return result_t::grant(std::move(apl), completer_factory(token.secret_access_key));
} else { // This is for all local users of type TYPE_RGW or TYPE_NONE
string subuser;
- auto apl = local_apl_factory->create_apl_local(cct, s, user_info, subuser, token.perm_mask);
+ auto apl = local_apl_factory->create_apl_local(cct, s, user->get_info(), subuser, token.perm_mask);
return result_t::grant(std::move(apl), completer_factory(token.secret_access_key));
}
}
return route == AwsRoute::QUERY_STRING && version == AwsVersion::UNKNOWN;
}
+