Merge pull request #16442 from theanalyst/rgw-admin-tenant-validate

rgw: validate tenant names during user create.

Reviewed-by: Casey Bodley <cbodley@redhat.com>
Reviewed-by: Pritha Srivastava <prsrivas@redhat.com>
This commit is contained in:
Yuri Weinstein 2017-08-02 08:59:54 -07:00 committed by GitHub
commit 0a3056df4a
9 changed files with 59 additions and 26 deletions

View File

@ -321,6 +321,11 @@ generated key is added to the keyring without replacing an existing key pair.
If ``access-key`` is specified and refers to an existing key owned by the user
then it will be modified.
.. versionadded:: Luminous
A ``tenant`` may either be specified as a part of uid or as an additional
request param.
:caps: users=write
Syntax
@ -342,6 +347,7 @@ Request Parameters
:Type: String
:Example: ``foo_user``
:Required: Yes
A tenant name may also specified as a part of ``uid``, by following the syntax ``tenant$user``, refer to `Multitenancy`_ for more details.
``display-name``
@ -408,6 +414,14 @@ Request Parameters
:Example: False [False]
:Required: No
.. versionadded:: Jewel
``tenant``
:Description: the Tenant under which a user is a part of.
:Type: string
:Example: tenant1
:Required: No
Response Entities
~~~~~~~~~~~~~~~~~
@ -418,6 +432,11 @@ If successful, the response contains the user information.
:Description: A container for the user data information.
:Type: Container
``tenant``
:Description: The tenant which user is a part of
:Type: String
:Parent: ``user``
``user_id``
:Description: The user id.
@ -1924,3 +1943,4 @@ Standard Error Responses
.. _Admin Guide: ../admin
.. _Quota Management: ../admin#quota-management
.. _Multitenancy: ./multitenancy

View File

@ -4435,6 +4435,9 @@ int main(int argc, const char **argv)
ret = user.add(user_op, &err_msg);
if (ret < 0) {
cerr << "could not create user: " << err_msg << std::endl;
if (ret == -ERR_INVALID_TENANT_NAME)
ret = -EINVAL;
return -ret;
}
if (!subuser.empty()) {

View File

@ -1834,18 +1834,6 @@ int RGWHandler_REST::allocate_formatter(struct req_state *s,
return 0;
}
int RGWHandler_REST::validate_tenant_name(string const& t)
{
struct tench {
static bool is_good(char ch) {
return isalnum(ch) || ch == '_';
}
};
std::string::const_iterator it =
std::find_if_not(t.begin(), t.end(), tench::is_good);
return (it == t.end())? 0: -ERR_INVALID_TENANT_NAME;
}
// This function enforces Amazon's spec for bucket names.
// (The requirements, not the recommendations.)
int RGWHandler_REST::validate_bucket_name(const string& bucket)

View File

@ -501,7 +501,6 @@ public:
RGWHandler_REST() {}
~RGWHandler_REST() override {}
static int validate_tenant_name(const string& bucket);
static int validate_bucket_name(const string& bucket);
static int validate_object_name(const string& object);

View File

@ -3206,7 +3206,7 @@ int RGWHandler_REST_S3::postauth_init()
<< " s->bucket=" << rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name) << dendl;
int ret;
ret = validate_tenant_name(s->bucket_tenant);
ret = rgw_validate_tenant_name(s->bucket_tenant);
if (ret)
return ret;
if (!s->bucket_name.empty()) {
@ -3221,7 +3221,7 @@ int RGWHandler_REST_S3::postauth_init()
if (!t->src_bucket.empty()) {
rgw_parse_url_bucket(t->src_bucket, s->user->user_id.tenant,
s->src_tenant_name, s->src_bucket_name);
ret = validate_tenant_name(s->src_tenant_name);
ret = rgw_validate_tenant_name(s->src_tenant_name);
if (ret)
return ret;
ret = valid_s3_bucket_name(s->src_bucket_name, relaxed_names);
@ -3237,8 +3237,8 @@ int RGWHandler_REST_S3::init(RGWRados *store, struct req_state *s,
int ret;
s->dialect = "s3";
ret = validate_tenant_name(s->bucket_tenant);
ret = rgw_validate_tenant_name(s->bucket_tenant);
if (ret)
return ret;
bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names;

View File

@ -2558,7 +2558,7 @@ int RGWHandler_REST_SWIFT::postauth_init()
<< dendl;
int ret;
ret = validate_tenant_name(s->bucket_tenant);
ret = rgw_validate_tenant_name(s->bucket_tenant);
if (ret)
return ret;
ret = validate_bucket_name(s->bucket_name);

View File

@ -76,6 +76,7 @@ void RGWOp_User_Create::execute()
std::string secret_key;
std::string key_type_str;
std::string caps;
std::string tenant_name;
bool gen_key;
bool suspended;
@ -96,6 +97,7 @@ void RGWOp_User_Create::execute()
RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
RESTArgs::get_string(s, "user-caps", caps, &caps);
RESTArgs::get_string(s, "tenant", tenant_name, &tenant_name);
RESTArgs::get_bool(s, "generate-key", true, &gen_key);
RESTArgs::get_bool(s, "suspended", false, &suspended);
RESTArgs::get_int32(s, "max-buckets", default_max_buckets, &max_buckets);
@ -108,6 +110,10 @@ void RGWOp_User_Create::execute()
return;
}
if (!tenant_name.empty()) {
uid.tenant = tenant_name;
}
// TODO: validate required args are passed in. (for eg. uid and display_name here)
op_state.set_user_id(uid);
op_state.set_display_name(display_name);

View File

@ -578,6 +578,18 @@ uint32_t rgw_str_to_perm(const char *str)
return RGW_PERM_INVALID;
}
int rgw_validate_tenant_name(const string& t)
{
struct tench {
static bool is_good(char ch) {
return isalnum(ch) || ch == '_';
}
};
std::string::const_iterator it =
std::find_if_not(t.begin(), t.end(), tench::is_good);
return (it == t.end())? 0: -ERR_INVALID_TENANT_NAME;
}
static bool validate_access_key(string& key)
{
const char *p = key.c_str();
@ -1886,6 +1898,13 @@ int RGWUser::check_op(RGWUserAdminOpState& op_state, std::string *err_msg)
return -EINVAL;
}
int ret = rgw_validate_tenant_name(op_id.tenant);
if (ret) {
set_err_msg(err_msg,
"invalid tenant only alphanumeric and _ characters are allowed");
return ret;
}
//set key type when it not set or set by context
if ((op_state.get_key_type() < 0) || op_state.key_type_setbycontext) {
op_state.set_key_type(KEY_TYPE_S3);

View File

@ -115,9 +115,6 @@ extern int rgw_get_user_attrs_by_uid(RGWRados *store,
* Given an RGWUserInfo, deletes the user and its bucket ACLs.
*/
extern int rgw_delete_user(RGWRados *store, RGWUserInfo& user, RGWObjVersionTracker& objv_tracker);
/**
* Store a list of the user's buckets, with associated functinos.
*/
/*
* remove the different indexes
@ -127,14 +124,11 @@ extern int rgw_remove_uid_index(RGWRados *store, rgw_user& uid);
extern int rgw_remove_email_index(RGWRados *store, string& email);
extern int rgw_remove_swift_name_index(RGWRados *store, string& swift_name);
/*
* An RGWUser class along with supporting classes created
* to support the creation of an RESTful administrative API
*/
extern void rgw_perm_to_str(uint32_t mask, char *buf, int len);
extern uint32_t rgw_str_to_perm(const char *str);
extern int rgw_validate_tenant_name(const string& t);
enum ObjectKeyType {
KEY_TYPE_SWIFT,
KEY_TYPE_S3,
@ -153,6 +147,10 @@ enum RGWUserId {
RGW_ACCESS_KEY,
};
/*
* An RGWUser class along with supporting classes created
* to support the creation of an RESTful administrative API
*/
struct RGWUserAdminOpState {
// user attributes
RGWUserInfo info;