Software / code / prosody-modules
Comparison
mod_auth_token/token_auth_utils.lib.lua @ 2956:d0ca211e1b0e
New HMAC token authentication module for Prosody.
| author | JC Brand <jc@opkode.com> |
|---|---|
| date | Tue, 27 Mar 2018 10:48:04 +0200 |
| child | 3472:ac1f63cdb6d6 |
comparison
equal
deleted
inserted
replaced
| 2938:f000ba14d531 | 2956:d0ca211e1b0e |
|---|---|
| 1 local base64 = require "util.encodings".base64; | |
| 2 local digest = require "openssl.digest"; | |
| 3 local hmac = require "openssl.hmac"; | |
| 4 local luatz = require "luatz"; | |
| 5 local otp = require "otp"; | |
| 6 | |
| 7 local DIGEST_TYPE = "SHA256"; | |
| 8 local OTP_DEVIATION = 1; | |
| 9 local OTP_DIGITS = 8; | |
| 10 local OTP_INTERVAL = 30; | |
| 11 | |
| 12 local nonce_cache = {}; | |
| 13 | |
| 14 function check_nonce(jid, otp, nonce) | |
| 15 -- We cache all nonces used per OTP, to ensure that a token cannot be used | |
| 16 -- more than once. | |
| 17 -- | |
| 18 -- We assume that the OTP is valid in the current time window. This is the | |
| 19 -- case because we only call check_nonce *after* the OTP has been verified. | |
| 20 -- | |
| 21 -- We only store one OTP per JID, so if a new OTP comes in, we wipe the | |
| 22 -- previous OTP and its cached nonces. | |
| 23 if nonce_cache[jid] == nil or nonce_cache[jid][otp] == nil then | |
| 24 nonce_cache[jid] = {} | |
| 25 nonce_cache[jid][otp] = {} | |
| 26 nonce_cache[jid][otp][nonce] = true | |
| 27 return true; | |
| 28 end | |
| 29 if nonce_cache[jid][otp][nonce] == true then | |
| 30 return false; | |
| 31 else | |
| 32 nonce_cache[jid][otp][nonce] = true; | |
| 33 return true; | |
| 34 end | |
| 35 end | |
| 36 | |
| 37 | |
| 38 function verify_token(username, password, realm, otp_seed, token_secret, log) | |
| 39 local totp = otp.new_totp_from_key(otp_seed, OTP_DIGITS, OTP_INTERVAL) | |
| 40 local token = string.match(password, "(%d+) ") | |
| 41 local otp = token:sub(1,8) | |
| 42 local nonce = token:sub(9) | |
| 43 local signature = base64.decode(string.match(password, " (.+)")) | |
| 44 local jid = username.."@"..realm | |
| 45 | |
| 46 if totp:verify(otp, OTP_DEVIATION, luatz.gmtime(luatz.time())) then | |
| 47 -- log("debug", "**** THE OTP WAS VERIFIED ****** "); | |
| 48 local hmac_ctx = hmac.new(token_secret, DIGEST_TYPE) | |
| 49 if signature == hmac_ctx:final(otp..nonce..jid) then | |
| 50 -- log("debug", "**** THE KEY WAS VERIFIED ****** "); | |
| 51 if check_nonce(jid, otp, nonce) then | |
| 52 -- log("debug", "**** THE NONCE WAS VERIFIED ****** "); | |
| 53 return true; | |
| 54 end | |
| 55 end | |
| 56 end | |
| 57 -- log("debug", "**** VERIFICATION FAILED ****** "); | |
| 58 return false; | |
| 59 end | |
| 60 | |
| 61 return { | |
| 62 OTP_DEVIATION = OTP_DIGITS, | |
| 63 OTP_DIGITS = OTP_DIGITS, | |
| 64 OTP_INTERVAL = OTP_INTERVAL, | |
| 65 DIGEST_TYPE = DIGEST_TYPE, | |
| 66 verify_token = verify_token; | |
| 67 } |