Uses JWT for token generation in prosody plugin.
This commit is contained in:
parent
5f6bba435c
commit
3406802aa8
|
@ -27,10 +27,9 @@ local provider = {};
|
||||||
|
|
||||||
local appId = module:get_option_string("app_id");
|
local appId = module:get_option_string("app_id");
|
||||||
local appSecret = module:get_option_string("app_secret");
|
local appSecret = module:get_option_string("app_secret");
|
||||||
local tokenLifetime = module:get_option_number("token_lifetime");
|
|
||||||
|
|
||||||
function provider.test_password(username, password)
|
function provider.test_password(username, password)
|
||||||
local result, msg = token_util.verify_password(password, appId, appSecret, tokenLifetime);
|
local result, msg = token_util.verify_password(password, appId, appSecret, nil);
|
||||||
if result == true then
|
if result == true then
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,25 +22,34 @@ end
|
||||||
|
|
||||||
local appId = parentCtx:get_option_string("app_id");
|
local appId = parentCtx:get_option_string("app_id");
|
||||||
local appSecret = parentCtx:get_option_string("app_secret");
|
local appSecret = parentCtx:get_option_string("app_secret");
|
||||||
local tokenLifetime = parentCtx:get_option_string("token_lifetime");
|
|
||||||
|
|
||||||
log("debug", "%s - starting MUC token verifier app_id: %s app_secret: %s token-lifetime: %s",
|
log("debug", "%s - starting MUC token verifier app_id: %s app_secret: %s",
|
||||||
tostring(host), tostring(appId), tostring(appSecret), tostring(tokenLifetime));
|
tostring(host), tostring(appId), tostring(appSecret));
|
||||||
|
|
||||||
local function handle_pre_create(event)
|
local function handle_pre_create(event)
|
||||||
|
|
||||||
local origin, stanza = event.origin, event.stanza;
|
local origin, stanza = event.origin, event.stanza;
|
||||||
local token = stanza:get_child("token", "http://jitsi.org/jitmeet/auth-token");
|
local token = stanza:get_child("token", "http://jitsi.org/jitmeet/auth-token");
|
||||||
|
|
||||||
-- token not required for admin users
|
-- token not required for admin users
|
||||||
local user_jid = stanza.attr.from;
|
local user_jid = stanza.attr.from;
|
||||||
if is_admin(user_jid) then
|
if is_admin(user_jid) then
|
||||||
log("debug", "Token not required from admin user: %s", user_jid);
|
log("debug", "Token not required from admin user: %s", user_jid);
|
||||||
return nil;
|
return nil;
|
||||||
end
|
end
|
||||||
log("debug", "Will verify token for user: %s ", user_jid);
|
|
||||||
|
local room = string.match(stanza.attr.to, "^(%w+)@");
|
||||||
|
log("debug", "Will verify token for user: %s, room: %s ", user_jid, room);
|
||||||
|
if room == nil then
|
||||||
|
log("error", "Unable to get name of the MUC room ? to: %s", stanza.attr.to);
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
|
||||||
if token ~= nil then
|
if token ~= nil then
|
||||||
token = token[1];
|
token = token[1];
|
||||||
end
|
end
|
||||||
local result, msg = token_util.verify_password(token, appId, appSecret, tokenLifetime);
|
|
||||||
|
local result, msg = token_util.verify_password(token, appId, appSecret, room);
|
||||||
if result ~= true then
|
if result ~= true then
|
||||||
log("debug", "Token verification failed: %s", msg);
|
log("debug", "Token verification failed: %s", msg);
|
||||||
origin.send(st.error_reply(stanza, "cancel", "not-allowed", msg));
|
origin.send(st.error_reply(stanza, "cancel", "not-allowed", msg));
|
||||||
|
|
|
@ -1,76 +1,38 @@
|
||||||
-- Token authentication
|
-- Token authentication
|
||||||
-- Copyright (C) 2015 Atlassian
|
-- Copyright (C) 2015 Atlassian
|
||||||
|
|
||||||
local hashes = require "util.hashes";
|
local jwt = require "luajwt";
|
||||||
|
|
||||||
local _M = {};
|
local _M = {};
|
||||||
|
|
||||||
local function calc_hash(password, appId, appSecret)
|
local function verify_password_impl(password, appId, appSecret, roomName)
|
||||||
local hash, room, ts = string.match(password, "(%w+)_(%w+)_(%d+)");
|
|
||||||
if hash ~= nil and room ~= nil and ts ~= nil then
|
|
||||||
log("debug", "Hash: '%s' room: '%s', ts: '%s'", hash, room, ts);
|
|
||||||
local toHash = room .. ts .. appId .. appSecret;
|
|
||||||
log("debug", "to be hashed: '%s'", toHash);
|
|
||||||
local hash = hashes.sha256(toHash, true);
|
|
||||||
log("debug", "hash: '%s'", hash);
|
|
||||||
return hash;
|
|
||||||
else
|
|
||||||
log("error", "Invalid password format: '%s'", password);
|
|
||||||
return nil;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function extract_hash(password)
|
local claims, err = jwt.decode(password, appSecret, true);
|
||||||
local hash, room, ts = string.match(password, "(%w+)_(%w+)_(%d+)");
|
if claims == nil then
|
||||||
return hash;
|
return nil, err;
|
||||||
end
|
|
||||||
|
|
||||||
local function extract_ts(password)
|
|
||||||
local hash, room, ts = string.match(password, "(%w+)_(%w+)_(%d+)");
|
|
||||||
return ts;
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_utc_timestamp()
|
|
||||||
return os.time(os.date("!*t")) * 1000;
|
|
||||||
end
|
|
||||||
|
|
||||||
local function verify_timestamp(ts, tokenLifetime)
|
|
||||||
return get_utc_timestamp() - ts <= tokenLifetime;
|
|
||||||
end
|
|
||||||
|
|
||||||
local function verify_password_impl(password, appId, appSecret, tokenLifetime)
|
|
||||||
|
|
||||||
if password == nil then
|
|
||||||
return nil, "password is missing";
|
|
||||||
end
|
|
||||||
|
|
||||||
if tokenLifetime == nil then
|
|
||||||
tokenLifetime = 24 * 60 * 60 * 1000;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local ts = extract_ts(password);
|
local issClaim = claims["iss"];
|
||||||
if ts == nil then
|
if issClaim == nil then
|
||||||
return nil, "timestamp not found in the password";
|
return nil, "Issuer field is missing";
|
||||||
end
|
end
|
||||||
local os_ts = get_utc_timestamp();
|
if issClaim ~= appId then
|
||||||
log("debug", "System TS: '%s' user TS: %s", tostring(os_ts), tostring(ts));
|
return nil, "Invalid application ID('iss' claim)";
|
||||||
local isValid = verify_timestamp(ts, tokenLifetime);
|
|
||||||
if not isValid then
|
|
||||||
return nil, "token expired";
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local realHash = calc_hash(password, appId, appSecret);
|
local roomClaim = claims["room"];
|
||||||
local givenhash = extract_hash(password);
|
if roomClaim == nil then
|
||||||
log("debug", "Compare '%s' to '%s'", tostring(realHash), tostring(givenhash));
|
return nil, "Room field is missing";
|
||||||
if realHash == givenhash then
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return nil, "invalid hash";
|
|
||||||
end
|
end
|
||||||
|
if roomName ~= nil and roomName ~= roomClaim then
|
||||||
|
return nil, "Invalid room name('room' claim)";
|
||||||
|
end
|
||||||
|
|
||||||
|
return true;
|
||||||
end
|
end
|
||||||
|
|
||||||
function _M.verify_password(password, appId, appSecret, tokenLifetime)
|
function _M.verify_password(password, appId, appSecret, roomName)
|
||||||
return verify_password_impl(password, appId, appSecret, tokenLifetime);
|
return verify_password_impl(password, appId, appSecret, roomName);
|
||||||
end
|
end
|
||||||
|
|
||||||
return _M;
|
return _M;
|
||||||
|
|
Loading…
Reference in New Issue