annotate mod_auth_token/README.markdown @ 5511:0860497152af

mod_http_oauth2: Record hash of client_id to allow future verification RFC 6819 section 5.2.2.2 states that refresh tokens MUST be bound to the client. In order to do that, we must record something that can definitely tie the client to the grant. Since the full client_id is so large (why we have this client_subset function), a hash is stored instead.
author Kim Alvefur <zash@zash.se>
date Fri, 02 Jun 2023 10:14:16 +0200
parents b4bcb84997e7
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2956
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
1 # mod_auth_token
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
2
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
3 This module enables Prosody to authenticate time-based one-time-pin (TOTP) HMAC tokens.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
4
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
5 This is an alternative to "external authentication" which avoids the need to
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
6 make a blocking HTTP call to the external authentication service (usually a web application backend).
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
7
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
8 Instead, the application generates the HMAC token, which is then sent to
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
9 Prosody via the XMPP client and Prosody verifies the authenticity of this
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
10 token.
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 If the token is verified, then the user is authenticated.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
13
3471
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
14 ## Luarocks dependencies
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
15
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
16 You'll need to install the following luarocks
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
17
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
18 otp 0.1-5
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
19 luatz 0.3-1
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
20
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
21 ## How to generate the TOTP seed and shared signing secret
2956
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
22
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
23 You'll need a shared OTP_SEED value for generating time-based one-time-pin
3471
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
24 (TOTP) values and a shared private key for signing the HMAC token.
2956
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
25
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
26 You can generate the OTP_SEED value with Python, like so:
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
27
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
28 >>> import pyotp
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
29 >>> pyotp.random_base32()
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
30 u'XVGR73KMZH2M4XMY'
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
31
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
32 and the shared secret key as follows:
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
33
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
34 >>> import pyotp
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
35 >>> pyotp.random_base32(length=32)
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
36 u'JYXEX4IQOEYFYQ2S3MC5P4ZT4SDHYEA7'
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
37
3471
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
38 ## Configuration
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
39
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
40 Firest you need to enable the relevant modules to your Prosody.cfg file.
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
41
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
42 Look for the line `modules_enabled` (either globally or for your
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
43 particular `VirtualHost`), and then add the following to tokens:
2956
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
44
3471
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
45 modules_enabled = {
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
46 -- Token authentication
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
47 "auth_token";
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
48 "sasl_token";
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
49 }
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
50
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
51 The previously generated token values also need to go into your Prosody.cfg file:
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
52
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
53 authentication = "token";
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
54 token_secret = "JYXEX4IQOEYFYQ2S3MC5P4ZT4SDHYEA7";
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
55 otp_seed = "XVGR73KMZH2M4XMY";
2956
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
56
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
57 The application that generates the tokens also needs access to these values.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
58
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
59 For an example on how to generate a token, take a look at the `generate_token`
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
60 function in the `test_token_auth.lua` file inside this directory.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
61
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
62 ## Custom SASL auth
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
63
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
64 This module depends on a custom SASL auth mechanism called X-TOKEN and which
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
65 is provided by the file `mod_sasl_token.lua`.
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
66
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
67 Prosody doesn't automatically pick up this file, so you'll need to update your
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
68 configuration file's `plugin_paths` to link to this subdirectory (for example
d0ca211e1b0e New HMAC token authentication module for Prosody.
JC Brand <jc@opkode.com>
parents:
diff changeset
69 to `/usr/lib/prosody-modules/mod_auth_token/`).
3471
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
70
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
71 ## Generating the token
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
72
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
73 Here's a Python snippet showing how you can generate the token that Prosody
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
74 will then verify:
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
75
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
76 import base64
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
77 import pyotp
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
78 import random
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
79
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
80 # Constants
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
81 OTP_INTERVAL = 30
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
82 OTP_DIGITS = 8
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
83
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
84 jid = '{}@{}'.format(username, domain)
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
85
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
86 otp_service = pyotp.TOTP(
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
87 OTP_SEED, # OTP_SEED must be set to the value generated previously (see above)
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
88 digits=OTP_DIGITS,
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
89 interval=OTP_INTERVAL
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
90 )
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
91 otp = otp_service.generate_otp(otp_service.timecode(datetime.utcnow()))
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
92
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
93 nonce = ''.join([str(random.randint(0, 9)) for i in range(32)])
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
94 string_to_sign = otp + nonce + jid
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
95 signature = hmac.new(token_secret, string_to_sign, hashlib.sha256).digest()
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
96 token = u"{} {}".format(otp+nonce, base64.b64encode(signature))
b4bcb84997e7 mod_auth_token: Update README.
JC Brand <jc@opkode.com>
parents: 2960
diff changeset
97