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)