Mercurial > prosody-modules
comparison mod_http_oauth2/mod_http_oauth2.lua @ 4260:c539334dd01a
mod_http_oauth2: Rescope oauth client config into users' storage
This produces client_id of the form owner@host/random and prevents
clients from being deleted by registering an account with the same name
and then deleting the account, as well as having the client
automatically be deleted when the owner account is removed.
On one hand, this leaks the bare JID of the creator to users. On the
other hand, it makes it obvious who made the oauth application.
This module is experimental and only for developers, so this can be
changed if a better method comes up.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 21 Nov 2020 23:55:10 +0100 |
parents | 721b528c01e1 |
children | d3af5f94d6df |
comparison
equal
deleted
inserted
replaced
4259:721b528c01e1 | 4260:c539334dd01a |
---|---|
8 local encodings = require "util.encodings"; | 8 local encodings = require "util.encodings"; |
9 local base64 = encodings.base64; | 9 local base64 = encodings.base64; |
10 | 10 |
11 local tokens = module:depends("tokenauth"); | 11 local tokens = module:depends("tokenauth"); |
12 | 12 |
13 local clients = module:open_store("oauth2_clients"); | 13 local clients = module:open_store("oauth2_clients", "map"); |
14 local codes = module:open_store("oauth2_codes", "map"); | 14 local codes = module:open_store("oauth2_codes", "map"); |
15 | 15 |
16 local function oauth_error(err_name, err_desc) | 16 local function oauth_error(err_name, err_desc) |
17 return errors.new({ | 17 return errors.new({ |
18 type = "modify"; | 18 type = "modify"; |
58 if not params.redirect_uri then return oauth_error("invalid_request", "missing 'redirect_uri'"); end | 58 if not params.redirect_uri then return oauth_error("invalid_request", "missing 'redirect_uri'"); end |
59 if params.scope and params.scope ~= "" then | 59 if params.scope and params.scope ~= "" then |
60 return oauth_error("invalid_scope", "unknown scope requested"); | 60 return oauth_error("invalid_scope", "unknown scope requested"); |
61 end | 61 end |
62 | 62 |
63 local client, err = clients:get(params.client_id); | 63 local client_owner, client_host, client_id = jid.prepped_split(params.client_id); |
64 module:log("debug", "clients:get(%q) --> %q, %q", params.client_id, client, err); | 64 if client_host ~= module.host then |
65 return oauth_error("invalid_client", "incorrect credentials"); | |
66 end | |
67 local client, err = clients:get(client_owner, client_id); | |
65 if err then error(err); end | 68 if err then error(err); end |
66 if not client then | 69 if not client then |
67 return oauth_error("invalid_client", "incorrect credentials"); | 70 return oauth_error("invalid_client", "incorrect credentials"); |
68 end | 71 end |
69 | 72 |
70 local code = uuid.generate(); | 73 local code = uuid.generate(); |
71 assert(codes:set(params.client_id, code, { issued = os.time(), granted_jid = granted_jid, })); | 74 assert(codes:set(client_owner, client_id .. "#" .. code, {issued = os.time(); granted_jid = granted_jid})); |
72 | 75 |
73 local redirect = url.parse(params.redirect_uri); | 76 local redirect = url.parse(params.redirect_uri); |
74 local query = http.formdecode(redirect.query or ""); | 77 local query = http.formdecode(redirect.query or ""); |
75 if type(query) ~= "table" then query = {}; end | 78 if type(query) ~= "table" then query = {}; end |
76 table.insert(query, { name = "code", value = code }) | 79 table.insert(query, { name = "code", value = code }) |
93 if not params.code then return oauth_error("invalid_request", "missing 'code'"); end | 96 if not params.code then return oauth_error("invalid_request", "missing 'code'"); end |
94 if params.scope and params.scope ~= "" then | 97 if params.scope and params.scope ~= "" then |
95 return oauth_error("invalid_scope", "unknown scope requested"); | 98 return oauth_error("invalid_scope", "unknown scope requested"); |
96 end | 99 end |
97 | 100 |
98 local client, err = clients:get(params.client_id); | 101 local client_owner, client_host, client_id = jid.prepped_split(params.client_id); |
102 if client_host ~= module.host then | |
103 module:log("debug", "%q ~= %q", client_host, module.host); | |
104 return oauth_error("invalid_client", "incorrect credentials"); | |
105 end | |
106 local client, err = clients:get(client_owner, client_id); | |
99 if err then error(err); end | 107 if err then error(err); end |
100 if not client or client.secret ~= params.client_secret then | 108 if not client or client.client_secret ~= params.client_secret then |
101 return oauth_error("invalid_client", "incorrect credentials"); | 109 module:log("debug", "client_secret mismatch"); |
102 end | 110 return oauth_error("invalid_client", "incorrect credentials"); |
103 local code, err = codes:get(params.client_id, params.code); | 111 end |
112 local code, err = codes:get(client_owner, client_id .. "#" .. params.code); | |
104 if err then error(err); end | 113 if err then error(err); end |
105 if not code or type(code) ~= "table" or os.difftime(os.time(), code.issued) > 900 then | 114 if not code or type(code) ~= "table" or os.difftime(os.time(), code.issued) > 900 then |
106 return oauth_error("invalid_client", "incorrect credentials"); | 115 module:log("debug", "authorization_code invalid or expired: %q", code); |
107 end | 116 return oauth_error("invalid_client", "incorrect credentials"); |
108 assert(codes:set(params.client_id, params.code, nil)); | 117 end |
109 | 118 assert(codes:set(client_owner, client_id .. "#" .. params.code, nil)); |
110 | 119 |
111 return json.encode(new_access_token(code.granted_jid, nil, nil)); | 120 return json.encode(new_access_token(code.granted_jid, nil, nil)); |
112 end | 121 end |
113 | 122 |
114 local function check_credentials(request) | 123 local function check_credentials(request) |