diff --git a/src/box/authentication.cc b/src/box/authentication.cc index dfdf8aaf7b86610e0f6bf1eff6509d2e1da6149e..5d5c9b10453e8a86c6ddbeaec264a2599a76b88e 100644 --- a/src/box/authentication.cc +++ b/src/box/authentication.cc @@ -69,6 +69,9 @@ authenticate(const char *user_name, uint32_t len, if (scramble_check(scramble, session->salt, user->hash2)) tnt_raise(ClientError, ER_PASSWORD_MISMATCH, user->name); + /* check and run auth triggers on success */ + if (! rlist_empty(&session_on_auth)) + session_run_on_auth_triggers(user->name); ok: credentials_init(&session->credentials, user); } diff --git a/src/box/lua/session.cc b/src/box/lua/session.cc index 082c53a9a1aaffd8593069ae5ec8d82b02a72da8..1021b22c6167692e0f6f3b8a83276a4219b2ee15 100644 --- a/src/box/lua/session.cc +++ b/src/box/lua/session.cc @@ -211,6 +211,17 @@ lbox_session_run_trigger(struct trigger *trigger, void * /* event */) lbox_call(L, 0, 0); } +static void +lbox_session_run_auth_trigger(struct trigger *trigger, void *event) +{ + lua_State *L = lua_newthread(tarantool_L); + LuarefGuard coro_guard(tarantool_L); + lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) trigger->data); + /* now only the user name comes in as an on_auth argument */ + lua_pushstring(L, (const char *)event); + lbox_call(L, 1, 0); +} + static int lbox_session_on_connect(struct lua_State *L) { @@ -225,6 +236,13 @@ lbox_session_on_disconnect(struct lua_State *L) lbox_session_run_trigger); } +static int +lbox_session_on_auth(struct lua_State *L) +{ + return lbox_trigger_reset(L, 2, &session_on_auth, + lbox_session_run_auth_trigger); +} + void session_storage_cleanup(int sid) { @@ -270,6 +288,7 @@ box_lua_session_init(struct lua_State *L) {"peer", lbox_session_peer}, {"on_connect", lbox_session_on_connect}, {"on_disconnect", lbox_session_on_disconnect}, + {"on_auth", lbox_session_on_auth}, {NULL, NULL} }; luaL_register_module(L, sessionlib_name, sessionlib); diff --git a/src/box/session.cc b/src/box/session.cc index 607f0d759780060084a1d6330bd9b4de4310f7fd..8f18cca19482b42a452945463b59e2e92d07bba1 100644 --- a/src/box/session.cc +++ b/src/box/session.cc @@ -42,6 +42,7 @@ struct mempool session_pool; RLIST_HEAD(session_on_connect); RLIST_HEAD(session_on_disconnect); +RLIST_HEAD(session_on_auth); static inline uint32_t sid_max() @@ -137,6 +138,7 @@ session_run_on_disconnect_triggers(struct session *session) void session_run_on_connect_triggers(struct session *session) { + /* Run on_connect with admin credentals */ struct fiber *fiber = fiber(); fiber_set_session(fiber, session); fiber_set_user(fiber, &admin_credentials); @@ -144,6 +146,12 @@ session_run_on_connect_triggers(struct session *session) /* Set session user to guest, until it is authenticated. */ } +void +session_run_on_auth_triggers(const char *user_name) +{ + trigger_run(&session_on_auth, (void *)user_name); +} + void session_destroy(struct session *session) { diff --git a/src/box/session.h b/src/box/session.h index 09a9ea34a52ba27c76a1a2d44497830a192b59c2..b78f566b7a78f605712b11df82dc8a4b574befee 100644 --- a/src/box/session.h +++ b/src/box/session.h @@ -120,6 +120,11 @@ extern struct rlist session_on_disconnect; void session_run_on_disconnect_triggers(struct session *session); +extern struct rlist session_on_auth; + +void +session_run_on_auth_triggers(const char *user_name); + void session_init(); diff --git a/test/box/auth.result b/test/box/auth.result new file mode 100644 index 0000000000000000000000000000000000000000..478ef191fdd5c51418c4f3baccb17af7638e0945 --- /dev/null +++ b/test/box/auth.result @@ -0,0 +1,133 @@ +session = box.session +--- +... +fiber = require('fiber') +--- +... +space = box.schema.space.create('tweedledum') +--- +... +index = space:create_index('primary', { type = 'hash' }) +--- +... +box.schema.user.create('test', {password='pass'}) +--- +... +box.schema.user.grant('test', 'read,write,execute', 'universe') +--- +... +box.schema.user.grant('guest', 'read,write,execute', 'universe') +--- +... +-- check how authentication trigger work +-- no args trigger +function auth_trigger() counter = counter + 1 end +--- +... +-- get user name as argument +function auth_trigger2(user_name) msg = 'user ' .. user_name .. ' is there' end +--- +... +net = { box = require('net.box') } +--- +... +-- set trigger +handle = session.on_auth(auth_trigger) +--- +... +-- check handle +type(handle) +--- +- function +... +-- check triggers list +#session.on_auth() +--- +- 1 +... +handle2 = session.on_auth(auth_trigger2) +--- +... +counter = 0 +--- +... +msg = '' +--- +... +LISTEN = require('uri').parse(box.cfg.listen) +--- +... +-- check connection with authentication(counter must be incremented) +c = net.box:new('test:pass@' .. LISTEN.host .. ':' .. LISTEN.service) +--- +... +while counter < 1 do fiber.sleep(0.001) end +--- +... +counter +--- +- 1 +... +msg +--- +- user test is there +... +-- check guest connection without authentication(no increment) +c1 = net.box:new(LISTEN.host, LISTEN.service) +--- +... +c1:ping() +--- +- true +... +counter +--- +- 1 +... +-- cleanup +c:close() +--- +... +c1:close() +--- +... +session.on_auth(nil, auth_trigger) +--- +... +session.on_auth(nil, auth_trigger2) +--- +... +session.on_auth() +--- +- [] +... +space:drop() +--- +... +session.uid() +--- +- 1 +... +session.user() +--- +- admin +... +session.sync() +--- +- 0 +... +session = nil +--- +... +fiber = nil +--- +... +box.schema.user.revoke('guest', 'read,write,execute', 'universe') +--- +... +box.schema.user.revoke('test', 'read,write,execute', 'universe') +--- +... +box.schema.user.drop('test', { if_exists = true}) +--- +... diff --git a/test/box/auth.test.lua b/test/box/auth.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..a8d65465dfd656aa136e5e6457399b146075f992 --- /dev/null +++ b/test/box/auth.test.lua @@ -0,0 +1,54 @@ +session = box.session +fiber = require('fiber') + +space = box.schema.space.create('tweedledum') +index = space:create_index('primary', { type = 'hash' }) +box.schema.user.create('test', {password='pass'}) +box.schema.user.grant('test', 'read,write,execute', 'universe') +box.schema.user.grant('guest', 'read,write,execute', 'universe') + +-- check how authentication trigger work +-- no args trigger +function auth_trigger() counter = counter + 1 end +-- get user name as argument +function auth_trigger2(user_name) msg = 'user ' .. user_name .. ' is there' end +net = { box = require('net.box') } + +-- set trigger +handle = session.on_auth(auth_trigger) +-- check handle +type(handle) +-- check triggers list +#session.on_auth() +handle2 = session.on_auth(auth_trigger2) +counter = 0 +msg = '' + +LISTEN = require('uri').parse(box.cfg.listen) + +-- check connection with authentication(counter must be incremented) +c = net.box:new('test:pass@' .. LISTEN.host .. ':' .. LISTEN.service) +while counter < 1 do fiber.sleep(0.001) end +counter +msg + +-- check guest connection without authentication(no increment) +c1 = net.box:new(LISTEN.host, LISTEN.service) +c1:ping() +counter + +-- cleanup +c:close() +c1:close() +session.on_auth(nil, auth_trigger) +session.on_auth(nil, auth_trigger2) +session.on_auth() +space:drop() +session.uid() +session.user() +session.sync() +session = nil +fiber = nil +box.schema.user.revoke('guest', 'read,write,execute', 'universe') +box.schema.user.revoke('test', 'read,write,execute', 'universe') +box.schema.user.drop('test', { if_exists = true})