mod_auth_token/token_auth_utils.lib.lua
author JC Brand <jc@opkode.com>
Thu, 28 Feb 2019 12:31:54 +0100
changeset 3476 ac1f63cdb6d6
parent 2960 d0ca211e1b0e
child 3572 6b3181fe5617
permissions -rw-r--r--
mod_auth_token: Check realm against module.host
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2960
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     1
local base64 = require "util.encodings".base64;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     2
local digest = require "openssl.digest";
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     3
local hmac = require "openssl.hmac";
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     4
local luatz = require "luatz";
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     5
local otp = require "otp";
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     6
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     7
local DIGEST_TYPE = "SHA256";
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     8
local OTP_DEVIATION = 1;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
     9
local OTP_DIGITS = 8;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    10
local OTP_INTERVAL = 30;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    11
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    12
local nonce_cache = {};
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    13
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    14
function check_nonce(jid, otp, nonce)
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    15
	-- We cache all nonces used per OTP, to ensure that a token cannot be used
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    16
	-- more than once.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    17
	--
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    18
	-- We assume that the OTP is valid in the current time window. This is the
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    19
	-- case because we only call check_nonce *after* the OTP has been verified.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    20
	--
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    21
	-- We only store one OTP per JID, so if a new OTP comes in, we wipe the
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    22
	-- previous OTP and its cached nonces.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    23
	if nonce_cache[jid] == nil or nonce_cache[jid][otp] == nil then
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    24
		nonce_cache[jid] = {}
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    25
		nonce_cache[jid][otp] = {}
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    26
		nonce_cache[jid][otp][nonce] = true
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    27
		return true;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    28
	end
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    29
	if nonce_cache[jid][otp][nonce] == true then
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    30
		return false;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    31
	else
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    32
		nonce_cache[jid][otp][nonce] = true;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    33
		return true;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    34
	end
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    35
end
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    36
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    37
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    38
function verify_token(username, password, realm, otp_seed, token_secret, log)
3476
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    39
	if (realm ~= module.host) then
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    40
		log("debug", "Verification failed: realm ~= module.host");
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    41
		return false;
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    42
	end
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    43
2960
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    44
	local totp = otp.new_totp_from_key(otp_seed, OTP_DIGITS, OTP_INTERVAL)
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    45
	local token = string.match(password, "(%d+) ")
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    46
	local otp = token:sub(1,8)
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    47
	local nonce = token:sub(9)
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    48
	local signature = base64.decode(string.match(password, " (.+)"))
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    49
	local jid = username.."@"..realm
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    50
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    51
	if totp:verify(otp, OTP_DEVIATION, luatz.gmtime(luatz.time())) then
3476
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    52
		log("debug", "The TOTP was verified");
2960
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    53
		local hmac_ctx = hmac.new(token_secret, DIGEST_TYPE)
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    54
		if signature == hmac_ctx:final(otp..nonce..jid) then
3476
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    55
			log("debug", "The key was verified");
2960
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    56
			if check_nonce(jid, otp, nonce) then
3476
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    57
				log("debug", "The nonce was verified");
2960
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    58
				return true;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    59
			end
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    60
		end
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    61
	end
3476
ac1f63cdb6d6 mod_auth_token: Check realm against module.host
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
    62
	log("debug", "Verification failed");
2960
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    63
	return false;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    64
end
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    65
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    66
return {
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    67
	OTP_DEVIATION = OTP_DIGITS,
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    68
	OTP_DIGITS = OTP_DIGITS,
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    69
	OTP_INTERVAL = OTP_INTERVAL,
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    70
	DIGEST_TYPE = DIGEST_TYPE,
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    71
	verify_token = verify_token;
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
    72
}