MXS-2574: Add PATCH for /users/inet endpoint
The alteration of user passwords is now done inside MaxScale. This prevents the possibility of a user locking themselves out.
This commit is contained in:
@ -71,6 +71,7 @@ const char* admin_disable_linux_account(const char *uname);
|
|||||||
bool admin_linux_account_enabled(const char *uname);
|
bool admin_linux_account_enabled(const char *uname);
|
||||||
|
|
||||||
const char* admin_add_inet_user(const char *uname, const char *password, enum user_account_type type);
|
const char* admin_add_inet_user(const char *uname, const char *password, enum user_account_type type);
|
||||||
|
const char* admin_alter_inet_user(const char* uname, const char* password);
|
||||||
const char* admin_remove_inet_user(const char* uname);
|
const char* admin_remove_inet_user(const char* uname);
|
||||||
bool admin_inet_user_exists(const char *uname);
|
bool admin_inet_user_exists(const char *uname);
|
||||||
bool admin_verify_inet_user(const char *uname, const char *password);
|
bool admin_verify_inet_user(const char *uname, const char *password);
|
||||||
|
@ -97,6 +97,17 @@ bool users_auth(USERS* users, const char* user, const char* password);
|
|||||||
*/
|
*/
|
||||||
bool users_find(USERS* users, const char* user);
|
bool users_find(USERS* users, const char* user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change password for a user
|
||||||
|
*
|
||||||
|
* @param users The users table
|
||||||
|
* @param user User to alter
|
||||||
|
* @param password The new password for the user
|
||||||
|
*
|
||||||
|
* @return True if password was changed
|
||||||
|
*/
|
||||||
|
bool users_change_password(USERS* users, const char* user, const char* password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if user is an administrator
|
* Check if user is an administrator
|
||||||
*
|
*
|
||||||
|
@ -192,10 +192,6 @@ exports.builder = function(yargs) {
|
|||||||
}, function(argv) {
|
}, function(argv) {
|
||||||
maxctrl(argv, function(host) {
|
maxctrl(argv, function(host) {
|
||||||
|
|
||||||
if (argv.u == argv.name) {
|
|
||||||
return error('Cannot alter current user')
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = {
|
var user = {
|
||||||
'data': {
|
'data': {
|
||||||
'id': argv.name,
|
'id': argv.name,
|
||||||
@ -206,10 +202,7 @@ exports.builder = function(yargs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getJson(host, 'users/inet/' + argv.name)
|
return doRequest(host, 'users/inet/' + argv.name, null, {method: 'PATCH', body: user})
|
||||||
.then((res) => user.data.attributes.account = res.data.attributes.account)
|
|
||||||
.then(() => doRequest(host, 'users/inet/' + argv.name, null, {method: 'DELETE'}))
|
|
||||||
.then(() => doRequest(host, 'users/inet', null, {method: 'POST', body: user}))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.usage('Usage: alter <command>')
|
.usage('Usage: alter <command>')
|
||||||
|
@ -195,11 +195,6 @@ describe("Alter Commands", function() {
|
|||||||
.should.be.rejected
|
.should.be.rejected
|
||||||
})
|
})
|
||||||
|
|
||||||
it('rejects alteration to current user', function() {
|
|
||||||
return doCommand('-u bob -p bob alter user bob bob2')
|
|
||||||
.should.be.rejected
|
|
||||||
})
|
|
||||||
|
|
||||||
it('creates user', function() {
|
it('creates user', function() {
|
||||||
return verifyCommand('create user testuser test', 'users/inet/testuser')
|
return verifyCommand('create user testuser test', 'users/inet/testuser')
|
||||||
})
|
})
|
||||||
@ -212,5 +207,13 @@ describe("Alter Commands", function() {
|
|||||||
return doCommand('destroy user testuser')
|
return doCommand('destroy user testuser')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('allows alteration to current user', function() {
|
||||||
|
return verifyCommand('create user bob bob --type=admin', 'users/inet/bob')
|
||||||
|
.then(() => doCommand('-u bob -p bob alter user bob bob2'))
|
||||||
|
.then(() => doCommand('-u bob -p bob2 alter user bob bob'))
|
||||||
|
.then(() => doCommand('-u bob -p bob list servers'))
|
||||||
|
.then(() => doCommand('-u bob -p bob destroy user bob'))
|
||||||
|
})
|
||||||
|
|
||||||
after(stopMaxScale)
|
after(stopMaxScale)
|
||||||
});
|
});
|
||||||
|
@ -138,6 +138,29 @@ static const char* admin_add_user(USERS** pusers,
|
|||||||
return ADMIN_SUCCESS;
|
return ADMIN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* admin_alter_user(USERS** pusers,
|
||||||
|
const char* fname,
|
||||||
|
const char* uname,
|
||||||
|
const char* password)
|
||||||
|
{
|
||||||
|
if (*pusers == NULL)
|
||||||
|
{
|
||||||
|
*pusers = users_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!users_change_password(*pusers, uname, password))
|
||||||
|
{
|
||||||
|
return ADMIN_ERR_USERNOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!admin_dump_users(*pusers, fname))
|
||||||
|
{
|
||||||
|
return ADMIN_ERR_FILEOPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ADMIN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static const char* admin_remove_user(USERS* users, const char* fname, const char* uname)
|
static const char* admin_remove_user(USERS* users, const char* fname, const char* uname)
|
||||||
{
|
{
|
||||||
if (!users_delete(users, uname))
|
if (!users_delete(users, uname))
|
||||||
@ -437,6 +460,19 @@ const char* admin_add_inet_user(const char* uname, const char* password, enum us
|
|||||||
return admin_add_user(&inet_users, INET_USERS_FILE_NAME, uname, password, type);
|
return admin_add_user(&inet_users, INET_USERS_FILE_NAME, uname, password, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter network user.
|
||||||
|
*
|
||||||
|
* @param uname The user to alter
|
||||||
|
* @param password The new password
|
||||||
|
*
|
||||||
|
* @return NULL on success or an error string on failure.
|
||||||
|
*/
|
||||||
|
const char* admin_alter_inet_user(const char* uname, const char* password)
|
||||||
|
{
|
||||||
|
return admin_alter_user(&inet_users, INET_USERS_FILE_NAME, uname, password);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove insecure remote (network) user
|
* Remove insecure remote (network) user
|
||||||
*
|
*
|
||||||
|
@ -2875,6 +2875,31 @@ bool runtime_remove_user(const char* id, enum user_type type)
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool runtime_alter_user(const std::string& user, const std::string& type, json_t* json)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
const char* password = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_PASSWORD));
|
||||||
|
|
||||||
|
if (!password)
|
||||||
|
{
|
||||||
|
config_runtime_error("No password provided");
|
||||||
|
}
|
||||||
|
else if (type != CN_INET)
|
||||||
|
{
|
||||||
|
config_runtime_error("Users of type '%s' cannot be altered", type.c_str());
|
||||||
|
}
|
||||||
|
else if (const char* err = admin_alter_inet_user(user.c_str(), password))
|
||||||
|
{
|
||||||
|
config_runtime_error("%s", err);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
bool validate_maxscale_json(json_t* json)
|
bool validate_maxscale_json(json_t* json)
|
||||||
{
|
{
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
|
@ -386,6 +386,17 @@ bool runtime_create_user_from_json(json_t* json);
|
|||||||
*/
|
*/
|
||||||
bool runtime_remove_user(const char* id, enum user_type type);
|
bool runtime_remove_user(const char* id, enum user_type type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Alter admin user password
|
||||||
|
*
|
||||||
|
* @param user Username
|
||||||
|
* @param type Type of the user
|
||||||
|
* @param json JSON defining the new user
|
||||||
|
*
|
||||||
|
* @return True if the user was altered successfully
|
||||||
|
*/
|
||||||
|
bool runtime_alter_user(const std::string& user, const std::string& type, json_t* json);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Alter core MaxScale parameters from JSON
|
* @brief Alter core MaxScale parameters from JSON
|
||||||
*
|
*
|
||||||
|
@ -760,6 +760,7 @@ HttpResponse cb_monitor_wait(const HttpRequest& request)
|
|||||||
MonitorManager::debug_wait_one_tick();
|
MonitorManager::debug_wait_one_tick();
|
||||||
return HttpResponse(MHD_HTTP_OK);
|
return HttpResponse(MHD_HTTP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpResponse cb_create_user(const HttpRequest& request)
|
HttpResponse cb_create_user(const HttpRequest& request)
|
||||||
{
|
{
|
||||||
mxb_assert(request.get_json());
|
mxb_assert(request.get_json());
|
||||||
@ -772,6 +773,19 @@ HttpResponse cb_create_user(const HttpRequest& request)
|
|||||||
return HttpResponse(MHD_HTTP_FORBIDDEN, runtime_get_json_error());
|
return HttpResponse(MHD_HTTP_FORBIDDEN, runtime_get_json_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HttpResponse cb_alter_user(const HttpRequest& request)
|
||||||
|
{
|
||||||
|
auto user = request.last_uri_part();
|
||||||
|
auto type = request.uri_part(1);
|
||||||
|
|
||||||
|
if (runtime_alter_user(user, type, request.get_json()))
|
||||||
|
{
|
||||||
|
return HttpResponse(MHD_HTTP_NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return HttpResponse(MHD_HTTP_FORBIDDEN, runtime_get_json_error());
|
||||||
|
}
|
||||||
|
|
||||||
HttpResponse cb_delete_user(const HttpRequest& request)
|
HttpResponse cb_delete_user(const HttpRequest& request)
|
||||||
{
|
{
|
||||||
string user = request.last_uri_part();
|
string user = request.last_uri_part();
|
||||||
@ -1044,6 +1058,7 @@ public:
|
|||||||
m_patch.push_back(SResource(new Resource(cb_alter_logs, 2, "maxscale", "logs")));
|
m_patch.push_back(SResource(new Resource(cb_alter_logs, 2, "maxscale", "logs")));
|
||||||
m_patch.push_back(SResource(new Resource(cb_alter_maxscale, 1, "maxscale")));
|
m_patch.push_back(SResource(new Resource(cb_alter_maxscale, 1, "maxscale")));
|
||||||
m_patch.push_back(SResource(new Resource(cb_alter_qc, 2, "maxscale", "query_classifier")));
|
m_patch.push_back(SResource(new Resource(cb_alter_qc, 2, "maxscale", "query_classifier")));
|
||||||
|
m_patch.push_back(SResource(new Resource(cb_alter_user, 3, "users", "inet", ":inetuser")));
|
||||||
|
|
||||||
/** Update resource relationships directly */
|
/** Update resource relationships directly */
|
||||||
m_patch.push_back(SResource(new Resource(cb_alter_server_service_relationship,
|
m_patch.push_back(SResource(new Resource(cb_alter_server_service_relationship,
|
||||||
|
@ -327,6 +327,13 @@ bool users_find(USERS* users, const char* user)
|
|||||||
return u->get(user);
|
return u->get(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool users_change_password(USERS* users, const char* user, const char* password)
|
||||||
|
{
|
||||||
|
Users* u = reinterpret_cast<Users*>(users);
|
||||||
|
UserInfo info;
|
||||||
|
return u->get(user, &info) && u->remove(user) && u->add(user, password, info.permissions);
|
||||||
|
}
|
||||||
|
|
||||||
bool users_auth(USERS* users, const char* user, const char* password)
|
bool users_auth(USERS* users, const char* user, const char* password)
|
||||||
{
|
{
|
||||||
Users* u = reinterpret_cast<Users*>(users);
|
Users* u = reinterpret_cast<Users*>(users);
|
||||||
|
Reference in New Issue
Block a user