Software /
code /
prosody
Comparison
util/sasl/oauthbearer.lua @ 12911:ab1164eda011
util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 01 Mar 2023 12:55:00 +0000 |
child | 12918:ed20555f163a |
comparison
equal
deleted
inserted
replaced
12910:5c90862e39aa | 12911:ab1164eda011 |
---|---|
1 local saslprep = require "util.encodings".stringprep.saslprep; | |
2 local nodeprep = require "util.encodings".stringprep.nodeprep; | |
3 local jid = require "util.jid"; | |
4 local json = require "util.json"; | |
5 local log = require "util.logger".init("sasl"); | |
6 local _ENV = nil; | |
7 | |
8 | |
9 local function oauthbearer(self, message) | |
10 if not message then | |
11 return "failure", "malformed-request"; | |
12 end | |
13 | |
14 if message == "\001" then | |
15 return "failure", "not-authorized"; | |
16 end | |
17 | |
18 local gs2_authzid, kvpairs = message:match("n,a=([^,]+),(.+)$"); | |
19 if not gs2_authzid then | |
20 return "failure", "malformed-request"; | |
21 end | |
22 | |
23 local auth_header; | |
24 for k, v in kvpairs:gmatch("([a-zA-Z]+)=([\033-\126 \009\r\n]*)\001") do | |
25 if k == "auth" then | |
26 auth_header = v; | |
27 break; | |
28 end | |
29 end | |
30 | |
31 if not auth_header then | |
32 return "failure", "malformed-request"; | |
33 end | |
34 | |
35 local username = jid.prepped_split(gs2_authzid); | |
36 | |
37 -- SASLprep username | |
38 username = saslprep(username); | |
39 | |
40 if not username or username == "" then | |
41 log("debug", "Username violates SASLprep."); | |
42 return "failure", "malformed-request", "Invalid username."; | |
43 end | |
44 | |
45 local _nodeprep = self.profile.nodeprep; | |
46 if _nodeprep ~= false then | |
47 username = (_nodeprep or nodeprep)(username); | |
48 if not username or username == "" then | |
49 return "failure", "malformed-request", "Invalid username or password." | |
50 end | |
51 end | |
52 | |
53 self.username = username; | |
54 | |
55 local token = auth_header:match("^Bearer (.+)$"); | |
56 | |
57 local correct, state, token_info = self.profile.oauthbearer(self, username, token, self.realm); | |
58 | |
59 if state == false then | |
60 return "failure", "account-disabled"; | |
61 elseif state == nil or not correct then | |
62 -- For token-level errors, RFC 7628 demands use of a JSON-encoded | |
63 -- challenge response upon failure. We relay additional info from | |
64 -- the auth backend if available. | |
65 return "challenge", json.encode({ | |
66 status = token_info and token_info.status or "invalid_token"; | |
67 scope = token_info and token_info.scope or nil; | |
68 ["openid-configuration"] = token_info and token_info.oidc_discovery_url or nil; | |
69 }); | |
70 end | |
71 | |
72 self.resource = token_info.resource; | |
73 self.role = token_info.role; | |
74 return "success"; | |
75 end | |
76 | |
77 local function init(registerMechanism) | |
78 registerMechanism("OAUTHBEARER", {"oauthbearer"}, oauthbearer); | |
79 end | |
80 | |
81 return { | |
82 init = init; | |
83 } |