|
1 local http = require "net.http"; |
|
2 local async = require "util.async"; |
|
3 local json = require "util.json"; |
|
4 local sasl = require "util.sasl"; |
|
5 |
|
6 -- TODO -- local issuer_identity = module:get_option_string("oauth_external_issuer"); |
|
7 local oidc_discovery_url = module:get_option_string("oauth_external_discovery_url") |
|
8 local validation_endpoint = module:get_option_string("oauth_external_validation_endpoint"); |
|
9 |
|
10 local username_field = module:get_option_string("oauth_external_username_field", "preferred_username"); |
|
11 |
|
12 -- XXX Hold up, does whatever done here even need any of these things? Are we |
|
13 -- the OAuth client? Is the XMPP client the OAuth client? What are we??? |
|
14 -- TODO -- local client_id = module:get_option_string("oauth_external_client_id"); |
|
15 -- TODO -- local client_secret = module:get_option_string("oauth_external_client_secret"); |
|
16 |
|
17 --[[ More or less required endpoints |
|
18 digraph "oauth endpoints" { |
|
19 issuer -> discovery -> { registration validation } |
|
20 registration -> { client_id client_secret } |
|
21 { client_id client_secret validation } -> required |
|
22 } |
|
23 --]] |
|
24 |
|
25 local host = module.host; |
|
26 local provider = {}; |
|
27 |
|
28 function provider.get_sasl_handler() |
|
29 local profile = {}; |
|
30 profile.http_client = http.default; -- TODO configurable |
|
31 local extra = { oidc_discovery_url = oidc_discovery_url }; |
|
32 function profile:oauthbearer(token) |
|
33 if token == "" then |
|
34 return false, nil, extra; |
|
35 end |
|
36 |
|
37 local ret, err = async.wait_for(self.profile.http_client:request(validation_endpoint, |
|
38 { headers = { ["Authorization"] = "Bearer " .. token; ["Accept"] = "application/json" } })); |
|
39 if err then |
|
40 return false, nil, extra; |
|
41 end |
|
42 local response = ret and json.decode(ret.body); |
|
43 if not (ret.code >= 200 and ret.code < 300) then |
|
44 return false, nil, response or extra; |
|
45 end |
|
46 if type(response) ~= "table" or type(response[username_field]) ~= "string" then |
|
47 return false, nil, nil; |
|
48 end |
|
49 |
|
50 return response[username_field], true, response; |
|
51 end |
|
52 return sasl.new(host, profile); |
|
53 end |
|
54 |
|
55 module:provides("auth", provider); |