server/protocol: option for dynamic authorization of client permissions

problem:
assuming gluster volume is already mounted (for gfapi: say client transport
connection has already established), now if somebody change the volume
permissions say *.allow | *.reject for a client, gluster should allow/terminate
the client connection based on the fresh set of volume options immediately,
but in existing scenario neither we have any option to set this behaviour nor
we take any action until and unless we remount the volume manually

solution:
Introduce 'dynamic-auth' option (default: on).
If 'dynamic-auth' is 'on' gluster will perform dynamic authentication to
allow/terminate client transport connection immediately in response to
*.allow | *.reject volume set options, thus if volume permissions have changed
for a particular client (say client is added to auth.reject list), his
transport connection to gluster volume will be terminated immediately.

Change-Id: I6243a6db41bf1e0babbf050a8e4f8620732e00d8
BUG: 1245380
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
Reviewed-on: http://review.gluster.org/12229
Tested-by: NetBSD Build System <jenkins@build.gluster.org>
Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
This commit is contained in:
Prasanna Kumar Kalever 2015-08-21 00:08:23 +05:30 committed by Raghavendra G
parent fc33ed37ff
commit 84e90b7565
6 changed files with 65 additions and 4 deletions

View File

@ -458,6 +458,8 @@ rpc_transport_destroy (rpc_transport_t *this)
GF_VALIDATE_OR_GOTO("rpc_transport", this, fail);
if (this->clnt_options)
dict_unref (this->clnt_options);
if (this->options)
dict_unref (this->options);
if (this->fini)

View File

@ -210,6 +210,8 @@ struct rpc_transport {
int bind_insecure;
void *dl_handle; /* handle of dlopen() */
char *ssl_name;
dict_t *clnt_options; /* store options received from
* client */
};
struct rpc_transport_ops {

View File

@ -1086,6 +1086,10 @@ struct volopt_map_entry glusterd_volopt_map[] = {
.voltype = "protocol/server",
.op_version = GD_OP_VERSION_3_6_0,
},
{ .key = "server.dynamic-auth",
.voltype = "protocol/server",
.op_version = GD_OP_VERSION_3_7_5,
},
{ .key = "client.send-gids",
.voltype = "protocol/client",
.type = NO_DOC,

View File

@ -598,6 +598,8 @@ server_setvolume (rpcsvc_request_t *req)
conf->auth_modules);
if (ret == AUTH_ACCEPT) {
/* Store options received from client side */
req->trans->clnt_options = dict_ref(params);
gf_msg (this->name, GF_LOG_INFO, 0, PS_MSG_CLIENT_ACCEPTED,
"accepted client from %s (version: %s)",

View File

@ -710,6 +710,7 @@ reconfigure (xlator_t *this, dict_t *options)
server_conf_t *conf =NULL;
rpcsvc_t *rpc_conf;
rpcsvc_listener_t *listeners;
rpc_transport_t *xprt = NULL;
int inode_lru_limit;
gf_boolean_t trace;
data_t *data;
@ -778,6 +779,7 @@ reconfigure (xlator_t *this, dict_t *options)
/* logging already done in validate_auth_options function. */
goto out;
}
dict_foreach (this->options, _delete_auth_opt, this->options);
dict_foreach (options, _copy_auth_opt, this->options);
@ -805,8 +807,41 @@ reconfigure (xlator_t *this, dict_t *options)
goto out;
}
(void) rpcsvc_set_allow_insecure (rpc_conf, options);
(void) rpcsvc_set_root_squash (rpc_conf, options);
ret = rpcsvc_auth_reconf (rpc_conf, options);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_ERROR,
"Failed to reconfigure authentication");
goto out;
}
GF_OPTION_RECONF ("dynamic-auth", conf->dync_auth, options,
bool, out);
if (conf->dync_auth) {
pthread_mutex_lock (&conf->mutex);
{
list_for_each_entry (xprt, &conf->xprt_list, list) {
/* check for client authorization */
ret = gf_authenticate (xprt->clnt_options,
options, conf->auth_modules);
if (ret == AUTH_ACCEPT) {
gf_msg (this->name, GF_LOG_TRACE, 0,
PS_MSG_CLIENT_ACCEPTED,
"authorized client, hence we "
"continue with this connection");
} else {
gf_msg (this->name, GF_LOG_INFO,
EACCES,
PS_MSG_AUTHENTICATE_ERROR,
"unauthorized client, hence "
"terminating the connection %s",
xprt->peerinfo.identifier);
rpc_transport_disconnect(xprt);
}
}
}
pthread_mutex_unlock (&conf->mutex);
}
ret = rpcsvc_set_outstanding_rpc_limit (rpc_conf, options,
RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT);
@ -957,6 +992,12 @@ init (xlator_t *this)
"Failed to initialize group cache.");
goto out;
}
ret = dict_get_str_boolean (this->options, "dynamic-auth",
_gf_true);
if (ret == -1)
conf->dync_auth = _gf_true;
else
conf->dync_auth = ret;
/* RPC related */
conf->rpc = rpcsvc_init (this, this->ctx, this->options, 0);
@ -1364,7 +1405,6 @@ struct volume_options options[] = {
"requests from a client. 0 means no limit (can "
"potentially run out of memory)"
},
{ .key = {"manage-gids"},
.type = GF_OPTION_TYPE_BOOL,
.default_value = "off",
@ -1385,6 +1425,13 @@ struct volume_options options[] = {
" responses faster, depending on available processing"
" power. Range 1-32 threads."
},
{ .key = {"dynamic-auth"},
.type = GF_OPTION_TYPE_BOOL,
.default_value = "on",
.description = "When 'on' perform dynamic authentication of volume "
"options in order to allow/terminate client "
"transport connection immediately in response to "
"*.allow | *.reject volume set options."
},
{ .key = {NULL} },
};

View File

@ -68,6 +68,10 @@ struct server_conf {
* configured */
gf_boolean_t parent_up;
gf_boolean_t dync_auth; /* if set authenticate dynamically,
* in case if volume set options
* (say *.allow | *.reject) are
* tweeked */
};
typedef struct server_conf server_conf_t;