MXS-1354: Add user account types to REST API
The user accounts can now be created with a specific account type. This allows read-only users to be created for the REST API.
This commit is contained in:
parent
ec045b7ab6
commit
9d24a63c10
@ -18,6 +18,7 @@
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <maxscale/dcb.h>
|
||||
#include <maxscale/users.h>
|
||||
|
||||
MXS_BEGIN_DECLS
|
||||
|
||||
@ -73,13 +74,11 @@ typedef struct admin_session
|
||||
|
||||
void admin_users_init();
|
||||
|
||||
const char* admin_enable_linux_account(const char *uname);
|
||||
const char *admin_enable_linux_admin_account(const char *uname);
|
||||
const char* admin_enable_linux_account(const char *uname, enum account_type type);
|
||||
const char* admin_disable_linux_account(const char *uname);
|
||||
bool admin_linux_account_enabled(const char *uname);
|
||||
|
||||
const char* admin_add_inet_user(const char *uname, const char *password);
|
||||
const char *admin_add_inet_admin_user(const char *uname, const char* password);
|
||||
const char* admin_add_inet_user(const char *uname, const char *password, enum account_type type);
|
||||
const char* admin_remove_inet_user(const char* uname);
|
||||
bool admin_inet_user_exists(const char *uname);
|
||||
bool admin_verify_inet_user(const char *uname, const char *password);
|
||||
|
@ -65,8 +65,9 @@ MXS_BEGIN_DECLS
|
||||
#define MXS_JSON_PTR_PARAM_SSL_CERT_VERIFY_DEPTH MXS_JSON_PTR_PARAMETERS "/ssl_cert_verify_depth"
|
||||
|
||||
/** Non-parameter JSON pointers */
|
||||
#define MXS_JSON_PTR_MODULE "/data/attributes/module"
|
||||
#define MXS_JSON_PTR_MODULE "/data/attributes/module"
|
||||
#define MXS_JSON_PTR_PASSWORD "/data/attributes/password"
|
||||
#define MXS_JSON_PTR_ACCOUNT "/data/attributes/account"
|
||||
|
||||
/**
|
||||
* Common configuration parameters names
|
||||
@ -75,6 +76,7 @@ MXS_BEGIN_DECLS
|
||||
* For example CN_PASSWORD resolves to the static string "password". This means
|
||||
* that the sizeof(CN_<name>) returns the actual size of that string.
|
||||
*/
|
||||
extern const char CN_ACCOUNT[];
|
||||
extern const char CN_ADDRESS[];
|
||||
extern const char CN_ARG_MAX[];
|
||||
extern const char CN_ARG_MIN[];
|
||||
|
@ -179,4 +179,22 @@ void users_diagnostic(DCB* dcb, USERS* users);
|
||||
*/
|
||||
json_t* users_diagnostic_json(USERS* users);
|
||||
|
||||
/**
|
||||
* Convert account_type to a string
|
||||
*
|
||||
* @param type Enum value
|
||||
*
|
||||
* @return String representation of @c type
|
||||
*/
|
||||
const char* account_type_to_str(enum account_type type);
|
||||
|
||||
/**
|
||||
* Convert JSON value to account_type value
|
||||
*
|
||||
* @param json JSON value to convert
|
||||
*
|
||||
* @return Enum value of @c json
|
||||
*/
|
||||
enum account_type json_to_account_type(json_t* json);
|
||||
|
||||
MXS_END_DECLS
|
||||
|
@ -122,7 +122,7 @@ static const char* admin_remove_user(USERS *users, const char* fname, const char
|
||||
return ADMIN_SUCCESS;
|
||||
}
|
||||
|
||||
static json_t* admin_user_json_data(const char* host, const char* user, enum user_type user_type)
|
||||
static json_t* admin_user_json_data(const char* host, const char* user, enum user_type user_type, enum account_type account)
|
||||
{
|
||||
ss_dassert(user_type != USER_TYPE_ALL);
|
||||
const char* type = user_type == USER_TYPE_INET ? CN_INET : CN_UNIX;
|
||||
@ -131,6 +131,10 @@ static json_t* admin_user_json_data(const char* host, const char* user, enum use
|
||||
json_object_set_new(entry, CN_ID, json_string(user));
|
||||
json_object_set_new(entry, CN_TYPE, json_string(type));
|
||||
|
||||
json_t* param = json_object();
|
||||
json_object_set_new(param, CN_ACCOUNT, json_string(account_type_to_str(account)));
|
||||
json_object_set_new(entry, CN_ATTRIBUTES, param);
|
||||
|
||||
std::string self = MXS_JSON_API_USERS;
|
||||
self += type;
|
||||
json_object_set_new(entry, CN_RELATIONSHIPS, mxs_json_self_link(host, self.c_str(), user));
|
||||
@ -146,7 +150,9 @@ static void user_types_to_json(USERS* users, json_t* arr, const char* host, enum
|
||||
|
||||
json_array_foreach(json, index, value)
|
||||
{
|
||||
json_array_append_new(arr, admin_user_json_data(host, json_string_value(value), type));
|
||||
const char* user = json_string_value(json_object_get(value, CN_NAME));
|
||||
enum account_type account = json_to_account_type(json_object_get(value, CN_ACCOUNT));
|
||||
json_array_append_new(arr, admin_user_json_data(host, user, type, account));
|
||||
}
|
||||
|
||||
json_decref(json);
|
||||
@ -170,11 +176,12 @@ static std::string path_from_type(enum user_type type)
|
||||
|
||||
json_t* admin_user_to_json(const char* host, const char* user, enum user_type type)
|
||||
{
|
||||
account_type account = admin_is_admin_user(user) ? ACCOUNT_ADMIN : ACCOUNT_BASIC;
|
||||
std::string path = path_from_type(type);
|
||||
path += "/";
|
||||
path += user;
|
||||
|
||||
return mxs_json_resource(host, path.c_str(), admin_user_json_data(host, user, type));
|
||||
return mxs_json_resource(host, path.c_str(), admin_user_json_data(host, user, type, account));
|
||||
}
|
||||
|
||||
json_t* admin_all_users_to_json(const char* host, enum user_type type)
|
||||
@ -333,21 +340,9 @@ static USERS *load_inet_users()
|
||||
*
|
||||
* @return NULL on success or an error string on failure.
|
||||
*/
|
||||
const char *admin_enable_linux_account(const char *uname)
|
||||
const char *admin_enable_linux_account(const char *uname, enum account_type type)
|
||||
{
|
||||
return admin_add_user(&linux_users, LINUX_USERS_FILE_NAME, uname, NULL, ACCOUNT_BASIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Linux account
|
||||
*
|
||||
* @param uname Name of Linux user
|
||||
*
|
||||
* @return NULL on success or an error string on failure.
|
||||
*/
|
||||
const char *admin_enable_linux_admin_account(const char *uname)
|
||||
{
|
||||
return admin_add_user(&linux_users, LINUX_USERS_FILE_NAME, uname, NULL, ACCOUNT_ADMIN);
|
||||
return admin_add_user(&linux_users, LINUX_USERS_FILE_NAME, uname, NULL, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -403,13 +398,6 @@ void mxs_crypt(const char* password, const char* salt, char* output)
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char* add_inet_user(const char *uname, const char* password, account_type type)
|
||||
{
|
||||
char cpassword[MXS_CRYPT_SIZE];
|
||||
mxs_crypt(password, ADMIN_SALT, cpassword);
|
||||
return admin_add_user(&inet_users, INET_USERS_FILE_NAME, uname, cpassword, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add insecure remote (network) basic user.
|
||||
*
|
||||
@ -418,22 +406,11 @@ static const char* add_inet_user(const char *uname, const char* password, accoun
|
||||
*
|
||||
* @return NULL on success or an error string on failure.
|
||||
*/
|
||||
const char *admin_add_inet_user(const char *uname, const char* password)
|
||||
const char *admin_add_inet_user(const char *uname, const char* password, enum account_type type)
|
||||
{
|
||||
return add_inet_user(uname, password, ACCOUNT_BASIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add insecure remote (network) admin user.
|
||||
*
|
||||
* @param uname Name of the new user.
|
||||
* @param password Password of the new user.
|
||||
*
|
||||
* @return NULL on success or an error string on failure.
|
||||
*/
|
||||
const char *admin_add_inet_admin_user(const char *uname, const char* password)
|
||||
{
|
||||
return add_inet_user(uname, password, ACCOUNT_ADMIN);
|
||||
char cpassword[MXS_CRYPT_SIZE];
|
||||
mxs_crypt(password, ADMIN_SALT, cpassword);
|
||||
return admin_add_user(&inet_users, INET_USERS_FILE_NAME, uname, cpassword, type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,6 +54,7 @@
|
||||
using std::set;
|
||||
using std::string;
|
||||
|
||||
const char CN_ACCOUNT[] = "account";
|
||||
const char CN_ADDRESS[] = "address";
|
||||
const char CN_ARG_MAX[] = "arg_max";
|
||||
const char CN_ARG_MIN[] = "arg_min";
|
||||
|
@ -23,11 +23,12 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <maxscale/atomic.h>
|
||||
#include <maxscale/jansson.hh>
|
||||
#include <maxscale/json_api.h>
|
||||
#include <maxscale/paths.h>
|
||||
#include <maxscale/platform.h>
|
||||
#include <maxscale/spinlock.h>
|
||||
#include <maxscale/jansson.hh>
|
||||
#include <maxscale/json_api.h>
|
||||
#include <maxscale/users.h>
|
||||
|
||||
#include "maxscale/config.h"
|
||||
#include "maxscale/monitor.h"
|
||||
@ -1723,6 +1724,7 @@ bool validate_user_json(json_t* json)
|
||||
json_t* id = mxs_json_pointer(json, MXS_JSON_PTR_ID);
|
||||
json_t* type = mxs_json_pointer(json, MXS_JSON_PTR_TYPE);
|
||||
json_t* password = mxs_json_pointer(json, MXS_JSON_PTR_PASSWORD);
|
||||
json_t* account = mxs_json_pointer(json, MXS_JSON_PTR_ACCOUNT);
|
||||
|
||||
if (!id)
|
||||
{
|
||||
@ -1740,6 +1742,18 @@ bool validate_user_json(json_t* json)
|
||||
{
|
||||
runtime_error("The '%s' field is not a string", MXS_JSON_PTR_TYPE);
|
||||
}
|
||||
else if (!account)
|
||||
{
|
||||
runtime_error("Request body does not define the '%s' field", MXS_JSON_PTR_ACCOUNT);
|
||||
}
|
||||
else if (!json_is_string(account))
|
||||
{
|
||||
runtime_error("The '%s' field is not a string", MXS_JSON_PTR_ACCOUNT);
|
||||
}
|
||||
else if (json_to_account_type(account) == ACCOUNT_UNKNOWN)
|
||||
{
|
||||
runtime_error("The '%s' field is not a valid account value", MXS_JSON_PTR_ACCOUNT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(json_string_value(type), CN_INET) == 0)
|
||||
@ -1780,14 +1794,15 @@ bool runtime_create_user_from_json(json_t* json)
|
||||
const char* user = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_ID));
|
||||
const char* password = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_PASSWORD));
|
||||
string strtype = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_TYPE));
|
||||
account_type type = json_to_account_type(mxs_json_pointer(json, MXS_JSON_PTR_ACCOUNT));
|
||||
const char* err = NULL;
|
||||
|
||||
if (strtype == CN_INET && (err = admin_add_inet_user(user, password)) == ADMIN_SUCCESS)
|
||||
if (strtype == CN_INET && (err = admin_add_inet_user(user, password, type)) == ADMIN_SUCCESS)
|
||||
{
|
||||
MXS_NOTICE("Create network user '%s'", user);
|
||||
rval = true;
|
||||
}
|
||||
else if (strtype == CN_UNIX && (err = admin_enable_linux_account(user)) == ADMIN_SUCCESS)
|
||||
else if (strtype == CN_UNIX && (err = admin_enable_linux_account(user, type)) == ADMIN_SUCCESS)
|
||||
{
|
||||
MXS_NOTICE("Enabled account '%s'", user);
|
||||
rval = true;
|
||||
|
@ -11,20 +11,7 @@
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 20-08-2014 Mark Riddoch Initial implementation
|
||||
* 23-05-2016 Massimiliano Pinto admin_add_user and admin_remove_user
|
||||
* no longer accept password parameter
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
// To ensure that ss_info_assert asserts also when building in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
@ -38,6 +25,7 @@
|
||||
#include <maxscale/adminusers.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/utils.h>
|
||||
#include <maxscale/users.h>
|
||||
|
||||
/**
|
||||
* test1 default user
|
||||
@ -76,13 +64,13 @@ test2()
|
||||
{
|
||||
const char *err;
|
||||
|
||||
if ((err = admin_enable_linux_account("user0")) != NULL)
|
||||
if ((err = admin_enable_linux_account("user0", ACCOUNT_ADMIN)) != NULL)
|
||||
{
|
||||
fprintf(stderr, "admin_add_user: test 2.1 (add user) failed, %s.\n", err);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (admin_enable_linux_account("user0") == NULL)
|
||||
if (admin_enable_linux_account("user0", ACCOUNT_ADMIN) == NULL)
|
||||
{
|
||||
fprintf(stderr, "admin_add_user: test 2.2 (add user) failed, duplicate.\n");
|
||||
|
||||
@ -98,7 +86,7 @@ test2()
|
||||
}
|
||||
|
||||
/* Add the user back, for test5. */
|
||||
if ((err = admin_enable_linux_account("user0")) != NULL)
|
||||
if ((err = admin_enable_linux_account("user0", ACCOUNT_ADMIN)) != NULL)
|
||||
{
|
||||
fprintf(stderr, "admin_add_user: test 2.4 (add user) failed, %s.\n", err);
|
||||
|
||||
@ -122,7 +110,7 @@ test3()
|
||||
{
|
||||
const char *err;
|
||||
|
||||
if ((err = admin_enable_linux_account("user1")) != NULL)
|
||||
if ((err = admin_enable_linux_account("user1", ACCOUNT_ADMIN)) != NULL)
|
||||
{
|
||||
fprintf(stderr, "admin_add_user: test 3.1 (add user) failed, %s.\n", err);
|
||||
|
||||
@ -180,7 +168,7 @@ test4()
|
||||
for (i = 1; i < n_users; i++)
|
||||
{
|
||||
sprintf(user, "user%d", i);
|
||||
if ((err = admin_enable_linux_account(user)) != NULL)
|
||||
if ((err = admin_enable_linux_account(user, ACCOUNT_ADMIN)) != NULL)
|
||||
{
|
||||
fprintf(stderr, "admin_add_user: test 4.1 (add user) failed, %s.\n", err);
|
||||
|
||||
@ -224,7 +212,7 @@ test5()
|
||||
{
|
||||
const char *err;
|
||||
|
||||
if ((err = admin_enable_linux_account("user")) != NULL)
|
||||
if ((err = admin_enable_linux_account("user", ACCOUNT_ADMIN)) != NULL)
|
||||
{
|
||||
fprintf(stderr, "admin_add_user: test 5.1 (add user) failed, %s.\n", err);
|
||||
|
||||
@ -259,11 +247,7 @@ main(int argc, char **argv)
|
||||
|
||||
unlink(buf);
|
||||
|
||||
// admin_verify() should be removed, since the maxadmin authentication has
|
||||
// been changed completely. However, telnetd still uses that admin_verify()
|
||||
// so I'll leave the function there for now. But telnetd should be dropped,
|
||||
// since it cannot use the same user file as maxadmin does.
|
||||
// result += test1();
|
||||
result += test1();
|
||||
result += test2();
|
||||
result += test3();
|
||||
result += test4();
|
||||
|
@ -30,41 +30,6 @@ namespace
|
||||
static const char STR_BASIC[] = "basic";
|
||||
static const char STR_ADMIN[] = "admin";
|
||||
|
||||
static const char* account_type_to_str(account_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ACCOUNT_BASIC:
|
||||
return STR_BASIC;
|
||||
|
||||
case ACCOUNT_ADMIN:
|
||||
return STR_ADMIN;
|
||||
|
||||
default:
|
||||
MXS_ERROR("Unknown enum account_type value: %d", (int)type);
|
||||
ss_dassert(!true);
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static account_type json_to_account_type(json_t* json)
|
||||
{
|
||||
std::string str = json_string_value(json);
|
||||
|
||||
if (str == STR_BASIC)
|
||||
{
|
||||
return ACCOUNT_BASIC;
|
||||
}
|
||||
else if (str == STR_ADMIN)
|
||||
{
|
||||
return ACCOUNT_ADMIN;
|
||||
}
|
||||
|
||||
MXS_ERROR("Unknown account type string: %s", str.c_str());
|
||||
ss_dassert(!true);
|
||||
return ACCOUNT_UNKNOWN;
|
||||
}
|
||||
|
||||
struct UserInfo
|
||||
{
|
||||
UserInfo():
|
||||
@ -180,7 +145,10 @@ public:
|
||||
|
||||
for (UserMap::const_iterator it = m_data.begin(); it != m_data.end(); it++)
|
||||
{
|
||||
json_array_append_new(rval, json_string(it->first.c_str()));
|
||||
json_t* obj = json_object();
|
||||
json_object_set_new(obj, CN_NAME, json_string(it->first.c_str()));
|
||||
json_object_set_new(obj, CN_ACCOUNT, json_string(account_type_to_str(it->second.permissions)));
|
||||
json_array_append_new(rval, obj);
|
||||
}
|
||||
|
||||
return rval;
|
||||
@ -217,7 +185,7 @@ public:
|
||||
{
|
||||
json_t* obj = json_object();
|
||||
json_object_set_new(obj, CN_NAME, json_string(it->first.c_str()));
|
||||
json_object_set_new(obj, CN_TYPE, json_string(account_type_to_str(it->second.permissions)));
|
||||
json_object_set_new(obj, CN_ACCOUNT, json_string(account_type_to_str(it->second.permissions)));
|
||||
json_object_set_new(obj, CN_PASSWORD, json_string(it->second.password.c_str()));
|
||||
json_array_append_new(arr, obj);
|
||||
}
|
||||
@ -248,7 +216,7 @@ private:
|
||||
json_array_foreach(json, i, value)
|
||||
{
|
||||
json_t* name = json_object_get(value, CN_NAME);
|
||||
json_t* type = json_object_get(value, CN_TYPE);
|
||||
json_t* type = json_object_get(value, CN_ACCOUNT);
|
||||
json_t* password = json_object_get(value, CN_PASSWORD);
|
||||
|
||||
if (name && json_is_string(name) &&
|
||||
@ -381,3 +349,34 @@ int users_default_loadusers(SERV_LISTENER *port)
|
||||
port->users = users_alloc();
|
||||
return MXS_AUTH_LOADUSERS_OK;
|
||||
}
|
||||
|
||||
const char* account_type_to_str(enum account_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ACCOUNT_BASIC:
|
||||
return STR_BASIC;
|
||||
|
||||
case ACCOUNT_ADMIN:
|
||||
return STR_ADMIN;
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum account_type json_to_account_type(json_t* json)
|
||||
{
|
||||
std::string str = json_string_value(json);
|
||||
|
||||
if (str == STR_BASIC)
|
||||
{
|
||||
return ACCOUNT_BASIC;
|
||||
}
|
||||
else if (str == STR_ADMIN)
|
||||
{
|
||||
return ACCOUNT_ADMIN;
|
||||
}
|
||||
|
||||
return ACCOUNT_UNKNOWN;
|
||||
}
|
||||
|
@ -2268,10 +2268,7 @@ static void do_inet_add_user(DCB *dcb, char *user, char *password, enum account_
|
||||
return;
|
||||
}
|
||||
|
||||
const char* (*f)(const char*, const char*) = type == ACCOUNT_ADMIN ?
|
||||
admin_add_inet_admin_user : admin_add_inet_user;
|
||||
|
||||
if ((err = f(user, password)) == NULL)
|
||||
if ((err = admin_add_inet_user(user, password, type)) == NULL)
|
||||
{
|
||||
dcb_printf(dcb, "Account %s for remote (network) usage has been successfully added.\n", user);
|
||||
}
|
||||
@ -2596,10 +2593,7 @@ static void do_enable_account(DCB *dcb, char *user, enum account_type type)
|
||||
return;
|
||||
}
|
||||
|
||||
const char* (*f)(const char*) = type == ACCOUNT_ADMIN ?
|
||||
admin_enable_linux_admin_account : admin_enable_linux_account;
|
||||
|
||||
if ((err = f(user)) == NULL)
|
||||
if ((err = admin_enable_linux_account(user, type)) == NULL)
|
||||
{
|
||||
dcb_printf(dcb, "The Linux user %s has successfully been enabled.\n", user);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user