rgw: fix mfa setting, verify on object deletion

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
This commit is contained in:
Yehuda Sadeh 2017-11-21 14:50:23 -08:00
parent 0c0046e259
commit 2d5d024f27
5 changed files with 86 additions and 23 deletions

View File

@ -84,6 +84,7 @@ rgw_http_errors rgw_http_s3_errors({
{ ERR_USER_SUSPENDED, {403, "UserSuspended" }},
{ ERR_REQUEST_TIME_SKEWED, {403, "RequestTimeTooSkewed" }},
{ ERR_QUOTA_EXCEEDED, {403, "QuotaExceeded" }},
{ ERR_MFA_REQUIRED, {403, "AccessDenied" }},
{ ENOENT, {404, "NoSuchKey" }},
{ ERR_NO_SUCH_BUCKET, {404, "NoSuchBucket" }},
{ ERR_NO_SUCH_WEBSITE_CONFIGURATION, {404, "NoSuchWebsiteConfiguration" }},

View File

@ -200,6 +200,7 @@ using ceph::crypto::MD5;
#define ERR_NO_SUCH_LC 2041
#define ERR_NO_SUCH_USER 2042
#define ERR_NO_SUCH_SUBUSER 2043
#define ERR_MFA_REQUIRED 2044
#define ERR_USER_SUSPENDED 2100
#define ERR_INTERNAL_ERROR 2200
#define ERR_NOT_IMPLEMENTED 2201
@ -1352,8 +1353,8 @@ struct RGWBucketInfo
bool versioned() const { return (flags & BUCKET_VERSIONED) != 0; }
int versioning_status() { return flags & (BUCKET_VERSIONED | BUCKET_VERSIONS_SUSPENDED | BUCKET_MFA_ENABLED); }
bool versioning_enabled() { return versioning_status() == BUCKET_VERSIONED; }
bool mfa_enabled() { return versioning_status() == BUCKET_MFA_ENABLED; }
bool versioning_enabled() { return (versioning_status() & (BUCKET_VERSIONED | BUCKET_VERSIONS_SUSPENDED)) == BUCKET_VERSIONED; }
bool mfa_enabled() { return (versioning_status() & BUCKET_MFA_ENABLED) != 0; }
bool datasync_flag_enabled() const { return (flags & BUCKET_DATASYNC_DISABLED) == 0; }
bool has_swift_versioning() const {

View File

@ -2171,6 +2171,12 @@ void RGWSetBucketVersioning::execute()
if (op_ret < 0)
return;
if (mfa_set_status &&
!s->mfa_verified) {
op_ret = -ERR_MFA_REQUIRED;
return;
}
if (!store->is_meta_master()) {
op_ret = forward_request_to_master(s, NULL, store, in_data, nullptr);
if (op_ret < 0) {
@ -2179,20 +2185,35 @@ void RGWSetBucketVersioning::execute()
}
}
bool modified = mfa_set_status;
op_ret = retry_raced_bucket_write(store, s, [this] {
if (mfa_set_status) {
if (mfa_status) {
s->bucket_info.flags |= BUCKET_MFA_ENABLED;
} else {
s->bucket_info.flags &= ~BUCKET_MFA_ENABLED;
}
}
if (versioning_status == VersioningEnabled) {
s->bucket_info.flags |= BUCKET_VERSIONED;
s->bucket_info.flags &= ~BUCKET_VERSIONS_SUSPENDED;
modified = true;
} else if (versioning_status == VersioningSuspended) {
s->bucket_info.flags |= (BUCKET_VERSIONED | BUCKET_VERSIONS_SUSPENDED);
modified = true;
} else {
return op_ret;
}
op_ret = store->put_bucket_instance_info(s->bucket_info, false, real_time(),
&s->bucket_attrs);
return op_ret;
return store->put_bucket_instance_info(s->bucket_info, false, real_time(),
&s->bucket_attrs);
});
if (!modified) {
return;
}
if (op_ret < 0) {
ldout(s->cct, 0) << "NOTICE: put_bucket_info on bucket=" << s->bucket.name
<< " returned err=" << op_ret << dendl;
@ -4327,6 +4348,13 @@ int RGWDeleteObj::verify_permission()
return -EACCES;
}
if (s->bucket_info.mfa_enabled() &&
!s->object.instance.empty() &&
!s->mfa_verified) {
ldout(s->cct, 5) << "NOTICE: object delete request with a versioned object, mfa auth not provided" << dendl;
return -ERR_MFA_REQUIRED;
}
return 0;
}
@ -5939,6 +5967,21 @@ void RGWDeleteMultiObj::execute()
if (multi_delete->is_quiet())
quiet = true;
if (s->bucket_info.mfa_enabled()) {
bool has_versioned = false;
for (auto i : multi_delete->objects) {
if (!i.instance.empty()) {
has_versioned = true;
break;
}
}
if (has_versioned && !s->mfa_verified) {
ldout(s->cct, 5) << "NOTICE: multi-object delete request with a versioned object, mfa auth not provided" << dendl;
op_ret = -ERR_MFA_REQUIRED;
goto error;
}
}
begin_response();
if (multi_delete->objects.empty()) {
goto done;

View File

@ -776,6 +776,7 @@ enum BucketVersionStatus {
class RGWSetBucketVersioning : public RGWOp {
protected:
int versioning_status;
bool mfa_set_status{false};
bool mfa_status{false};
bufferlist in_data;
public:

View File

@ -885,30 +885,33 @@ void RGWGetBucketVersioning_ObjStore_S3::send_response()
struct ver_config_status {
int status{VersioningSuspended};
int mfa_status{0};
enum MFAStatus {
MFA_UNKNOWN,
MFA_DISABLED,
MFA_ENABLED,
} mfa_status{MFA_UNKNOWN};
int retcode{0};
void decode_xml(XMLObj *obj) {
dout(0) << __FILE__ << ":" << __LINE__ << dendl;
string status_str;
string mfa_str;
RGWXMLDecoder::decode_xml("Status", status_str, obj);
dout(0) << __FILE__ << ":" << __LINE__ << dendl;
if (status_str == "Enabled") {
status = VersioningEnabled;
} else if (status_str != "Suspended") {
status = VersioningStatusInvalid;
}
dout(0) << __FILE__ << ":" << __LINE__ << " status_str=" << status_str << dendl;
RGWXMLDecoder::decode_xml("MfaDelete", mfa_str, obj);
dout(0) << __FILE__ << ":" << __LINE__ << " mfa_str=" << mfa_str << dendl;
if (mfa_str == "Enabled") {
mfa_status = 1;
} else if (mfa_str == "Disabled") {
mfa_status = 0;
} else {
mfa_status = -EINVAL;
if (RGWXMLDecoder::decode_xml("MfaDelete", mfa_str, obj)) {
if (mfa_str == "Enabled") {
mfa_status = MFA_ENABLED;
} else if (mfa_str == "Disabled") {
mfa_status = MFA_DISABLED;
} else {
retcode = -EINVAL;
}
}
}
};
@ -937,14 +940,17 @@ int RGWSetBucketVersioning_ObjStore_S3::get_params()
}
if (!parser.parse(data, len, 1)) {
ldout(s->cct, 10) << "failed to parse data: " << data << dendl;
ldout(s->cct, 10) << "NOTICE: failed to parse data: " << data << dendl;
r = -EINVAL;
return r;
}
ver_config_status status_conf;
RGWXMLDecoder::decode_xml("VersioningConfiguration", status_conf, &parser);
if (!RGWXMLDecoder::decode_xml("VersioningConfiguration", status_conf, &parser)) {
ldout(s->cct, 10) << "NOTICE: bad versioning config input" << dendl;
return -EINVAL;
}
if (!store->is_meta_master()) {
/* only need to keep this data around if we're not meta master */
@ -956,10 +962,21 @@ int RGWSetBucketVersioning_ObjStore_S3::get_params()
r = -EINVAL;
}
if (status_conf.mfa_status >= 0) {
mfa_status = (bool)status_conf.mfa_status;
} else {
r = -EINVAL;
if (status_conf.mfa_status != ver_config_status::MFA_UNKNOWN) {
mfa_set_status = true;
switch (status_conf.mfa_status) {
case ver_config_status::MFA_DISABLED:
mfa_status = false;
break;
case ver_config_status::MFA_ENABLED:
mfa_status = true;
break;
default:
ldout(s->cct, 0) << "ERROR: RGWSetBucketVersioning_ObjStore_S3::get_params(): unexpected switch case mfa_status=" << status_conf.mfa_status << dendl;
r = -EIO;
}
} else if (status_conf.retcode < 0) {
r = status_conf.retcode;
}
return r;
}