diff --git a/src/box/auth_ldap.c b/src/box/auth_ldap.c index b96b1d9dd4bb59bc927988087c85d17ffc00b510..0675835c8fd25af4c600effa852bbd554a9e1697 100644 --- a/src/box/auth_ldap.c +++ b/src/box/auth_ldap.c @@ -292,7 +292,7 @@ auth_ldap_new(void) { struct auth_method *method = xmalloc(sizeof(*method)); method->name = AUTH_LDAP_NAME; - method->flags = 0; + method->flags = AUTH_METHOD_PASSWORDLESS_DATA_PREPARE; method->auth_method_delete = auth_ldap_delete; method->auth_data_prepare = auth_ldap_data_prepare; method->auth_request_prepare = auth_ldap_request_prepare; diff --git a/src/box/authentication.h b/src/box/authentication.h index 35fd4cfe212a7943d86454ec59d23a0e560897b5..a843a1b8cfd31d48dbeaef396789000cf2dbdd0d 100644 --- a/src/box/authentication.h +++ b/src/box/authentication.h @@ -53,6 +53,12 @@ enum auth_method_flag { * communication channel is encrypted (e.g. with SSL/TLS). */ AUTH_METHOD_REQUIRES_ENCRYPTION = 1 << 0, + /** + * Set if the authentication method does not need + * password in auth_method::auth_data_prepare. + * This is opt-in because most methods require password. + */ + AUTH_METHOD_PASSWORDLESS_DATA_PREPARE = 1 << 1, }; /** diff --git a/src/box/lua/misc.cc b/src/box/lua/misc.cc index 1d0c517bb6c3f90ede7a40b32024611e5c9aeaa0..f0676873afe68bc2e7f932ea4a10a13b25ad560c 100644 --- a/src/box/lua/misc.cc +++ b/src/box/lua/misc.cc @@ -236,6 +236,28 @@ lbox_generate_space_id(lua_State *L) /** {{{ Helper that generates user auth data. **/ +/** + * Takes authentication method name (e.g. 'chap-sha1'). + * Returns true if password is needed to produce auth data, false otherwise. + * Raises Lua error if the specified authentication method doesn't exist. + */ +static int +lbox_prepare_auth_needs_password(lua_State *L) +{ + size_t method_name_len; + const char *method_name = luaL_checklstring(L, 1, &method_name_len); + const struct auth_method *method = auth_method_by_name(method_name, + method_name_len); + if (method == NULL) { + diag_set(ClientError, ER_UNKNOWN_AUTH_METHOD, + tt_cstr(method_name, method_name_len)); + return luaT_error(L); + } + int pwdless = method->flags & AUTH_METHOD_PASSWORDLESS_DATA_PREPARE; + lua_pushboolean(L, !pwdless); + return 1; +} + /** * Takes authentication method name (e.g. 'chap-sha1'), password and user name. * Returns authentication data that can be stored in the _user space. @@ -507,6 +529,7 @@ void box_lua_misc_init(struct lua_State *L) { static const struct luaL_Reg boxlib_internal[] = { + {"prepare_auth_needs_password", lbox_prepare_auth_needs_password}, {"prepare_auth", lbox_prepare_auth}, {"select", lbox_select}, {"new_tuple_format", lbox_tuple_format_new}, diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index ea072a45622aa254b798b9155b4177fcb20e8172..12a439ad3cca86b4740f14d4e0aea364d6089dae 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -3205,10 +3205,14 @@ box.schema.user.password = function(password, name) return internal.prepare_auth(box.cfg.auth_type, password, name) end -local function prepare_auth_list(password, name) +local function prepare_auth_list_needs_password(auth_type) + return internal.prepare_auth_needs_password(auth_type) +end + +local function prepare_auth_list(auth_type, password, name) return { - [box.cfg.auth_type] = - internal.prepare_auth(box.cfg.auth_type, password, name) + [auth_type] = + internal.prepare_auth(auth_type, password, name) } end @@ -3228,9 +3232,11 @@ end local function chpasswd(uid, new_password, name) local _user = box.space[box.schema.USER_ID] + local auth_type = box.cfg.auth_type + local auth_list = prepare_auth_list(auth_type, new_password, name) local auth_history = prepare_auth_history(uid) check_password(new_password, auth_history) - _user:update({uid}, {{'=', 5, prepare_auth_list(new_password, name)}, + _user:update({uid}, {{'=', 5, auth_list}, {'=', 6, auth_history}, {'=', 7, math.floor(fiber.time())}}) end @@ -3257,17 +3263,25 @@ end box.schema.user.create = function(name, opts) local uid = user_or_role_resolve(name) opts = opts or {} - check_param_table(opts, { password = 'string', if_not_exists = 'boolean' }) + check_param_table(opts, {auth_type = 'string', + password = 'string', + if_not_exists = 'boolean'}) if uid then if not opts.if_not_exists then box.error(box.error.USER_EXISTS, name) end return end + local auth_type = opts.auth_type or box.cfg.auth_type local auth_list - if opts.password then + if not prepare_auth_list_needs_password(auth_type) then + if opts.password then + log.warn(auth_type .. " doesn't need password") + end + auth_list = prepare_auth_list(auth_type, '', name) + elseif opts.password then check_password(opts.password) - auth_list = prepare_auth_list(opts.password, name) + auth_list = prepare_auth_list(auth_type, opts.password, name) else auth_list = setmap({}) end