feat(jwt) refactor token authentication plugin to use new luajwtjitsi version

This commit is contained in:
philip-cc 2022-04-19 11:06:20 +00:00 committed by GitHub
parent dbc8f21b01
commit 46dd88c91b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 100 deletions

View File

@ -61,7 +61,7 @@ case "$1" in
sed -i '/^\s*--\s*"token_verification"/ s/--\s*//' $PROSODY_HOST_CONFIG sed -i '/^\s*--\s*"token_verification"/ s/--\s*//' $PROSODY_HOST_CONFIG
# Install luajwt # Install luajwt
if ! luarocks install luajwtjitsi 2.0-0; then if ! luarocks install luajwtjitsi 3.0-0; then
echo "Failed to install luajwtjitsi - try installing it manually" echo "Failed to install luajwtjitsi - try installing it manually"
fi fi

View File

@ -33,6 +33,7 @@ function Util.new(module)
self.appId = module:get_option_string("app_id"); self.appId = module:get_option_string("app_id");
self.appSecret = module:get_option_string("app_secret"); self.appSecret = module:get_option_string("app_secret");
self.asapKeyServer = module:get_option_string("asap_key_server"); self.asapKeyServer = module:get_option_string("asap_key_server");
self.signatureAlgorithm = module:get_option_string("signature_algorithm");
self.allowEmptyToken = module:get_option_boolean("allow_empty_token"); self.allowEmptyToken = module:get_option_boolean("allow_empty_token");
self.cache = require"util.cache".new(cacheSize); self.cache = require"util.cache".new(cacheSize);
@ -85,6 +86,15 @@ function Util.new(module)
return nil; return nil;
end end
-- Set defaults for signature algorithm
if self.signatureAlgorithm == nil then
if self.asapKeyServer ~= nil then
self.signatureAlgorithm = "RS256"
elseif self.appSecret ~= nil then
self.signatureAlgorithm = "HS256"
end
end
--array of accepted issuers: by default only includes our appId --array of accepted issuers: by default only includes our appId
self.acceptedIssuers = module:get_option_array('asap_accepted_issuers',{self.appId}) self.acceptedIssuers = module:get_option_array('asap_accepted_issuers',{self.appId})
@ -143,94 +153,6 @@ function Util:get_public_key(keyId)
end end
end end
--- Verifies issuer part of token
-- @param 'issClaim' claim from the token to verify
-- @param 'acceptedIssuers' list of issuers to check
-- @return nil and error string or true for accepted claim
function Util:verify_issuer(issClaim, acceptedIssuers)
if not acceptedIssuers then
acceptedIssuers = self.acceptedIssuers
end
module:log("debug", "verify_issuer claim: %s against accepted: %s", issClaim, acceptedIssuers);
for i, iss in ipairs(acceptedIssuers) do
if iss == '*' then
-- "*" indicates to accept any issuer in the claims so return success
return true;
end
if issClaim == iss then
-- claim matches an accepted issuer so return success
return true;
end
end
-- if issClaim not found in acceptedIssuers, fail claim
return nil, "Invalid issuer ('iss' claim)";
end
--- Verifies audience part of token
-- @param 'audClaim' claim from the token to verify
-- @return nil and error string or true for accepted claim
function Util:verify_audience(audClaim)
module:log("debug", "verify_audience claim: %s against accepted: %s", audClaim, self.acceptedAudiences);
for i, aud in ipairs(self.acceptedAudiences) do
if aud == '*' then
-- "*" indicates to accept any audience in the claims so return success
return true;
end
if audClaim == aud then
-- claim matches an accepted audience so return success
return true;
end
end
-- if audClaim not found in acceptedAudiences, fail claim
return nil, "Invalid audience ('aud' claim)";
end
--- Verifies token
-- @param token the token to verify
-- @param secret the secret to use to verify token
-- @param acceptedIssuers the list of accepted issuers to check
-- @return nil and error or the extracted claims from the token
function Util:verify_token(token, secret, acceptedIssuers)
local claims, err = jwt.decode(token, secret, true);
if claims == nil then
return nil, err;
end
local alg = claims["alg"];
if alg ~= nil and (alg == "none" or alg == "") then
return nil, "'alg' claim must not be empty";
end
local issClaim = claims["iss"];
if issClaim == nil then
return nil, "'iss' claim is missing";
end
--check the issuer against the accepted list
local issCheck, issCheckErr = self:verify_issuer(issClaim, acceptedIssuers);
if issCheck == nil then
return nil, issCheckErr;
end
if self.requireRoomClaim then
local roomClaim = claims["room"];
if roomClaim == nil then
return nil, "'room' claim is missing";
end
end
local audClaim = claims["aud"];
if audClaim == nil then
return nil, "'aud' claim is missing";
end
--check the audience against the accepted list
local audCheck, audCheckErr = self:verify_audience(audClaim);
if audCheck == nil then
return nil, audCheckErr;
end
return claims;
end
--- Verifies token and process needed values to be stored in the session. --- Verifies token and process needed values to be stored in the session.
-- Token is obtained from session.auth_token. -- Token is obtained from session.auth_token.
-- Stores in session the following values: -- Stores in session the following values:
@ -255,11 +177,13 @@ function Util:process_and_verify_token(session, acceptedIssuers)
end end
end end
local pubKey; local key;
if session.public_key then if session.public_key then
-- We're using an public key stored in the session
module:log("debug","Public key was found on the session"); module:log("debug","Public key was found on the session");
pubKey = session.public_key; key = session.public_key;
elseif self.asapKeyServer and session.auth_token ~= nil then elseif self.asapKeyServer and session.auth_token ~= nil then
-- We're fetching an public key from an ASAP server
local dotFirst = session.auth_token:find("%."); local dotFirst = session.auth_token:find("%.");
if not dotFirst then return false, "not-allowed", "Invalid token" end if not dotFirst then return false, "not-allowed", "Invalid token" end
local header, err = json_safe.decode(basexx.from_url64(session.auth_token:sub(1,dotFirst-1))); local header, err = json_safe.decode(basexx.from_url64(session.auth_token:sub(1,dotFirst-1)));
@ -274,23 +198,38 @@ function Util:process_and_verify_token(session, acceptedIssuers)
if alg == nil then if alg == nil then
return false, "not-allowed", "'alg' claim is missing"; return false, "not-allowed", "'alg' claim is missing";
end end
if alg.sub(alg,1,2) ~= "RS" then -- do not remove - needed to protect jwt.decode in verify_token if alg.sub(alg,1,2) ~= "RS" then
return false, "not-allowed", "'kid' claim only support with RS family"; return false, "not-allowed", "'kid' claim only support with RS family";
end end
pubKey = self:get_public_key(kid); key = self:get_public_key(kid);
if pubKey == nil then if key == nil then
return false, "not-allowed", "could not obtain public key"; return false, "not-allowed", "could not obtain public key";
end end
elseif self.appSecret ~= nil then
-- We're using a symmetric secret
key = self.appSecret
end
if key == nil then
return false, "not-allowed", "signature verification key is missing";
end end
-- now verify the whole token -- now verify the whole token
local claims, msg; local claims, msg = jwt.verify(
if self.asapKeyServer then session.auth_token,
claims, msg = self:verify_token(session.auth_token, pubKey, acceptedIssuers); self.signatureAlgorithm,
else key,
claims, msg = self:verify_token(session.auth_token, self.appSecret, acceptedIssuers); acceptedIssuers,
end self.acceptedAudiences
)
if claims ~= nil then if claims ~= nil then
if self.requireRoomClaim then
local roomClaim = claims["room"];
if roomClaim == nil then
return false, "'room' claim is missing";
end
end
-- Binds room name to the session which is later checked on MUC join -- Binds room name to the session which is later checked on MUC join
session.jitsi_meet_room = claims["room"]; session.jitsi_meet_room = claims["room"];
-- Binds domain name to the session -- Binds domain name to the session